diff options
Diffstat (limited to 'src/i_sdlsound.c')
-rw-r--r-- | src/i_sdlsound.c | 249 |
1 files changed, 154 insertions, 95 deletions
diff --git a/src/i_sdlsound.c b/src/i_sdlsound.c index b6fc9787..b26fb1b2 100644 --- a/src/i_sdlsound.c +++ b/src/i_sdlsound.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- // // Copyright(C) 1993-1996 Id Software, Inc. -// Copyright(C) 2005 Simon Howard +// Copyright(C) 2005-8 Simon Howard // Copyright(C) 2008 David Flater // // This program is free software; you can redistribute it and/or @@ -38,28 +38,30 @@ #include <samplerate.h> #endif -#include "deh_main.h" +#include "deh_str.h" +#include "i_sound.h" #include "i_system.h" -#include "s_sound.h" #include "m_argv.h" #include "w_wad.h" #include "z_zone.h" -#include "doomdef.h" +#include "doomtype.h" #define LOW_PASS_FILTER #define NUM_CHANNELS 16 static boolean sound_initialised = false; -static Mix_Chunk sound_chunks[NUMSFX]; -static int channels_playing[NUM_CHANNELS]; +static sfxinfo_t *channels_playing[NUM_CHANNELS]; static int mixer_freq; static Uint16 mixer_format; static int mixer_channels; -static uint32_t (*ExpandSoundData)(byte *data, int samplerate, int length, - Mix_Chunk *destination) = NULL; +static boolean use_sfx_prefix; +static void (*ExpandSoundData)(sfxinfo_t *sfxinfo, + byte *data, + int samplerate, + int length) = NULL; int use_libsamplerate = 0; @@ -70,26 +72,50 @@ int use_libsamplerate = 0; static void ReleaseSoundOnChannel(int channel) { int i; - int id = channels_playing[channel]; + sfxinfo_t *sfxinfo = channels_playing[channel]; - if (!id) + if (sfxinfo == NULL) { return; } - channels_playing[channel] = sfx_None; + channels_playing[channel] = NULL; for (i=0; i<NUM_CHANNELS; ++i) { // Playing on this channel? if so, don't release. - if (channels_playing[i] == id) + if (channels_playing[i] == sfxinfo) return; } // Not used on any channel, and can be safely released - - Z_ChangeTag(sound_chunks[id].abuf, PU_CACHE); + + Z_ChangeTag(sfxinfo->driver_data, PU_CACHE); +} + +// Allocate a new Mix_Chunk along with its data, storing +// the result in the variable pointed to by variable + +static Mix_Chunk *AllocateChunk(sfxinfo_t *sfxinfo, uint32_t len) +{ + Mix_Chunk *chunk; + + // Allocate the chunk and the audio buffer together + + chunk = Z_Malloc(len + sizeof(Mix_Chunk), + PU_STATIC, + &sfxinfo->driver_data); + sfxinfo->driver_data = chunk; + + // Skip past the chunk structure for the audio buffer + + chunk->abuf = (byte *) (chunk + 1); + chunk->alen = len; + chunk->allocated = 1; + chunk->volume = MIX_MAX_VOLUME; + + return chunk; } #ifdef HAVE_LIBSAMPLERATE @@ -128,15 +154,17 @@ static int SRC_ConversionMode(void) // Returns number of clipped samples. // DWF 2008-02-10 with cleanups by Simon Howard. -static uint32_t ExpandSoundData_SRC(byte *data, - int samplerate, - int length, - Mix_Chunk *destination) +static void ExpandSoundData_SRC(sfxinfo_t *sfxinfo, + byte *data, + int samplerate, + int length) { SRC_DATA src_data; uint32_t i, abuf_index=0, clipped=0; + uint32_t alen; int retn; int16_t *expanded; + Mix_Chunk *chunk; src_data.input_frames = length; src_data.data_in = malloc(length * sizeof(float)); @@ -163,12 +191,14 @@ static uint32_t ExpandSoundData_SRC(byte *data, retn = src_simple(&src_data, SRC_ConversionMode(), 1); assert(retn == 0); - // Convert the result back into 16-bit integers. + // Allocate the new chunk. + + alen = src_data.output_frames_gen * 4; - destination->alen = src_data.output_frames_gen * 4; - destination->abuf = Z_Malloc(destination->alen, PU_STATIC, - &destination->abuf); - expanded = (int16_t *) destination->abuf; + chunk = AllocateChunk(sfxinfo, src_data.output_frames_gen * 4); + expanded = (int16_t *) chunk->abuf; + + // Convert the result back into 16-bit integers. for (i=0; i<src_data.output_frames_gen; ++i) { @@ -197,12 +227,15 @@ static uint32_t ExpandSoundData_SRC(byte *data, int32_t cvtval_i = cvtval_f + (cvtval_f < 0 ? -0.5 : 0.5); // Asymmetrical sound worries me, so we won't use -32768. - if (cvtval_i < -INT16_MAX) { - cvtval_i = -INT16_MAX; - ++clipped; - } else if (cvtval_i > INT16_MAX) { - cvtval_i = INT16_MAX; - ++clipped; + if (cvtval_i < -INT16_MAX) + { + cvtval_i = -INT16_MAX; + ++clipped; + } + else if (cvtval_i > INT16_MAX) + { + cvtval_i = INT16_MAX; + ++clipped; } // Left and right channels @@ -213,7 +246,13 @@ static uint32_t ExpandSoundData_SRC(byte *data, free(src_data.data_in); free(src_data.data_out); - return clipped; + + if (clipped > 0) + { + fprintf(stderr, "Sound '%s': clipped %u samples (%0.2f %%)\n", + sfxinfo->name, clipped, + 400.0 * clipped / chunk->alen); + } } #endif @@ -250,12 +289,13 @@ static boolean ConvertibleRatio(int freq1, int freq2) // Generic sound expansion function for any sample rate. // Returns number of clipped samples (always 0). -static uint32_t ExpandSoundData_SDL(byte *data, - int samplerate, - int length, - Mix_Chunk *destination) +static void ExpandSoundData_SDL(sfxinfo_t *sfxinfo, + byte *data, + int samplerate, + int length) { SDL_AudioCVT convertor; + Mix_Chunk *chunk; uint32_t expanded_length; // Calculate the length of the expanded version of the sample. @@ -266,9 +306,9 @@ static uint32_t ExpandSoundData_SDL(byte *data, expanded_length *= 4; - destination->alen = expanded_length; - destination->abuf - = Z_Malloc(expanded_length, PU_STATIC, &destination->abuf); + // Allocate a chunk in which to expand the sound + + chunk = AllocateChunk(sfxinfo, expanded_length); // If we can, use the standard / optimised SDL conversion routines. @@ -278,7 +318,7 @@ static uint32_t ExpandSoundData_SDL(byte *data, AUDIO_U8, 1, samplerate, mixer_format, mixer_channels, mixer_freq)) { - convertor.buf = destination->abuf; + convertor.buf = chunk->abuf; convertor.len = length; memcpy(convertor.buf, data, length); @@ -286,7 +326,7 @@ static uint32_t ExpandSoundData_SDL(byte *data, } else { - Sint16 *expanded = (Sint16 *) destination->abuf; + Sint16 *expanded = (Sint16 *) chunk->abuf; int expanded_length; int expand_ratio; int i; @@ -344,25 +384,22 @@ static uint32_t ExpandSoundData_SDL(byte *data, } #endif /* #ifdef LOW_PASS_FILTER */ } - - return 0; } // Load and convert a sound effect // Returns true if successful -static boolean CacheSFX(int sound) +static boolean CacheSFX(sfxinfo_t *sfxinfo) { int lumpnum; unsigned int lumplen; int samplerate; - int clipped; unsigned int length; byte *data; // need to load the sound - lumpnum = S_sfx[sound].lumpnum; + lumpnum = sfxinfo->lumpnum; data = W_CacheLumpNum(lumpnum, PU_STATIC); lumplen = W_LumpLength(lumpnum); @@ -390,23 +427,8 @@ static boolean CacheSFX(int sound) } // Sample rate conversion - // DWF 2008-02-10: sound_chunks[sound].alen and abuf are determined - // by ExpandSoundData. - sound_chunks[sound].allocated = 1; - sound_chunks[sound].volume = MIX_MAX_VOLUME; - - clipped = ExpandSoundData(data + 8, - samplerate, - length, - &sound_chunks[sound]); - - if (clipped) - { - fprintf(stderr, "Sound %d: clipped %u samples (%0.2f %%)\n", - sound, clipped, - 400.0 * clipped / sound_chunks[sound].alen); - } + ExpandSoundData(sfxinfo, data + 8, samplerate, length); // don't need the original lump any more @@ -415,18 +437,47 @@ static boolean CacheSFX(int sound) return true; } +static void GetSfxLumpName(sfxinfo_t *sfx, char *buf) +{ + // Linked sfx lumps? Get the lump number for the sound linked to. + + if (sfx->link != NULL) + { + sfx = sfx->link; + } + + // Doom adds a DS* prefix to sound lumps; Heretic and Hexen don't + // do this. + + if (use_sfx_prefix) + { + sprintf(buf, "ds%s", DEH_String(sfx->name)); + } + else + { + strcpy(buf, DEH_String(sfx->name)); + } +} + #ifdef HAVE_LIBSAMPLERATE // Preload all the sound effects - stops nasty ingame freezes -static void I_PrecacheSounds(void) +static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds) { char namebuf[9]; int i; - printf("I_PrecacheSounds: Precaching all sound effects.."); + // Don't need to precache the sounds unless we are using libsamplerate. - for (i=sfx_pistol; i<NUMSFX; ++i) + if (use_libsamplerate == 0) + { + return; + } + + printf("I_SDL_PrecacheSounds: Precaching all sound effects.."); + + for (i=0; i<num_sounds; ++i) { if ((i % 6) == 0) { @@ -434,17 +485,17 @@ static void I_PrecacheSounds(void) fflush(stdout); } - sprintf(namebuf, "ds%s", DEH_String(S_sfx[i].name)); + GetSfxLumpName(&sounds[i], namebuf); - S_sfx[i].lumpnum = W_CheckNumForName(namebuf); + sounds[i].lumpnum = W_CheckNumForName(namebuf); - if (S_sfx[i].lumpnum != -1) + if (sounds[i].lumpnum != -1) { - CacheSFX(i); + // Try to cache the sound and then release it as cache - if (sound_chunks[i].abuf != NULL) + if (CacheSFX(&sounds[i])) { - Z_ChangeTag(sound_chunks[i].abuf, PU_CACHE); + Z_ChangeTag(sounds[i].driver_data, PU_CACHE); } } } @@ -452,37 +503,49 @@ static void I_PrecacheSounds(void) printf("\n"); } +#else + +static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds) +{ + // no-op +} + #endif -static Mix_Chunk *GetSFXChunk(int sound_id) +// Load a SFX chunk into memory and ensure that it is locked. + +static boolean LockSound(sfxinfo_t *sfxinfo) { - if (sound_chunks[sound_id].abuf == NULL) + // If the sound isn't loaded, load it now + + if (sfxinfo->driver_data == NULL) { - if (!CacheSFX(sound_id)) - return NULL; + if (!CacheSFX(sfxinfo)) + { + return false; + } } else { - // don't free the sound while it is playing! + // Lock the sound effect into memory - Z_ChangeTag(sound_chunks[sound_id].abuf, PU_STATIC); + Z_ChangeTag(sfxinfo->driver_data, PU_STATIC); } - return &sound_chunks[sound_id]; + return true; } - // // Retrieve the raw data lump index // for a given SFX name. // -static int I_SDL_GetSfxLumpNum(sfxinfo_t* sfx) +static int I_SDL_GetSfxLumpNum(sfxinfo_t *sfx) { char namebuf[9]; - sprintf(namebuf, "ds%s", DEH_String(sfx->name)); - + GetSfxLumpName(sfx, namebuf); + return W_GetNumForName(namebuf); } @@ -515,7 +578,7 @@ static void I_SDL_UpdateSoundParams(int handle, int vol, int sep) // is set, but currently not used by mixing. // -static int I_SDL_StartSound(int id, int channel, int vol, int sep) +static int I_SDL_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep) { Mix_Chunk *chunk; @@ -531,18 +594,18 @@ static int I_SDL_StartSound(int id, int channel, int vol, int sep) // Get the sound data - chunk = GetSFXChunk(id); - - if (chunk == NULL) + if (!LockSound(sfxinfo)) { - return -1; + return -1; } + chunk = (Mix_Chunk *) sfxinfo->driver_data; + // play sound Mix_PlayChannelTimed(channel, chunk, 0, -1); - channels_playing[channel] = id; + channels_playing[channel] = sfxinfo; // set separation, etc. @@ -613,20 +676,17 @@ static void I_SDL_ShutdownSound(void) } -static boolean I_SDL_InitSound(void) +static boolean I_SDL_InitSound(boolean _use_sfx_prefix) { int i; - // No sounds yet + use_sfx_prefix = _use_sfx_prefix; - for (i=0; i<NUMSFX; ++i) - { - sound_chunks[i].abuf = NULL; - } + // No sounds yet for (i=0; i<NUM_CHANNELS; ++i) { - channels_playing[i] = sfx_None; + channels_playing[i] = NULL; } if (SDL_Init(SDL_INIT_AUDIO) < 0) @@ -655,8 +715,6 @@ static boolean I_SDL_InitSound(void) } ExpandSoundData = ExpandSoundData_SRC; - - I_PrecacheSounds(); } #else if (use_libsamplerate != 0) @@ -698,5 +756,6 @@ sound_module_t sound_sdl_module = I_SDL_StartSound, I_SDL_StopSound, I_SDL_SoundIsPlaying, + I_SDL_PrecacheSounds, }; |