123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- /*
- ===========================================================================
- Copyright (C) 1999-2005 Id Software, Inc.
- This file is part of Quake III Arena source code.
- Quake III Arena source code is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
- Quake III Arena source code 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. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Foobar; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ===========================================================================
- */
- /*****************************************************************************
- * name: snd_mem.c
- *
- * desc: sound caching
- *
- * $Archive: /MissionPack/code/client/snd_mem.c $
- *
- *****************************************************************************/
- #include "snd_local.h"
- #define DEF_COMSOUNDMEGS "8"
- /*
- ===============================================================================
- memory management
- ===============================================================================
- */
- static sndBuffer *buffer = NULL;
- static sndBuffer *freelist = NULL;
- static int inUse = 0;
- static int totalInUse = 0;
- short *sfxScratchBuffer = NULL;
- sfx_t *sfxScratchPointer = NULL;
- int sfxScratchIndex = 0;
- void SND_free(sndBuffer *v) {
- *(sndBuffer **)v = freelist;
- freelist = (sndBuffer*)v;
- inUse += sizeof(sndBuffer);
- }
- sndBuffer* SND_malloc() {
- sndBuffer *v;
- redo:
- if (freelist == NULL) {
- S_FreeOldestSound();
- goto redo;
- }
- inUse -= sizeof(sndBuffer);
- totalInUse += sizeof(sndBuffer);
- v = freelist;
- freelist = *(sndBuffer **)freelist;
- v->next = NULL;
- return v;
- }
- void SND_setup() {
- sndBuffer *p, *q;
- cvar_t *cv;
- int scs;
- cv = Cvar_Get( "com_soundMegs", DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE );
- scs = (cv->integer*1536);
- buffer = malloc(scs*sizeof(sndBuffer) );
- // allocate the stack based hunk allocator
- sfxScratchBuffer = malloc(SND_CHUNK_SIZE * sizeof(short) * 4); //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
- sfxScratchPointer = NULL;
- inUse = scs*sizeof(sndBuffer);
- p = buffer;;
- q = p + scs;
- while (--q > p)
- *(sndBuffer **)q = q-1;
-
- *(sndBuffer **)q = NULL;
- freelist = p + scs - 1;
- Com_Printf("Sound memory manager started\n");
- }
- /*
- ===============================================================================
- WAV loading
- ===============================================================================
- */
- static byte *data_p;
- static byte *iff_end;
- static byte *last_chunk;
- static byte *iff_data;
- static int iff_chunk_len;
- static short GetLittleShort(void)
- {
- short val = 0;
- val = *data_p;
- val = val + (*(data_p+1)<<8);
- data_p += 2;
- return val;
- }
- static 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;
- }
- static void FindNextChunk(char *name)
- {
- while (1)
- {
- data_p=last_chunk;
- if (data_p >= iff_end)
- { // didn't find the chunk
- data_p = NULL;
- return;
- }
-
- data_p += 4;
- iff_chunk_len = GetLittleLong();
- if (iff_chunk_len < 0)
- {
- data_p = NULL;
- return;
- }
- data_p -= 8;
- last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
- if (!strncmp((char *)data_p, name, 4))
- return;
- }
- }
- static void FindChunk(char *name)
- {
- last_chunk = iff_data;
- FindNextChunk (name);
- }
- /*
- ============
- GetWavinfo
- ============
- */
- static wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
- {
- wavinfo_t info;
- Com_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((char *)data_p+8, "WAVE", 4)))
- {
- Com_Printf("Missing RIFF/WAVE chunks\n");
- return info;
- }
- // get "fmt " chunk
- iff_data = data_p + 12;
- // DumpChunks ();
- FindChunk("fmt ");
- if (!data_p)
- {
- Com_Printf("Missing fmt chunk\n");
- return info;
- }
- data_p += 8;
- info.format = GetLittleShort();
- info.channels = GetLittleShort();
- info.rate = GetLittleLong();
- data_p += 4+2;
- info.width = GetLittleShort() / 8;
- if (info.format != 1)
- {
- Com_Printf("Microsoft PCM format only\n");
- return info;
- }
- // find data chunk
- FindChunk("data");
- if (!data_p)
- {
- Com_Printf("Missing data chunk\n");
- return info;
- }
- data_p += 4;
- info.samples = GetLittleLong () / info.width;
- info.dataofs = data_p - wav;
- return info;
- }
- /*
- ================
- ResampleSfx
- resample / decimate to the current source rate
- ================
- */
- static void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) {
- int outcount;
- int srcsample;
- float stepscale;
- int i;
- int sample, samplefrac, fracstep;
- int part;
- sndBuffer *chunk;
-
- stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
- outcount = sfx->soundLength / stepscale;
- sfx->soundLength = outcount;
- samplefrac = 0;
- fracstep = stepscale * 256;
- chunk = sfx->soundData;
- for (i=0 ; i<outcount ; i++)
- {
- srcsample = samplefrac >> 8;
- samplefrac += fracstep;
- if( inwidth == 2 ) {
- sample = LittleShort ( ((short *)data)[srcsample] );
- } else {
- sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
- }
- part = (i&(SND_CHUNK_SIZE-1));
- if (part == 0) {
- sndBuffer *newchunk;
- newchunk = SND_malloc();
- if (chunk == NULL) {
- sfx->soundData = newchunk;
- } else {
- chunk->next = newchunk;
- }
- chunk = newchunk;
- }
- chunk->sndChunk[part] = sample;
- }
- }
- /*
- ================
- ResampleSfx
- resample / decimate to the current source rate
- ================
- */
- static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) {
- int outcount;
- int srcsample;
- float stepscale;
- int i;
- int sample, samplefrac, fracstep;
-
- stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
- outcount = samples / stepscale;
- samplefrac = 0;
- fracstep = stepscale * 256;
- for (i=0 ; i<outcount ; i++)
- {
- srcsample = samplefrac >> 8;
- samplefrac += fracstep;
- if( inwidth == 2 ) {
- sample = LittleShort ( ((short *)data)[srcsample] );
- } else {
- sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
- }
- sfx[i] = sample;
- }
- return outcount;
- }
- //=============================================================================
- /*
- ==============
- S_LoadSound
- The filename may be different than sfx->name in the case
- of a forced fallback of a player specific sound
- ==============
- */
- qboolean S_LoadSound( sfx_t *sfx )
- {
- byte *data;
- short *samples;
- wavinfo_t info;
- int size;
- // player specific sounds are never directly loaded
- if ( sfx->soundName[0] == '*') {
- return qfalse;
- }
- // load it in
- size = FS_ReadFile( sfx->soundName, (void **)&data );
- if ( !data ) {
- return qfalse;
- }
- info = GetWavinfo( sfx->soundName, data, size );
- if ( info.channels != 1 ) {
- Com_Printf ("%s is a stereo wav file\n", sfx->soundName);
- FS_FreeFile (data);
- return qfalse;
- }
- if ( info.width == 1 ) {
- Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName);
- }
- if ( info.rate != 22050 ) {
- Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName);
- }
- samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2);
- sfx->lastTimeUsed = Com_Milliseconds()+1;
- // each of these compression schemes works just fine
- // but the 16bit quality is much nicer and with a local
- // install assured we can rely upon the sound memory
- // manager to do the right thing for us and page
- // sound in as needed
- if( sfx->soundCompressed == qtrue) {
- sfx->soundCompressionMethod = 1;
- sfx->soundData = NULL;
- sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
- S_AdpcmEncodeSound(sfx, samples);
- #if 0
- } else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
- sfx->soundCompressionMethod = 3;
- sfx->soundData = NULL;
- sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
- encodeMuLaw( sfx, samples);
- } else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
- sfx->soundCompressionMethod = 2;
- sfx->soundData = NULL;
- sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
- encodeWavelet( sfx, samples);
- #endif
- } else {
- sfx->soundCompressionMethod = 0;
- sfx->soundLength = info.samples;
- sfx->soundData = NULL;
- ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse );
- }
-
- Hunk_FreeTempMemory(samples);
- FS_FreeFile( data );
- return qtrue;
- }
- void S_DisplayFreeMemory() {
- Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
- }
|