X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=snd_mem.c;h=d0671eb8740fb88ef143148178beb8500933442f;hp=09758a63057b1887860157b2b2315218433e95d1;hb=1e1dbc1c5b89ae4ab8cdd9b32dc6413c67f5dd84;hpb=e4b3858e7aca0ead91be1d8f675db084d025abad diff --git a/snd_mem.c b/snd_mem.c index 09758a63..d0671eb8 100644 --- a/snd_mem.c +++ b/snd_mem.c @@ -8,7 +8,7 @@ of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. @@ -21,82 +21,47 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -int cache_full_cycle; +#include "snd_ogg.h" -byte *S_Alloc (int size); /* ================ ResampleSfx ================ */ -void ResampleSfx (sfx_t *sfx, int inrate, byte *data, char *name) +void ResampleSfx (sfxcache_t *sc, qbyte *data, char *name) { - int outcount; - int srcsample, srclength; - float stepscale; - int i; - int samplefrac, fracstep; - sfxcache_t *sc; - - sc = Cache_Check (&sfx->cache); - if (!sc) - return; + int i, outcount, srcsample, srclength, samplefrac, fracstep; - stepscale = (float)inrate / shm->speed; // this is usually 0.5, 1, or 2 + // 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; - outcount = sc->length / stepscale; + 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 = sc->loopstart / stepscale; + sc->loopstart = (double) sc->loopstart * (double) shm->speed / (double) sc->speed; sc->speed = shm->speed; -// if (loadas8bit.value) -// sc->width = 1; -// else -// sc->width = inwidth; -// sc->stereo = 0; // resample / decimate to the current source rate - if (stepscale == 1/* && inwidth == 1*/ && sc->width == 1) - { -// fast special case - /* - // LordHavoc: I do not serve the readability gods... - int *indata, *outdata; - int count4, count1; - count1 = outcount << sc->stereo; - count4 = count1 >> 2; - indata = (void *)data; - outdata = (void *)sc->data; - while (count4--) - *outdata++ = *indata++ ^ 0x80808080; - if (count1 & 2) - ((short*)outdata)[0] = ((short*)indata)[0] ^ 0x8080; - if (count1 & 1) - ((char*)outdata)[2] = ((char*)indata)[2] ^ 0x80; - */ - if (sc->stereo) // LordHavoc: stereo sound support - outcount *= 2; - for (i=0 ; idata)[i] = ((unsigned char *)data)[i] - 128; - } - else if (stepscale == 1/* && inwidth == 2*/ && sc->width == 2) // LordHavoc: quick case for 16bit + if (fracstep == 256) { - if (sc->stereo) // LordHavoc: stereo sound support - outcount *= 2; - for (i=0 ; idata)[i] = LittleShort (((short *)data)[i]); + // 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] = ((short *)data)[i]; } else { -// general case - Con_DPrintf("ResampleSfx: resampling sound %s\n", sfx->name); + // general case samplefrac = 0; - fracstep = stepscale*256; if ((fracstep & 255) == 0) // skipping points on perfect multiple { srcsample = 0; @@ -109,8 +74,8 @@ void ResampleSfx (sfx_t *sfx, int inrate, byte *data, char *name) fracstep <<= 1; for (i=0 ; idata, (sc->length << sc->stereo) * sc->width); -#endif + //COM_WriteFile (va("sound/%s.pcm", name), sc->data, (sc->length << sc->stereo) * sc->width); } //============================================================================= /* ============== -S_LoadSound +S_LoadWavFile ============== */ -sfxcache_t *S_LoadSound (sfx_t *s) +sfxcache_t *S_LoadWavFile (const char *filename, sfx_t *s) { - char namebuffer[256]; - byte *data; - wavinfo_t info; - int len; - float stepscale; - sfxcache_t *sc; - -// see if still in memory - sc = Cache_Check (&s->cache); - if (sc) - return sc; - -//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf); -// load it in - strcpy(namebuffer, "sound/"); - strcat(namebuffer, s->name); - -// Con_Printf ("loading %s\n",namebuffer); - - data = COM_LoadMallocFile(namebuffer, false); + qbyte *data; + wavinfo_t info; + int len; + sfxcache_t *sc; + // Load the file + data = FS_LoadFile(filename, tempmempool, false); if (!data) - { - Con_Printf ("Couldn't load %s\n", namebuffer); return NULL; - } - info = GetWavinfo (s->name, data, com_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); - qfree(data); + // Don't try to load it if it's not a WAV file + if (memcmp (data, "RIFF", 4) || memcmp (data + 8, "WAVE", 4)) return NULL; - } - /* - if (info.channels != 1) + + info = GetWavinfo (s->name, data, fs_filesize); + // Stereo sounds are allowed (intended for music) + if (info.channels < 1 || info.channels > 2) { - Con_Printf ("%s is a stereo sample\n",s->name); + Con_Printf("%s has an unsupported number of channels (%i)\n",s->name, info.channels); + Mem_Free(data); return NULL; } - */ - - stepscale = (float)info.rate / shm->speed; - len = info.samples / stepscale; + // calculate resampled length + len = (int) ((double) info.samples * (double) shm->speed / (double) info.rate); len = len * info.width * info.channels; - sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name); + Mem_FreePool(&s->mempool); + s->mempool = Mem_AllocPool(s->name); + sc = s->sfxcache = Mem_Alloc(s->mempool, len + sizeof(sfxcache_t)); if (!sc) { - qfree(data); + Con_Printf("failed to allocate memory for sound \"%s\"\n", s->name); + 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 (s, sc->speed, data + info.dataofs, s->name); +#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 + + ResampleSfx(sc, data + info.dataofs, s->name); - qfree(data); + Mem_Free(data); return sc; } +/* +============== +S_LoadSound +============== +*/ +sfxcache_t *S_LoadSound (sfx_t *s, int complain) +{ + char namebuffer[MAX_QPATH]; + size_t len; + sfxcache_t *sc; + qboolean modified_name = false; + + // see if still in memory + if (!shm || !shm->speed) + return NULL; + if (s->sfxcache && (s->sfxcache->speed == shm->speed)) + return s->sfxcache; + + len = snprintf (namebuffer, sizeof (namebuffer), "sound/%s", s->name); + if (len >= sizeof (namebuffer)) + return NULL; + + // Try to load it as a WAV file + sc = S_LoadWavFile (namebuffer, s); + if (sc != NULL) + 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; + } + sc = OGG_LoadVorbisFile (namebuffer, s); + if (sc != NULL) + return sc; + + // 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 NULL; +} + +void S_UnloadSound(sfx_t *s) +{ + if (s->sfxcache) + { + s->sfxcache = NULL; + Mem_FreePool(&s->mempool); + } +} + /* =============================================================================== @@ -330,30 +351,30 @@ WAV loading */ -byte *data_p; -byte *iff_end; -byte *last_chunk; -byte *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; } @@ -368,7 +389,7 @@ void FindNextChunk(char *name) data_p = NULL; return; } - + data_p += 4; iff_chunk_len = GetLittleLong(); if (iff_chunk_len < 0) @@ -376,8 +397,6 @@ void FindNextChunk(char *name) data_p = NULL; return; } -// if (iff_chunk_len > 1024*1024) -// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len); data_p -= 8; last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); if (!strncmp(data_p, name, 4)) @@ -394,8 +413,8 @@ void FindChunk(char *name) void DumpChunks(void) { - char str[5]; - + char str[5]; + str[4] = 0; data_p=iff_data; do @@ -403,7 +422,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); } @@ -413,44 +432,44 @@ void DumpChunks(void) GetWavinfo ============ */ -wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) +wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength) { - wavinfo_t info; - int i; - int format; - int samples; + 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 + // find "RIFF" chunk 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; } -// get "fmt " chunk + // get "fmt " chunk iff_data = data_p + 12; -// DumpChunks (); + //DumpChunks (); 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; } @@ -459,15 +478,14 @@ wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) data_p += 4+2; info.width = GetLittleShort() / 8; -// get cue chunk + // get cue chunk FindChunk("cue "); if (data_p) { data_p += 32; info.loopstart = GetLittleLong(); -// Con_Printf("loopstart=%d\n", sfx->loopstart); - // if the next chunk is a LIST chunk, look for a cue length marker + // if the next chunk is a LIST chunk, look for a cue length marker FindNextChunk ("LIST"); if (data_p) { @@ -476,23 +494,22 @@ wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) data_p += 24; i = GetLittleLong (); // samples in loop info.samples = info.loopstart + i; -// Con_Printf("looped length: %i\n", i); } } } else info.loopstart = -1; -// find data chunk + // find data chunk FindChunk("data"); if (!data_p) { - Con_Printf("Missing data chunk\n"); + Con_Print("Missing data chunk\n"); return info; } data_p += 4; - samples = GetLittleLong () / info.width; + samples = GetLittleLong () / info.width / info.channels; if (info.samples) { @@ -503,7 +520,7 @@ wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) info.samples = samples; info.dataofs = data_p - wav; - + return info; }