📄 snd_dma.c
字号:
if (ch->entnum == listener_number) {
ch->leftvol = ch->master_vol;
ch->rightvol = ch->master_vol;
} else {
if (ch->fixed_origin) {
VectorCopy( ch->origin, origin );
} else {
VectorCopy( loopSounds[ ch->entnum ].origin, origin );
}
S_SpatializeOrigin (origin, ch->master_vol, &ch->leftvol, &ch->rightvol);
}
}
// add loopsounds
S_AddLoopSounds ();
}
/*
========================
S_ScanChannelStarts
Returns qtrue if any new sounds were started since the last mix
========================
*/
qboolean S_ScanChannelStarts( void ) {
channel_t *ch;
int i;
qboolean newSamples;
newSamples = qfalse;
ch = s_channels;
for (i=0; i<MAX_CHANNELS ; i++, ch++) {
if ( !ch->thesfx ) {
continue;
}
// if this channel was just started this frame,
// set the sample count to it begins mixing
// into the very first sample
if ( ch->startSample == START_SAMPLE_IMMEDIATE ) {
ch->startSample = s_paintedtime;
newSamples = qtrue;
continue;
}
// if it is completely finished by now, clear it
if ( ch->startSample + (ch->thesfx->soundLength) <= s_paintedtime ) {
S_ChannelFree(ch);
}
}
return newSamples;
}
/*
============
S_Update
Called once each time through the main loop
============
*/
void S_Update( void ) {
int i;
int total;
channel_t *ch;
if ( !s_soundStarted || s_soundMuted ) {
Com_DPrintf ("not started or muted\n");
return;
}
//
// debugging output
//
if ( s_show->integer == 2 ) {
total = 0;
ch = s_channels;
for (i=0 ; i<MAX_CHANNELS; i++, ch++) {
if (ch->thesfx && (ch->leftvol || ch->rightvol) ) {
Com_Printf ("%f %f %s\n", ch->leftvol, ch->rightvol, ch->thesfx->soundName);
total++;
}
}
Com_Printf ("----(%i)---- painted: %i\n", total, s_paintedtime);
}
// add raw data from streamed samples
S_UpdateBackgroundTrack();
// mix some sound
S_Update_();
}
void S_GetSoundtime(void)
{
int samplepos;
static int buffers;
static int oldsamplepos;
int fullsamples;
fullsamples = dma.samples / dma.channels;
// it is possible to miscount buffers if it has wrapped twice between
// calls to S_Update. Oh well.
samplepos = SNDDMA_GetDMAPos();
if (samplepos < oldsamplepos)
{
buffers++; // buffer wrapped
if (s_paintedtime > 0x40000000)
{ // time to chop things off to avoid 32 bit limits
buffers = 0;
s_paintedtime = fullsamples;
S_StopAllSounds ();
}
}
oldsamplepos = samplepos;
s_soundtime = buffers*fullsamples + samplepos/dma.channels;
#if 0
// check to make sure that we haven't overshot
if (s_paintedtime < s_soundtime)
{
Com_DPrintf ("S_Update_ : overflow\n");
s_paintedtime = s_soundtime;
}
#endif
if ( dma.submission_chunk < 256 ) {
s_paintedtime = s_soundtime + s_mixPreStep->value * dma.speed;
} else {
s_paintedtime = s_soundtime + dma.submission_chunk;
}
}
void S_Update_(void) {
unsigned endtime;
int samps;
static float lastTime = 0.0f;
float ma, op;
float thisTime, sane;
static int ot = -1;
if ( !s_soundStarted || s_soundMuted ) {
return;
}
thisTime = Com_Milliseconds();
// Updates s_soundtime
S_GetSoundtime();
if (s_soundtime == ot) {
return;
}
ot = s_soundtime;
// clear any sound effects that end before the current time,
// and start any new sounds
S_ScanChannelStarts();
sane = thisTime - lastTime;
if (sane<11) {
sane = 11; // 85hz
}
ma = s_mixahead->value * dma.speed;
op = s_mixPreStep->value + sane*dma.speed*0.01;
if (op < ma) {
ma = op;
}
// mix ahead of current position
endtime = s_soundtime + ma;
// mix to an even submission block size
endtime = (endtime + dma.submission_chunk-1)
& ~(dma.submission_chunk-1);
// never mix more than the complete buffer
samps = dma.samples >> (dma.channels-1);
if (endtime - s_soundtime > samps)
endtime = s_soundtime + samps;
SNDDMA_BeginPainting ();
S_PaintChannels (endtime);
SNDDMA_Submit ();
lastTime = thisTime;
}
/*
===============================================================================
console functions
===============================================================================
*/
void S_Play_f( void ) {
int i;
sfxHandle_t h;
char name[256];
i = 1;
while ( i<Cmd_Argc() ) {
if ( !Q_strrchr(Cmd_Argv(i), '.') ) {
Com_sprintf( name, sizeof(name), "%s.wav", Cmd_Argv(1) );
} else {
Q_strncpyz( name, Cmd_Argv(i), sizeof(name) );
}
h = S_RegisterSound( name, qfalse );
if( h ) {
S_StartLocalSound( h, CHAN_LOCAL_SOUND );
}
i++;
}
}
void S_Music_f( void ) {
int c;
c = Cmd_Argc();
if ( c == 2 ) {
S_StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(1) );
s_backgroundLoop[0] = 0;
} else if ( c == 3 ) {
S_StartBackgroundTrack( Cmd_Argv(1), Cmd_Argv(2) );
} else {
Com_Printf ("music <musicfile> [loopfile]\n");
return;
}
}
void S_SoundList_f( void ) {
int i;
sfx_t *sfx;
int size, total;
char type[4][16];
char mem[2][16];
strcpy(type[0], "16bit");
strcpy(type[1], "adpcm");
strcpy(type[2], "daub4");
strcpy(type[3], "mulaw");
strcpy(mem[0], "paged out");
strcpy(mem[1], "resident ");
total = 0;
for (sfx=s_knownSfx, i=0 ; i<s_numSfx ; i++, sfx++) {
size = sfx->soundLength;
total += size;
Com_Printf("%6i[%s] : %s[%s]\n", size, type[sfx->soundCompressionMethod], sfx->soundName, mem[sfx->inMemory] );
}
Com_Printf ("Total resident: %i\n", total);
S_DisplayFreeMemory();
}
/*
===============================================================================
background music functions
===============================================================================
*/
int FGetLittleLong( fileHandle_t f ) {
int v;
FS_Read( &v, sizeof(v), f );
return LittleLong( v);
}
int FGetLittleShort( fileHandle_t f ) {
short v;
FS_Read( &v, sizeof(v), f );
return LittleShort( v);
}
// returns the length of the data in the chunk, or 0 if not found
int S_FindWavChunk( fileHandle_t f, char *chunk ) {
char name[5];
int len;
int r;
name[4] = 0;
len = 0;
r = FS_Read( name, 4, f );
if ( r != 4 ) {
return 0;
}
len = FGetLittleLong( f );
if ( len < 0 || len > 0xfffffff ) {
len = 0;
return 0;
}
len = (len + 1 ) & ~1; // pad to word boundary
// s_nextWavChunk += len + 8;
if ( strcmp( name, chunk ) ) {
return 0;
}
return len;
}
/*
======================
S_StopBackgroundTrack
======================
*/
void S_StopBackgroundTrack( void ) {
if ( !s_backgroundFile ) {
return;
}
Sys_EndStreamedFile( s_backgroundFile );
FS_FCloseFile( s_backgroundFile );
s_backgroundFile = 0;
s_rawend = 0;
}
/*
======================
S_StartBackgroundTrack
======================
*/
void S_StartBackgroundTrack( const char *intro, const char *loop ){
int len;
char dump[16];
char name[MAX_QPATH];
if ( !intro ) {
intro = "";
}
if ( !loop || !loop[0] ) {
loop = intro;
}
Com_DPrintf( "S_StartBackgroundTrack( %s, %s )\n", intro, loop );
Q_strncpyz( name, intro, sizeof( name ) - 4 );
COM_DefaultExtension( name, sizeof( name ), ".wav" );
if ( !intro[0] ) {
return;
}
Q_strncpyz( s_backgroundLoop, loop, sizeof( s_backgroundLoop ) );
// close the background track, but DON'T reset s_rawend
// if restarting the same back ground track
if ( s_backgroundFile ) {
Sys_EndStreamedFile( s_backgroundFile );
FS_FCloseFile( s_backgroundFile );
s_backgroundFile = 0;
}
//
// open up a wav file and get all the info
//
FS_FOpenFileRead( name, &s_backgroundFile, qtrue );
if ( !s_backgroundFile ) {
Com_Printf( S_COLOR_YELLOW "WARNING: couldn't open music file %s\n", name );
return;
}
// skip the riff wav header
FS_Read(dump, 12, s_backgroundFile);
if ( !S_FindWavChunk( s_backgroundFile, "fmt " ) ) {
Com_Printf( "No fmt chunk in %s\n", name );
FS_FCloseFile( s_backgroundFile );
s_backgroundFile = 0;
return;
}
// save name for soundinfo
s_backgroundInfo.format = FGetLittleShort( s_backgroundFile );
s_backgroundInfo.channels = FGetLittleShort( s_backgroundFile );
s_backgroundInfo.rate = FGetLittleLong( s_backgroundFile );
FGetLittleLong( s_backgroundFile );
FGetLittleShort( s_backgroundFile );
s_backgroundInfo.width = FGetLittleShort( s_backgroundFile ) / 8;
if ( s_backgroundInfo.format != WAV_FORMAT_PCM ) {
FS_FCloseFile( s_backgroundFile );
s_backgroundFile = 0;
Com_Printf("Not a microsoft PCM format wav: %s\n", name);
return;
}
if ( s_backgroundInfo.channels != 2 || s_backgroundInfo.rate != 22050 ) {
Com_Printf(S_COLOR_YELLOW "WARNING: music file %s is not 22k stereo\n", name );
}
if ( ( len = S_FindWavChunk( s_backgroundFile, "data" ) ) == 0 ) {
FS_FCloseFile( s_backgroundFile );
s_backgroundFile = 0;
Com_Printf("No data chunk in %s\n", name);
return;
}
s_backgroundInfo.samples = len / (s_backgroundInfo.width * s_backgroundInfo.channels);
s_backgroundSamples = s_backgroundInfo.samples;
//
// start the background streaming
//
Sys_BeginStreamedFile( s_backgroundFile, 0x10000 );
}
/*
======================
S_UpdateBackgroundTrack
======================
*/
void S_UpdateBackgroundTrack( void ) {
int bufferSamples;
int fileSamples;
byte raw[30000]; // just enough to fit in a mac stack frame
int fileBytes;
int r;
static float musicVolume = 0.5f;
if ( !s_backgroundFile ) {
return;
}
// graeme see if this is OK
musicVolume = (musicVolume + (s_musicVolume->value * 2))/4.0f;
// don't bother playing anything if musicvolume is 0
if ( musicVolume <= 0 ) {
return;
}
// see how many samples should be copied into the raw buffer
if ( s_rawend < s_soundtime ) {
s_rawend = s_soundtime;
}
while ( s_rawend < s_soundtime + MAX_RAW_SAMPLES ) {
bufferSamples = MAX_RAW_SAMPLES - (s_rawend - s_soundtime);
// decide how much data needs to be read from the file
fileSamples = bufferSamples * s_backgroundInfo.rate / dma.speed;
// don't try and read past the end of the file
if ( fileSamples > s_backgroundSamples ) {
fileSamples = s_backgroundSamples;
}
// our max buffer size
fileBytes = fileSamples * (s_backgroundInfo.width * s_backgroundInfo.channels);
if ( fileBytes > sizeof(raw) ) {
fileBytes = sizeof(raw);
fileSamples = fileBytes / (s_backgroundInfo.width * s_backgroundInfo.channels);
}
r = Sys_StreamedRead( raw, 1, fileBytes, s_backgroundFile );
if ( r != fileBytes ) {
Com_Printf("StreamedRead failure on music track\n");
S_StopBackgroundTrack();
return;
}
// byte swap if needed
S_ByteSwapRawSamples( fileSamples, s_backgroundInfo.width, s_backgroundInfo.channels, raw );
// add to raw buffer
S_RawSamples( fileSamples, s_backgroundInfo.rate,
s_backgroundInfo.width, s_backgroundInfo.channels, raw, musicVolume );
s_backgroundSamples -= fileSamples;
if ( !s_backgroundSamples ) {
// loop
if (s_backgroundLoop[0]) {
Sys_EndStreamedFile( s_backgroundFile );
FS_FCloseFile( s_backgroundFile );
s_backgroundFile = 0;
S_StartBackgroundTrack( s_backgroundLoop, s_backgroundLoop );
if ( !s_backgroundFile ) {
return; // loop failed to restart
}
} else {
s_backgroundFile = 0;
return;
}
}
}
}
/*
======================
S_FreeOldestSound
======================
*/
void S_FreeOldestSound() {
int i, oldest, used;
sfx_t *sfx;
sndBuffer *buffer, *nbuffer;
oldest = Com_Milliseconds();
used = 0;
for (i=1 ; i < s_numSfx ; i++) {
sfx = &s_knownSfx[i];
if (sfx->inMemory && sfx->lastTimeUsed<oldest) {
used = i;
oldest = sfx->lastTimeUsed;
}
}
sfx = &s_knownSfx[used];
Com_DPrintf("S_FreeOldestSound: freeing sound %s\n", sfx->soundName);
buffer = sfx->soundData;
while(buffer != NULL) {
nbuffer = buffer->next;
SND_free(buffer);
buffer = nbuffer;
}
sfx->inMemory = qfalse;
sfx->soundData = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -