📄 snd_dma.c
字号:
if (entityNum == listener_number) {
allowed = 8;
}
ch = s_channels;
inplay = 0;
for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
if (ch[i].entnum == entityNum && ch[i].thesfx == sfx) {
if (time - ch[i].allocTime < 50) {
// if (Cvar_VariableValue( "cg_showmiss" )) {
// Com_Printf("double sound start\n");
// }
return;
}
inplay++;
}
}
if (inplay>allowed) {
return;
}
sfx->lastTimeUsed = time;
ch = S_ChannelMalloc(); // entityNum, entchannel);
if (!ch) {
ch = s_channels;
oldest = sfx->lastTimeUsed;
chosen = -1;
for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
if (ch->entnum != listener_number && ch->entnum == entityNum && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) {
oldest = ch->allocTime;
chosen = i;
}
}
if (chosen == -1) {
ch = s_channels;
for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
if (ch->entnum != listener_number && ch->allocTime<oldest && ch->entchannel != CHAN_ANNOUNCER) {
oldest = ch->allocTime;
chosen = i;
}
}
if (chosen == -1) {
if (ch->entnum == listener_number) {
for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
if (ch->allocTime<oldest) {
oldest = ch->allocTime;
chosen = i;
}
}
}
if (chosen == -1) {
Com_Printf("dropping sound\n");
return;
}
}
}
ch = &s_channels[chosen];
ch->allocTime = sfx->lastTimeUsed;
}
if (origin) {
VectorCopy (origin, ch->origin);
ch->fixed_origin = qtrue;
} else {
ch->fixed_origin = qfalse;
}
ch->master_vol = 127;
ch->entnum = entityNum;
ch->thesfx = sfx;
ch->startSample = START_SAMPLE_IMMEDIATE;
ch->entchannel = entchannel;
ch->leftvol = ch->master_vol; // these will get calced at next spatialize
ch->rightvol = ch->master_vol; // unless the game isn't running
ch->doppler = qfalse;
}
/*
==================
S_StartLocalSound
==================
*/
void S_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) {
if ( !s_soundStarted || s_soundMuted ) {
return;
}
if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
Com_Printf( S_COLOR_YELLOW, "S_StartLocalSound: handle %i out of range\n", sfxHandle );
return;
}
S_StartSound (NULL, listener_number, channelNum, sfxHandle );
}
/*
==================
S_ClearSoundBuffer
If we are about to perform file access, clear the buffer
so sound doesn't stutter.
==================
*/
void S_ClearSoundBuffer( void ) {
int clear;
if (!s_soundStarted)
return;
// stop looping sounds
Com_Memset(loopSounds, 0, MAX_GENTITIES*sizeof(loopSound_t));
Com_Memset(loop_channels, 0, MAX_CHANNELS*sizeof(channel_t));
numLoopChannels = 0;
S_ChannelSetup();
s_rawend = 0;
if (dma.samplebits == 8)
clear = 0x80;
else
clear = 0;
SNDDMA_BeginPainting ();
if (dma.buffer)
// TTimo: due to a particular bug workaround in linux sound code,
// have to optionally use a custom C implementation of Com_Memset
// not affecting win32, we have #define Snd_Memset Com_Memset
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
Snd_Memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
SNDDMA_Submit ();
}
/*
==================
S_StopAllSounds
==================
*/
void S_StopAllSounds(void) {
if ( !s_soundStarted ) {
return;
}
// stop the background music
S_StopBackgroundTrack();
S_ClearSoundBuffer ();
}
/*
==============================================================
continuous looping sounds are added each frame
==============================================================
*/
void S_StopLoopingSound(int entityNum) {
loopSounds[entityNum].active = qfalse;
// loopSounds[entityNum].sfx = 0;
loopSounds[entityNum].kill = qfalse;
}
/*
==================
S_ClearLoopingSounds
==================
*/
void S_ClearLoopingSounds( qboolean killall ) {
int i;
for ( i = 0 ; i < MAX_GENTITIES ; i++) {
if (killall || loopSounds[i].kill == qtrue || (loopSounds[i].sfx && loopSounds[i].sfx->soundLength == 0)) {
loopSounds[i].kill = qfalse;
S_StopLoopingSound(i);
}
}
numLoopChannels = 0;
}
/*
==================
S_AddLoopingSound
Called during entity generation for a frame
Include velocity in case I get around to doing doppler...
==================
*/
void S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
sfx_t *sfx;
if ( !s_soundStarted || s_soundMuted ) {
return;
}
if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
Com_Printf( S_COLOR_YELLOW, "S_AddLoopingSound: handle %i out of range\n", sfxHandle );
return;
}
sfx = &s_knownSfx[ sfxHandle ];
if (sfx->inMemory == qfalse) {
S_memoryLoad(sfx);
}
if ( !sfx->soundLength ) {
Com_Error( ERR_DROP, "%s has length 0", sfx->soundName );
}
VectorCopy( origin, loopSounds[entityNum].origin );
VectorCopy( velocity, loopSounds[entityNum].velocity );
loopSounds[entityNum].active = qtrue;
loopSounds[entityNum].kill = qtrue;
loopSounds[entityNum].doppler = qfalse;
loopSounds[entityNum].oldDopplerScale = 1.0;
loopSounds[entityNum].dopplerScale = 1.0;
loopSounds[entityNum].sfx = sfx;
if (s_doppler->integer && VectorLengthSquared(velocity)>0.0) {
vec3_t out;
float lena, lenb;
loopSounds[entityNum].doppler = qtrue;
lena = DistanceSquared(loopSounds[listener_number].origin, loopSounds[entityNum].origin);
VectorAdd(loopSounds[entityNum].origin, loopSounds[entityNum].velocity, out);
lenb = DistanceSquared(loopSounds[listener_number].origin, out);
if ((loopSounds[entityNum].framenum+1) != cls.framecount) {
loopSounds[entityNum].oldDopplerScale = 1.0;
} else {
loopSounds[entityNum].oldDopplerScale = loopSounds[entityNum].dopplerScale;
}
loopSounds[entityNum].dopplerScale = lenb/(lena*100);
if (loopSounds[entityNum].dopplerScale<=1.0) {
loopSounds[entityNum].doppler = qfalse; // don't bother doing the math
}
}
loopSounds[entityNum].framenum = cls.framecount;
}
/*
==================
S_AddLoopingSound
Called during entity generation for a frame
Include velocity in case I get around to doing doppler...
==================
*/
void S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle ) {
sfx_t *sfx;
if ( !s_soundStarted || s_soundMuted ) {
return;
}
if ( sfxHandle < 0 || sfxHandle >= s_numSfx ) {
Com_Printf( S_COLOR_YELLOW, "S_AddRealLoopingSound: handle %i out of range\n", sfxHandle );
return;
}
sfx = &s_knownSfx[ sfxHandle ];
if (sfx->inMemory == qfalse) {
S_memoryLoad(sfx);
}
if ( !sfx->soundLength ) {
Com_Error( ERR_DROP, "%s has length 0", sfx->soundName );
}
VectorCopy( origin, loopSounds[entityNum].origin );
VectorCopy( velocity, loopSounds[entityNum].velocity );
loopSounds[entityNum].sfx = sfx;
loopSounds[entityNum].active = qtrue;
loopSounds[entityNum].kill = qfalse;
loopSounds[entityNum].doppler = qfalse;
}
/*
==================
S_AddLoopSounds
Spatialize all of the looping sounds.
All sounds are on the same cycle, so any duplicates can just
sum up the channel multipliers.
==================
*/
void S_AddLoopSounds (void) {
int i, j, time;
int left_total, right_total, left, right;
channel_t *ch;
loopSound_t *loop, *loop2;
static int loopFrame;
numLoopChannels = 0;
time = Com_Milliseconds();
loopFrame++;
for ( i = 0 ; i < MAX_GENTITIES ; i++) {
loop = &loopSounds[i];
if ( !loop->active || loop->mergeFrame == loopFrame ) {
continue; // already merged into an earlier sound
}
if (loop->kill) {
S_SpatializeOrigin( loop->origin, 127, &left_total, &right_total); // 3d
} else {
S_SpatializeOrigin( loop->origin, 90, &left_total, &right_total); // sphere
}
loop->sfx->lastTimeUsed = time;
for (j=(i+1); j< MAX_GENTITIES ; j++) {
loop2 = &loopSounds[j];
if ( !loop2->active || loop2->doppler || loop2->sfx != loop->sfx) {
continue;
}
loop2->mergeFrame = loopFrame;
if (loop2->kill) {
S_SpatializeOrigin( loop2->origin, 127, &left, &right); // 3d
} else {
S_SpatializeOrigin( loop2->origin, 90, &left, &right); // sphere
}
loop2->sfx->lastTimeUsed = time;
left_total += left;
right_total += right;
}
if (left_total == 0 && right_total == 0) {
continue; // not audible
}
// allocate a channel
ch = &loop_channels[numLoopChannels];
if (left_total > 255) {
left_total = 255;
}
if (right_total > 255) {
right_total = 255;
}
ch->master_vol = 127;
ch->leftvol = left_total;
ch->rightvol = right_total;
ch->thesfx = loop->sfx;
ch->doppler = loop->doppler;
ch->dopplerScale = loop->dopplerScale;
ch->oldDopplerScale = loop->oldDopplerScale;
numLoopChannels++;
if (numLoopChannels == MAX_CHANNELS) {
return;
}
}
}
//=============================================================================
/*
=================
S_ByteSwapRawSamples
If raw data has been loaded in little endien binary form, this must be done.
If raw data was calculated, as with ADPCM, this should not be called.
=================
*/
void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
int i;
if ( width != 2 ) {
return;
}
if ( LittleShort( 256 ) == 256 ) {
return;
}
if ( s_channels == 2 ) {
samples <<= 1;
}
for ( i = 0 ; i < samples ; i++ ) {
((short *)data)[i] = LittleShort( ((short *)data)[i] );
}
}
portable_samplepair_t *S_GetRawSamplePointer() {
return s_rawsamples;
}
/*
============
S_RawSamples
Music streaming
============
*/
void S_RawSamples( int samples, int rate, int width, int s_channels, const byte *data, float volume ) {
int i;
int src, dst;
float scale;
int intVolume;
if ( !s_soundStarted || s_soundMuted ) {
return;
}
intVolume = 256 * volume;
if ( s_rawend < s_soundtime ) {
Com_DPrintf( "S_RawSamples: resetting minimum: %i < %i\n", s_rawend, s_soundtime );
s_rawend = s_soundtime;
}
scale = (float)rate / dma.speed;
//Com_Printf ("%i < %i < %i\n", s_soundtime, s_paintedtime, s_rawend);
if (s_channels == 2 && width == 2)
{
if (scale == 1.0)
{ // optimized case
for (i=0 ; i<samples ; i++)
{
dst = s_rawend&(MAX_RAW_SAMPLES-1);
s_rawend++;
s_rawsamples[dst].left = ((short *)data)[i*2] * intVolume;
s_rawsamples[dst].right = ((short *)data)[i*2+1] * intVolume;
}
}
else
{
for (i=0 ; ; i++)
{
src = i*scale;
if (src >= samples)
break;
dst = s_rawend&(MAX_RAW_SAMPLES-1);
s_rawend++;
s_rawsamples[dst].left = ((short *)data)[src*2] * intVolume;
s_rawsamples[dst].right = ((short *)data)[src*2+1] * intVolume;
}
}
}
else if (s_channels == 1 && width == 2)
{
for (i=0 ; ; i++)
{
src = i*scale;
if (src >= samples)
break;
dst = s_rawend&(MAX_RAW_SAMPLES-1);
s_rawend++;
s_rawsamples[dst].left = ((short *)data)[src] * intVolume;
s_rawsamples[dst].right = ((short *)data)[src] * intVolume;
}
}
else if (s_channels == 2 && width == 1)
{
intVolume *= 256;
for (i=0 ; ; i++)
{
src = i*scale;
if (src >= samples)
break;
dst = s_rawend&(MAX_RAW_SAMPLES-1);
s_rawend++;
s_rawsamples[dst].left = ((char *)data)[src*2] * intVolume;
s_rawsamples[dst].right = ((char *)data)[src*2+1] * intVolume;
}
}
else if (s_channels == 1 && width == 1)
{
intVolume *= 256;
for (i=0 ; ; i++)
{
src = i*scale;
if (src >= samples)
break;
dst = s_rawend&(MAX_RAW_SAMPLES-1);
s_rawend++;
s_rawsamples[dst].left = (((byte *)data)[src]-128) * intVolume;
s_rawsamples[dst].right = (((byte *)data)[src]-128) * intVolume;
}
}
if ( s_rawend > s_soundtime + MAX_RAW_SAMPLES ) {
Com_DPrintf( "S_RawSamples: overflowed %i > %i\n", s_rawend, s_soundtime );
}
}
//=============================================================================
/*
=====================
S_UpdateEntityPosition
let the sound system know where an entity currently is
======================
*/
void S_UpdateEntityPosition( int entityNum, const vec3_t origin ) {
if ( entityNum < 0 || entityNum > MAX_GENTITIES ) {
Com_Error( ERR_DROP, "S_UpdateEntityPosition: bad entitynum %i", entityNum );
}
VectorCopy( origin, loopSounds[entityNum].origin );
}
/*
============
S_Respatialize
Change the volumes of all the playing sounds for changes in their positions
============
*/
void S_Respatialize( int entityNum, const vec3_t head, vec3_t axis[3], int inwater ) {
int i;
channel_t *ch;
vec3_t origin;
if ( !s_soundStarted || s_soundMuted ) {
return;
}
listener_number = entityNum;
VectorCopy(head, listener_origin);
VectorCopy(axis[0], listener_axis[0]);
VectorCopy(axis[1], listener_axis[1]);
VectorCopy(axis[2], listener_axis[2]);
// update spatialization for dynamic sounds
ch = s_channels;
for ( i = 0 ; i < MAX_CHANNELS ; i++, ch++ ) {
if ( !ch->thesfx ) {
continue;
}
// anything coming from the view entity will always be full volume
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -