openmohaa/code/client/snd_mem.c

282 lines
7.2 KiB
C
Raw Normal View History

2016-03-27 11:49:47 +02:00
/*
===========================================================================
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
2023-05-24 19:40:09 +02:00
along with Quake III Arena source code; if not, write to the Free Software
2016-03-27 11:49:47 +02:00
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 $
*
*****************************************************************************/
2016-03-27 11:49:47 +02:00
#include "snd_local.h"
2023-05-24 19:40:09 +02:00
#include "snd_codec.h"
2016-03-27 11:49:47 +02:00
#define DEF_COMSOUNDMEGS 16
2016-03-27 11:49:47 +02:00
/*
===============================================================================
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);
2016-03-27 11:49:47 +02:00
}
2023-05-24 19:40:09 +02:00
sndBuffer* SND_malloc(void) {
2016-03-27 11:49:47 +02:00
sndBuffer *v;
int oldInUse = inUse;
while (!freelist) {
if (!S_FreeOldestSound()) {
Com_Error(ERR_FATAL, "Out of SND allocations. Start the game with an higher com_soundMegs value and try again.");
return NULL;
}
2016-03-27 11:49:47 +02:00
}
inUse -= sizeof(sndBuffer);
totalInUse += sizeof(sndBuffer);
2016-03-27 11:49:47 +02:00
v = freelist;
freelist = *(sndBuffer **)freelist;
2016-03-27 11:49:47 +02:00
v->next = NULL;
return v;
}
2023-05-24 19:40:09 +02:00
void SND_setup(void) {
2016-03-27 11:49:47 +02:00
sndBuffer *p, *q;
cvar_t *cv;
int scs;
cv = Cvar_Get( "com_soundMegs", XSTRING(DEF_COMSOUNDMEGS), CVAR_LATCH | CVAR_ARCHIVE );
2016-03-27 11:49:47 +02:00
scs = (cv->integer*1536);
2016-03-27 11:49:47 +02:00
buffer = malloc(scs*sizeof(sndBuffer) );
2016-03-27 11:49:47 +02:00
// allocate the stack based hunk allocator
sfxScratchBuffer = malloc(SND_CHUNK_SIZE * sizeof(short) * 4); //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
2016-03-27 11:49:47 +02:00
sfxScratchPointer = NULL;
inUse = scs*sizeof(sndBuffer);
2016-03-27 11:49:47 +02:00
p = buffer;;
q = p + scs;
while (--q > p)
*(sndBuffer **)q = q-1;
*(sndBuffer **)q = NULL;
2016-03-27 11:49:47 +02:00
freelist = p + scs - 1;
Com_Printf("Sound memory manager started\n");
2016-03-27 11:49:47 +02:00
}
2023-05-24 19:40:09 +02:00
void SND_shutdown(void)
2016-03-27 11:49:47 +02:00
{
2023-05-24 19:40:09 +02:00
free(sfxScratchBuffer);
free(buffer);
2016-03-27 11:49:47 +02:00
}
/*
================
ResampleSfx
resample / decimate to the current source rate
================
*/
2023-05-24 19:40:09 +02:00
static int ResampleSfx( sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, qboolean compressed ) {
2016-03-27 11:49:47 +02:00
int outcount;
int srcsample;
float stepscale;
2023-05-24 19:40:09 +02:00
int i, j;
2016-03-27 11:49:47 +02:00
int sample, samplefrac, fracstep;
int part;
sndBuffer *chunk;
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
2016-03-27 11:49:47 +02:00
2023-05-24 19:40:09 +02:00
outcount = samples / stepscale;
2016-03-27 11:49:47 +02:00
2023-05-24 19:40:09 +02:00
srcsample = 0;
2016-03-27 11:49:47 +02:00
samplefrac = 0;
2023-05-24 19:40:09 +02:00
fracstep = stepscale * 256 * channels;
2016-03-27 11:49:47 +02:00
chunk = sfx->soundData;
for (i=0 ; i<outcount ; i++)
2016-03-27 11:49:47 +02:00
{
2023-05-24 19:40:09 +02:00
srcsample += samplefrac >> 8;
samplefrac &= 255;
2016-03-27 11:49:47 +02:00
samplefrac += fracstep;
2023-05-24 19:40:09 +02:00
for (j=0 ; j<channels ; j++)
{
if( inwidth == 2 ) {
sample = ( ((short *)data)[srcsample+j] );
} else {
2023-05-24 19:40:09 +02:00
sample = (unsigned int)( (unsigned char)(data[srcsample+j]) - 128) << 8;
}
part = (i*channels+j)&(SND_CHUNK_SIZE-1);
if (part == 0) {
sndBuffer *newchunk;
newchunk = SND_malloc();
if (chunk == NULL) {
sfx->soundData = newchunk;
} else {
chunk->next = newchunk;
}
chunk = newchunk;
2016-03-27 11:49:47 +02:00
}
2023-05-24 19:40:09 +02:00
chunk->sndChunk[part] = sample;
}
2023-05-18 19:47:37 +02:00
}
2023-05-24 19:40:09 +02:00
return outcount;
2016-03-27 11:49:47 +02:00
}
/*
================
ResampleSfx
resample / decimate to the current source rate
================
*/
2023-05-24 19:40:09 +02:00
static int ResampleSfxRaw( short *sfx, int channels, int inrate, int inwidth, int samples, byte *data ) {
2016-03-27 11:49:47 +02:00
int outcount;
int srcsample;
float stepscale;
2023-05-24 19:40:09 +02:00
int i, j;
2016-03-27 11:49:47 +02:00
int sample, samplefrac, fracstep;
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
2016-03-27 11:49:47 +02:00
outcount = samples / stepscale;
2023-05-24 19:40:09 +02:00
srcsample = 0;
2016-03-27 11:49:47 +02:00
samplefrac = 0;
2023-05-24 19:40:09 +02:00
fracstep = stepscale * 256 * channels;
2016-03-27 11:49:47 +02:00
for (i=0 ; i<outcount ; i++)
2016-03-27 11:49:47 +02:00
{
2023-05-24 19:40:09 +02:00
srcsample += samplefrac >> 8;
samplefrac &= 255;
2016-03-27 11:49:47 +02:00
samplefrac += fracstep;
2023-05-24 19:40:09 +02:00
for (j=0 ; j<channels ; j++)
{
if( inwidth == 2 ) {
sample = LittleShort ( ((short *)data)[srcsample+j] );
} else {
sample = (int)( (unsigned char)(data[srcsample+j]) - 128) << 8;
}
sfx[i*channels+j] = sample;
2016-03-27 11:49:47 +02:00
}
}
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;
2023-05-24 19:40:09 +02:00
snd_info_t info;
// int size;
2016-03-27 11:49:47 +02:00
// load it in
2023-05-24 19:40:09 +02:00
data = S_CodecLoad(sfx->soundName, &info);
if(!data)
2016-03-27 11:49:47 +02:00
return qfalse;
if ( info.width == 1 ) {
2023-05-24 19:40:09 +02:00
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName);
2016-03-27 11:49:47 +02:00
}
2023-05-29 15:24:24 +02:00
//if ( info.rate != 22050 ) {
// Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName);
//}
2016-03-27 11:49:47 +02:00
2023-05-24 19:40:09 +02:00
samples = Hunk_AllocateTempMemory(info.channels * info.samples * sizeof(short) * 2);
2016-03-27 11:49:47 +02:00
sfx->lastTimeUsed = Com_Milliseconds()+1;
2016-03-27 11:49:47 +02:00
// 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
2023-05-24 19:40:09 +02:00
if( info.channels == 1 && sfx->soundCompressed == qtrue) {
2016-03-27 11:49:47 +02:00
sfx->soundCompressionMethod = 1;
sfx->soundData = NULL;
2023-05-24 19:40:09 +02:00
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs );
S_AdpcmEncodeSound(sfx, samples);
2016-03-27 11:49:47 +02:00
#if 0
2023-05-24 19:40:09 +02:00
} else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
2016-03-27 11:49:47 +02:00
sfx->soundCompressionMethod = 3;
sfx->soundData = NULL;
2023-05-24 19:40:09 +02:00
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) );
encodeMuLaw( sfx, samples);
2023-05-24 19:40:09 +02:00
} else if (info.channels == 1 && info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
2016-03-27 11:49:47 +02:00
sfx->soundCompressionMethod = 2;
sfx->soundData = NULL;
2023-05-24 19:40:09 +02:00
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, (data + info.dataofs) );
encodeWavelet( sfx, samples);
2016-03-27 11:49:47 +02:00
#endif
} else {
2016-03-27 11:49:47 +02:00
sfx->soundCompressionMethod = 0;
sfx->soundData = NULL;
2023-05-24 19:40:09 +02:00
sfx->soundLength = ResampleSfx( sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse );
2016-03-27 11:49:47 +02:00
}
2023-05-24 19:40:09 +02:00
sfx->soundChannels = info.channels;
Hunk_FreeTempMemory(samples);
2023-05-24 19:40:09 +02:00
Hunk_FreeTempMemory(data);
2016-03-27 11:49:47 +02:00
return qtrue;
}
2023-05-24 19:40:09 +02:00
void S_DisplayFreeMemory(void) {
Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
2016-03-27 11:49:47 +02:00
}