X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_mem.c;h=519ef0e27924a3049b533a8c6ee33ed64208161e;hp=47398c6e0bde95f92279ed238d5c60dd82543410;hb=6986e09fa77045fa21edaf84f6d849140f927d1b;hpb=57252d1b300d96b2353bf9d564b0de281552d2c5 diff --git a/snd_mem.c b/snd_mem.c index 47398c6e..519ef0e2 100644 --- a/snd_mem.c +++ b/snd_mem.c @@ -17,194 +17,66 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// snd_mem.c: sound caching -#include "quakedef.h" -qbyte *S_Alloc (int size); +#include "darkplaces.h" + +#include "snd_main.h" +#include "snd_ogg.h" +#include "snd_wav.h" +#ifdef USEXMP +#include "snd_xmp.h" +#endif +#include "sound.h" + +void SCR_PushLoadingScreen (const char *, float); +void SCR_PopLoadingScreen (qbool); /* -================ -ResampleSfx -================ +==================== +Snd_CreateRingBuffer + +If "buffer" is NULL, the function allocates one buffer of "sampleframes" sample frames itself +(if "sampleframes" is 0, the function chooses the size). +==================== */ -void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name) +snd_ringbuffer_t *Snd_CreateRingBuffer (const snd_format_t* format, unsigned int sampleframes, void* buffer) { - int i, outcount, srcsample, srclength, samplefrac, fracstep; + snd_ringbuffer_t *ringbuffer; - // this is usually 0.5 (128), 1 (256), or 2 (512) - fracstep = ((double) sc->speed / (double) shm->speed) * 256.0; - - srclength = sc->length << sc->stereo; + // If the caller provides a buffer, it must give us its size + if (sampleframes == 0 && buffer != NULL) + return NULL; - outcount = (double) sc->length * (double) shm->speed / (double) sc->speed; - sc->length = outcount; - if (sc->loopstart != -1) - sc->loopstart = (double) sc->loopstart * (double) shm->speed / (double) sc->speed; + ringbuffer = (snd_ringbuffer_t*)Mem_Alloc(snd_mempool, sizeof (*ringbuffer)); + memset(ringbuffer, 0, sizeof(*ringbuffer)); + memcpy(&ringbuffer->format, format, sizeof(ringbuffer->format)); - sc->speed = shm->speed; + // If we haven't been given a buffer + if (buffer == NULL) + { + unsigned int maxframes; + size_t memsize; -// resample / decimate to the current source rate + if (sampleframes == 0) + maxframes = (format->speed + 1) / 2; // Make the sound buffer large enough for containing 0.5 sec of sound + else + maxframes = sampleframes; - if (fracstep == 256) - { - // fast case for direct transfer - if (sc->width == 1) // 8bit - for (i = 0;i < srclength;i++) - ((signed char *)sc->data)[i] = ((unsigned char *)data)[i] - 128; - else //if (sc->width == 2) // 16bit - for (i = 0;i < srclength;i++) - ((short *)sc->data)[i] = LittleShort (((short *)data)[i]); + memsize = maxframes * format->width * format->channels; + ringbuffer->ring = (unsigned char *) Mem_Alloc(snd_mempool, memsize); + ringbuffer->maxframes = maxframes; } else { - // general case - Con_DPrintf("ResampleSfx: resampling sound %s\n", name); - samplefrac = 0; - if ((fracstep & 255) == 0) // skipping points on perfect multiple - { - srcsample = 0; - fracstep >>= 8; - if (sc->width == 2) - { - short *out = (void *)sc->data, *in = (void *)data; - if (sc->stereo) // LordHavoc: stereo sound support - { - fracstep <<= 1; - for (i=0 ; idata; - unsigned char *in = (void *)data; - if (sc->stereo) // LordHavoc: stereo sound support - { - fracstep <<= 1; - for (i=0 ; iwidth == 2) - { - short *out = (void *)sc->data, *in = (void *)data; - if (sc->stereo) // LordHavoc: stereo sound support - { - for (i=0 ; i> 8) << 1; - a = in[srcsample ]; - if (srcsample+2 >= srclength) - b = 0; - else - b = in[srcsample+2]; - sample = (((b - a) * (samplefrac & 255)) >> 8) + a; - *out++ = (short) sample; - a = in[srcsample+1]; - if (srcsample+2 >= srclength) - b = 0; - else - b = in[srcsample+3]; - sample = (((b - a) * (samplefrac & 255)) >> 8) + a; - *out++ = (short) sample; - samplefrac += fracstep; - } - } - else - { - for (i=0 ; i> 8; - a = in[srcsample ]; - if (srcsample+1 >= srclength) - b = 0; - else - b = in[srcsample+1]; - sample = (((b - a) * (samplefrac & 255)) >> 8) + a; - *out++ = (short) sample; - samplefrac += fracstep; - } - } - } - else - { - signed char *out = (void *)sc->data; - unsigned char *in = (void *)data; - if (sc->stereo) // LordHavoc: stereo sound support - { - for (i=0 ; i> 8) << 1; - a = (int) in[srcsample ] - 128; - if (srcsample+2 >= srclength) - b = 0; - else - b = (int) in[srcsample+2] - 128; - sample = (((b - a) * (samplefrac & 255)) >> 8) + a; - *out++ = (signed char) sample; - a = (int) in[srcsample+1] - 128; - if (srcsample+2 >= srclength) - b = 0; - else - b = (int) in[srcsample+3] - 128; - sample = (((b - a) * (samplefrac & 255)) >> 8) + a; - *out++ = (signed char) sample; - samplefrac += fracstep; - } - } - else - { - for (i=0 ; i> 8; - a = (int) in[srcsample ] - 128; - if (srcsample+1 >= srclength) - b = 0; - else - b = (int) in[srcsample+1] - 128; - sample = (((b - a) * (samplefrac & 255)) >> 8) + a; - *out++ = (signed char) sample; - samplefrac += fracstep; - } - } - } - } + ringbuffer->ring = (unsigned char *) buffer; + ringbuffer->maxframes = sampleframes; } - // LordHavoc: use this for testing if it ever becomes useful again - //COM_WriteFile (va("sound/%s.pcm", name), sc->data, (sc->length << sc->stereo) * sc->width); + return ringbuffer; } + //============================================================================= /* @@ -212,248 +84,91 @@ void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name) S_LoadSound ============== */ -sfxcache_t *S_LoadSound (sfx_t *s, int complain) +qbool S_LoadSound (sfx_t *sfx, qbool complain) { - char namebuffer[256]; - qbyte *data; - wavinfo_t info; - int len; - sfxcache_t *sc; + char namebuffer[MAX_QPATH + 16]; + size_t len; - // see if still in memory - if (s->sfxcache) - return s->sfxcache; + // See if already loaded + if (sfx->fetcher != NULL) + return true; - // load it in - strcpy(namebuffer, "sound/"); - strcat(namebuffer, s->name); + // If we weren't able to load it previously, no need to retry + // Note: S_PrecacheSound clears this flag to cause a retry + if (sfx->flags & SFXFLAG_FILEMISSING) + return false; - data = FS_LoadFile(namebuffer, false); + // No sound? + if (snd_renderbuffer == NULL) + return false; - if (!data) - { - if (complain) - Con_Printf ("Couldn't load %s\n", namebuffer); - return NULL; - } + // Initialize volume peak to 0; if ReplayGain is supported, the loader will change this away + sfx->volume_peak = 0.0; - info = GetWavinfo (s->name, data, fs_filesize); - // LordHavoc: stereo sounds are now allowed (intended for music) - if (info.channels < 1 || info.channels > 2) - { - Con_Printf ("%s has an unsupported number of channels (%i)\n",s->name, info.channels); - Mem_Free(data); - return NULL; - } + if (developer_loading.integer) + Con_Printf("loading sound %s\n", sfx->name); - // calculate resampled length - len = (int) ((double) info.samples * (double) shm->speed / (double) info.rate); - len = len * info.width * info.channels; + SCR_PushLoadingScreen(sfx->name, 1); - // FIXME: add S_UnloadSounds or something? - Mem_FreePool(&s->mempool); - s->mempool = Mem_AllocPool(s->name); - sc = s->sfxcache = Mem_Alloc(s->mempool, len + sizeof(sfxcache_t)); - if (!sc) + // LadyHavoc: if the sound filename does not begin with sound/, try adding it + if (strncasecmp(sfx->name, "sound/", 6)) { - Mem_FreePool(&s->mempool); - Mem_Free(data); - return NULL; - } - - sc->length = info.samples; - sc->loopstart = info.loopstart; - sc->speed = info.rate; - sc->width = info.width; - sc->stereo = info.channels == 2; - - ResampleSfx (sc, data + info.dataofs, s->name); - - Mem_Free(data); - return sc; -} - - - -/* -=============================================================================== - -WAV loading - -=============================================================================== -*/ - - -qbyte *data_p; -qbyte *iff_end; -qbyte *last_chunk; -qbyte *iff_data; -int iff_chunk_len; - - -short GetLittleShort(void) -{ - short val = 0; - val = *data_p; - val = val + (*(data_p+1)<<8); - data_p += 2; - return val; -} - -int GetLittleLong(void) -{ - int val = 0; - val = *data_p; - val = val + (*(data_p+1)<<8); - val = val + (*(data_p+2)<<16); - val = val + (*(data_p+3)<<24); - data_p += 4; - return val; -} - -void FindNextChunk(char *name) -{ - while (1) - { - data_p=last_chunk; - - if (data_p >= iff_end) - { // didn't find the chunk - data_p = NULL; - return; + dpsnprintf (namebuffer, sizeof(namebuffer), "sound/%s", sfx->name); + len = strlen(namebuffer); + if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".wav")) + { + if (S_LoadWavFile (namebuffer, sfx)) + goto loaded; + memcpy (namebuffer + len - 3, "ogg", 4); } - - data_p += 4; - iff_chunk_len = GetLittleLong(); - if (iff_chunk_len < 0) + if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".ogg")) { - data_p = NULL; - return; + if (OGG_LoadVorbisFile (namebuffer, sfx)) + goto loaded; } - data_p -= 8; - last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); - if (!strncmp(data_p, name, 4)) - return; - } -} - -void FindChunk(char *name) -{ - last_chunk = iff_data; - FindNextChunk (name); -} - - -void DumpChunks(void) -{ - char str[5]; - - str[4] = 0; - data_p=iff_data; - do - { - memcpy (str, data_p, 4); - data_p += 4; - iff_chunk_len = GetLittleLong(); - Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); - data_p += (iff_chunk_len + 1) & ~1; - } while (data_p < iff_end); -} - -/* -============ -GetWavinfo -============ -*/ -wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength) -{ - wavinfo_t info; - int i; - int format; - int samples; - - memset (&info, 0, sizeof(info)); - - if (!wav) - return info; - - iff_data = wav; - iff_end = wav + wavlength; - - // find "RIFF" chunk - FindChunk("RIFF"); - if (!(data_p && !strncmp(data_p+8, "WAVE", 4))) - { - Con_Printf("Missing RIFF/WAVE chunks\n"); - return info; +#ifdef USEXMP + else if (len >= 1) + { + if (XMP_LoadModFile (namebuffer, sfx)) + goto loaded; + } +#endif } - // get "fmt " chunk - iff_data = data_p + 12; - //DumpChunks (); - - FindChunk("fmt "); - if (!data_p) + // LadyHavoc: then try without the added sound/ as wav and ogg + dpsnprintf (namebuffer, sizeof(namebuffer), "%s", sfx->name); + len = strlen(namebuffer); + // request foo.wav: tries foo.wav, then foo.ogg + // request foo.ogg: tries foo.ogg only + // request foo.mod: tries foo.mod only + if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".wav")) { - Con_Printf("Missing fmt chunk\n"); - return info; + if (S_LoadWavFile (namebuffer, sfx)) + goto loaded; + memcpy (namebuffer + len - 3, "ogg", 4); } - data_p += 8; - format = GetLittleShort(); - if (format != 1) + if (len >= 4 && !strcasecmp (namebuffer + len - 4, ".ogg")) { - Con_Printf("Microsoft PCM format only\n"); - return info; + if (OGG_LoadVorbisFile (namebuffer, sfx)) + goto loaded; } - - info.channels = GetLittleShort(); - info.rate = GetLittleLong(); - data_p += 4+2; - info.width = GetLittleShort() / 8; - - // get cue chunk - FindChunk("cue "); - if (data_p) +#ifdef USEXMP + else if (len >= 1) { - data_p += 32; - info.loopstart = GetLittleLong(); - - // if the next chunk is a LIST chunk, look for a cue length marker - FindNextChunk ("LIST"); - if (data_p) - { - if (!strncmp (data_p + 28, "mark", 4)) - { // this is not a proper parse, but it works with cooledit... - data_p += 24; - i = GetLittleLong (); // samples in loop - info.samples = info.loopstart + i; - } - } - } - else - info.loopstart = -1; - - // find data chunk - FindChunk("data"); - if (!data_p) - { - Con_Printf("Missing data chunk\n"); - return info; + if (XMP_LoadModFile (namebuffer, sfx)) + goto loaded; } +#endif - data_p += 4; - samples = GetLittleLong () / info.width / info.channels; + // Can't load the sound! + sfx->flags |= SFXFLAG_FILEMISSING; + if (complain) + Con_Printf(CON_ERROR "Failed to load sound \"%s\"\n", sfx->name); - if (info.samples) - { - if (samples < info.samples) - Host_Error ("Sound %s has a bad loop length", name); - } - else - info.samples = samples; + SCR_PopLoadingScreen(false); + return false; - info.dataofs = data_p - wav; - - return info; +loaded: + SCR_PopLoadingScreen(false); + return true; } -