From c2035e5ff7ee83997c906010e613f1471c01867e Mon Sep 17 00:00:00 2001 From: James Haley Date: Mon, 16 Jun 2008 21:52:45 -0500 Subject: [PATCH] Imported new Eternity Engine sound code. Applied EE priority/singularity/pitch/volume bug fixes. Fixed conflicts between SDL.h and z_zone.h. --- .gitignore | 5 + Source/I_main.c | 42 ++- Source/I_sound.c | 752 +++++++++++++++++++++++++++++++--------------- Source/I_sound.h | 14 +- Source/I_system.c | 6 +- Source/I_video.c | 5 +- Source/S_sound.c | 741 ++++++++++++++++++++++++++------------------- Source/Sounds.h | 3 + Source/Z_zone.h | 8 + WinMBF.dsp | 240 +++++++++++---- 10 files changed, 1200 insertions(+), 616 deletions(-) diff --git a/.gitignore b/.gitignore index 674deb69..48c5306e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,8 @@ .*.swp .DS_store # Simulated Subversion default ignores end here +# The contents of the svn:ignore property on the branch root. +/Debug +/WinMBF.opt +/WinMBF.plg +/WinMBF.ncb diff --git a/Source/I_main.c b/Source/I_main.c index 193facdb..ef91273c 100644 --- a/Source/I_main.c +++ b/Source/I_main.c @@ -28,13 +28,14 @@ static const char rcsid[] = "$Id: i_main.c,v 1.8 1998/05/15 00:34:03 killough Exp $"; - + +#include "SDL.h" // haleyjd + +#include "z_zone.h" #include "doomdef.h" #include "m_argv.h" #include "d_main.h" -#include "i_system.h" - -#include "SDL.h" // haleyjd +#include "i_system.h" void I_Quit(void); @@ -52,16 +53,41 @@ int main(int argc, char **argv) myargc = argc; myargv = argv; + // SoM: From CHOCODOOM Thank you fraggle!! +#ifdef _WIN32 + + // Allow -gdi as a shortcut for using the windib driver. + + //! + // @category video + // @platform windows + // + // Use the Windows GDI driver instead of DirectX. + // + + // From the SDL 1.2.10 release notes: + // + // > The "windib" video driver is the default now, to prevent + // > problems with certain laptops, 64-bit Windows, and Windows + // > Vista. + // + // The hell with that. + + // SoM: the gdi interface is much faster for windowed modes which are more + // commonly used. Thus, GDI is default. + if(M_CheckParm("-directx")) + putenv("SDL_VIDEODRIVER=directx"); + else if(M_CheckParm("-gdi") > 0 || getenv("SDL_VIDEODRIVER") == NULL) + putenv("SDL_VIDEODRIVER=windib"); +#endif + // haleyjd: init SDL if(SDL_Init(INIT_FLAGS) == -1) { puts("Failed to initialize SDL library.\n"); return -1; } - - // haleyjd: ignore mouse events at startup - SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); - + // haleyjd: set key repeat properties SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY/2, SDL_DEFAULT_REPEAT_INTERVAL*4); diff --git a/Source/I_sound.c b/Source/I_sound.c index 0d6273e8..2ccfbf2d 100644 --- a/Source/I_sound.c +++ b/Source/I_sound.c @@ -29,15 +29,13 @@ static const char rcsid[] = "$Id: i_sound.c,v 1.15 1998/05/03 22:32:33 killough Exp $"; -#include -//#include - // haleyjd #include "SDL.h" #include "SDL_audio.h" #include "SDL_mixer.h" #include +#include "z_zone.h" #include "doomstat.h" #include "mmus2mid.h" //jff 1/16/98 declarations for MUS->MIDI converter #include "i_sound.h" @@ -49,6 +47,8 @@ rcsid[] = "$Id: i_sound.c,v 1.15 1998/05/03 22:32:33 killough Exp $"; // Needed for calling the actual sound output. int SAMPLECOUNT = 512; +void I_CacheSound(sfxinfo_t *sound); + // haleyjd #define MAX_CHANNELS 32 #define NUM_CHANNELS 256 @@ -67,8 +67,8 @@ boolean mus_init = false; int detect_voices; //jff 3/4/98 enables voice detection prior to install_sound //jff 1/22/98 make these visible here to disable sound/music on install err -// MWM 2000-01-08: Sample rate in samples/second -int snd_samplerate=11025; +// haleyjd 10/28/05: updated for Julian's music code, need full quality now +int snd_samplerate = 44100; // The actual output device. int audio_fd; @@ -94,6 +94,10 @@ typedef struct { // Hardware left and right channel volume lookup. int *leftvol_lookup; int *rightvol_lookup; + // haleyjd 06/16/08: channel lock -- do not modify when locked! + volatile int lock; + // haleyjd 06/16/08: unique id number + int idnum; } channel_info_t; channel_info_t channelinfo[MAX_CHANNELS]; @@ -104,21 +108,57 @@ int steptable[256]; // Volume lookups. int vol_lookup[128*256]; -/* cph - * stopchan - * Stops a sound, unlocks the data - */ -static void stopchan(int i) +// +// stopchan +// +// cph +// Stops a sound, unlocks the data +// +static void stopchan(int handle) { - if(!snd_init) - return; + int cnum; - if(channelinfo[i].data) /* cph - prevent excess unlocks */ +#ifdef RANGECHECK + // haleyjd 02/18/05: bounds checking + if(handle < 0 || handle >= MAX_CHANNELS) + return; +#endif + + // haleyjd 02/18/05: sound channel locking in case of + // multithreaded access to channelinfo[].data. Make Eternity + // sleep for the minimum timeslice to give another thread + // chance to clear the lock. + while(channelinfo[handle].lock) + SDL_Delay(1); + + if(channelinfo[handle].data) { - channelinfo[i].data = NULL; + channelinfo[handle].data = NULL; + + if(channelinfo[handle].id) + { + // haleyjd 06/03/06: see if we can free the sound + for(cnum = 0; cnum < MAX_CHANNELS; ++cnum) + { + if(cnum == handle) + continue; + if(channelinfo[cnum].id && + channelinfo[cnum].id->data == channelinfo[handle].id->data) + return; // still being used by some channel + } + + // set sample to PU_CACHE level + Z_ChangeTag(channelinfo[handle].id->data, PU_CACHE); + } } + + channelinfo[handle].id = NULL; } +#define SOUNDHDRSIZE 8 + +// +// addsfx // // This function adds a sound to the // list of currently active sounds, @@ -127,58 +167,136 @@ static void stopchan(int i) // Returns a handle. // // haleyjd: needs to take a sfxinfo_t ptr, not a sound id num +// haleyjd 06/03/06: changed to return boolean for failure or success // -int addsfx(sfxinfo_t *sfx, int channel) +static boolean addsfx(sfxinfo_t *sfx, int channel) { - size_t len; + size_t lumplen; int lump; - if(!snd_init) - return channel; +#ifdef RANGECHECK + if(channel < 0 || channel >= MAX_CHANNELS) + I_Error("addsfx: channel out of range!\n"); +#endif + + // haleyjd 02/18/05: null ptr check + if(!snd_init || !sfx) + return false; stopchan(channel); // We will handle the new SFX. // Set pointer to raw data. - // haleyjd 11/05/03: rewrote to minimize work and fully support - // precaching - // haleyjd: Eternity sfxinfo_t does not have a lumpnum field lump = I_GetSfxLumpNum(sfx); // replace missing sounds with a reasonable default if(lump == -1) lump = W_GetNumForName("DSPISTOL"); + + lumplen = W_LumpLength(lump); + + // haleyjd 10/08/04: do not play zero-length sound lumps + if(lumplen <= SOUNDHDRSIZE) + return false; - if(!sfx->data) - sfx->data = W_CacheLumpNum(lump, PU_STATIC); + // haleyjd 06/03/06: rewrote again to make sound data properly freeable + if(sfx->data == NULL) + { + byte *data; + Uint32 samplerate, samplelen; - /* Find padded length */ - len = W_LumpLength(lump); - len -= 8; + // haleyjd: this should always be called (if lump is already loaded, + // W_CacheLumpNum handles that for us). + data = (byte *)W_CacheLumpNum(lump, PU_STATIC); + + // Check the header, and ensure this is a valid sound + if(data[0] != 0x03 || data[1] != 0x00) + { + Z_ChangeTag(data, PU_CACHE); + return false; + } + + samplerate = (data[3] << 8) | data[2]; + samplelen = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4]; + + // don't play sounds that think they're longer than they really are + if(samplelen > lumplen - SOUNDHDRSIZE) + { + Z_ChangeTag(data, PU_CACHE); + return false; + } + + sfx->alen = (Uint32)(((ULong64)samplelen * snd_samplerate) / samplerate); + sfx->data = Z_Malloc(sfx->alen, PU_STATIC, &sfx->data); + + // haleyjd 04/23/08: Convert sound to target samplerate + if(sfx->alen != samplelen) + { + unsigned int i; + byte *dest = (byte *)sfx->data; + byte *src = data + SOUNDHDRSIZE; + + unsigned int step = (samplerate << 16) / snd_samplerate; + unsigned int stepremainder = 0, j = 0; + + // do linear filtering operation + for(i = 0; i < sfx->alen && j < samplelen - 1; ++i) + { + int d = (((unsigned int)src[j ] * (0x10000 - stepremainder)) + + ((unsigned int)src[j+1] * stepremainder)) >> 16; + + if(d > 255) + dest[i] = 255; + else if(d < 0) + dest[i] = 0; + else + dest[i] = (byte)d; + + stepremainder += step; + j += (stepremainder >> 16); + + stepremainder &= 0xffff; + } + // fill remainder (if any) with final sample byte + for(; i < sfx->alen; ++i) + dest[i] = src[j]; + } + else + { + // sound is already at target samplerate, copy data + memcpy(sfx->data, data + SOUNDHDRSIZE, samplelen); + } + + // haleyjd 06/03/06: don't need original lump data any more + Z_ChangeTag(data, PU_CACHE); + } + else + Z_ChangeTag(sfx->data, PU_STATIC); // reset to static cache level channelinfo[channel].data = sfx->data; - /* Set pointer to end of raw data. */ - channelinfo[channel].enddata = channelinfo[channel].data + len - 1; - channelinfo[channel].samplerate = (channelinfo[channel].data[3]<<8)+channelinfo[channel].data[2]; - channelinfo[channel].data += 8; /* Skip header */ + // Set pointer to end of raw data. + channelinfo[channel].enddata = (byte *)sfx->data + sfx->alen - 1; channelinfo[channel].stepremainder = 0; - // Should be gametic, I presume. - channelinfo[channel].starttime = gametic; - // Preserve sound SFX id, - // e.g. for avoiding duplicates of chainsaw. + // Preserve sound SFX id channelinfo[channel].id = sfx; - return channel; + return true; } int forceFlipPan; -static void updateSoundParams(int handle, int volume, int seperation, int pitch) +// +// updateSoundParams +// +// Changes sound parameters in response to stereo panning and relative location +// change. +// +static void updateSoundParams(int handle, int volume, int separation, int pitch) { int slot = handle; int rightvol; @@ -189,35 +307,36 @@ static void updateSoundParams(int handle, int volume, int seperation, int pitch) return; #ifdef RANGECHECK - if(handle>=MAX_CHANNELS) + if(handle < 0 || handle >= MAX_CHANNELS) I_Error("I_UpdateSoundParams: handle out of range"); #endif + // Set stepping // MWM 2000-12-24: Calculates proportion of channel samplerate // to global samplerate for mixing purposes. // Patched to shift left *then* divide, to minimize roundoff errors // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz if(pitched_sounds) - channelinfo[slot].step = step + (((channelinfo[slot].samplerate<<16)/snd_samplerate)-65536); + channelinfo[slot].step = step; else - channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/snd_samplerate); + channelinfo[slot].step = 1 << 16; // Separation, that is, orientation/stereo. // range is: 1 - 256 - seperation += 1; + separation += 1; // SoM 7/1/02: forceFlipPan accounted for here if(forceFlipPan) - seperation = 257 - seperation; + separation = 257 - separation; // Per left/right channel. // x^2 seperation, // adjust volume properly. - volume *= 8; + //volume *= 8; - leftvol = volume - ((volume*seperation*seperation) >> 16); - seperation = seperation - 257; - rightvol= volume - ((volume*seperation*seperation) >> 16); + leftvol = volume - ((volume*separation*separation) >> 16); + separation = separation - 257; + rightvol= volume - ((volume*separation*separation) >> 16); // Sanity check, clamp volume. if(rightvol < 0 || rightvol > 127) @@ -228,33 +347,36 @@ static void updateSoundParams(int handle, int volume, int seperation, int pitch) // Get the proper lookup table piece // for this volume level??? - channelinfo[slot].leftvol_lookup = &vol_lookup[leftvol*256]; + channelinfo[slot].leftvol_lookup = &vol_lookup[leftvol*256]; channelinfo[slot].rightvol_lookup = &vol_lookup[rightvol*256]; } +// // SFX API -// Note: this was called by S_Init. -// However, whatever they did in the -// old DPMS based DOS version, this -// were simply dummies in the Linux -// version. -// See soundserver initdata(). // +// +// I_UpdateSoundParams +// // Update the sound parameters. Used to control volume, // pan, and pitch changes such as when a player turns. - +// void I_UpdateSoundParams(int handle, int vol, int sep, int pitch) { if(!snd_init) return; - SDL_LockAudio(); updateSoundParams(handle, vol, sep, pitch); - SDL_UnlockAudio(); } -void I_SetChannels() +// +// I_SetChannels +// +// Init internal lookups (raw data, mixing buffer, channels). +// This function sets up internal lookups used during +// the mixing process. +// +void I_SetChannels(void) { int i; int j; @@ -262,16 +384,15 @@ void I_SetChannels() int *steptablemid = steptable + 128; // Okay, reset internal mixing channels to zero. - for(i = 0; i < MAX_CHANNELS; i++) + for(i = 0; i < MAX_CHANNELS; ++i) { memset(&channelinfo[i], 0, sizeof(channel_info_t)); } // This table provides step widths for pitch parameters. - // I fail to see that this is currently used. for(i=-128 ; i<128 ; i++) { - steptablemid[i] = (int)(pow(1.2, ((double)i/(64.0*snd_samplerate/11025)))*65536.0); + steptablemid[i] = (int)(pow(1.2, (double)i / 64.0) * 65536.0); } @@ -289,7 +410,9 @@ void I_SetChannels() } } - +// +// I_SetSfxVolume +// void I_SetSfxVolume(int volume) { // Identical to DOS. @@ -297,93 +420,141 @@ void I_SetSfxVolume(int volume) // the menu/config file setting // to the state variable used in // the mixing. - snd_SfxVolume = volume; + + snd_SfxVolume = volume; } // jff 1/21/98 moved music volume down into MUSIC API with the rest +// +// I_GetSfxLumpNum // // Retrieve the raw data lump index // for a given SFX name. // -int I_GetSfxLumpNum(sfxinfo_t* sfx) +int I_GetSfxLumpNum(sfxinfo_t *sfx) { - char namebuf[9]; - memset(namebuf, 0, sizeof(namebuf)); - sprintf(namebuf, "ds%s", sfx->name); - return W_CheckNumForName(namebuf); + char namebuf[16]; + + memset(namebuf, 0, sizeof(namebuf)); + + strcpy(namebuf, "DS"); + strcpy(namebuf+2, sfx->name); + + return W_CheckNumForName(namebuf); } // Almost all of the sound code from this point on was // rewritten by Lee Killough, based on Chi's rough initial // version. - +// +// I_StartSound +// // This function adds a sound to the list of currently // active sounds, which is maintained as a given number // of internal channels. Returns a handle. - -int I_StartSound(int sfx, int vol, int sep, int pitch, int pri) +// +int I_StartSound(sfxinfo_t *sound, int cnum, int vol, int sep, int pitch, int pri) { - static int handle = -1; - sfxinfo_t *sound; - - if(!snd_init) - return 0; - - sound = &S_sfx[sfx]; - - // move up one slot, with wraparound - if(++handle >= MAX_CHANNELS) - handle = 0; - - SDL_LockAudio(); + static unsigned int id = 0; + int handle; - // haleyjd 09/03/03: this should use handle, NOT cnum, and - // the return value is plain redundant. Whoever wrote this was - // out of it. - addsfx(sound, handle); - - updateSoundParams(handle, vol, sep, pitch); - SDL_UnlockAudio(); + if(!snd_init) + return -1; - // Reference for s_sound.c to use when calling functions below - return handle; + // haleyjd: turns out this is too simplistic. see below. + /* + // SoM: reimplement hardware channel wrap-around + if(++handle >= MAX_CHANNELS) + handle = 0; + */ + + // haleyjd 06/03/06: look for an unused hardware channel + for(handle = 0; handle < MAX_CHANNELS; ++handle) + { + if(channelinfo[handle].data == NULL) + break; + } + + // all used? don't play the sound. It's preferable to miss a sound + // than it is to cut off one already playing, which sounds weird. + if(handle == MAX_CHANNELS) + return -1; + + // haleyjd 02/18/05: cannot proceed until channel is unlocked + while(channelinfo[handle].lock) + SDL_Delay(1); + + if(addsfx(sound, handle)) + { + channelinfo[handle].idnum = id++; // give the sound a unique id + updateSoundParams(handle, vol, sep, pitch); + } + else + handle = -1; + + return handle; } +// +// I_StopSound +// // Stop the sound. Necessary to prevent runaway chainsaw, // and to stop rocket launches when an explosion occurs. - -void I_StopSound (int handle) +// +void I_StopSound(int handle) { if(!snd_init) return; - + #ifdef RANGECHECK - if(handle >= MAX_CHANNELS) + if(handle < 0 || handle >= MAX_CHANNELS) I_Error("I_StopSound: handle out of range"); #endif - SDL_LockAudio(); stopchan(handle); - SDL_UnlockAudio(); } -// We can pretend that any sound that we've associated a handle -// with is always playing. - +// +// I_SoundIsPlaying +// +// haleyjd: wow, this can actually do something in the Windows version :P +// int I_SoundIsPlaying(int handle) { if(!snd_init) - return 0; - + return false; + #ifdef RANGECHECK - if(handle >= MAX_CHANNELS) + if(handle < 0 || handle >= MAX_CHANNELS) I_Error("I_SoundIsPlaying: handle out of range"); #endif + return (channelinfo[handle].data != NULL); } +// +// I_SoundID +// +// haleyjd: returns the unique id number assigned to a specific instance +// of a sound playing on a given channel. This is required to make sure +// that the higher-level sound code doesn't start updating sounds that have +// been displaced without it noticing. +// +int I_SoundID(int handle) +{ + if(!snd_init) + return 0; + +#ifdef RANGECHECK + if(handle < 0 || handle >= MAX_CHANNELS) + I_Error("I_SoundID: handle out of range\n"); +#endif + + return channelinfo[handle].idnum; +} + // This function loops all active (internal) sound // channels, retrieves a given number of samples // from the raw sound data, modifies it according @@ -396,39 +567,45 @@ int I_SoundIsPlaying(int handle) // // allegro does this now -void I_UpdateSound( void ) +void I_UpdateSound(void) { } + +#define STEP sizeof(Sint16) +#define STEPSHIFT 1 + +// +// I_SDLUpdateSound +// +// SDL_mixer postmix callback routine. Possibly dispatched asynchronously. +// We do our own mixing on up to 32 digital sound channels. +// static void I_SDLUpdateSound(void *userdata, Uint8 *stream, int len) { // Mix current sound data. // Data, from raw sound, for right and left. - register unsigned char sample; - register int dl; - register int dr; + register Uint8 sample; + register Sint32 dl; + register Sint32 dr; // Pointers in audio stream, left, right, end. - short *leftout; - short *rightout; - short *leftend; - - // Step in stream, left and right, thus two. - int step; + Sint16 *leftout; + Sint16 *rightout; + Sint16 *leftend; // Mixing channel index. int chan; - + // Left and right channel // are in audio stream, alternating. - leftout = (signed short *)stream; - rightout = ((signed short *)stream)+1; - step = 2; + leftout = (Sint16 *)stream; + rightout = leftout + 1; // Determine end, for left channel only // (right channel is implicit). - leftend = leftout + (len / 4) * step; - + leftend = leftout + len / STEP; + // Mix sounds into the mixing buffer. // Loop over step*SAMPLECOUNT, // that is 512 values for two channels. @@ -441,74 +618,71 @@ static void I_SDLUpdateSound(void *userdata, Uint8 *stream, int len) // Love thy L2 cache - made this a loop. // Now more channels could be set at compile time // as well. Thus loop those channels. - for(chan = 0; chan < MAX_CHANNELS; chan++ ) + for(chan = 0; chan < MAX_CHANNELS; ++chan) { // Check channel, if active. - if(channelinfo[chan].data) + if(!channelinfo[chan].data) + continue; + + // haleyjd 02/18/05: lock the channel to prevent possible race + // conditions in the below loop that could modify + // channelinfo[chan].data while it's being used here. + channelinfo[chan].lock = 1; + + // Get the raw data from the channel. + // Sounds are now prefiltered. + sample = *(channelinfo[chan].data); + + // Add left and right part + // for this channel (sound) + // to the current data. + // Adjust volume accordingly. + dl += channelinfo[chan].leftvol_lookup[sample]; + dr += channelinfo[chan].rightvol_lookup[sample]; + + // Increment index ??? + channelinfo[chan].stepremainder += channelinfo[chan].step; + + // MSB is next sample??? + channelinfo[chan].data += channelinfo[chan].stepremainder >> 16; + + // Limit to LSB??? + channelinfo[chan].stepremainder &= 0xffff; + + // Check whether we are done. + if(channelinfo[chan].data >= channelinfo[chan].enddata) { - // Get the raw data from the channel. - // no filtering - // sample = *channelinfo[chan].data; - // linear filtering - sample = (((unsigned int)channelinfo[chan].data[0] * (0x10000 - channelinfo[chan].stepremainder)) - + ((unsigned int)channelinfo[chan].data[1] * (channelinfo[chan].stepremainder))) >> 16; - - // Add left and right part - // for this channel (sound) - // to the current data. - // Adjust volume accordingly. - dl += channelinfo[chan].leftvol_lookup[sample]; - dr += channelinfo[chan].rightvol_lookup[sample]; - - // Increment index ??? - channelinfo[chan].stepremainder += channelinfo[chan].step; - - // MSB is next sample??? - channelinfo[chan].data += channelinfo[chan].stepremainder >> 16; - - // Limit to LSB??? - channelinfo[chan].stepremainder &= 0xffff; - - // Check whether we are done. - if(channelinfo[chan].data >= channelinfo[chan].enddata) - stopchan(chan); + // haleyjd 02/18/05: unlock channel + channelinfo[chan].lock = 0; + stopchan(chan); } + else // haleyjd 02/18/05: unlock channel + channelinfo[chan].lock = 0; } // Clamp to range. Left hardware channel. if(dl > SHRT_MAX) - { *leftout = SHRT_MAX; - } else if(dl < SHRT_MIN) - { *leftout = SHRT_MIN; - } else - { *leftout = (short)dl; - } // Same for right hardware channel. if(dr > SHRT_MAX) - { *rightout = SHRT_MAX; - } else if(dr < SHRT_MIN) - { *rightout = SHRT_MIN; - } else - { *rightout = (short)dr; - } // Increment current pointers in stream - leftout += step; - rightout += step; + leftout += STEP; + rightout += STEP; } } + // This would be used to write out the mixbuffer // during each game loop update. // Updates sound buffer and audio device at runtime. @@ -520,6 +694,11 @@ void I_SubmitSound(void) //allegro is doing all the sound mixing now } +// +// I_ShutdownSound +// +// atexit handler. +// void I_ShutdownSound(void) { if(snd_init) @@ -529,13 +708,40 @@ void I_ShutdownSound(void) } } -void I_InitSound(void) +// +// I_CacheSound +// +// haleyjd 11/05/03: fixed for SDL sound engine +// haleyjd 09/24/06: added sound aliases +// +void I_CacheSound(sfxinfo_t *sound) { + if(sound->link) + I_CacheSound(sound->link); + else + { + int lump = I_GetSfxLumpNum(sound); + + // replace missing sounds with a reasonable default + if(lump == -1) + lump = W_GetNumForName("DSPISTOL"); + + W_CacheLumpNum(lump, PU_CACHE); + } +} + +// +// I_InitSound +// +// SoM 9/14/02: Rewrite. code taken from prboom to use SDL_Mixer +// +void I_InitSound(void) +{ if(!nosfxparm) { int audio_buffers; - puts("I_InitSound: "); + printf("I_InitSound: "); /* Initialize variables */ audio_buffers = SAMPLECOUNT * snd_samplerate / 11025; @@ -576,18 +782,39 @@ void I_InitSound(void) // MUSIC API. // +// julian (10/25/2005): rewrote (nearly) entirely + #include "mmus2mid.h" #include "m_misc.h" -static Mix_Music *music[2] = { NULL, NULL }; +// Only one track at a time +static Mix_Music *music = NULL; -const char *music_name = "eetemp.mid"; +// Some tracks are directly streamed from the RWops; +// we need to free them in the end +static SDL_RWops *rw = NULL; +// Same goes for buffers that were allocated to convert music; +// since this concerns mus, we could do otherwise but this +// approach is better for consistency +static void *music_block = NULL; + +// Macro to make code more readable +#define CHECK_MUSIC(h) ((h) && music != NULL) + +// +// I_ShutdownMusic +// +// atexit handler. +// void I_ShutdownMusic(void) { - I_StopSong(0); + I_UnRegisterSong(1); } +// +// I_InitMusic +// void I_InitMusic(void) { switch(mus_card) @@ -597,7 +824,7 @@ void I_InitMusic(void) mus_init = true; break; default: - printf("I_InitMusic: Using No MIDI Device.\n"); + printf("I_InitMusic: Music is disabled.\n"); break; } @@ -611,107 +838,162 @@ void I_PlaySong(int handle, int looping) if(!mus_init) return; - if(handle >= 0 && music[handle]) + if(CHECK_MUSIC(handle) && Mix_PlayMusic(music, looping ? -1 : 0) == -1) { - if(Mix_PlayMusic(music[handle], looping ? -1 : 0) == -1) - I_Error("I_PlaySong: please report this error\n"); + dprintf("I_PlaySong: Mix_PlayMusic failed\n"); + return; } + + // haleyjd 10/28/05: make sure volume settings remain consistent + I_SetMusicVolume(snd_MusicVolume); } +// +// I_SetMusicVolume +// void I_SetMusicVolume(int volume) { - if(!mus_init) - return; - - Mix_VolumeMusic(volume*8); + // haleyjd 09/04/06: adjust to use scale from 0 to 15 + Mix_VolumeMusic((volume * 128) / 15); } -void I_PauseSong (int handle) +static int paused_midi_volume; + +// +// I_PauseSong +// +void I_PauseSong(int handle) { + if(CHECK_MUSIC(handle)) + { + // Not for mids + if(Mix_GetMusicType(music) != MUS_MID) + Mix_PauseMusic(); + else + { + // haleyjd 03/21/06: set MIDI volume to zero on pause + paused_midi_volume = Mix_VolumeMusic(-1); + Mix_VolumeMusic(0); + } + } } -void I_ResumeSong (int handle) +// +// I_ResumeSong +// +void I_ResumeSong(int handle) { + if(CHECK_MUSIC(handle)) + { + // Not for mids + if(Mix_GetMusicType(music) != MUS_MID) + Mix_ResumeMusic(); + else + Mix_VolumeMusic(paused_midi_volume); + } } +// +// I_StopSong +// void I_StopSong(int handle) { - if(!mus_init) - return; - - Mix_HaltMusic(); + if(CHECK_MUSIC(handle)) + Mix_HaltMusic(); } +// +// I_UnRegisterSong +// void I_UnRegisterSong(int handle) { - if(!mus_init) - return; - - if(handle >= 0 && music[handle]) - { - Mix_FreeMusic(music[handle]); - music[handle] = NULL; + if(CHECK_MUSIC(handle)) + { + // Stop and free song + I_StopSong(handle); + Mix_FreeMusic(music); + + // Free RWops + if(rw != NULL) + SDL_FreeRW(rw); + + // Free music block + if(music_block != NULL) + free(music_block); + + // Reinitialize all this + music = NULL; + rw = NULL; + music_block = NULL; } } -// jff 1/16/98 created to convert data to MIDI ala Allegro - -int I_RegisterSong(void *data) +// +// I_RegisterSong +// +int I_RegisterSong(void *data, int size) { - int err; - MIDI mididata; - char fullMusicName[PATH_MAX + 1]; - - UBYTE *mid; - int midlen; - - music[0] = NULL; // ensure its null - - // haleyjd: don't return negative music handles - if(!mus_init) - return 0; - - memset(&mididata,0,sizeof(MIDI)); - - if((err = MidiToMIDI((byte *)data, &mididata)) && // try midi first - (err = mmus2mid((byte *)data, &mididata, 89, 0))) // now try mus - { - dprintf("Error loading midi: %d", err); - return 0; - } - - MIDIToMidi(&mididata,&mid,&midlen); - - // haleyjd 03/15/03: fixed for -cdrom - if(M_CheckParm("-cdrom")) - sprintf(fullMusicName, "%s/%s", "c:/doomdata", music_name); - else - sprintf(fullMusicName, "%s/%s", D_DoomExeDir(), music_name); + if(music != NULL) + I_UnRegisterSong(1); - if(!M_WriteFile(fullMusicName, mid, midlen)) - { - dprintf("Error writing music to %s", music_name); - free(mid); - return 0; - } - - free(mid); - - music[0] = Mix_LoadMUS(fullMusicName); + rw = SDL_RWFromMem(data, size); + music = Mix_LoadMUS_RW(rw); - if(!music[0]) - { - dprintf("Couldn't load MIDI from %s: %s\n", - fullMusicName, Mix_GetError()); + // It's not recognized by SDL_mixer, is it a mus? + if(music == NULL) + { + int err; + MIDI mididata; + UBYTE *mid; + int midlen; + + SDL_FreeRW(rw); + rw = NULL; + + memset(&mididata, 0, sizeof(MIDI)); + + if((err = mmus2mid((byte *)data, &mididata, 89, 0))) + { + // Nope, not a mus. + dprintf("Error loading music: %d", err); + return 0; + } + + // Hurrah! Let's make it a mid and give it to SDL_mixer + MIDIToMidi(&mididata, &mid, &midlen); + rw = SDL_RWFromMem(mid, midlen); + music = Mix_LoadMUS_RW(rw); + + if(music == NULL) + { + // Conversion failed, free everything + SDL_FreeRW(rw); + rw = NULL; + free(mid); + } + else + { + // Conversion succeeded + // -> save memory block to free when unregistering + music_block = mid; + } } - return 0; + // the handle is a simple boolean + return music != NULL; } +// +// I_QrySongPlaying +// // Is the song playing? +// int I_QrySongPlaying(int handle) { - return 0; + // haleyjd: this is never called + // julian: and is that a reason not to code it?!? + // haleyjd: ::shrugs:: + return CHECK_MUSIC(handle); } //---------------------------------------------------------------------------- diff --git a/Source/I_sound.h b/Source/I_sound.h index 3309ac75..d27c34b5 100644 --- a/Source/I_sound.h +++ b/Source/I_sound.h @@ -41,7 +41,7 @@ extern char* sndserver_filename; #endif // Init at program start... -void I_InitSound(); +void I_InitSound(void); // ... update sound buffer and audio device at runtime... void I_UpdateSound(void); @@ -55,13 +55,14 @@ void I_ShutdownSound(void); // // Initialize channels? -void I_SetChannels(); +void I_SetChannels(void); // Get raw data lump index for sound descriptor. -int I_GetSfxLumpNum (sfxinfo_t *sfxinfo); +int I_GetSfxLumpNum(sfxinfo_t *sfxinfo); // Starts a sound in a particular sound channel. -int I_StartSound(int id, int vol, int sep, int pitch, int priority); +int I_StartSound(sfxinfo_t *sound, int cnum, int vol, int sep, int pitch, + int pri); // Stops a sound channel. void I_StopSound(int handle); @@ -75,6 +76,9 @@ int I_SoundIsPlaying(int handle); // and pitch of a sound channel. void I_UpdateSoundParams(int handle, int vol, int sep, int pitch); +// haleyjd +int I_SoundID(int handle); + // // MUSIC I/O // @@ -89,7 +93,7 @@ void I_PauseSong(int handle); void I_ResumeSong(int handle); // Registers a song handle to song data. -int I_RegisterSong(void *data); +int I_RegisterSong(void *data, int size); // Called by anything that wishes to start music. // plays a song, and when the song is done, diff --git a/Source/I_system.c b/Source/I_system.c index 85e3b92b..c661b3cf 100644 --- a/Source/I_system.c +++ b/Source/I_system.c @@ -28,8 +28,6 @@ static const char rcsid[] = "$Id: i_system.c,v 1.14 1998/05/03 22:33:13 killough Exp $"; -#include - // haleyjd #ifdef _MSC_VER #include @@ -38,7 +36,7 @@ rcsid[] = "$Id: i_system.c,v 1.14 1998/05/03 22:33:13 killough Exp $"; #include "SDL.h" - +#include "z_zone.h" #include "i_system.h" #include "i_sound.h" #include "doomstat.h" @@ -84,7 +82,7 @@ static Long64 I_GetTime_Scale = 1<<24; int I_GetTime_Scaled(void) { // haleyjd: - return (Long64) I_GetTime_RealTime() * I_GetTime_Scale >> 24; + return (int)((Long64) I_GetTime_RealTime() * I_GetTime_Scale >> 24); } static int I_GetTime_FastDemo(void) diff --git a/Source/I_video.c b/Source/I_video.c index 3efb94b9..9017a6b1 100644 --- a/Source/I_video.c +++ b/Source/I_video.c @@ -29,12 +29,9 @@ static const char rcsid[] = "$Id: i_video.c,v 1.12 1998/05/03 22:40:35 killough Exp $"; -#include "z_zone.h" /* memory allocation wrappers -- killough */ - -#include - #include "SDL.h" // haleyjd +#include "z_zone.h" /* memory allocation wrappers -- killough */ #include "doomstat.h" #include "v_video.h" #include "d_main.h" diff --git a/Source/S_sound.c b/Source/S_sound.c index d5731cd0..782bb37f 100644 --- a/Source/S_sound.c +++ b/Source/S_sound.c @@ -66,11 +66,17 @@ extern int snd_card, mus_card; extern boolean nosfxparm, nomusicparm; //jff end sound enabling variables readable here -typedef struct +typedef struct channel_s { - sfxinfo_t *sfxinfo; // sound information (if null, channel avail.) - const mobj_t *origin;// origin of sound - int handle; // handle of the sound being played + sfxinfo_t *sfxinfo; // sound information (if null, channel avail.) + const mobj_t *origin; // origin of sound + int volume; // volume scale value for effect -- haleyjd 05/29/06 + int pitch; // pitch modifier -- haleyjd 06/03/06 + int handle; // handle of the sound being played + int o_priority; // haleyjd 09/27/06: stored priority value + int priority; // current priority value + int singularity; // haleyjd 09/27/06: stored singularity value + int idnum; // haleyjd 09/30/06: unique id num for sound event } channel_t; // the set of channels available @@ -103,207 +109,315 @@ int idmusnum; // Internals. // +// +// S_StopChannel +// +// Stops a sound channel. +// static void S_StopChannel(int cnum) { - if (channels[cnum].sfxinfo) - { - if (I_SoundIsPlaying(channels[cnum].handle)) - I_StopSound(channels[cnum].handle); // stop the sound playing - channels[cnum].sfxinfo = 0; - } +#ifdef RANGECHECK + if(cnum < 0 || cnum >= numChannels) + I_Error("S_StopChannel: handle %d out of range\n", cnum); +#endif + + if(channels[cnum].sfxinfo) + { + if(I_SoundIsPlaying(channels[cnum].handle)) + I_StopSound(channels[cnum].handle); // stop the sound playing + + // haleyjd 09/27/06: clear the entire channel + memset(&channels[cnum], 0, sizeof(channel_t)); + } } +// +// S_AdjustSoundParams +// +// Alters a playing sound's volume and stereo separation to account for +// the position and angle of the listener relative to the source. +// +// haleyjd: added channel volume scale value +// haleyjd: added priority scaling +// static int S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, - int *vol, int *sep, int *pitch) + int chanvol, int *vol, int *sep, int *pitch, + int *pri) { - fixed_t adx, ady, dist; - angle_t angle; + fixed_t adx, ady, dist; + angle_t angle; + int basevolume; // haleyjd - // calculate the distance to sound origin - // and clip it if necessary - // - // killough 11/98: scale coordinates down before calculations start - // killough 12/98: use exact distance formula instead of approximation + // haleyjd 08/12/04: we cannot adjust a sound for a NULL listener. + if(!listener) + return 1; - adx = abs((listener->x >> FRACBITS) - (source->x >> FRACBITS)); - ady = abs((listener->y >> FRACBITS) - (source->y >> FRACBITS)); + // haleyjd 05/29/06: this function isn't supposed to be called for NULL sources +#ifdef RANGECHECK + if(!source) + I_Error("S_AdjustSoundParams: NULL source\n"); +#endif + + // calculate the distance to sound origin + // and clip it if necessary + // + // killough 11/98: scale coordinates down before calculations start + // killough 12/98: use exact distance formula instead of approximation + + adx = abs((listener->x >> FRACBITS) - (source->x >> FRACBITS)); + ady = abs((listener->y >> FRACBITS) - (source->y >> FRACBITS)); + + if(ady > adx) + dist = adx, adx = ady, ady = dist; + + dist = adx ? FixedDiv(adx, finesine[(tantoangle[FixedDiv(ady,adx) >> DBITS] + + ANG90) >> ANGLETOFINESHIFT]) : 0; - if (ady > adx) - dist = adx, adx = ady, ady = dist; + // haleyjd 05/29/06: allow per-channel volume scaling + basevolume = (snd_SfxVolume * chanvol) / 15; - dist = adx ? FixedDiv(adx, finesine[(tantoangle[FixedDiv(ady,adx) >> DBITS] - + ANG90) >> ANGLETOFINESHIFT]) : 0; - - if (!dist) // killough 11/98: handle zero-distance as special case - { + if(!dist) // killough 11/98: handle zero-distance as special case + { *sep = NORM_SEP; - *vol = snd_SfxVolume; + *vol = basevolume; return *vol > 0; - } + } - if (dist > S_CLIPPING_DIST >> FRACBITS) - return 0; + if(dist > S_CLIPPING_DIST >> FRACBITS) + return 0; - // angle of source to listener - angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y); + // angle of source to listener + angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y); + + if(angle <= listener->angle) + angle += 0xffffffff; + angle -= listener->angle; + angle >>= ANGLETOFINESHIFT; - if (angle <= listener->angle) - angle += 0xffffffff; - angle -= listener->angle; - angle >>= ANGLETOFINESHIFT; + // stereo separation + *sep = NORM_SEP - FixedMul(S_STEREO_SWING>>FRACBITS,finesine[angle]); - // stereo separation - *sep = NORM_SEP - FixedMul(S_STEREO_SWING>>FRACBITS,finesine[angle]); + // volume calculation + *vol = dist < S_CLOSE_DIST >> FRACBITS ? basevolume : + basevolume * ((S_CLIPPING_DIST>>FRACBITS)-dist) / + S_ATTENUATOR; - // volume calculation - *vol = dist < S_CLOSE_DIST >> FRACBITS ? snd_SfxVolume : - snd_SfxVolume * ((S_CLIPPING_DIST>>FRACBITS)-dist) / - S_ATTENUATOR; + // haleyjd 09/27/06: decrease priority with volume attenuation + *pri = *pri + (127 - *vol); + + if(*pri > 255) // cap to 255 + *pri = 255; return *vol > 0; } // // S_getChannel : -// If none available, return -1. Otherwise channel #. // - -static int S_getChannel(const void *origin, sfxinfo_t *sfxinfo) +// If none available, return -1. Otherwise channel #. +// haleyjd 09/27/06: fixed priority/singularity bugs +// Note that a higher priority number means lower priority! +// +static int S_getChannel(const mobj_t *origin, sfxinfo_t *sfxinfo, + int priority, int singularity) { - // channel number to use - int cnum; - channel_t *c; + // channel number to use + int cnum; + int lowestpriority = -1; // haleyjd + int lpcnum = -1; - // Find an open channel - // killough 12/98: replace is_pickup hack with singularity flag - for (cnum=0; cnumsingularity == sfxinfo->singularity) + // haleyjd 09/28/06: moved this here. If we kill a sound already + // being played, we can use that channel. There is no need to + // search for a free one again because we already know of one. + + // kill old sound + // killough 12/98: replace is_pickup hack with singularity flag + // haleyjd 06/12/08: only if subchannel matches + for(cnum = 0; cnum < numChannels; ++cnum) + { + if(channels[cnum].sfxinfo && + channels[cnum].singularity == singularity && + channels[cnum].origin == origin) { - S_StopChannel(cnum); - break; + S_StopChannel(cnum); + break; } + } + + // Find an open channel + if(cnum == numChannels) + { + // haleyjd 09/28/06: it isn't necessary to look for playing sounds in + // the same singularity class again, as we just did that above. Here + // we are looking for an open channel. We will also keep track of the + // channel found with the lowest sound priority while doing this. + for(cnum = 0; cnum < numChannels && channels[cnum].sfxinfo; ++cnum) + { + if(channels[cnum].priority > lowestpriority) + { + lowestpriority = channels[cnum].priority; + lpcnum = cnum; + } + } + } - // None available - if (cnum == numChannels) - { // Look for lower priority - for (cnum=0 ; cnumpriority >= sfxinfo->priority) - break; - if (cnum == numChannels) - return -1; // No lower priority. Sorry, Charlie. + // None available? + if(cnum == numChannels) + { + // Look for lower priority + // haleyjd: we have stored the channel found with the lowest priority + // in the loop above + if(priority > lowestpriority) + return -1; // No lower priority. Sorry, Charlie. else - S_StopChannel(cnum); // Otherwise, kick out lower priority. - } + { + S_StopChannel(lpcnum); // Otherwise, kick out lowest priority. + cnum = lpcnum; + } + } - c = &channels[cnum]; // channel is decided to be cnum. - c->sfxinfo = sfxinfo; - c->origin = origin; - return cnum; +#ifdef RANGECHECK + if(cnum >= numChannels) + I_Error("S_getChannel: handle %d out of range\n", cnum); +#endif + + return cnum; } + void S_StartSound(const mobj_t *origin, int sfx_id) { - int sep, pitch, priority, cnum; - int volume = snd_SfxVolume; - sfxinfo_t *sfx; - - //jff 1/22/98 return if sound is not enabled - if (!snd_card || nosfxparm) - return; + int sep, pitch, o_priority, priority, singularity, cnum, handle; + int volumeScale = 127; + int volume = snd_SfxVolume; + sfxinfo_t *sfx; + + //jff 1/22/98 return if sound is not enabled + if(!snd_card || nosfxparm) + return; #ifdef RANGECHECK - // check for bogus sound # - if (sfx_id < 1 || sfx_id > NUMSFX) - I_Error("Bad sfx #: %d", sfx_id); + // check for bogus sound # + if(sfx_id < 1 || sfx_id > NUMSFX) + I_Error("Bad sfx #: %d", sfx_id); #endif - sfx = &S_sfx[sfx_id]; - - // Initialize sound parameters - if (sfx->link) - { + sfx = &S_sfx[sfx_id]; + + // 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 - { + volumeScale += sfx->volume; + } + else pitch = NORM_PITCH; - priority = NORM_PRIORITY; - } - // Check to see if it is audible, modify the params - // killough 3/7/98, 4/25/98: code rearranged slightly + // haleyjd 09/29/06: rangecheck volumeScale now! + if(volumeScale < 0) + volumeScale = 0; + else if(volumeScale > 127) + volumeScale = 127; - if (!origin || origin == players[displayplayer].mo) - sep = NORM_SEP; - else - if (!S_AdjustSoundParams(players[displayplayer].mo, origin, &volume, - &sep, &pitch)) - return; - else - if (origin->x == players[displayplayer].mo->x && - origin->y == players[displayplayer].mo->y) - sep = NORM_SEP; + // haleyjd: modified so that priority value is always used + // haleyjd: also modified to get and store proper singularity value + o_priority = priority = sfx->priority; + singularity = sfx->singularity; - if (pitched_sounds) - { + // Check to see if it is audible, modify the params + // killough 3/7/98, 4/25/98: code rearranged slightly + + if(!origin || origin == players[displayplayer].mo) + { + sep = NORM_SEP; + volume = (volume * volumeScale) / 15; // haleyjd 05/29/06: scale volume + if(volume < 1) + return; + if(volume > 127) + volume = 127; + } + else + { + if(!S_AdjustSoundParams(players[displayplayer].mo, origin, volumeScale, + &volume, &sep, &pitch, &priority)) + return; + else if(origin->x == players[displayplayer].mo->x && + origin->y == players[displayplayer].mo->y) + sep = NORM_SEP; + } + + if(pitched_sounds) + { // hacks to vary the sfx pitches - if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit) - pitch += 8 - (M_Random()&15); - else - if (sfx_id != sfx_itemup && sfx_id != sfx_tink) - pitch += 16 - (M_Random()&31); + if(sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit) + pitch += 8 - (M_Random()&15); + else if(sfx_id != sfx_itemup && sfx_id != sfx_tink) + pitch += 16 - (M_Random()&31); + + if(pitch < 0) + pitch = 0; + + if(pitch > 255) + pitch = 255; + } - if (pitch<0) - pitch = 0; + // try to find a channel + if((cnum = S_getChannel(origin, sfx, priority, singularity)) < 0) + return; - if (pitch>255) - pitch = 255; - } +#ifdef RANGECHECK + if(cnum < 0 || cnum >= numChannels) + I_Error("S_StartSfxInfo: handle %d out of range\n", cnum); +#endif - // kill old sound - // killough 12/98: replace is_pickup hack with singularity flag - for (cnum=0 ; cnumsingularity == sfx->singularity && - channels[cnum].origin == origin) - { - S_StopChannel(cnum); - break; - } + channels[cnum].sfxinfo = sfx; + channels[cnum].origin = origin; - // try to find a channel - cnum = S_getChannel(origin, sfx); + while(sfx->link) + sfx = sfx->link; // sf: skip thru link(s) - if (cnum<0) - return; + // Assigns the handle to one of the channels in the mix/output buffer. + handle = I_StartSound(sfx, cnum, volume, sep, pitch, priority); + + // haleyjd: check to see if the sound was started + if(handle >= 0) + { + channels[cnum].handle = handle; + + // haleyjd 05/29/06: record volume scale value + // haleyjd 06/03/06: record pitch too (wtf is going on here??) + // haleyjd 09/27/06: store priority and singularity values (!!!) + channels[cnum].volume = volumeScale; + channels[cnum].pitch = pitch; + channels[cnum].o_priority = o_priority; // original priority + channels[cnum].priority = priority; // scaled priority + channels[cnum].singularity = singularity; + channels[cnum].idnum = I_SoundID(handle); // unique instance id + } + else // haleyjd: the sound didn't start, so clear the channel info + memset(&channels[cnum], 0, sizeof(channel_t)); - // Assigns the handle to one of the channels in the mix/output buffer. - channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority); } +// +// S_StopSound +// void S_StopSound(const mobj_t *origin) { - int cnum; + int cnum; + + //jff 1/22/98 return if sound is not enabled + if(!snd_card || nosfxparm) + return; - //jff 1/22/98 return if sound is not enabled - if (!snd_card || nosfxparm) - return; - - for (cnum=0 ; cnumhandle); mus_paused = true; - } + } } void S_ResumeSound(void) { - if (mus_playing && mus_paused) - { + if(mus_playing && mus_paused) + { I_ResumeSong(mus_playing->handle); mus_paused = false; - } + } } // @@ -334,50 +448,56 @@ void S_ResumeSound(void) void S_UpdateSounds(const mobj_t *listener) { - int cnum; - - //jff 1/22/98 return if sound is not enabled - if (!snd_card || nosfxparm) - return; - - for (cnum=0 ; cnumsfxinfo; - if (sfx) - { - if (I_SoundIsPlaying(c->handle)) + + // haleyjd: has this software channel lost its hardware channel? + if(c->idnum != I_SoundID(c->handle)) + { + // clear the channel and keep going + memset(c, 0, sizeof(channel_t)); + continue; + } + + if(sfx) + { + if(I_SoundIsPlaying(c->handle)) + { + // initialize parameters + int volume = snd_SfxVolume; + int pitch = c->pitch; // haleyjd 06/03/06: use channel's pitch! + int sep = NORM_SEP; + int pri = c->o_priority; // haleyjd 09/27/06: priority + + // check non-local sounds for distance clipping + // or modify their params + + if(c->origin && listener != c->origin) // killough 3/20/98 { - // initialize parameters - int volume = snd_SfxVolume; - int pitch = NORM_PITCH; - int 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) // killough 3/20/98 - if (!S_AdjustSoundParams(listener, c->origin, - &volume, &sep, &pitch)) + if(!S_AdjustSoundParams(listener, + c->origin, + c->volume, + &volume, + &sep, + &pitch, + &pri)) S_StopChannel(cnum); - else + else + { I_UpdateSoundParams(c->handle, volume, sep, pitch); + c->priority = pri; // haleyjd + } } - else // if channel is allocated but sound has stopped, free it + } + else // if channel is allocated but sound has stopped, free it S_StopChannel(cnum); } } @@ -385,69 +505,75 @@ void S_UpdateSounds(const mobj_t *listener) void S_SetMusicVolume(int volume) { - //jff 1/22/98 return if music is not enabled - if (!mus_card || nomusicparm) - return; + //jff 1/22/98 return if music is not enabled + if(!mus_card || nomusicparm) + return; #ifdef RANGECHECK - if (volume < 0 || volume > 127) - I_Error("Attempt to set music volume at %d", volume); + if(volume < 0 || volume > 16) + I_Error("Attempt to set music volume at %d\n", volume); #endif - I_SetMusicVolume(127); - I_SetMusicVolume(volume); - snd_MusicVolume = volume; + // haleyjd: I don't think it should do this in SDL +#if 0 + I_SetMusicVolume(127); +#endif + + I_SetMusicVolume(volume); + snd_MusicVolume = volume; } + void S_SetSfxVolume(int volume) { - //jff 1/22/98 return if sound is not enabled - if (!snd_card || nosfxparm) - return; - + //jff 1/22/98 return if sound is not enabled + if(!snd_card || nosfxparm) + return; + #ifdef RANGECHECK - if (volume < 0 || volume > 127) - I_Error("Attempt to set sfx volume at %d", volume); + if(volume < 0 || volume > 127) + I_Error("Attempt to set sfx volume at %d", volume); #endif - - snd_SfxVolume = volume; + + snd_SfxVolume = volume; } void S_ChangeMusic(int musicnum, int looping) { - musicinfo_t *music; - - //jff 1/22/98 return if music is not enabled - if (!mus_card || nomusicparm) - return; - - if (musicnum <= mus_None || musicnum >= NUMMUSIC) - I_Error("Bad music number %d", musicnum); - - music = &S_music[musicnum]; - - if (mus_playing == music) - return; - - // shutdown old music - S_StopMusic(); - - // get lumpnum if neccessary - if (!music->lumpnum) - { + musicinfo_t *music; + + //jff 1/22/98 return if music is not enabled + if(!mus_card || nomusicparm) + return; + + if(musicnum <= mus_None || musicnum >= NUMMUSIC) + I_Error("Bad music number %d", musicnum); + + music = &S_music[musicnum]; + + if(mus_playing == music) + return; + + // shutdown old music + S_StopMusic(); + + // get lumpnum if neccessary + if(!music->lumpnum) + { char namebuf[9]; sprintf(namebuf, "d_%s", music->name); music->lumpnum = W_GetNumForName(namebuf); - } - - // load & register it - music->data = W_CacheLumpNum(music->lumpnum, PU_MUSIC); - music->handle = I_RegisterSong(music->data); - - // play it - I_PlaySong(music->handle, looping); - - mus_playing = music; + } + + // load & register it + music->data = W_CacheLumpNum(music->lumpnum, PU_STATIC); + // julian: added lump length + music->handle = I_RegisterSong(music->data, W_LumpLength(music->lumpnum)); + + // play it + I_PlaySong(music->handle, looping); + + mus_playing = music; } // @@ -455,23 +581,23 @@ void S_ChangeMusic(int musicnum, int looping) // void S_StartMusic(int m_id) { - S_ChangeMusic(m_id, false); + S_ChangeMusic(m_id, false); } void S_StopMusic(void) { - if (!mus_playing) - return; - - 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_playing) + return; + + 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 = NULL; + mus_playing = NULL; } // @@ -481,50 +607,57 @@ void S_StopMusic(void) // void S_Start(void) { - int cnum,mnum; - - // kill all playing sounds at start of level - // (trust me - a good idea) - - //jff 1/22/98 skip sound init if sound not enabled - if (snd_card && !nosfxparm) - for (cnum=0 ; cnum