Change sound pitch
tracked
Journey Bunny
Straightforward gaming feature, common to things like engine sounds--but also anything that "changes speed or intensity over time".
I'd like to propose llAudioSoundPitch(float pitch_multiplier)
This function would affect playback for the currently attached sound in the following way:
final_pitch = sound_asset_pitch x emitter_pitch x sound_instance_pitch x pitch_multiplier
Where final_pitch is the sound played by the viewer, sound_asset_pitch is the pitch sampled from the audio asset, emitter_pitch is any distortion up or down currently applied by the viewer due to motion, and sound_instance_pitch is the current multiplier already in place (if there is one).
Defaults are 1 for everything except the original asset.
Eg, subsequent calls of llAudioSoundPitch(0.5) at timed intervals will successively cut the pitch in half, altering the sound.
In this way, a single sound file can be made to serve many uses, decreasing the need for "speed up", "slow down", "idle", "full speed" sound assets.
Log In
Spidey Linden
Merged in a post:
Add playback pitch control and fading
Huns Valen
Similar to https://feedback.secondlife.com/feature-requests/p/change-sound-pitch but with more details that would greatly increase usability.
I would use this for realistic aircraft engine sounds, instead of having to upload 11 distinct engine sounds (throttle 0 through 100, step 10) I could upload one or a few and use this to set the exact correct pitch. A throttle setting of e.g. 35 doesn't have to use the sound for 30, I can use finer gradations at lower throttle settings for higher precision, etc.
This is not just about vehicles. Anything a game designer would expect from UnrealEngine, Unity, etc. should be possible here as long as it doesn't require spatial audio or output chain effects (awareness of obstacles, EQ/reverb, etc.)
ROI:
- I don't have to upload 10 sounds to get 10 engine pitches, and you don't have to pay to store or stream them. The client's CPU does the work instead of your opex.
- You enable MUCH richer audio experiences that can give people a very large number of reasons to come back. Right now, SL is full of beautiful places that there's no reason to visit more than once because they are _not interactive at all._ The more ways you give us to do "game engine"-style stuff relevant in _this_ decade, the more acquisition and retention we can help you drive.
Some use cases would be:
- Vehicles (obviously)
- Musical instruments (you could do a full sequencer with this), whether preprogrammed, manual, or algorithmic/generative
- Interactive games/toys/art installations
- Mutable/frangible objects that respond to stress/tension/compression
- Various user interfaces (HUDs, kiosks, etc.)
- Critters
- Weapons
- Weather (beyond just the wind)
- Industrial machinery (motors, turbines, pumps, etc) that respond to conditions
- Anything else where a creator would want to go beyond "play it or loop it".
API:
- integer handle = llPlaySoundEffect(list attributes); // >= 0 on success, <0 = error code
- integer llAdjustSoundEffect(integer handle, list attributes); // 1 = success, <0 = error code
- integer llStopSoundEffect(integer handle); // 1 = success, 0 = fail
Attributes is a strided list, just like llSetPrimitiveParams() etc. Some particulars were selected to make them easy to integrate with OpenAL.
Basics:
- LINK_NUM, integer: Which prim in the linkset. Optional. Default current.
- SFX_SOUND, string|key: Same as llPlaySound(). Required.
- SFX_VOLUME, float: Same as llPlaySound(). Required.
Time:
- SFX_START_TIME, float: Moves the playhead to this many seconds into the sample at the beginning of playback. Optional, default 0.
- SFX_END_TIME, float: Can be used to shorten the sample at runtime. Optional, default full sample length. If <= SFX_START_TIME, throw an error
- SFX_SET_TIME, float: Immediately moves the playhead to a particular time index in a sound already playing. Optional. Does not account for playback speed. Setting time before SFX_START_TIME or after SFX_END_TIME throws an error. Does not modify playback direction (so if it's in SFX_PINGPONG [below], playback will keep going in whatever direction it was before.)
Speed: (This just makes the sample play faster or slower, inherently causing a pitch change, which is the main point for any game developer. It doesn't Paul-strech or pitch-correct it.)
- SFX_SPEED_START, float: Adjusts playback speed multiplier at start of playback. <1 = slower, >1 = faster. Optional, default = 1.
- SFX_SPEED_END, float: Sets target playback speed multiplier. Optional, default = 1. When SFX_SPEED_END != SFX_SPEED_START, the playback speed will be linear-interpolated (ramped) between SFX_SPEED_START and SFX_SPEED_END.
- SFX_SPEED_ADJUST, float: Adjusts the current playback speed multiplier of a sound already playing. If there's an active ramp (lerp) between SFX_SPEED_START and SFX_SPEED_END, it's cancelled.
- The ramp occurs between SFX_START_TIME (default 0) and SFX_END_TIME (default end of clip).
- The ramp will restart from SFX_SPEED_START if in SFX_LOOP (see below).
- The ramp will reverse direction along with playback direction if in SFX_PINGPONG (see below).
Loop/pingpong (mutually-exclusive, error if you try to set more than one):
- SFX_ONE_SHOT, boolean: Whether the sound should play once, and then stop. Optional. Default TRUE. This is only needed for adjusting a sound that's already playing in LOOP or PINGPONG, and will have the effect of canceling playback as soon as the playhead reaches either the start or end time, depending on whether it's in pingpong/loop.
- SFX_LOOP, boolean: Whether the sound should be played in a loop, like llLoopSound() except that it respects start/end time offsets.
- SFX_PINGPONG, boolean: Whether the sound should ping-pong (play forward from SFX_START_TIME until reaching SFX_END_TIME, then backwards to SFX_START_TIME, then again forwards, etc., until the sound is stopped.
Nexii Malthus
Note it might be good to come up with a modern SLua API as well as implementation alternative of how it could look like in a modern language with rich data structures instead of the list-based llFunction coding style that we are heavily used to.
Huns Valen
Nexii Malthus
local throttle = 0.35
local engine = ll.PlaySoundEffect{
sound = "jet_engine_loop",
volume = 1.0,
loop = true,
speed_start = 0.6 + throttle * 0.8
}
ll.AdjustSoundEffect(engine, {
speed_adjust = 0.6 + throttle * 0.8
})
ll.StopSoundEffect(handle)
Nexii Malthus
Huns Valen
object-based approach
local engine = llsound.play(soundName, {
volume = 1.0,
loop = true,
speed = 0.6 + throttle * 0.8
})
engine.adjustSpeed(0.6 + throttle * 0.8)
Huns Valen
Examples:
// Minimum, just play a sound.
integer handle = llPlaySoundEffect([
SFX_SOUND, "door_click",
SFX_VOLUME, 1.0
]);
// Set up an engine sound.
float throttle = 0.35; // 0–1
integer handle = llPlaySoundEffect([
SFX_SOUND, "jet_engine_loop",
SFX_VOLUME, 1.0,
SFX_LOOP, TRUE,
SFX_SPEED_START, 0.6 + throttle * 0.8
]);
// Modulate engine sound at runtime.
llAdjustSoundEffect(handle, [
SFX_SPEED_ADJUST, 0.6 + throttle * 0.8
]);
// Weapon charge-up sound.
integer handle = llPlaySoundEffect([
SFX_SOUND, "energy_charge",
SFX_VOLUME, 1.0,
SFX_SPEED_START, 0.5,
SFX_SPEED_END, 1.6
]);
// You have a "sound sprite" with a bunch of different hit sounds. You want to play one in particular.
// One asset load => many distinct sounds.
integer handle = llPlaySoundEffect([
SFX_SOUND, "metal_impacts",
SFX_VOLUME, 1.0,
SFX_START_TIME, 1.8,
SFX_END_TIME, 2.6
]);
// Motor sound that ping-pongs back and forth in a loop.
integer handle = llPlaySoundEffect([
SFX_SOUND, "servo_loop",
SFX_VOLUME, 0.7,
SFX_START_TIME, 0.2,
SFX_END_TIME, 1.4,
SFX_PINGPONG, TRUE
]);
// Musical instrument.
float pitch = 1.25;
integer handle = llPlaySoundEffect([
SFX_SOUND, "piano_note",
SFX_VOLUME, 1.0,
SFX_SPEED_START, pitch
]);
// DJ looper lets you jump 3.5 seconds into a loop. (Assumes handle is already playing.)
llAdjustSoundEffect(handle, [
SFX_SET_TIME, 3.5
]);
// Stop the sound.
llStopSoundEffect(handle);
Soanos Pacer
Playback pitch, Pitch shifting, playback speed, and volume would be good to have, with additional option to vary sound volume.
If anyone remembers how Protracker works, that would be close to what I would like to see.
Huns Valen
Soanos Pacer Covered above ^^^, definitely with you re: .mod and other tracker formats. Timers can run at ~20Hz which MIGHT be good enough for playing back melodies, depending on how consistent the timing is + how predictable the code path from timer entry to playing sound. If it's steady enough, it should be possible to write sequencers and full-on trackers. If not, it will still be useful for all other purposes where you'd want to do these things (but not on a musical cadence).
Broken Voxel
UPBOATED [Pun Intended] hehe, but seriously, this is a great idea.
Gun Stratten
This can be used for more then just engine sounds. Anything that can benefit from slight variations. bullet sounds? footsteps? Door opening with a 10% Swing in pitch can make a world of difference.
Nelson Jenkins
I've been sitting on a JIRA feature request for this for over a decade. Vehicles in SL with actual engine dynamics - especially necessary once game_control hits main grid - will never make sense until this happens. I've also got a ton of other projects where this could be useful, especially a MIDI sequencer.
Also - this only needs to be pitch shifting in the sense of adjusting the sample playback speed. That is, playback time doesn't need to remain constant. So that should be a pretty simple addition. The FMOD API specifically refers to pitch shifting as a constant-time operation that just adjusts pitch - I don't know if that's computationally wise in real time en masse, and the distortion would be unhelpful. Resampling alone would be enough and would make more sense for virtually all SL applications. I'm not sure how that's done in FMOD at first glance but should be a trivial operation.
Spidey Linden
marked this post as
tracked
Issue tracked. We have no estimate when it may be implemented. Please see future updates here.
Jabadahut50 Resident
We've needed this for a very long time. I'd like to see more than just pitch, but pitch alone would dramatically increase the utility of sounds in SL.
Extrude Ragu
This feature will become more important when
game_control
reaches the grid and people start driving vehicles with gamepad.That's because for things like vehicles being controlled with a gamepad, players are going to really notice the disconnect between the sound being heard and the input on their controller, and make the game appear to be broken.
Load More
→