openmohaa/code/client/snd_mem.c

281 lines
7.1 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
along with Quake III Arena source code; 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"
#include "snd_codec.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( void ) {
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( void ) {
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" );
}
void SND_shutdown( void )
{
free( sfxScratchBuffer );
free( buffer );
}
/*
================
ResampleSfx
resample / decimate to the current source rate
================
*/
static int ResampleSfx( sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, qboolean compressed ) {
int outcount;
int srcsample;
float stepscale;
int i, j;
int sample, samplefrac, fracstep;
int part;
sndBuffer *chunk;
stepscale = ( float )inrate / dma.speed; // this is usually 0.5, 1, or 2
outcount = samples / stepscale;
samplefrac = 0;
fracstep = stepscale * 256 * channels;
chunk = sfx->soundData;
for( i = 0; i<outcount; i++ )
{
srcsample = samplefrac >> 8;
samplefrac += fracstep;
for( j = 0; j<channels; j++ )
{
if( inwidth == 2 ) {
sample = ( ( ( short * )data )[ srcsample + j ] );
}
else {
sample = ( 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;
}
chunk->sndChunk[ part ] = sample;
}
}
return outcount;
}
/*
================
ResampleSfx
resample / decimate to the current source rate
================
*/
static int ResampleSfxRaw( short *sfx, int channels, int inrate, int inwidth, int samples, byte *data ) {
int outcount;
int srcsample;
float stepscale;
int i, j;
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 * channels;
for( i = 0; i<outcount; i++ )
{
srcsample = samplefrac >> 8;
samplefrac += fracstep;
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;
}
}
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;
snd_info_t info;
// int size;
// load it in
data = S_CodecLoad( sfx->soundName, &info );
if( !data )
return qfalse;
if( info.width == 1 ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName );
}
if( info.rate != 22050 ) {
Com_DPrintf( S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName );
}
samples = Hunk_AllocateTempMemory( info.channels * 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( info.channels == 1 && sfx->soundCompressed == qtrue ) {
sfx->soundCompressionMethod = 1;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs );
S_AdpcmEncodeSound( sfx, samples );
#if 0
}
else if( info.channels == 1 && info.samples>( SND_CHUNK_SIZE * 16 ) && info.width >1 ) {
sfx->soundCompressionMethod = 3;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, ( data + info.dataofs ) );
encodeMuLaw( sfx, samples );
}
else if( info.channels == 1 && info.samples>( SND_CHUNK_SIZE * 6400 ) && info.width >1 ) {
sfx->soundCompressionMethod = 2;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, ( data + info.dataofs ) );
encodeWavelet( sfx, samples );
#endif
}
else {
sfx->soundCompressionMethod = 0;
sfx->soundData = NULL;
sfx->soundLength = ResampleSfx( sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse );
}
sfx->soundChannels = info.channels;
Hunk_FreeTempMemory( samples );
Hunk_FreeTempMemory( data );
return qtrue;
}
void S_DisplayFreeMemory( void ) {
Com_Printf( "%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse );
}