From e91f243989fc8f617ad89fd41b2887174c39e817 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 16 Jun 2007 16:04:00 +0000 Subject: Clean up sound code Subversion-branch: /trunk/chocolate-doom Subversion-revision: 911 --- src/s_sound.c | 1129 +++++++++++++++++++++++++-------------------------------- 1 file changed, 493 insertions(+), 636 deletions(-) (limited to 'src/s_sound.c') diff --git a/src/s_sound.c b/src/s_sound.c index 56cb18c9..1477415e 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -23,10 +23,6 @@ // //----------------------------------------------------------------------------- - - - - #include #include @@ -45,42 +41,30 @@ #include "doomstat.h" - -// Purpose? -const char snd_prefixen[] -= { 'P', 'P', 'A', 'S', 'S', 'S', 'M', 'M', 'M', 'S', 'S', 'S' }; - -#define S_MAX_VOLUME 127 - // when to clip out sounds // Does not fit the large outdoor areas. -#define S_CLIPPING_DIST (1200*0x10000) + +#define S_CLIPPING_DIST (1200 * FRACUNIT) // Distance tp origin when sounds should be maxed out. // This should relate to movement clipping resolution // (see BLOCKMAP handling). -// In the source code release: (160*0x10000). Changed back to the +// In the source code release: (160*FRACUNIT). Changed back to the // Vanilla value of 200 (why was this changed?) -#define S_CLOSE_DIST (200*0x10000) - -#define S_ATTENUATOR ((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS) +#define S_CLOSE_DIST (200 * FRACUNIT) -// Adjustable by menu. -#define NORM_VOLUME snd_MaxVolume +// The range over which sound attenuates -#define NORM_PITCH 128 -#define NORM_PRIORITY 64 -#define NORM_SEP 128 +#define S_ATTENUATOR ((S_CLIPPING_DIST - S_CLOSE_DIST) >> FRACBITS) -#define S_PITCH_PERTURB 1 -#define S_STEREO_SWING (96*0x10000) +// Stereo separation -// percent attenuation from front to back -#define S_IFRACVOL 30 +#define S_STEREO_SWING (96 * FRACUNIT) -#define NA 0 -#define S_NUMCHANNELS 2 +#define NORM_PITCH 128 +#define NORM_PRIORITY 64 +#define NORM_SEP 128 // Disable music on OSX by default; there are problems with SDL_mixer. @@ -97,403 +81,476 @@ int snd_sfxdevice = SNDDEVICE_SB; typedef struct { // sound information (if null, channel avail.) - sfxinfo_t* sfxinfo; + sfxinfo_t *sfxinfo; // origin of sound - void* origin; + mobj_t *origin; // handle of the sound being played - int handle; + int handle; } channel_t; -// the set of channels available -static channel_t* channels; +// The set of channels available + +static channel_t *channels; // Maximum volume of a sound effect. // Internal default is max out of 0-15. + int sfxVolume = 8; // Maximum volume of music. + int musicVolume = 8; // Internal volume level, ranging from 0-127 -static int snd_SfxVolume; - -// whether songs are mus_paused -static boolean mus_paused; +static int snd_SfxVolume; -// music currently being played -static musicinfo_t* mus_playing=0; +// Whether songs are mus_paused -// following is set -// by the defaults code in M_misc: -// number of channels available +static boolean mus_paused; -int numChannels = 8; +// Music currently being played -static int nextcleanup; +static musicinfo_t *mus_playing = NULL; +// Number of channels to use +int numChannels = 8; // -// Internals. +// Initializes sound stuff, including volume +// Sets channels, SFX and music volume, +// allocates channel buffer, sets S_sfx lookup. // -int -S_getChannel -( void* origin, - sfxinfo_t* sfxinfo ); +void S_Init(int sfxVolume, int musicVolume) +{ + int i; -int -S_AdjustSoundParams -( mobj_t* listener, - mobj_t* source, - int* vol, - int* sep, - int* pitch ); + I_InitSound(); -void S_StopChannel(int cnum); + S_SetSfxVolume(sfxVolume); + S_SetMusicVolume(musicVolume); + // Allocating the internal channels for mixing + // (the maximum numer of sounds rendered + // simultaneously) within zone memory. + channels = Z_Malloc(numChannels*sizeof(channel_t), PU_STATIC, 0); + // Free all channels for use + for (i=0 ; isfxinfo) + { + // stop the sound playing + if (I_SoundIsPlaying(c->handle)) + { + I_StopSound(c->handle); + } + + // check to see if other channels are playing the sound + + for (i=0; isfxinfo == channels[i].sfxinfo) + { + break; + } + } + + // degrade usefulness of sound data + + c->sfxinfo->usefulness--; + c->sfxinfo = NULL; + } +} // // Per level startup code. // Kills playing sounds at start of level, // determines music if any, changes music. // + void S_Start(void) { - int cnum; - int mnum; - - // kill all playing sounds at start of level - // (trust me - a good idea) - for (cnum=0 ; cnum mus_e3m9) - // mnum -= mus_e3m9; - - S_ChangeMusic(mnum, true); - - nextcleanup = 15; -} + { + int spmus[]= + { + // Song - Who? - Where? + + mus_e3m4, // American e4m1 + mus_e3m2, // Romero e4m2 + mus_e3m3, // Shawn e4m3 + mus_e1m5, // American e4m4 + mus_e2m7, // Tim e4m5 + mus_e2m4, // Romero e4m6 + mus_e2m6, // J.Anderson e4m7 CHIRON.WAD + mus_e2m5, // Shawn e4m8 + mus_e1m9 // Tim e4m9 + }; + + if (gameepisode < 4) + { + mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1; + } + else + { + mnum = spmus[gamemap-1]; + } + } + + S_ChangeMusic(mnum, true); +} + +void S_StopSound(mobj_t *origin) +{ + int cnum; + for (cnum=0 ; cnumpriority >= sfxinfo->priority) + { + break; + } + } + + if (cnum == numChannels) + { + // FUCK! No lower priority. Sorry, Charlie. + return -1; + } + else + { + // Otherwise, kick out lower priority. + S_StopChannel(cnum); + } + } + + c = &channels[cnum]; + + // channel is decided to be cnum. + c->sfxinfo = sfxinfo; + c->origin = origin; + + return cnum; +} + +// +// Changes volume, stereo-separation, and pitch variables +// from the norm of a sound effect to be played. +// If the sound is not audible, returns a 0. +// Otherwise, modifies parameters and returns 1. +// + +static int S_AdjustSoundParams(mobj_t *listener, mobj_t *source, + int *vol, int *sep, int *pitch) { + fixed_t approx_dist; + fixed_t adx; + fixed_t ady; + angle_t angle; - int rc; - int sep; - int pitch; - int priority; - sfxinfo_t* sfx; - int cnum; - - mobj_t* origin = (mobj_t *) origin_p; - - - // Debug. - /*fprintf( stderr, - "S_StartSoundAtVolume: playing sound %d (%s)\n", - sfx_id, S_sfx[sfx_id].name );*/ - - // check for bogus sound # - if (sfx_id < 1 || sfx_id > NUMSFX) - I_Error("Bad sfx #: %d", sfx_id); - - sfx = &S_sfx[sfx_id]; - - // Initialize sound parameters - if (sfx->link) - { - pitch = sfx->pitch; - priority = sfx->priority; - volume += sfx->volume; - - if (volume < 1) - return; + // calculate the distance to sound origin + // and clip it if necessary + adx = abs(listener->x - source->x); + ady = abs(listener->y - source->y); + + // From _GG1_ p.428. Appox. eucledian distance fast. + approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1); - if (volume > snd_SfxVolume) - volume = snd_SfxVolume; - } - else - { - pitch = NORM_PITCH; - priority = NORM_PRIORITY; - } - - - // Check to see if it is audible, - // and if not, modify the params - if (origin && origin != players[consoleplayer].mo) - { - rc = S_AdjustSoundParams(players[consoleplayer].mo, - origin, - &volume, - &sep, - &pitch); - - if ( origin->x == players[consoleplayer].mo->x - && origin->y == players[consoleplayer].mo->y) - { - sep = NORM_SEP; + if (gamemap != 8 && approx_dist > S_CLIPPING_DIST) + { + return 0; } - if (!rc) - return; - } - else - { - sep = NORM_SEP; - } - - // hacks to vary the sfx pitches - if (sfx_id >= sfx_sawup - && sfx_id <= sfx_sawhit) - { - pitch += 8 - (M_Random()&15); - - if (pitch<0) - pitch = 0; - else if (pitch>255) - pitch = 255; - } - else if (sfx_id != sfx_itemup - && sfx_id != sfx_tink) - { - pitch += 16 - (M_Random()&31); - - if (pitch<0) - pitch = 0; - else if (pitch>255) - pitch = 255; - } - - // kill old sound - S_StopSound(origin); - - // try to find a channel - cnum = S_getChannel(origin, sfx); - - if (cnum<0) - return; - - // - // This is supposed to handle the loading/caching. - // For some odd reason, the caching is done nearly - // each time the sound is needed? - // - - // get lumpnum if necessary - if (sfx->lumpnum < 0) - sfx->lumpnum = I_GetSfxLumpNum(sfx); - - // increase the usefulness - if (sfx->usefulness++ < 0) - sfx->usefulness = 1; - - // Assigns the handle to one of the channels in the - // mix/output buffer. - channels[cnum].handle = I_StartSound(sfx_id, - cnum, - volume, - sep, - pitch, - priority); -} - -void -S_StartSound -( void* origin, - int sfx_id ) -{ -#ifdef SAWDEBUG - // if (sfx_id == sfx_sawful) - // sfx_id = sfx_itemup; -#endif - - S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume); + // angle of source to listener + angle = R_PointToAngle2(listener->x, + listener->y, + source->x, + source->y); + + if (angle > listener->angle) + { + angle = angle - listener->angle; + } + else + { + angle = angle + (0xffffffff - listener->angle); + } + + angle >>= ANGLETOFINESHIFT; + // stereo separation + *sep = 128 - (FixedMul(S_STEREO_SWING, finesine[angle]) >> FRACBITS); - // UNUSED. We had problems, had we not? -#ifdef SAWDEBUG -{ - int i; - int n; - - static mobj_t* last_saw_origins[10] = {1,1,1,1,1,1,1,1,1,1}; - static int first_saw=0; - static int next_saw=0; - - if (sfx_id == sfx_sawidl - || sfx_id == sfx_sawful - || sfx_id == sfx_sawhit) - { - for (i=first_saw;i!=next_saw;i=(i+1)%10) - if (last_saw_origins[i] != origin) - fprintf(stderr, "old origin 0x%lx != " - "origin 0x%lx for sfx %d\n", - last_saw_origins[i], - origin, - sfx_id); - - last_saw_origins[next_saw] = origin; - next_saw = (next_saw + 1) % 10; - if (next_saw == first_saw) - first_saw = (first_saw + 1) % 10; - - for (n=i=0; i1) - { - for (i=0; i S_CLIPPING_DIST) + { + approx_dist = S_CLIPPING_DIST; + } + + *vol = 15+ ((snd_SfxVolume-15) + *((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) + / S_ATTENUATOR; + } + else + { + // distance effect + *vol = (snd_SfxVolume + * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) + / S_ATTENUATOR; + } + + return (*vol > 0); } -#endif - -} +void S_StartSound(void *origin_p, int sfx_id) +{ + sfxinfo_t *sfx; + mobj_t *origin; + int rc; + int sep; + int pitch; + int priority; + int cnum; + int volume; + + origin = (mobj_t *) origin_p; + volume = snd_SfxVolume; + // check for bogus sound # + if (sfx_id < 1 || sfx_id > NUMSFX) + { + I_Error("Bad sfx #: %d", sfx_id); + } + sfx = &S_sfx[sfx_id]; -void S_StopSound(void *origin) -{ + // Initialize sound parameters + if (sfx->link) + { + pitch = sfx->pitch; + priority = sfx->priority; + volume += sfx->volume; + + if (volume < 1) + { + return; + } + + if (volume > snd_SfxVolume) + { + volume = snd_SfxVolume; + } + } + else + { + pitch = NORM_PITCH; + priority = NORM_PRIORITY; + } - int cnum; - for (cnum=0 ; cnumx == players[consoleplayer].mo->x + && origin->y == players[consoleplayer].mo->y) + { + sep = NORM_SEP; + } + + if (!rc) + { + return; + } + } + else + { + sep = NORM_SEP; } -} + // hacks to vary the sfx pitches + if (sfx_id >= sfx_sawup + && sfx_id <= sfx_sawhit) + { + pitch += 8 - (M_Random()&15); + + if (pitch < 0) + { + pitch = 0; + } + else if (pitch > 255) + { + pitch = 255; + } + } + else if (sfx_id != sfx_itemup + && sfx_id != sfx_tink) + { + pitch += 16 - (M_Random()&31); + + if (pitch < 0) + { + pitch = 0; + } + else if (pitch > 255) + { + pitch = 255; + } + } + // kill old sound + S_StopSound(origin); + // try to find a channel + cnum = S_GetChannel(origin, sfx); + if (cnum < 0) + { + return; + } + // + // This is supposed to handle the loading/caching. + // For some odd reason, the caching is done nearly + // each time the sound is needed? + // + // get lumpnum if necessary + if (sfx->lumpnum < 0) + { + sfx->lumpnum = I_GetSfxLumpNum(sfx); + } + // increase the usefulness + if (sfx->usefulness++ < 0) + { + sfx->usefulness = 1; + } + // Assigns the handle to one of the channels in the + // mix/output buffer. + channels[cnum].handle = I_StartSound(sfx_id, + cnum, + volume, + sep, + pitch, + priority); +} // // Stop and resume music, during game PAUSE. // + void S_PauseSound(void) { if (mus_playing && !mus_paused) { - I_PauseSong(mus_playing->handle); - mus_paused = true; + I_PauseSong(mus_playing->handle); + mus_paused = true; } } @@ -501,162 +558,133 @@ void S_ResumeSound(void) { if (mus_playing && mus_paused) { - I_ResumeSong(mus_playing->handle); - mus_paused = false; + I_ResumeSong(mus_playing->handle); + mus_paused = false; } } - // // Updates music & sounds // -void S_UpdateSounds(void* listener_p) -{ - int audible; - int cnum; - int volume; - int sep; - int pitch; - sfxinfo_t* sfx; - channel_t* c; - - mobj_t* listener = (mobj_t*)listener_p; - - - // Clean up unused data. - // This is currently not done for 16bit (sounds cached static). - // DOS 8bit remains. - /*if (gametic > nextcleanup) - { - for (i=1 ; i -1) - { - if (--S_sfx[i].usefulness == -1) - { - Z_ChangeTag(S_sfx[i].data, PU_CACHE); - S_sfx[i].data = 0; - } - } - } - nextcleanup = gametic + 15; - }*/ - - for (cnum=0 ; cnumsfxinfo; - - if (c->sfxinfo) - { - if (I_SoundIsPlaying(c->handle)) - { - // initialize parameters - volume = snd_SfxVolume; - pitch = NORM_PITCH; - sep = NORM_SEP; - - if (sfx->link) - { - pitch = sfx->pitch; - volume += sfx->volume; - if (volume < 1) - { - S_StopChannel(cnum); - continue; - } - else if (volume > snd_SfxVolume) - { - volume = snd_SfxVolume; - } - } - - // check non-local sounds for distance clipping - // or modify their params - if (c->origin && listener_p != c->origin) - { - audible = S_AdjustSoundParams(listener, - c->origin, - &volume, - &sep, - &pitch); - - if (!audible) - { - S_StopChannel(cnum); - } - else - I_UpdateSoundParams(c->handle, volume, sep, pitch); - } - } - else - { - // if channel is allocated but sound has stopped, - // free it - S_StopChannel(cnum); - } - } + c = &channels[cnum]; + sfx = c->sfxinfo; + + if (c->sfxinfo) + { + if (I_SoundIsPlaying(c->handle)) + { + // initialize parameters + volume = snd_SfxVolume; + pitch = NORM_PITCH; + sep = NORM_SEP; + + if (sfx->link) + { + pitch = sfx->pitch; + volume += sfx->volume; + if (volume < 1) + { + S_StopChannel(cnum); + continue; + } + else if (volume > snd_SfxVolume) + { + volume = snd_SfxVolume; + } + } + + // check non-local sounds for distance clipping + // or modify their params + if (c->origin && listener != c->origin) + { + audible = S_AdjustSoundParams(listener, + c->origin, + &volume, + &sep, + &pitch); + + if (!audible) + { + S_StopChannel(cnum); + } + else + { + I_UpdateSoundParams(c->handle, volume, sep, pitch); + } + } + } + else + { + // if channel is allocated but sound has stopped, + // free it + S_StopChannel(cnum); + } + } } - // kill music if it is a single-play && finished - // if ( mus_playing - // && !I_QrySongPlaying(mus_playing->handle) - // && !mus_paused ) - // S_StopMusic(); } - void S_SetMusicVolume(int volume) { if (volume < 0 || volume > 127) { - I_Error("Attempt to set music volume at %d", - volume); + I_Error("Attempt to set music volume at %d", + volume); } I_SetMusicVolume(127); I_SetMusicVolume(volume); } - - void S_SetSfxVolume(int volume) { - if (volume < 0 || volume > 127) - I_Error("Attempt to set sfx volume at %d", volume); + { + I_Error("Attempt to set sfx volume at %d", volume); + } snd_SfxVolume = volume; - } // // Starts some music with the music id found in sounds.h. // + void S_StartMusic(int m_id) { S_ChangeMusic(m_id, false); } -void -S_ChangeMusic -( int musicnum, - int looping ) +void S_ChangeMusic(int musicnum, int looping) { - musicinfo_t* music = NULL; - char namebuf[9]; + musicinfo_t* music = NULL; + char namebuf[9]; - if ( (musicnum <= mus_None) - || (musicnum >= NUMMUSIC) ) + if (musicnum <= mus_None || musicnum >= NUMMUSIC) { - I_Error("Bad music number %d", musicnum); + I_Error("Bad music number %d", musicnum); } else - music = &S_music[musicnum]; + { + music = &S_music[musicnum]; + } if (mus_playing == music) - return; + { + return; + } // shutdown old music S_StopMusic(); @@ -664,12 +692,12 @@ S_ChangeMusic // get lumpnum if neccessary if (!music->lumpnum) { - sprintf(namebuf, "d_%s", DEH_String(music->name)); - music->lumpnum = W_GetNumForName(namebuf); + sprintf(namebuf, "d_%s", DEH_String(music->name)); + music->lumpnum = W_GetNumForName(namebuf); } // load & register it - music->data = (void *) W_CacheLumpNum(music->lumpnum, PU_MUSIC); + music->data = W_CacheLumpNum(music->lumpnum, PU_MUSIC); music->handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum)); // play it @@ -683,192 +711,21 @@ boolean S_MusicPlaying(void) return I_QrySongPlaying(NULL); } - void S_StopMusic(void) { if (mus_playing) { - if (mus_paused) - I_ResumeSong(mus_playing->handle); - - I_StopSong(mus_playing->handle); - I_UnRegisterSong(mus_playing->handle); - Z_ChangeTag(mus_playing->data, PU_CACHE); - - mus_playing->data = 0; - mus_playing = 0; + if (mus_paused) + { + I_ResumeSong(mus_playing->handle); + } + + I_StopSong(mus_playing->handle); + I_UnRegisterSong(mus_playing->handle); + Z_ChangeTag(mus_playing->data, PU_CACHE); + + mus_playing->data = 0; + mus_playing = 0; } } -void S_StopChannel(int cnum) -{ - - int i; - channel_t* c = &channels[cnum]; - - if (c->sfxinfo) - { - // stop the sound playing - if (I_SoundIsPlaying(c->handle)) - { -#ifdef SAWDEBUG - if (c->sfxinfo == &S_sfx[sfx_sawful]) - fprintf(stderr, "stopped\n"); -#endif - I_StopSound(c->handle); - } - - // check to see - // if other channels are playing the sound - for (i=0 ; isfxinfo == channels[i].sfxinfo) - { - break; - } - } - - // degrade usefulness of sound data - c->sfxinfo->usefulness--; - - c->sfxinfo = 0; - } -} - - - -// -// Changes volume, stereo-separation, and pitch variables -// from the norm of a sound effect to be played. -// If the sound is not audible, returns a 0. -// Otherwise, modifies parameters and returns 1. -// -int -S_AdjustSoundParams -( mobj_t* listener, - mobj_t* source, - int* vol, - int* sep, - int* pitch ) -{ - fixed_t approx_dist; - fixed_t adx; - fixed_t ady; - angle_t angle; - - // calculate the distance to sound origin - // and clip it if necessary - adx = abs(listener->x - source->x); - ady = abs(listener->y - source->y); - - // From _GG1_ p.428. Appox. eucledian distance fast. - approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1); - - if (gamemap != 8 - && approx_dist > S_CLIPPING_DIST) - { - return 0; - } - - // angle of source to listener - angle = R_PointToAngle2(listener->x, - listener->y, - source->x, - source->y); - - if (angle > listener->angle) - angle = angle - listener->angle; - else - angle = angle + (0xffffffff - listener->angle); - - angle >>= ANGLETOFINESHIFT; - - // stereo separation - *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS); - - // volume calculation - if (approx_dist < S_CLOSE_DIST) - { - *vol = snd_SfxVolume; - } - else if (gamemap == 8) - { - if (approx_dist > S_CLIPPING_DIST) - approx_dist = S_CLIPPING_DIST; - - *vol = 15+ ((snd_SfxVolume-15) - *((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) - / S_ATTENUATOR; - } - else - { - // distance effect - *vol = (snd_SfxVolume - * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) - / S_ATTENUATOR; - } - - return (*vol > 0); -} - - - - -// -// S_getChannel : -// If none available, return -1. Otherwise channel #. -// -int -S_getChannel -( void* origin, - sfxinfo_t* sfxinfo ) -{ - // channel number to use - int cnum; - - channel_t* c; - - // Find an open channel - for (cnum=0 ; cnumpriority >= sfxinfo->priority) break; - - if (cnum == numChannels) - { - // FUCK! No lower priority. Sorry, Charlie. - return -1; - } - else - { - // Otherwise, kick out lower priority. - S_StopChannel(cnum); - } - } - - c = &channels[cnum]; - - // channel is decided to be cnum. - c->sfxinfo = sfxinfo; - c->origin = origin; - - return cnum; -} - - - - -- cgit v1.2.3