X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=snd_mem.c;h=d924d66e1e517fd4be374902563d8704eb5afeb5;hb=ad40941adf0fe050fcc609b588cc05266bf26b84;hp=3eab525707b7eb2065df721d0212edc1e2855f7a;hpb=179f1e04d60bf39b24520add2e383b6b4ccc53de;p=xonotic%2Fdarkplaces.git diff --git a/snd_mem.c b/snd_mem.c index 3eab5257..d924d66e 100644 --- a/snd_mem.c +++ b/snd_mem.c @@ -21,39 +21,39 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" +#include "snd_ogg.h" + + /* ================ ResampleSfx ================ */ -void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name) +size_t ResampleSfx (const qbyte *in_data, size_t in_length, const snd_format_t* in_format, qbyte *out_data, const char* sfxname) { - int i, outcount, srcsample, srclength, samplefrac, fracstep; + int samplefrac, fracstep; + size_t i, srcsample, srclength, outcount; // this is usually 0.5 (128), 1 (256), or 2 (512) - fracstep = ((double) sc->speed / (double) shm->speed) * 256.0; + fracstep = ((double) in_format->speed / (double) shm->format.speed) * 256.0; - srclength = sc->length << sc->stereo; + srclength = in_length * in_format->channels; - outcount = (double) sc->length * (double) shm->speed / (double) sc->speed; - Con_DPrintf("ResampleSfx: resampling sound %s from %dhz to %dhz (%d samples to %d samples)\n", name, sc->speed, shm->speed, sc->length, outcount); - sc->length = outcount; - if (sc->loopstart != -1) - sc->loopstart = (double) sc->loopstart * (double) shm->speed / (double) sc->speed; - - sc->speed = shm->speed; + outcount = (double) in_length * (double) shm->format.speed / (double) in_format->speed; + Con_DPrintf("ResampleSfx: resampling sound \"%s\" from %dHz to %dHz (%d samples to %d samples)\n", + sfxname, in_format->speed, shm->format.speed, in_length, outcount); // resample / decimate to the current source rate if (fracstep == 256) { // fast case for direct transfer - if (sc->width == 1) // 8bit + if (in_format->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 + ((signed char *)out_data)[i] = ((unsigned char *)in_data)[i] - 128; + else //if (sb->width == 2) // 16bit for (i = 0;i < srclength;i++) - ((short *)sc->data)[i] = LittleShort (((short *)data)[i]); + ((short *)out_data)[i] = ((short *)in_data)[i]; } else { @@ -63,16 +63,17 @@ void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name) { srcsample = 0; fracstep >>= 8; - if (sc->width == 2) + if (in_format->width == 2) { - short *out = (void *)sc->data, *in = (void *)data; - if (sc->stereo) // LordHavoc: stereo sound support + short *out = (short*)out_data; + const short *in = (const short*)in_data; + if (in_format->channels == 2) // LordHavoc: stereo sound support { fracstep <<= 1; for (i=0 ; idata; - unsigned char *in = (void *)data; - if (sc->stereo) // LordHavoc: stereo sound support + signed char *out = out_data; + const unsigned char *in = in_data; + if (in_format->channels == 2) { fracstep <<= 1; for (i=0 ; iwidth == 2) + if (in_format->width == 2) { - short *out = (void *)sc->data, *in = (void *)data; - if (sc->stereo) // LordHavoc: stereo sound support + short *out = (short*)out_data; + const short *in = (const short*)in_data; + if (in_format->channels == 2) { for (i=0 ; idata; - unsigned char *in = (void *)data; - if (sc->stereo) // LordHavoc: stereo sound support + signed char *out = out_data; + const unsigned char *in = in_data; + if (in_format->channels == 2) { for (i=0 ; idata, (sc->length << sc->stereo) * sc->width); + return outcount; } //============================================================================= +wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength); + +/* +==================== +WAV_FetchSound +==================== +*/ +static const sfxbuffer_t* WAV_FetchSound (channel_t* ch, unsigned int start, unsigned int nbsamples) +{ + return ch->sfx->fetcher_data; +} + + +snd_fetcher_t wav_fetcher = { WAV_FetchSound, NULL }; + + /* ============== -S_LoadSound +S_LoadWavFile ============== */ -sfxcache_t *S_LoadSound (sfx_t *s, int complain) +qboolean S_LoadWavFile (const char *filename, sfx_t *s) { - char namebuffer[MAX_QPATH]; qbyte *data; wavinfo_t info; int len; - sfxcache_t *sc; - - // see if still in memory - if (s->sfxcache) - return s->sfxcache; + sfxbuffer_t* sb; - // load it in - strcpy(namebuffer, "sound/"); - strcat(namebuffer, s->name); - - data = FS_LoadFile(namebuffer, false); + Mem_FreePool (&s->mempool); + s->mempool = Mem_AllocPool(s->name); + // Load the file + data = FS_LoadFile(filename, s->mempool, false); if (!data) { - s->silentlymissing = !complain; - if (complain) - Con_Printf("Couldn't load %s\n", namebuffer); - return NULL; + Mem_FreePool (&s->mempool); + return false; + } + + // Don't try to load it if it's not a WAV file + if (memcmp (data, "RIFF", 4) || memcmp (data + 8, "WAVE", 4)) + { + Mem_FreePool (&s->mempool); + return false; } + Con_DPrintf ("Loading WAV file \"%s\"\n", filename); + info = GetWavinfo (s->name, data, fs_filesize); - // LordHavoc: stereo sounds are now allowed (intended for music) + // Stereo sounds are 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; + Mem_FreePool (&s->mempool); + return false; } // calculate resampled length - len = (int) ((double) info.samples * (double) shm->speed / (double) info.rate); + len = (int) ((double) info.samples * (double) shm->format.speed / (double) info.rate); len = len * info.width * info.channels; - // 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) + sb = Mem_Alloc (s->mempool, len + sizeof (*sb) - sizeof (sb->data)); + if (sb == NULL) { Con_Printf("failed to allocate memory for sound \"%s\"\n", s->name); Mem_FreePool(&s->mempool); - Mem_Free(data); - return NULL; + return false; + } + + s->fetcher = &wav_fetcher; + s->fetcher_data = sb; + s->format.speed = info.rate; + s->format.width = info.width; + s->format.channels = info.channels; + if (info.loopstart < 0) + s->loopstart = -1; + else + s->loopstart = (double) s->loopstart * (double) shm->format.speed / (double) s->format.speed; + +#if BYTE_ORDER != LITTLE_ENDIAN + // We must convert the WAV data from little endian + // to the machine endianess before resampling it + if (info.width == 2) + { + int i; + short* ptr; + + len = info.samples * info.channels; + ptr = (short*)(data + info.dataofs); + for (i = 0; i < len; i++) + ptr[i] = LittleShort (ptr[i]); + } +#endif + + sb->length = ResampleSfx (data + info.dataofs, info.samples, &s->format, sb->data, s->name); + s->format.speed = shm->format.speed; + s->total_length = sb->length; + sb->offset = 0; + + Mem_Free (data); + return true; +} + + +/* +============== +S_LoadSound +============== +*/ +qboolean S_LoadSound (sfx_t *s, int complain) +{ + char namebuffer[MAX_QPATH]; + size_t len; + qboolean modified_name = false; + + // see if still in memory + if (!shm || !shm->format.speed) + return false; + if (s->fetcher != NULL) + { + if (s->format.speed != shm->format.speed) + Sys_Error ("S_LoadSound: sound %s hasn't been resampled (%uHz instead of %uHz)", s->name); + return true; } - sc->length = info.samples; - sc->loopstart = info.loopstart; - sc->speed = info.rate; - sc->width = info.width; - sc->stereo = info.channels == 2; + len = snprintf (namebuffer, sizeof (namebuffer), "sound/%s", s->name); + if (len >= sizeof (namebuffer)) + return false; - ResampleSfx(sc, data + info.dataofs, s->name); + // Try to load it as a WAV file + if (S_LoadWavFile (namebuffer, s)) + return true; - Mem_Free(data); - return sc; + // Else, try to load it as an Ogg Vorbis file + if (!strcasecmp (namebuffer + len - 4, ".wav")) + { + strcpy (namebuffer + len - 3, "ogg"); + modified_name = true; + } + if (OGG_LoadVorbisFile (namebuffer, s)) + return true; + + // Can't load the sound! + if (!complain) + s->flags |= SFXFLAG_SILENTLYMISSING; + else + s->flags &= ~SFXFLAG_SILENTLYMISSING; + if (complain) + { + if (modified_name) + strcpy (namebuffer + len - 3, "wav"); + Con_Printf("Couldn't load %s\n", namebuffer); + } + return false; } +void S_UnloadSound(sfx_t *s) +{ + if (s->fetcher != NULL) + { + unsigned int i; + + s->fetcher = NULL; + s->fetcher_data = NULL; + Mem_FreePool(&s->mempool); + + // At this point, some per-channel data pointers may point to freed zones. + // Practically, it shouldn't be a problem; but it's wrong, so we fix that + for (i = 0; i < total_channels ; i++) + if (channels[i].sfx == s) + channels[i].fetcher_data = NULL; + } +} /* @@ -284,30 +390,30 @@ WAV loading */ -qbyte *data_p; -qbyte *iff_end; -qbyte *last_chunk; -qbyte *iff_data; -int iff_chunk_len; +static qbyte *data_p; +static qbyte *iff_end; +static qbyte *last_chunk; +static qbyte *iff_data; +static int iff_chunk_len; short GetLittleShort(void) { - short val = 0; - val = *data_p; - val = val + (*(data_p+1)<<8); + short val; + + val = BuffLittleShort (data_p); 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); + + val = BuffLittleLong (data_p); data_p += 4; + return val; } @@ -355,7 +461,7 @@ void DumpChunks(void) 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); + 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); } @@ -384,7 +490,7 @@ wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength) FindChunk("RIFF"); if (!(data_p && !strncmp(data_p+8, "WAVE", 4))) { - Con_Printf("Missing RIFF/WAVE chunks\n"); + Con_Print("Missing RIFF/WAVE chunks\n"); return info; } @@ -395,14 +501,14 @@ wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength) FindChunk("fmt "); if (!data_p) { - Con_Printf("Missing fmt chunk\n"); + Con_Print("Missing fmt chunk\n"); return info; } data_p += 8; format = GetLittleShort(); if (format != 1) { - Con_Printf("Microsoft PCM format only\n"); + Con_Print("Microsoft PCM format only\n"); return info; } @@ -437,7 +543,7 @@ wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength) FindChunk("data"); if (!data_p) { - Con_Printf("Missing data chunk\n"); + Con_Print("Missing data chunk\n"); return info; }