Advanced sound (was: Sprites - Rendering or Control?)

David Olofson <david.olofson at reologica.se> schrieb am 24 Feb 2001:

Further, I’d also like to address advanced audio/video integration and other
issues that seem to be totally ignored in anything but commercial top titles.
Why doesn’t anyone play anything more interesting that music + one-shot
sampled sound effects? With the CPU power we have nowadays, there should be
no problem having every single event affect the sound effects dynamically;
space ships should have engine sound that’s directly affected by the movement
of the ship, doppler effect etc.

GLtron does the following for it’s engine sound:

  • distance & speed based volume
  • panning according to sound source
  • doppler effects

It goes something like this:

Compute the angle between your viewing vector and the direction to the
sound source. Use that to compute a panning value between -1 and 1
(something like sin(angle)).

Compute distance and scale volume accordingly. Code snippet:

#define VOLSCALE_BASE 1000
*vol =
(dist2 > VOLSCALE_BASE * game->settings->game_speed) ?
(VOLSCALE_BASE * game->settings->game_speed / dist2) : (1.0);

dist2 is the distance squared. Sound volume is proportional to 1/r^2
where r is the distance. Since this has a singularity, we just clamped the
volume scale to 1.0 from a certain point on.

Compute frequency shift for doppler effect: The new frequency is:

v1,v2: speed
r: vector to the sound source
u: speed of sound

f’ = f * ( u + v1r/|r| ) / (u + v2r/|r| )

Then I pan the sound in a temporary buffer and frequency shift it on the fly
(using SDL_mixers Mix_SetPostMix functions) to the general audio stream.

The code for mixing the frequency shifted sound effect is as follows
(assumes signed 16 bit audio format):

void fxShift(float shift, Uint8 *target, Uint8 *source, int len, int *consumed) {
int i, j, k;
float l;
float pa = 0;

len /= 4;

for(i = 0; i < len; i++) { // LR pairs
for(j = 0; j < 2; j++) { // channels
pa = i * shift;
k = (int) pa;
l = pa - k;

  *(Sint16*) (target + 2 * j + 4 * i) +=
    ( *(Sint16*) (source + 2 * j + 4 * (k + 0) ) * ( 1 - l ) +
      *(Sint16*) (source + 2 * j + 4 * (k + 2) ) * ( l ) );
  
}

}
*consumed = ( (int)(len * shift + 0.49999) ) * 4;
}

Panning in-place:

void fxPan(float pan, float vol, Uint8 *buf, int len) {
int i;

float left_vol = - vol * ( -1.0 + pan ) / 2.0;
float right_vol = vol * ( 1.0 + pan ) / 2.0;

for(i = 0; i < len; i += 4) {
(Sint16) (buf + i) *= left_vol;
(Sint16) (buf + i + 2) *= right_vol;
}
}

Word of caution: this code does not check for overflowing Sint16’s

One thing that worried me a little was how to deal with the
3rd person camera. Do I make calculations based on camera or 'character’
position? I decided to use the character position troughout, but
use the camera viewing vector for panning.

  • Andreas