🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

an efficient sfx audio synthesis algorithm

Started by
2 comments, last by CCH Audio 9 years, 2 months ago

i've coded a lot of audio dsp and not much games, so this may be banal as i eg. haven't had much application for bitwise ops. it may not be the best source, perhaps it's still useful. sorriez if i'm duplicating stuf presented better elsewhere.

i enjoy synthesis to the extent where i limit my use of resources - so i stick to procedural audio and sound. i'm also "given" to efficient and "elegant" solutions, which more or less means very particular and narrow minded smile.png here's how i have gone about creating sound effects for a simple, ~minimalist game i'm working on -


the most basic element of the coutured sound event is the envelope.. unless the algorithm doesn't require it (eg. mass-spring or sample impulse to decaying resonance). the simplest envelope is linear, but the simplest envelope a person with a self image to protect implements is exponential -

envrate = .6 * SAMPLERATE;
envrate = pow(0.01, 1.0 / envrate);

env = 1.0; // initialise event

env *= envrate; // loop event

the loop also checks if the envelope is below a threshold and .. i implement envelopes with stages in a switch statement .. so terminating the envelope changes the stage. complex envelopes of course can have many stages, and even for single stage envelopes, i may have more than one "active" stage, eg. stage 1 lasts a single sample and recalculates stuf that is modulated, making synthesized events dynamic and more interesting smile.png

..and instead of doing this in a simpler way with ints or something, i like to smooth the attack of the envelope (which otherwise may be punishing to the ears with duration) by routing it through a low pass filter. i do this in the most banal fashion for an audio coder as well, 6dB filter smile.png

envf = pi2 * 50.f / SAMPLERATE; // w or angular frequency relating hertz to samplerate

envbuf = 0;

envbuf += envf * (env - envbuf); // loop this and use envbuf as the smoothed envelope

note envbuf would have to be treated for denormals if left running, if using a branch to limit when it runs to when it's being fed non-zero data, it's not necessary.

to reproduce the sound exactly, when the envelope is shut off, i would recommend zeroing out the lowpass buffer and other params smile.png

so we have an envelope describing an event.. now we need a signal to envelope.. doubles have much better performance tolerances here so i opt for them routinely.

simple case is to use white noise and envelope it, for explosions, all sorts of stuff by changing the envelope time.

my simplest class of explosion sound effects improve this by using the exponential envelope to modify the cutoff of the filter, which can sound very realistic with prudent parameterisation. i route the noise into the lowpass, then apply the envelope to this as the lowpass will apply some smoothing if it has been reset to zero.

the filter frequency has to remain below pi/2 (maybe below 1 theoretically but i have safely ignored this for short events) -

tbh i also streamline this by throwing out the filter cutoff coefficient altogether and replacing it entirely with the scaled envelope.. we want this ....

buf += cutoff * (signal - buf);

we can be "proper"
buf += (1.0 + env * scale) * cutoff * (signal - buf);

or just
buf += env * scale * (signal - buf);

or even drop the scale coefficient if the height of the envelope is convenient. as the sound drops to low frequencies, it is more visceral.

next, i wanted something more than white noise.

one of the main effects i needed was a bouncing sound, which is very dynamic. i used six sine oscillators at ratios of spherical harmonics (analysed basketball, perfect after i tuned down a few octaves..)

oscs can be floats, have two states, real and imag

s0 = 1.f; s1 = 0.f; // initialise

s0 -= w * s1;

s1 += w * s0;

sine output = s1, cosine = s0 (approximately.. "good enuf")

w is modulated in this case but iirc instability occurs above pi/4

there are simplifications of this form that can include decay and stuff. it won't run forever, needs to have the states reset to unity (x-y..) every now and then, or if your events last only a few seconds, just reset to 1 and 0/quadrature.

i could have used nonlinear processing (easy would be out * out * out) or clipping to add harmonics and impact and make a "pretty convincing spherical impact" but just the pitch and dynamic envelope modulation was nice. bounce sounds range from very short to over a second with a wide tonal range than is fun for the object. of course, you could use a sample, and modulate dynamics and pitch envelope as well, but procedural elitism may smite you.

the new part for me in these sounds was creating other complex events in the old fashioned way i know not much about..

the oscillator is initialised with two unsigned shorts. the selection of starting values is a tonal parameter.

..these settings gave me a nice gritty crunching sound i used as an impact sound -

switch (hs) {

case 1:

h0 = 30090; h1 = 31800;
hs = 2;
break;
case 2:
h0++; h1++;
(h0 & (h1 >> 2)) > 200 ? o = 24.f : o = -24.f;
hb += (1.0 + he * 19.0) * hf * (o - hb);
o = hb * he; outl += o; outr += o;

he *= hr; if (he < .0001) hb = he = hs = 0;

iirc the envelope was 0.6 seconds.. obviously changing any of these values or structure will affect the tone. i developed this sound from a sort of apple biting sound.. changing the >>2 to higher values produces increasingly slower stepping sounds.. bells and dings that i'm sure i've heard in games before. it's not the most amazing range ever, but if you dig around it does have several "ranges" of timbres that can be adapted to various things. of course, just incrementing two ints is not very exciting. the trick is to find possibilities that oscillate smile.png and of course there are many ways to do this.

also produced some cyclic sounds by eg. running the switch statement on a >> or / so incrementing steps or loops through coefficient sets.

so, a starting point, experiment.

i dunno maaan, i guess if there were a pac-man sfx guide i figure i'd probably have heard about it in my field? maybe not smile.png

neither a follower nor a leader behttp://www.xoxos.net
Advertisement

alright did a quick search for anyone else..

https://www.youtube.com/watch?&v=GtQdIYUtAHg

one short line of code, lots of sound.. obviously i am comparatively nescient :)

neither a follower nor a leader behttp://www.xoxos.net

..so i've cooked my sfx down to stuff like this...

//trigger sound

s = 1;//could do s = 61440 or somethnig for short sounds..

//audio routine

if (s) {out += (char)s*((s+43217)&91)&(s>>7|s>>12)<<6); s++}

just gotta hunt around for timbres, but as the video demonstrates, there's a lot of range. i'm sure there's a simple bitwise way to remove the conditional but i'm not expert enough with bitops to find it yet :)

neither a follower nor a leader behttp://www.xoxos.net

Cool stuff, you should break some of those algorithms down into actual synth modules.

This topic is closed to new replies.

Advertisement