engine: client: consolidate dma, s_listener and bunch of separate sound globals into one snd global struct. Replace bit fields with bit flags in preparation for SoundAPI

Remove s_combine_sounds, it never worked great and was disabled by default.
This commit is contained in:
Alibek Omarov
2026-04-06 06:00:40 +05:00
parent 75fb6c5f34
commit 729c985eaf
13 changed files with 486 additions and 506 deletions

View File

@@ -255,9 +255,9 @@ static void AVI_StreamAudio( movie_state_t *Avi )
rawchan_t *ch = NULL; rawchan_t *ch = NULL;
// keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled // keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled
qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !s_listener.streaming : false; qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !snd.streaming : false;
if( !dma.initialized || disable_stream || cl.paused || !Avi->cached_audio ) if( !snd.initialized || disable_stream || cl.paused || !Avi->cached_audio )
return; return;
ch = S_FindRawChannel( Avi->entnum, true ); ch = S_FindRawChannel( Avi->entnum, true );
@@ -268,14 +268,14 @@ static void AVI_StreamAudio( movie_state_t *Avi )
ch->master_vol = Avi->volume; ch->master_vol = Avi->volume;
ch->dist_mult = (Avi->attn / SND_CLIP_DISTANCE); ch->dist_mult = (Avi->attn / SND_CLIP_DISTANCE);
if( ch->s_rawend < soundtime ) if( ch->s_rawend < snd.soundtime )
ch->s_rawend = soundtime; ch->s_rawend = snd.soundtime;
while( ch->s_rawend < soundtime + ch->max_samples ) while( ch->s_rawend < snd.soundtime + ch->max_samples )
{ {
size_t copy; size_t copy;
buffer_samples = ch->max_samples - (ch->s_rawend - soundtime); buffer_samples = ch->max_samples - (ch->s_rawend - snd.soundtime);
file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED); file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED);
if( file_samples <= 1 ) return; // no more samples need if( file_samples <= 1 ) return; // no more samples need

View File

@@ -1381,7 +1381,7 @@ qboolean CL_GetEntitySpatialization( channel_t *ch )
if( ch->entnum == 0 ) if( ch->entnum == 0 )
{ {
ch->staticsound = true; SetBits( ch->flags, FL_CHAN_STATIC_SOUND );
return true; // static sound return true; // static sound
} }

View File

@@ -152,7 +152,7 @@ sfx_t *S_FindName( const char *pname, qboolean *pfInCache )
uint i, hash; uint i, hash;
string name; string name;
if( COM_StringEmptyOrNULL( pname ) || !dma.initialized ) if( COM_StringEmptyOrNULL( pname ) || !snd.initialized )
return NULL; return NULL;
if( Q_strlen( pname ) >= sizeof( sfx->name )) if( Q_strlen( pname ) >= sizeof( sfx->name ))
@@ -247,7 +247,7 @@ void S_BeginRegistration( void )
{ {
int i; int i;
snd_ambient = false; snd.have_ambient_sfx = false;
// check for automatic ambient sounds // check for automatic ambient sounds
for( i = 0; i < NUM_AMBIENTS; i++ ) for( i = 0; i < NUM_AMBIENTS; i++ )
@@ -255,8 +255,9 @@ void S_BeginRegistration( void )
if( !GI->ambientsound[i][0] ) if( !GI->ambientsound[i][0] )
continue; // empty slot continue; // empty slot
ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] ); snd.ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] );
if( ambient_sfx[i] ) snd_ambient = true; // allow auto-ambients if( snd.ambient_sfx[i] )
snd.have_ambient_sfx = true; // allow auto-ambients
} }
s_registering = true; s_registering = true;
@@ -273,7 +274,7 @@ void S_EndRegistration( void )
sfx_t *sfx; sfx_t *sfx;
int i; int i;
if( !s_registering || !dma.initialized ) if( !s_registering || !snd.initialized )
return; return;
// free any sounds not from this registration sequence // free any sounds not from this registration sequence
@@ -306,7 +307,7 @@ sound_t S_RegisterSound( const char *name )
{ {
sfx_t *sfx; sfx_t *sfx;
if( COM_StringEmptyOrNULL( name ) || !dma.initialized ) if( COM_StringEmptyOrNULL( name ) || !snd.initialized )
return -1; return -1;
if( S_TestSoundChar( name, '!' )) if( S_TestSoundChar( name, '!' ))
@@ -330,7 +331,7 @@ sound_t S_RegisterSound( const char *name )
sfx_t *S_GetSfxByHandle( sound_t handle ) sfx_t *S_GetSfxByHandle( sound_t handle )
{ {
if( !dma.initialized ) if( !snd.initialized )
return NULL; return NULL;
// create new sfx // create new sfx
@@ -369,7 +370,7 @@ void S_FreeSounds( void )
sfx_t *sfx; sfx_t *sfx;
int i; int i;
if( !dma.initialized ) if( !snd.initialized )
return; return;
// stop all sounds // stop all sounds

View File

@@ -31,19 +31,18 @@ struct
int in_seconds; int in_seconds;
} soundfade; } soundfade;
dma_t dma;
poolhandle_t sndpool; poolhandle_t sndpool;
sound_t ambient_sfx[NUM_AMBIENTS];
qboolean snd_ambient = false;
qboolean snd_fade_sequence = false; qboolean snd_fade_sequence = false;
listener_t s_listener;
channel_t channels[MAX_CHANNELS]; // this confuses the shit out of qt creator parser
rawchan_t *raw_channels[MAX_RAW_CHANNELS]; // and good luck if you rely on shitty old msvc
int total_channels; snd_globals_t snd =
{
int soundtime; // sample PAIRS .channels = (channel_t[MAX_CHANNELS]){},
int paintedtime; // sample PAIRS .max_channels = MAX_CHANNELS,
.raw_channels = (rawchan_t*[MAX_RAW_CHANNELS]){},
.max_raw_channels = MAX_RAW_CHANNELS,
};
static CVAR_DEFINE( s_volume, "volume", "0.7", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sound volume" ); static CVAR_DEFINE( s_volume, "volume", "0.7", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sound volume" );
CVAR_DEFINE( s_musicvolume, "MP3Volume", "1.0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "background music volume" ); CVAR_DEFINE( s_musicvolume, "MP3Volume", "1.0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "background music volume" );
@@ -52,7 +51,6 @@ static CVAR_DEFINE_AUTO( s_show, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "show play
CVAR_DEFINE_AUTO( s_lerping, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "apply interpolation to sound output" ); CVAR_DEFINE_AUTO( s_lerping, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "apply interpolation to sound output" );
static CVAR_DEFINE( s_ambient_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" ); static CVAR_DEFINE( s_ambient_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" );
static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" ); static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" );
static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" );
CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" ); CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" );
CVAR_DEFINE_AUTO( s_test, "0", 0, "engine developer cvar for quick testing new features" ); CVAR_DEFINE_AUTO( s_test, "0", 0, "engine developer cvar for quick testing new features" );
CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" ); CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" );
@@ -158,7 +156,7 @@ S_IsClient
*/ */
static qboolean S_IsClient( int entnum ) static qboolean S_IsClient( int entnum )
{ {
return entnum == s_listener.entnum; return entnum == snd.entnum;
} }
@@ -175,11 +173,9 @@ void S_FreeChannel( channel_t *ch )
{ {
ch->sfx = NULL; ch->sfx = NULL;
ch->name[0] = '\0'; ch->name[0] = '\0';
ch->use_loop = false; ch->flags = 0;
ch->is_sentence = false;
ch->forced_end = ch->sample = 0.0; ch->forced_end = ch->sample = 0.0;
ch->data = NULL; ch->data = NULL;
ch->finished = false;
SND_CloseMouth( ch ); SND_CloseMouth( ch );
} }
@@ -240,7 +236,7 @@ static qboolean SND_FStreamIsPlaying( sfx_t *sfx )
{ {
for( int i = NUM_AMBIENTS; i < MAX_DYNAMIC_CHANNELS; i++ ) for( int i = NUM_AMBIENTS; i < MAX_DYNAMIC_CHANNELS; i++ )
{ {
if( channels[i].sfx == sfx ) if( snd.channels[i].sfx == sfx )
return true; return true;
} }
return false; return false;
@@ -257,14 +253,14 @@ static int SND_GetChannelTimeLeft( const channel_t *ch )
{ {
int remaining; int remaining;
if( ch->finished || !ch->sfx || !ch->sfx->cache ) if( FBitSet( ch->flags, FL_CHAN_FINISHED ) || !ch->sfx || !ch->sfx->cache )
return 0; return 0;
if( ch->is_sentence ) // sentences are special, count all remaining words if( FBitSet( ch->flags, FL_CHAN_IS_SENTENCE )) // sentences are special, count all remaining words
{ {
int i; int i;
if( ch->sentence_finished ) if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ) )
return 0; return 0;
// current word // current word
@@ -294,7 +290,7 @@ static int SND_GetChannelTimeLeft( const channel_t *ch )
else else
{ {
int samples = ch->sfx->cache->samples; int samples = ch->sfx->cache->samples;
int curpos = S_AdjustLoopedSamplePosition( ch->sfx->cache, ch->sample, ch->use_loop ); int curpos = S_AdjustLoopedSamplePosition( ch->sfx->cache, ch->sample, FBitSet( ch->flags, FL_CHAN_USE_LOOP ));
remaining = bound( 0, samples - curpos, samples ); remaining = bound( 0, samples - curpos, samples );
} }
@@ -332,7 +328,7 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean
for( ch_idx = NUM_AMBIENTS; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ ) for( ch_idx = NUM_AMBIENTS; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ )
{ {
channel_t *ch = &channels[ch_idx]; channel_t *ch = &snd.channels[ch_idx];
// Never override a streaming sound that is currently playing or // Never override a streaming sound that is currently playing or
// voice over IP data that is playing or any sound on CHAN_VOICE( acting ) // voice over IP data that is playing or any sound on CHAN_VOICE( acting )
@@ -363,14 +359,14 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean
if( first_to_die == -1 ) if( first_to_die == -1 )
return NULL; return NULL;
if( channels[first_to_die].sfx ) if( snd.channels[first_to_die].sfx )
{ {
// don't restart looping sounds for the same entity // don't restart looping sounds for the same entity
wavdata_t *sc = channels[first_to_die].sfx->cache; wavdata_t *sc = snd.channels[first_to_die].sfx->cache;
if( sc && FBitSet( sc->flags, SOUND_LOOPED )) if( sc && FBitSet( sc->flags, SOUND_LOOPED ))
{ {
channel_t *ch = &channels[first_to_die]; channel_t *ch = &snd.channels[first_to_die];
if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx == sfx ) if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx == sfx )
{ {
@@ -381,10 +377,10 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean
} }
// be sure and release previous channel if sentence. // be sure and release previous channel if sentence.
S_FreeChannel( &( channels[first_to_die] )); S_FreeChannel( &( snd.channels[first_to_die] ));
} }
return &channels[first_to_die]; return &snd.channels[first_to_die];
} }
/* /*
@@ -403,32 +399,32 @@ channel_t *SND_PickStaticChannel( const vec3_t pos, sfx_t *sfx )
int i; int i;
// check for replacement sound, or find the best one to replace // check for replacement sound, or find the best one to replace
for( i = MAX_DYNAMIC_CHANNELS; i < total_channels; i++ ) for( i = MAX_DYNAMIC_CHANNELS; i < snd.total_channels; i++ )
{ {
if( channels[i].sfx == NULL ) if( snd.channels[i].sfx == NULL )
break; break;
if( VectorCompare( pos, channels[i].origin ) && channels[i].sfx == sfx ) if( VectorCompare( pos, snd.channels[i].origin ) && snd.channels[i].sfx == sfx )
break; break;
} }
if( i < total_channels ) if( i < snd.total_channels )
{ {
// reuse an empty static sound channel // reuse an empty static sound channel
ch = &channels[i]; ch = &snd.channels[i];
} }
else else
{ {
// no empty slots, alloc a new static sound channel // no empty slots, alloc a new static sound channel
if( total_channels == MAX_CHANNELS ) if( snd.total_channels == snd.max_channels )
{ {
Con_DPrintf( S_ERROR "%s: no free channels\n", __func__ ); Con_DPrintf( S_ERROR "%s: no free channels\n", __func__ );
return NULL; return NULL;
} }
// get a channel for the static sound // get a channel for the static sound
ch = &channels[total_channels]; ch = &snd.channels[snd.total_channels];
total_channels++; snd.total_channels++;
} }
return ch; return ch;
} }
@@ -444,7 +440,7 @@ static qboolean S_MaybeAlterChannel( channel_t *ch, int entnum, int entchannel,
// if no sfx passed, check if it's a sentence // if no sfx passed, check if it's a sentence
if( !sfx ) if( !sfx )
{ {
if( !ch->is_sentence ) if( !FBitSet( ch->flags, FL_CHAN_IS_SENTENCE ))
return false; return false;
} }
else else
@@ -485,34 +481,21 @@ returns FALSE if sound was not found (sound is not playing)
*/ */
static int S_AlterChannel( int entnum, int channel, const sfx_t *sfx, int vol, int pitch, int flags ) static int S_AlterChannel( int entnum, int channel, const sfx_t *sfx, int vol, int pitch, int flags )
{ {
channel_t *ch; // This is a sentence name.
int i; // For sentences: assume that the entity is only playing one sentence
// at a time, so we can just shut off
// any channel that has ch->is_sentence >= 0 and matches the entnum.
qboolean is_sentence = S_TestSoundChar( sfx->name, '!' );
if( S_TestSoundChar( sfx->name, '!' )) for( int i = NUM_AMBIENTS; i < snd.total_channels; i++ )
{ {
// This is a sentence name. channel_t *ch = &snd.channels[i];
// For sentences: assume that the entity is only playing one sentence
// at a time, so we can just shut off
// any channel that has ch->is_sentence >= 0 and matches the entnum.
for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ ) if( S_MaybeAlterChannel( ch, entnum, channel, flags, is_sentence ? NULL : sfx, pitch, vol ))
{
if( S_MaybeAlterChannel( ch, entnum, channel, flags, NULL, pitch, vol ))
return true;
}
// channel not found
return false;
}
// regular sound or streaming sound
for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ )
{
if( S_MaybeAlterChannel( ch, entnum, channel, flags, sfx, pitch, vol ))
return true; return true;
} }
// channel not found
return false; return false;
} }
@@ -554,7 +537,7 @@ static void SND_Spatialize( channel_t *ch )
return; return;
} }
if( !ch->staticsound ) if( !FBitSet( ch->flags, FL_CHAN_STATIC_SOUND ))
{ {
if( !CL_GetEntitySpatialization( ch )) if( !CL_GetEntitySpatialization( ch ))
{ {
@@ -567,11 +550,11 @@ static void SND_Spatialize( channel_t *ch )
// source_vec is vector from listener to sound source // source_vec is vector from listener to sound source
// player sounds come from 1' in front of player // player sounds come from 1' in front of player
vec3_t source_vec; vec3_t source_vec;
VectorSubtract( ch->origin, s_listener.origin, source_vec ); VectorSubtract( ch->origin, snd.origin, source_vec );
// normalize source_vec and get distance from listener to source // normalize source_vec and get distance from listener to source
float dist = VectorNormalizeLength( source_vec ); float dist = VectorNormalizeLength( source_vec );
float dot = DotProduct( s_listener.right, source_vec ); float dot = DotProduct( snd.right, source_vec );
if( !FBitSet( host.bugcomp, BUGCOMP_SPATIALIZE_SOUND_WITH_ATTN_NONE )) if( !FBitSet( host.bugcomp, BUGCOMP_SPATIALIZE_SOUND_WITH_ATTN_NONE ))
{ {
@@ -610,7 +593,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
int vol, ch_idx; int vol, ch_idx;
qboolean bIgnore = false; qboolean bIgnore = false;
if( !dma.initialized ) return; if( !snd.initialized ) return;
sfx = S_GetSfxByHandle( handle ); sfx = S_GetSfxByHandle( handle );
if( !sfx ) return; if( !sfx ) return;
@@ -633,8 +616,10 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
SetBits( flags, SND_STOP_LOOPING ); SetBits( flags, SND_STOP_LOOPING );
// pick a channel to play on // pick a channel to play on
if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( pos, sfx ); if( chan == CHAN_STATIC )
else target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); target_chan = SND_PickStaticChannel( pos, sfx );
else
target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore );
if( !target_chan ) if( !target_chan )
{ {
@@ -647,15 +632,21 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
memset( target_chan, 0, sizeof( *target_chan )); memset( target_chan, 0, sizeof( *target_chan ));
VectorCopy( pos, target_chan->origin ); VectorCopy( pos, target_chan->origin );
target_chan->staticsound = ( ent == 0 ) ? true : false;
target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true; if( ent == 0 )
target_chan->localsound = (flags & SND_LOCALSOUND) ? true : false; SetBits( target_chan->flags, FL_CHAN_STATIC_SOUND );
if( !FBitSet( flags, SND_STOP_LOOPING ))
SetBits( target_chan->flags, FL_CHAN_USE_LOOP );
if( FBitSet( flags, SND_LOCALSOUND ))
SetBits( target_chan->flags, FL_CHAN_LOCAL_SOUND );
target_chan->dist_mult = (attn / SND_CLIP_DISTANCE); target_chan->dist_mult = (attn / SND_CLIP_DISTANCE);
target_chan->master_vol = vol; target_chan->master_vol = vol;
target_chan->entnum = ent; target_chan->entnum = ent;
target_chan->entchannel = chan; target_chan->entchannel = chan;
target_chan->basePitch = pitch; target_chan->basePitch = pitch;
target_chan->is_sentence = false;
target_chan->sfx = sfx; target_chan->sfx = sfx;
pSource = NULL; pSource = NULL;
@@ -723,7 +714,7 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float
qboolean bIgnore = false; qboolean bIgnore = false;
int vol; int vol;
if( !dma.initialized ) return; if( !snd.initialized ) return;
sfx = S_GetSfxByHandle( handle ); sfx = S_GetSfxByHandle( handle );
if( !sfx ) return; if( !sfx ) return;
@@ -731,8 +722,10 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float
if( pitch <= 1 ) pitch = PITCH_NORM; // Invasion issues if( pitch <= 1 ) pitch = PITCH_NORM; // Invasion issues
// pick a channel to play on // pick a channel to play on
if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( pos, sfx ); if( chan == CHAN_STATIC )
else target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); target_chan = SND_PickStaticChannel( pos, sfx );
else
target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore );
if( !target_chan ) if( !target_chan )
{ {
@@ -745,15 +738,21 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float
memset( target_chan, 0, sizeof( *target_chan )); memset( target_chan, 0, sizeof( *target_chan ));
VectorCopy( pos, target_chan->origin ); VectorCopy( pos, target_chan->origin );
target_chan->staticsound = ( ent == 0 ) ? true : false;
target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true; if( ent == 0 )
target_chan->localsound = (flags & SND_LOCALSOUND) ? true : false; SetBits( target_chan->flags, FL_CHAN_STATIC_SOUND );
if( !FBitSet( flags, SND_STOP_LOOPING ))
SetBits( target_chan->flags, FL_CHAN_USE_LOOP );
if( FBitSet( flags, SND_LOCALSOUND ))
SetBits( target_chan->flags, FL_CHAN_LOCAL_SOUND );
target_chan->dist_mult = (attn / SND_CLIP_DISTANCE); target_chan->dist_mult = (attn / SND_CLIP_DISTANCE);
target_chan->master_vol = vol; target_chan->master_vol = vol;
target_chan->entnum = ent; target_chan->entnum = ent;
target_chan->entchannel = chan; target_chan->entchannel = chan;
target_chan->basePitch = pitch; target_chan->basePitch = pitch;
target_chan->is_sentence = false;
target_chan->sfx = sfx; target_chan->sfx = sfx;
pSource = NULL; pSource = NULL;
@@ -775,7 +774,7 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float
target_chan->word_index = wordIndex; // restore current word target_chan->word_index = wordIndex; // restore current word
VOX_LoadWord( target_chan ); VOX_LoadWord( target_chan );
if( !target_chan->sentence_finished ) if( !FBitSet( target_chan->flags, FL_CHAN_SENTENCE_FINISHED ))
{ {
target_chan->sfx = target_chan->words[target_chan->word_index].sfx; target_chan->sfx = target_chan->words[target_chan->word_index].sfx;
sfx = target_chan->sfx; sfx = target_chan->sfx;
@@ -835,7 +834,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
sfx_t *sfx = NULL; sfx_t *sfx = NULL;
int vol, fvox = 0; int vol, fvox = 0;
if( !dma.initialized ) return; if( !snd.initialized ) return;
sfx = S_GetSfxByHandle( handle ); sfx = S_GetSfxByHandle( handle );
if( !sfx ) return; if( !sfx ) return;
@@ -877,7 +876,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
// load regular or stream sound // load regular or stream sound
pSource = S_LoadSound( sfx ); pSource = S_LoadSound( sfx );
ch->sfx = sfx; ch->sfx = sfx;
ch->is_sentence = false; ClearBits( ch->flags, FL_CHAN_IS_SENTENCE );
ch->name[0] = '\0'; ch->name[0] = '\0';
} }
@@ -890,9 +889,15 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa
pitch *= (sys_timescale.value + 1) / 2; pitch *= (sys_timescale.value + 1) / 2;
// never update positions if source entity is 0 // never update positions if source entity is 0
ch->staticsound = ( ent == 0 ) ? true : false; if( ent == 0 ) SetBits( ch->flags, FL_CHAN_STATIC_SOUND );
ch->use_loop = (flags & SND_STOP_LOOPING) ? false : true; else ClearBits( ch->flags, FL_CHAN_STATIC_SOUND );
ch->localsound = (flags & SND_LOCALSOUND) ? true : false;
if( !FBitSet( flags, SND_STOP_LOOPING )) SetBits( ch->flags, FL_CHAN_USE_LOOP );
else ClearBits( ch->flags, FL_CHAN_USE_LOOP );
if( FBitSet( flags, SND_LOCALSOUND )) SetBits( ch->flags, FL_CHAN_LOCAL_SOUND );
else ClearBits( ch->flags, FL_CHAN_LOCAL_SOUND );
ch->master_vol = vol; ch->master_vol = vol;
ch->dist_mult = (attn / SND_CLIP_DISTANCE); ch->dist_mult = (attn / SND_CLIP_DISTANCE);
ch->entchannel = CHAN_STATIC; ch->entchannel = CHAN_STATIC;
@@ -914,9 +919,9 @@ void S_StartLocalSound( const char *name, float volume, qboolean reliable )
if( reliable ) channel = CHAN_STATIC; if( reliable ) channel = CHAN_STATIC;
if( !dma.initialized ) return; if( !snd.initialized ) return;
sfxHandle = S_RegisterSound( name ); sfxHandle = S_RegisterSound( name );
S_StartSound( NULL, s_listener.entnum, channel, sfxHandle, volume, ATTN_NONE, PITCH_NORM, flags ); S_StartSound( NULL, snd.entnum, channel, sfxHandle, volume, ATTN_NONE, PITCH_NORM, flags );
} }
/* /*
@@ -929,32 +934,35 @@ grab all static sounds playing at current channel
int S_GetCurrentStaticSounds( soundlist_t *pout, int size ) int S_GetCurrentStaticSounds( soundlist_t *pout, int size )
{ {
int sounds_left = size; int sounds_left = size;
int i;
if( !dma.initialized ) if( !snd.initialized )
return 0; return 0;
for( i = MAX_DYNAMIC_CHANNELS; i < total_channels && sounds_left; i++ ) for( int i = MAX_DYNAMIC_CHANNELS; i < snd.total_channels && sounds_left; i++ )
{ {
if( channels[i].entchannel == CHAN_STATIC && channels[i].sfx && channels[i].sfx->name[0] ) const channel_t *ch = &snd.channels[i];
{
if( channels[i].is_sentence && channels[i].name[0] )
Q_strncpy( pout->name, channels[i].name, sizeof( pout->name ));
else Q_strncpy( pout->name, channels[i].sfx->name, sizeof( pout->name ));
pout->entnum = channels[i].entnum;
VectorCopy( channels[i].origin, pout->origin );
pout->volume = (float)channels[i].master_vol / 255.0f;
pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE;
pout->looping = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED ));
pout->pitch = channels[i].basePitch;
pout->channel = channels[i].entchannel;
pout->wordIndex = channels[i].word_index;
pout->samplePos = channels[i].sample;
pout->forcedEnd = channels[i].forced_end;
sounds_left--; if( ch->entchannel != CHAN_STATIC || !ch->sfx || !ch->sfx->name[0] )
pout++; continue;
}
if( FBitSet( ch->flags, FL_CHAN_IS_SENTENCE ) && ch->name[0] )
Q_strncpy( pout->name, ch->name, sizeof( pout->name ));
else
Q_strncpy( pout->name, ch->sfx->name, sizeof( pout->name ));
pout->entnum = ch->entnum;
VectorCopy( ch->origin, pout->origin );
pout->volume = (float)ch->master_vol / 255.0f;
pout->attenuation = ch->dist_mult * SND_CLIP_DISTANCE;
pout->looping = ( FBitSet( ch->flags, FL_CHAN_USE_LOOP ) && FBitSet( ch->sfx->cache->flags, SOUND_LOOPED ));
pout->pitch = ch->basePitch;
pout->channel = ch->entchannel;
pout->wordIndex = ch->word_index;
pout->samplePos = ch->sample;
pout->forcedEnd = ch->forced_end;
sounds_left--;
pout++;
} }
return ( size - sounds_left ); return ( size - sounds_left );
@@ -972,31 +980,35 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
int sounds_left = size; int sounds_left = size;
int i, looped; int i, looped;
if( !dma.initialized ) if( !snd.initialized )
return 0; return 0;
for( i = 0; i < MAX_CHANNELS && sounds_left; i++ ) for( i = 0; i < snd.max_channels && sounds_left; i++ )
{ {
if( !channels[i].sfx || !channels[i].sfx->name[0] || !Q_stricmp( channels[i].sfx->name, "*default" )) const channel_t *ch = &snd.channels[i];
if( !ch->sfx || !ch->sfx->name[0] || !Q_stricmp( ch->sfx->name, "*default" ))
continue; // don't serialize default sounds continue; // don't serialize default sounds
looped = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED )); looped = ( FBitSet( ch->flags, FL_CHAN_USE_LOOP ) && FBitSet( ch->sfx->cache->flags, SOUND_LOOPED ));
if( channels[i].entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible()) if( ch->entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible())
continue; // never serialize static looped sounds. It will be restoring in game code continue; // never serialize static looped sounds. It will be restoring in game code
if( channels[i].is_sentence && channels[i].name[0] ) if( FBitSet( ch->flags, FL_CHAN_IS_SENTENCE ) && ch->name[0] )
Q_strncpy( pout->name, channels[i].name, sizeof( pout->name )); Q_strncpy( pout->name, ch->name, sizeof( pout->name ));
else Q_strncpy( pout->name, channels[i].sfx->name, sizeof( pout->name )); else
pout->entnum = (channels[i].entnum < 0) ? 0 : channels[i].entnum; Q_strncpy( pout->name, ch->sfx->name, sizeof( pout->name ));
VectorCopy( channels[i].origin, pout->origin );
pout->volume = (float)channels[i].master_vol / 255.0f; pout->entnum = (ch->entnum < 0) ? 0 : ch->entnum;
pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE; VectorCopy( ch->origin, pout->origin );
pout->pitch = channels[i].basePitch; pout->volume = (float)ch->master_vol / 255.0f;
pout->channel = channels[i].entchannel; pout->attenuation = ch->dist_mult * SND_CLIP_DISTANCE;
pout->wordIndex = channels[i].word_index; pout->pitch = ch->basePitch;
pout->samplePos = channels[i].sample; pout->channel = ch->entchannel;
pout->forcedEnd = channels[i].forced_end; pout->wordIndex = ch->word_index;
pout->samplePos = ch->sample;
pout->forcedEnd = ch->forced_end;
pout->looping = looped; pout->looping = looped;
sounds_left--; sounds_left--;
@@ -1013,18 +1025,14 @@ S_InitAmbientChannels
*/ */
static void S_InitAmbientChannels( void ) static void S_InitAmbientChannels( void )
{ {
int ambient_channel; for( int i = 0; i < NUM_AMBIENTS; i++ )
channel_t *chan;
for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ )
{ {
chan = &channels[ambient_channel]; channel_t *ch = &snd.channels[i];
chan->staticsound = true; SetBits( ch->flags, FL_CHAN_USE_LOOP | FL_CHAN_STATIC_SOUND );
chan->use_loop = true; ch->entchannel = CHAN_STATIC;
chan->entchannel = CHAN_STATIC; ch->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE);
chan->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE); ch->basePitch = PITCH_NORM;
chan->basePitch = PITCH_NORM;
} }
} }
@@ -1037,27 +1045,27 @@ static void S_UpdateAmbientSounds( void )
{ {
int ambient_channel; int ambient_channel;
if( !snd_ambient ) if( !snd.have_ambient_sfx )
return; return;
// calc ambient sound levels // calc ambient sound levels
if( !cl.worldmodel ) if( !cl.worldmodel )
return; return;
mleaf_t *leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes, cl.worldmodel ); mleaf_t *leaf = Mod_PointInLeaf( snd.origin, cl.worldmodel->nodes, cl.worldmodel );
if( !leaf || !s_ambient_level.value ) if( !leaf || !s_ambient_level.value )
{ {
for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) for( int i = 0; i < NUM_AMBIENTS; i++ )
channels[ambient_channel].sfx = NULL; snd.channels[i].sfx = NULL;
return; return;
} }
for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) for( int i = 0; i < NUM_AMBIENTS; i++ )
{ {
channel_t *chan = &channels[ambient_channel]; channel_t *chan = &snd.channels[i];
chan->sfx = S_GetSfxByHandle( ambient_sfx[ambient_channel] ); chan->sfx = S_GetSfxByHandle( snd.ambient_sfx[i] );
// ambient is unused // ambient is unused
if( !chan->sfx ) if( !chan->sfx )
@@ -1116,9 +1124,9 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create )
int best = -1; int best = -1;
int free = -1; int free = -1;
for( int i = 0; i < MAX_RAW_CHANNELS; i++ ) for( int i = 0; i < snd.max_raw_channels; i++ )
{ {
ch = raw_channels[i]; ch = snd.raw_channels[i];
if( free < 0 && !ch ) if( free < 0 && !ch )
{ {
@@ -1132,7 +1140,7 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create )
if( ch->entnum == entnum ) if( ch->entnum == entnum )
return ch; return ch;
time = ch->s_rawend - paintedtime; time = ch->s_rawend - snd.paintedtime;
if( time < best_time ) if( time < best_time )
{ {
best = i; best = i;
@@ -1150,14 +1158,14 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create )
if( best < 0 ) if( best < 0 )
return NULL; // no free slots return NULL; // no free slots
if( !raw_channels[best] ) if( !snd.raw_channels[best] )
{ {
size_t raw_samples = MAX_RAW_SAMPLES; size_t raw_samples = MAX_RAW_SAMPLES;
raw_channels[best] = Mem_Calloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * raw_samples ); snd.raw_channels[best] = Mem_Calloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * raw_samples );
raw_channels[best]->max_samples = raw_samples; snd.raw_channels[best]->max_samples = raw_samples;
} }
ch = raw_channels[best]; ch = snd.raw_channels[best];
ch->entnum = entnum; ch->entnum = entnum;
ch->s_rawend = 0; ch->s_rawend = 0;
@@ -1174,8 +1182,8 @@ uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint ma
uint fracstep, samplefrac; uint fracstep, samplefrac;
uint src, dst; uint src, dst;
if( rawend < paintedtime ) if( rawend < snd.paintedtime )
rawend = paintedtime; rawend = snd.paintedtime;
fracstep = ((double) rate / (double)SOUND_DMA_SPEED) * (double)(1 << S_RAW_SAMPLES_PRECISION_BITS); fracstep = ((double) rate / (double)SOUND_DMA_SPEED) * (double)(1 << S_RAW_SAMPLES_PRECISION_BITS);
samplefrac = 0; samplefrac = 0;
@@ -1262,14 +1270,14 @@ static void S_FreeIdleRawChannels( void )
{ {
int i; int i;
for( i = 0; i < MAX_RAW_CHANNELS; i++ ) for( i = 0; i < snd.max_raw_channels; i++ )
{ {
rawchan_t *ch = raw_channels[i]; rawchan_t *ch = snd.raw_channels[i];
if( !ch ) if( !ch )
continue; continue;
if( ch->s_rawend >= paintedtime ) if( ch->s_rawend >= snd.paintedtime )
continue; continue;
if( ch->entnum > 0 ) if( ch->entnum > 0 )
@@ -1280,9 +1288,9 @@ static void S_FreeIdleRawChannels( void )
Voice_StopChannel( ch->entnum ); Voice_StopChannel( ch->entnum );
} }
if(( paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC ) if(( snd.paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC )
{ {
raw_channels[i] = NULL; snd.raw_channels[i] = NULL;
Mem_Free( ch ); Mem_Free( ch );
} }
} }
@@ -1297,9 +1305,9 @@ static void S_ClearRawChannels( void )
{ {
int i; int i;
for( i = 0; i < MAX_RAW_CHANNELS; i++ ) for( i = 0; i < snd.max_raw_channels; i++ )
{ {
rawchan_t *ch = raw_channels[i]; rawchan_t *ch = snd.raw_channels[i];
if( !ch ) continue; if( !ch ) continue;
ch->s_rawend = 0; ch->s_rawend = 0;
@@ -1314,14 +1322,14 @@ S_SpatializeRawChannels
*/ */
static void S_SpatializeRawChannels( void ) static void S_SpatializeRawChannels( void )
{ {
for( int i = 0; i < MAX_RAW_CHANNELS; i++ ) for( int i = 0; i < snd.max_raw_channels; i++ )
{ {
rawchan_t *ch = raw_channels[i]; rawchan_t *ch = snd.raw_channels[i];
if( !ch ) if( !ch )
continue; continue;
if( ch->s_rawend < paintedtime ) if( ch->s_rawend < snd.paintedtime )
{ {
ch->leftvol = ch->rightvol = 0; ch->leftvol = ch->rightvol = 0;
continue; continue;
@@ -1339,11 +1347,11 @@ static void S_SpatializeRawChannels( void )
{ {
vec3_t source_vec; vec3_t source_vec;
VectorSubtract( ch->origin, s_listener.origin, source_vec ); VectorSubtract( ch->origin, snd.origin, source_vec );
// normalize source_vec and get distance from listener to source // normalize source_vec and get distance from listener to source
float dist = VectorNormalizeLength( source_vec ); float dist = VectorNormalizeLength( source_vec );
float dot = DotProduct( s_listener.right, source_vec ); float dot = DotProduct( snd.right, source_vec );
// don't pan sounds with no attenuation // don't pan sounds with no attenuation
if( ch->dist_mult <= 0.0f ) dot = 0.0f; if( ch->dist_mult <= 0.0f ) dot = 0.0f;
@@ -1366,16 +1374,9 @@ S_FreeRawChannels
*/ */
static void S_FreeRawChannels( void ) static void S_FreeRawChannels( void )
{ {
int i;
// free raw samples // free raw samples
for( i = 0; i < MAX_RAW_CHANNELS; i++ ) for( int i = 0; i < snd.max_raw_channels; i++ )
{ Mem_Free2( &snd.raw_channels[i] );
if( raw_channels[i] )
Mem_Free( raw_channels[i] );
}
memset( raw_channels, 0, sizeof( raw_channels ));
} }
//============================================================================= //=============================================================================
@@ -1390,8 +1391,10 @@ static void S_ClearBuffer( void )
S_ClearRawChannels(); S_ClearRawChannels();
SNDDMA_BeginPainting (); SNDDMA_BeginPainting ();
if( dma.buffer )
memset( dma.buffer, 0, dma.samples * 2 ); if( snd.buffer )
memset( snd.buffer, 0, snd.samples * 2 );
SNDDMA_Submit (); SNDDMA_Submit ();
S_ClearBuffers( PAINTBUFFER_SIZE ); S_ClearBuffers( PAINTBUFFER_SIZE );
@@ -1408,7 +1411,7 @@ void GAME_EXPORT S_StopSound( int entnum, int channel, const char *soundname )
{ {
sfx_t *sfx; sfx_t *sfx;
if( !dma.initialized ) return; if( !snd.initialized ) return;
sfx = S_FindName( soundname, NULL ); sfx = S_FindName( soundname, NULL );
S_AlterChannel( entnum, channel, sfx, 0, 0, SND_STOP ); S_AlterChannel( entnum, channel, sfx, 0, 0, SND_STOP );
} }
@@ -1422,19 +1425,21 @@ void S_StopAllSounds( qboolean ambient )
{ {
int i; int i;
if( !dma.initialized ) return; if( !snd.initialized ) return;
total_channels = MAX_DYNAMIC_CHANNELS; // no statics snd.total_channels = MAX_DYNAMIC_CHANNELS; // no statics
for( i = 0; i < MAX_CHANNELS; i++ ) for( i = 0; i < snd.max_channels; i++ )
{ {
if( !channels[i].sfx ) continue; if( !snd.channels[i].sfx )
S_FreeChannel( &channels[i] ); continue;
S_FreeChannel( &snd.channels[i] );
} }
SX_ClearState(); SX_ClearState();
// clear all the channels // clear all the channels
memset( channels, 0, sizeof( channels )); memset( snd.channels, 0, sizeof( snd.channels[0] ) * snd.max_channels );
// restart the ambient sounds // restart the ambient sounds
if( ambient ) S_InitAmbientChannels (); if( ambient ) S_InitAmbientChannels ();
@@ -1459,22 +1464,22 @@ static int S_GetSoundtime( void )
static int buffers, oldsamplepos; static int buffers, oldsamplepos;
int samplepos, fullsamples; int samplepos, fullsamples;
fullsamples = dma.samples / 2; fullsamples = snd.samples / 2;
// it is possible to miscount buffers // it is possible to miscount buffers
// if it has wrapped twice between // if it has wrapped twice between
// calls to S_Update. Oh well. // calls to S_Update. Oh well.
samplepos = dma.samplepos; samplepos = snd.samplepos;
if( samplepos < oldsamplepos ) if( samplepos < oldsamplepos )
{ {
buffers++; // buffer wrapped buffers++; // buffer wrapped
if( paintedtime > 0x40000000 ) if( snd.paintedtime > 0x40000000 )
{ {
// time to chop things off to avoid 32 bit limits // time to chop things off to avoid 32 bit limits
buffers = 0; buffers = 0;
paintedtime = fullsamples; snd.paintedtime = fullsamples;
S_StopAllSounds( true ); S_StopAllSounds( true );
} }
} }
@@ -1492,25 +1497,25 @@ static void S_UpdateChannels( void )
SNDDMA_BeginPainting(); SNDDMA_BeginPainting();
if( !dma.buffer ) return; if( !snd.buffer ) return;
// updates DMA time // updates DMA time
soundtime = S_GetSoundtime(); snd.soundtime = S_GetSoundtime();
// soundtime - total samples that have been played out to hardware at dmaspeed // soundtime - total samples that have been played out to hardware at dmaspeed
// paintedtime - total samples that have been mixed at speed // paintedtime - total samples that have been mixed at speed
// endtime - target for samples in mixahead buffer at speed // endtime - target for samples in mixahead buffer at speed
endtime = soundtime + s_mixahead.value * SOUND_DMA_SPEED; endtime = snd.soundtime + s_mixahead.value * SOUND_DMA_SPEED;
samps = dma.samples >> 1; samps = snd.samples >> 1;
if((int)(endtime - soundtime) > samps ) if((int)(endtime - snd.soundtime) > samps )
endtime = soundtime + samps; endtime = snd.soundtime + samps;
if(( endtime - paintedtime ) & 0x3 ) if(( endtime - snd.paintedtime ) & 0x3 )
{ {
// the difference between endtime and painted time should align on // the difference between endtime and painted time should align on
// boundaries of 4 samples. this is important when upsampling from 11khz -> 44khz. // boundaries of 4 samples. this is important when upsampling from 11khz -> 44khz.
endtime -= ( endtime - paintedtime ) & 0x3; endtime -= ( endtime - snd.paintedtime ) & 0x3;
} }
S_PaintChannels( endtime ); S_PaintChannels( endtime );
@@ -1527,7 +1532,7 @@ Don't let sound skip if going slow
*/ */
void S_ExtraUpdate( void ) void S_ExtraUpdate( void )
{ {
if( !dma.initialized ) return; if( !snd.initialized ) return;
S_UpdateChannels (); S_UpdateChannels ();
} }
@@ -1543,9 +1548,9 @@ void S_UpdateFrame( struct ref_viewpass_s *rvp )
if( !FBitSet( rvp->flags, RF_DRAW_WORLD ) || FBitSet( rvp->flags, RF_ONLY_CLIENTDRAW )) if( !FBitSet( rvp->flags, RF_DRAW_WORLD ) || FBitSet( rvp->flags, RF_ONLY_CLIENTDRAW ))
return; return;
VectorCopy( rvp->vieworigin, s_listener.origin ); VectorCopy( rvp->vieworigin, snd.origin );
AngleVectors( rvp->viewangles, s_listener.forward, s_listener.right, s_listener.up ); AngleVectors( rvp->viewangles, snd.forward, snd.right, snd.up );
s_listener.entnum = rvp->viewentity; // can be camera entity too snd.entnum = rvp->viewentity; // can be camera entity too
} }
/* /*
@@ -1557,11 +1562,7 @@ Called once each time through the main loop
*/ */
void SND_UpdateSound( void ) void SND_UpdateSound( void )
{ {
int i, j, total; if( !snd.initialized ) return;
channel_t *ch, *combine;
con_nprint_t info;
if( !dma.initialized ) return;
// if the loading plaque is up, clear everything // if the loading plaque is up, clear everything
// out to make sure we aren't looping a dirty // out to make sure we aren't looping a dirty
@@ -1575,55 +1576,15 @@ void SND_UpdateSound( void )
// update general area ambient sound sources // update general area ambient sound sources
S_UpdateAmbientSounds(); S_UpdateAmbientSounds();
combine = NULL;
// update spatialization for static and dynamic sounds // update spatialization for static and dynamic sounds
for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ ) for( int i = NUM_AMBIENTS; i < snd.total_channels; i++ )
{ {
if( !ch->sfx ) continue; channel_t *ch = &snd.channels[i];
SND_Spatialize( ch ); // respatialize channel
if( !ch->leftvol && !ch->rightvol ) if( !ch->sfx )
continue; continue;
// try to combine static sounds with a previous channel of the same SND_Spatialize( ch ); // respatialize channel
// sound effect so we don't mix five torches every frame
// g-cont: perfomance option, probably kill stereo effect in most cases
if( i >= MAX_DYNAMIC_CHANNELS && s_combine_sounds.value )
{
// see if it can just use the last one
if( combine && combine->sfx == ch->sfx )
{
combine->leftvol += ch->leftvol;
combine->rightvol += ch->rightvol;
ch->leftvol = ch->rightvol = 0;
continue;
}
// search for one
combine = channels + MAX_DYNAMIC_CHANNELS;
for( j = MAX_DYNAMIC_CHANNELS; j < i; j++, combine++ )
{
if( combine->sfx == ch->sfx )
break;
}
if( j == total_channels )
{
combine = NULL;
}
else
{
if( combine != ch )
{
combine->leftvol += ch->leftvol;
combine->rightvol += ch->rightvol;
ch->leftvol = ch->rightvol = 0;
}
continue;
}
}
} }
S_SpatializeRawChannels(); S_SpatializeRawChannels();
@@ -1631,26 +1592,33 @@ void SND_UpdateSound( void )
// debugging output // debugging output
if( s_show.value != 0.0f ) if( s_show.value != 0.0f )
{ {
info.color[0] = 1.0f; con_nprint_t info =
info.color[1] = 0.6f;
info.color[2] = 0.0f;
info.time_to_live = 0.5f;
for( i = 0, total = 1, ch = channels; i < MAX_CHANNELS; i++, ch++ )
{ {
if( ch->sfx && ( ch->leftvol || ch->rightvol )) .color[0] = 1.0f,
{ .color[1] = 0.6f,
info.index = total; .color[2] = 0.0f,
Con_NXPrintf( &info, "chan %i, pos (%.f %.f %.f) ent %i, lv%3i rv%3i %s\n", .index = 1,
.time_to_live = 0.5f,
};
for( int i = 0; i < MAX_CHANNELS; i++ )
{
channel_t *ch = &snd.channels[i];
if( !ch->sfx || ( !ch->leftvol && !ch->rightvol ))
continue;
Con_NXPrintf( &info, "chan %i, pos (%.f %.f %.f) ent %i, lv%3i rv%3i %s\n",
i, ch->origin[0], ch->origin[1], ch->origin[2], ch->entnum, ch->leftvol, ch->rightvol, ch->sfx->name ); i, ch->origin[0], ch->origin[1], ch->origin[2], ch->entnum, ch->leftvol, ch->rightvol, ch->sfx->name );
total++;
} info.index++;
} }
int total = info.index - 1;
VectorSet( info.color, 1.0f, 1.0f, 1.0f ); VectorSet( info.color, 1.0f, 1.0f, 1.0f );
info.index = 0; info.index = 0;
Con_NXPrintf( &info, "room_type: %i (%s) ----(%i)---- painted: %i\n", idsp_room, Cvar_VariableString( "dsp_coeff_table" ), total - 1, paintedtime ); Con_NXPrintf( &info, "room_type: %i (%s) ----(%i)---- painted: %i\n", idsp_room, Cvar_VariableString( "dsp_coeff_table" ), total, snd.paintedtime );
} }
S_StreamBackgroundTrack (); S_StreamBackgroundTrack ();
@@ -1880,12 +1848,12 @@ S_SoundInfo_f
*/ */
void S_SoundInfo_f( void ) void S_SoundInfo_f( void )
{ {
Con_Printf( "Audio backend: %s\n", dma.backendName ); Con_Printf( "Audio backend: %s\n", snd.backend_name );
Con_Printf( "%5d channel(s)\n", 2 ); Con_Printf( "%5d channel(s)\n", 2 );
Con_Printf( "%5d samples\n", dma.samples ); Con_Printf( "%5d samples\n", snd.samples );
Con_Printf( "%5d bits/sample\n", 16 ); Con_Printf( "%5d bits/sample\n", 16 );
Con_Printf( "%5d bytes/sec\n", SOUND_DMA_SPEED ); Con_Printf( "%5d bytes/sec\n", SOUND_DMA_SPEED );
Con_Printf( "%5d total_channels\n", total_channels ); Con_Printf( "%5d total_channels\n", snd.total_channels );
S_PrintBackgroundTrackState (); S_PrintBackgroundTrackState ();
} }
@@ -1931,7 +1899,6 @@ qboolean S_Init( void )
Cvar_RegisterVariable( &s_lerping ); Cvar_RegisterVariable( &s_lerping );
Cvar_RegisterVariable( &s_ambient_level ); Cvar_RegisterVariable( &s_ambient_level );
Cvar_RegisterVariable( &s_ambient_fade ); Cvar_RegisterVariable( &s_ambient_fade );
Cvar_RegisterVariable( &s_combine_sounds );
Cvar_RegisterVariable( &snd_mute_losefocus ); Cvar_RegisterVariable( &snd_mute_losefocus );
Cvar_RegisterVariable( &s_test ); Cvar_RegisterVariable( &s_test );
Cvar_RegisterVariable( &s_samplecount ); Cvar_RegisterVariable( &s_samplecount );
@@ -1959,7 +1926,7 @@ qboolean S_Init( void )
Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" ); Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" );
sndpool = Mem_AllocPool( "Sound Zone" ); sndpool = Mem_AllocPool( "Sound Zone" );
dma.backendName = "None"; snd.backend_name = "None";
if( !SNDDMA_Init( )) if( !SNDDMA_Init( ))
{ {
Con_Printf( "Audio: sound system can't be initialized\n" ); Con_Printf( "Audio: sound system can't be initialized\n" );
@@ -1967,11 +1934,11 @@ qboolean S_Init( void )
return false; return false;
} }
soundtime = 0; snd.soundtime = 0;
paintedtime = 0; snd.paintedtime = 0;
// clear ambient sounds // clear ambient sounds
memset( ambient_sfx, 0, sizeof( ambient_sfx )); memset( snd.ambient_sfx, 0, sizeof( snd.ambient_sfx ));
SX_Init (); SX_Init ();
S_StopAllSounds ( true ); S_StopAllSounds ( true );
@@ -1986,7 +1953,7 @@ qboolean S_Init( void )
// ======================================================================= // =======================================================================
void S_Shutdown( void ) void S_Shutdown( void )
{ {
if( !dma.initialized ) return; if( !snd.initialized ) return;
Cmd_RemoveCommand( "play" ); Cmd_RemoveCommand( "play" );
Cmd_RemoveCommand( "playvol" ); Cmd_RemoveCommand( "playvol" );

View File

@@ -120,7 +120,7 @@ static void S_MixAudio( portable_samplepair_t *pbuf, const int *pvol, const void
static int S_AdjustNumSamples( channel_t *chan, int num_samples, double rate, double timecompress_rate ) static int S_AdjustNumSamples( channel_t *chan, int num_samples, double rate, double timecompress_rate )
{ {
if( chan->finished ) if( FBitSet( chan->flags, FL_CHAN_FINISHED ))
return 0; return 0;
// if channel is set to end at specific sample, // if channel is set to end at specific sample,
@@ -132,7 +132,7 @@ static int S_AdjustNumSamples( channel_t *chan, int num_samples, double rate, do
if( end_sample >= chan->forced_end ) if( end_sample >= chan->forced_end )
{ {
chan->finished = true; SetBits( chan->flags, FL_CHAN_FINISHED );
return floor(( chan->forced_end - chan->sample ) / ( rate * timecompress_rate )); return floor(( chan->forced_end - chan->sample ) / ( rate * timecompress_rate ));
} }
} }
@@ -153,7 +153,7 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i
// timecompress at 100% is skipping the entire sfx, so mark as finished and exit // timecompress at 100% is skipping the entire sfx, so mark as finished and exit
if( timecompress >= 100 ) if( timecompress >= 100 )
{ {
chan->finished = true; SetBits( chan->flags, FL_CHAN_FINISHED );
return 0; return 0;
} }
@@ -173,7 +173,7 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i
// get sample pointer and also amount of samples available // get sample pointer and also amount of samples available
const void *audio = NULL; const void *audio = NULL;
int available = S_RetrieveAudioSamples( chan->sfx->cache, &audio, chan->sample, request_num_samples, chan->use_loop ); int available = S_RetrieveAudioSamples( chan->sfx->cache, &audio, chan->sample, request_num_samples, FBitSet( chan->flags, FL_CHAN_USE_LOOP ));
// no samples available, exit // no samples available, exit
if( !available ) if( !available )
@@ -196,7 +196,7 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i
// samples couldn't be retrieved, mark as finished // samples couldn't be retrieved, mark as finished
if( num_samples > 0 ) if( num_samples > 0 )
chan->finished = true; SetBits( chan->flags, FL_CHAN_FINISHED );
// total amount of samples mixed // total amount of samples mixed
return offset - initial_offset; return offset - initial_offset;
@@ -206,10 +206,10 @@ static int VOX_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan,
{ {
int offset = 0; int offset = 0;
if( chan->sentence_finished ) if( FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED ))
return 0; return 0;
while( num_samples > 0 && !chan->sentence_finished ) while( num_samples > 0 && !FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED ))
{ {
int outputCount = S_MixChannelToBuffer( pbuf, chan, num_samples, out_rate, pitch, offset, chan->words[chan->word_index].timecompress ); int outputCount = S_MixChannelToBuffer( pbuf, chan, num_samples, out_rate, pitch, offset, chan->words[chan->word_index].timecompress );
@@ -217,13 +217,13 @@ static int VOX_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan,
num_samples -= outputCount; num_samples -= outputCount;
// if we finished load a next word // if we finished load a next word
if( chan->finished ) if( FBitSet( chan->flags, FL_CHAN_FINISHED ))
{ {
VOX_FreeWord( chan ); VOX_FreeWord( chan );
chan->word_index++; chan->word_index++;
VOX_LoadWord( chan ); VOX_LoadWord( chan );
if( !chan->sentence_finished ) if( !FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED ))
chan->sfx = chan->words[chan->word_index].sfx; chan->sfx = chan->words[chan->word_index].sfx;
} }
} }
@@ -235,7 +235,7 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
{ {
const qboolean local = Host_IsLocalGame(); const qboolean local = Host_IsLocalGame();
const qboolean ingame = CL_IsInGame(); const qboolean ingame = CL_IsInGame();
const int num_samples = ( end - paintedtime ) / ( SOUND_DMA_SPEED / rate ); const int num_samples = ( end - snd.paintedtime ) / ( SOUND_DMA_SPEED / rate );
// FWGS feature: make everybody sound like chipmunks when we're going fast // FWGS feature: make everybody sound like chipmunks when we're going fast
const float pitch_mult = ( sys_timescale.value + 1 ) / 2; const float pitch_mult = ( sys_timescale.value + 1 ) / 2;
@@ -248,25 +248,25 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
if( cl.background && cls.key_dest == key_console ) if( cl.background && cls.key_dest == key_console )
return num_mixed_channels; // no sounds in console with background map return num_mixed_channels; // no sounds in console with background map
for( int i = 0; i < total_channels; i++ ) for( int i = 0; i < snd.total_channels; i++ )
{ {
channel_t *ch = &channels[i]; channel_t *ch = &snd.channels[i];
if( !ch->sfx ) if( !ch->sfx )
continue; continue;
if( !cl.background ) if( !cl.background )
{ {
if( cls.key_dest == key_console && ch->localsound ) if( cls.key_dest == key_console && FBitSet( ch->flags, FL_CHAN_LOCAL_SOUND ))
{ {
// play, playvol // play, playvol
} }
else if(( cls.key_dest == key_menu || cl.paused ) && !ch->localsound && local ) else if(( cls.key_dest == key_menu || cl.paused ) && !FBitSet( ch->flags, FL_CHAN_LOCAL_SOUND ) && local )
{ {
// play only local sounds, keep pause for other // play only local sounds, keep pause for other
continue; continue;
} }
else if( cls.key_dest != key_menu && !ingame && !ch->staticsound ) else if( cls.key_dest != key_menu && !ingame && !FBitSet( ch->flags, FL_CHAN_STATIC_SOUND ))
{ {
// play only ambient sounds, keep pause for other // play only ambient sounds, keep pause for other
continue; continue;
@@ -285,7 +285,7 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
// if it's also not looping, free it // if it's also not looping, free it
if( ch->leftvol < 8 && ch->rightvol < 8 ) if( ch->leftvol < 8 && ch->rightvol < 8 )
{ {
if( !FBitSet( sc->flags, SOUND_LOOPED ) || !ch->use_loop ) if( !FBitSet( sc->flags, SOUND_LOOPED ) || !FBitSet( ch->flags, FL_CHAN_USE_LOOP ))
{ {
if( ch->inauduble_free_time == 0.0f ) if( ch->inauduble_free_time == 0.0f )
ch->inauduble_free_time = host.realtime + MAX_CHANNEL_INAUDIBLE_TIME; ch->inauduble_free_time = host.realtime + MAX_CHANNEL_INAUDIBLE_TIME;
@@ -308,9 +308,9 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
if( ent != NULL ) if( ent != NULL )
{ {
if( sc->width == 1 ) if( sc->width == 1 )
SND_MoveMouth8( &ent->mouth, ch->sample, sc, num_samples, ch->use_loop ); SND_MoveMouth8( &ent->mouth, ch->sample, sc, num_samples, FBitSet( ch->flags, FL_CHAN_USE_LOOP ));
else else
SND_MoveMouth16( &ent->mouth, ch->sample, sc, num_samples, ch->use_loop ); SND_MoveMouth16( &ent->mouth, ch->sample, sc, num_samples, FBitSet( ch->flags, FL_CHAN_USE_LOOP ));
} }
} }
@@ -318,18 +318,18 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
num_mixed_channels++; num_mixed_channels++;
if( ch->is_sentence ) if( FBitSet( ch->flags, FL_CHAN_IS_SENTENCE ))
{ {
VOX_MixChannelToBuffer( dst, ch, num_samples, rate, pitch ); VOX_MixChannelToBuffer( dst, ch, num_samples, rate, pitch );
if( ch->sentence_finished ) if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ))
S_FreeChannel( ch ); S_FreeChannel( ch );
} }
else else
{ {
S_MixChannelToBuffer( dst, ch, num_samples, rate, pitch, 0, 0 ); S_MixChannelToBuffer( dst, ch, num_samples, rate, pitch, 0, 0 );
if( ch->finished ) if( FBitSet( ch->flags, FL_CHAN_FINISHED ))
S_FreeChannel( ch ); S_FreeChannel( ch );
} }
} }
@@ -375,7 +375,7 @@ static int S_MixNormalChannelsToRoombuffer( int end, int count )
// until there is no real usecase, let's keep it simple // until there is no real usecase, let's keep it simple
int num_mixed_channels = S_MixNormalChannels( roombuffer, end, SOUND_11k ); int num_mixed_channels = S_MixNormalChannels( roombuffer, end, SOUND_11k );
if( dma.format.speed >= SOUND_22k ) if( snd.format.speed >= SOUND_22k )
{ {
if( num_mixed_channels > 0 ) if( num_mixed_channels > 0 )
S_UpsampleBuffer( roombuffer, count / ( SOUND_22k / SOUND_11k )); S_UpsampleBuffer( roombuffer, count / ( SOUND_22k / SOUND_11k ));
@@ -383,7 +383,7 @@ static int S_MixNormalChannelsToRoombuffer( int end, int count )
num_mixed_channels += S_MixNormalChannels( roombuffer, end, SOUND_22k ); num_mixed_channels += S_MixNormalChannels( roombuffer, end, SOUND_22k );
} }
if( dma.format.speed >= SOUND_44k ) if( snd.format.speed >= SOUND_44k )
{ {
if( num_mixed_channels > 0 ) if( num_mixed_channels > 0 )
S_UpsampleBuffer( roombuffer, count / ( SOUND_44k / SOUND_22k )); S_UpsampleBuffer( roombuffer, count / ( SOUND_44k / SOUND_22k ));
@@ -402,10 +402,10 @@ static int S_MixRawChannels( int end )
return 0; return 0;
// paint in the raw channels // paint in the raw channels
for( size_t i = 0; i < ARRAYSIZE( raw_channels ); i++ ) for( size_t i = 0; i < snd.max_raw_channels; i++ )
{ {
// copy from the streaming sound source // copy from the streaming sound source
rawchan_t *ch = raw_channels[i]; rawchan_t *ch = snd.raw_channels[i];
if( !ch ) if( !ch )
continue; continue;
@@ -434,7 +434,7 @@ static int S_MixRawChannels( int end )
uint stop = (end < ch->s_rawend) ? end : ch->s_rawend; uint stop = (end < ch->s_rawend) ? end : ch->s_rawend;
const uint mask = ch->max_samples - 1; const uint mask = ch->max_samples - 1;
for( size_t i = 0, j = paintedtime; j < stop; i++, j++ ) for( size_t i = 0, j = snd.paintedtime; j < stop; i++, j++ )
{ {
pbuf[i].left += ( ch->rawsamples[j & mask].left * ch->leftvol ) >> 8; pbuf[i].left += ( ch->rawsamples[j & mask].left * ch->leftvol ) >> 8;
pbuf[i].right += ( ch->rawsamples[j & mask].right * ch->rightvol ) >> 8; pbuf[i].right += ( ch->rawsamples[j & mask].right * ch->rightvol ) >> 8;
@@ -443,8 +443,8 @@ static int S_MixRawChannels( int end )
if( ch->entnum > 0 ) if( ch->entnum > 0 )
{ {
cl_entity_t *ent = CL_GetEntityByIndex( ch->entnum ); cl_entity_t *ent = CL_GetEntityByIndex( ch->entnum );
int pos = paintedtime & ( ch->max_samples - 1 ); int pos = snd.paintedtime & ( ch->max_samples - 1 );
int count = bound( 0, ch->max_samples - pos, stop - paintedtime ); int count = bound( 0, ch->max_samples - pos, stop - snd.paintedtime );
if( ent ) if( ent )
SND_MoveMouthRaw( &ent->mouth, &ch->rawsamples[pos], count ); SND_MoveMouthRaw( &ent->mouth, &ch->rawsamples[pos], count );
@@ -486,8 +486,8 @@ static void S_WriteLinearBlastStereo16( short *snd_out, const int *snd_p, size_t
static void S_TransferPaintBuffer( const portable_samplepair_t *src, int endtime ) static void S_TransferPaintBuffer( const portable_samplepair_t *src, int endtime )
{ {
const int *snd_p = (const int *)src; const int *snd_p = (const int *)src;
const int sampleMask = ((dma.samples >> 1) - 1); const int sampleMask = ((snd.samples >> 1) - 1);
int lpaintedtime = paintedtime; int lpaintedtime = snd.paintedtime;
SNDDMA_BeginPainting (); SNDDMA_BeginPainting ();
@@ -496,9 +496,9 @@ static void S_TransferPaintBuffer( const portable_samplepair_t *src, int endtime
// handle recirculating buffer issues // handle recirculating buffer issues
int lpos = lpaintedtime & sampleMask; int lpos = lpaintedtime & sampleMask;
short *snd_out = (short *)dma.buffer + (lpos << 1); short *snd_out = (short *)snd.buffer + (lpos << 1);
int snd_linear_count = (dma.samples>>1) - lpos; int snd_linear_count = (snd.samples>>1) - lpos;
if( lpaintedtime + snd_linear_count > endtime ) if( lpaintedtime + snd_linear_count > endtime )
snd_linear_count = endtime - lpaintedtime; snd_linear_count = endtime - lpaintedtime;
@@ -526,14 +526,14 @@ void S_PaintChannels( int endtime )
{ {
int gain = S_GetMasterVolume() * 256; int gain = S_GetMasterVolume() * 256;
while( paintedtime < endtime ) while( snd.paintedtime < endtime )
{ {
// if paintbuffer is smaller than DMA buffer // if paintbuffer is smaller than DMA buffer
int end = endtime; int end = endtime;
if( end - paintedtime > PAINTBUFFER_SIZE ) if( end - snd.paintedtime > PAINTBUFFER_SIZE )
end = paintedtime + PAINTBUFFER_SIZE; end = snd.paintedtime + PAINTBUFFER_SIZE;
const int num_samples = end - paintedtime; const int num_samples = end - snd.paintedtime;
S_ClearBuffers( num_samples ); S_ClearBuffers( num_samples );
@@ -550,6 +550,6 @@ void S_PaintChannels( int endtime )
// transfer out according to DMA format // transfer out according to DMA format
S_TransferPaintBuffer( paintbuffer, end ); S_TransferPaintBuffer( paintbuffer, end );
paintedtime = end; snd.paintedtime = end;
} }
} }

View File

@@ -92,7 +92,7 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, int
{ {
S_StopBackgroundTrack(); S_StopBackgroundTrack();
if( !dma.initialized ) return; if( !snd.initialized ) return;
// check for special symbols // check for special symbols
if( introTrack && *introTrack == '*' ) if( introTrack && *introTrack == '*' )
@@ -132,9 +132,9 @@ S_StopBackgroundTrack
*/ */
void S_StopBackgroundTrack( void ) void S_StopBackgroundTrack( void )
{ {
s_listener.stream_paused = false; snd.stream_paused = false;
if( !dma.initialized ) return; if( !snd.initialized ) return;
if( !s_bgTrack.stream ) return; if( !s_bgTrack.stream ) return;
FS_FreeStream( s_bgTrack.stream ); FS_FreeStream( s_bgTrack.stream );
@@ -149,7 +149,7 @@ S_StreamSetPause
*/ */
void S_StreamSetPause( int pause ) void S_StreamSetPause( int pause )
{ {
s_listener.stream_paused = pause; snd.stream_paused = pause;
} }
/* /*
@@ -197,11 +197,11 @@ void S_StreamBackgroundTrack( void )
int r, fileBytes; int r, fileBytes;
rawchan_t *ch = NULL; rawchan_t *ch = NULL;
if( !dma.initialized || !s_bgTrack.stream || s_listener.streaming ) if( !snd.initialized || !s_bgTrack.stream || snd.streaming )
return; return;
// don't bother playing anything if musicvolume is 0 // don't bother playing anything if musicvolume is 0
if( !s_musicvolume.value || cl.paused || s_listener.stream_paused ) if( !s_musicvolume.value || cl.paused || snd.stream_paused )
return; return;
if( !cl.background ) if( !cl.background )
@@ -218,14 +218,14 @@ void S_StreamBackgroundTrack( void )
Assert( ch != NULL ); Assert( ch != NULL );
// see how many samples should be copied into the raw buffer // see how many samples should be copied into the raw buffer
if( ch->s_rawend < soundtime ) if( ch->s_rawend < snd.soundtime )
ch->s_rawend = soundtime; ch->s_rawend = snd.soundtime;
while( ch->s_rawend < soundtime + ch->max_samples ) while( ch->s_rawend < snd.soundtime + ch->max_samples )
{ {
const stream_t *info = s_bgTrack.stream; const stream_t *info = s_bgTrack.stream;
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime); bufferSamples = ch->max_samples - (ch->s_rawend - snd.soundtime);
// decide how much data needs to be read from the file // decide how much data needs to be read from the file
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED ); fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
@@ -283,9 +283,9 @@ S_StartStreaming
*/ */
void S_StartStreaming( void ) void S_StartStreaming( void )
{ {
if( !dma.initialized ) return; if( !snd.initialized ) return;
// begin streaming movie soundtrack // begin streaming movie soundtrack
s_listener.streaming = true; snd.streaming = true;
} }
/* /*
@@ -295,6 +295,6 @@ S_StopStreaming
*/ */
void S_StopStreaming( void ) void S_StopStreaming( void )
{ {
if( !dma.initialized ) return; if( !snd.initialized ) return;
s_listener.streaming = false; snd.streaming = false;
} }

View File

@@ -140,7 +140,7 @@ static void S_TrimStartEndTimes( channel_t *ch, wavdata_t *wav, int start, int e
void VOX_LoadWord( channel_t *ch ) void VOX_LoadWord( channel_t *ch )
{ {
ch->sentence_finished = true; SetBits( ch->flags, FL_CHAN_SENTENCE_FINISHED );
if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX ) if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX )
return; return;
@@ -155,7 +155,7 @@ void VOX_LoadWord( channel_t *ch )
if( !data ) if( !data )
return; return;
ch->sentence_finished = false; ClearBits( ch->flags, FL_CHAN_SENTENCE_FINISHED );
ch->data = data; ch->data = data;
int start = word->start; int start = word->start;
@@ -171,7 +171,7 @@ void VOX_FreeWord( channel_t *ch )
{ {
// TODO: don't set random fields to zero lol, was memset before // TODO: don't set random fields to zero lol, was memset before
ch->sample = ch->forced_end = 0.0; ch->sample = ch->forced_end = 0.0;
ch->finished = false; ClearBits( ch->flags, FL_CHAN_FINISHED );
ch->data = NULL; ch->data = NULL;
if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX ) if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX )
@@ -179,7 +179,7 @@ void VOX_FreeWord( channel_t *ch )
voxword_t *word = &ch->words[ch->word_index]; voxword_t *word = &ch->words[ch->word_index];
if( !word->sfx || word->in_cache ) if( !word->sfx || FBitSet( word->flags, FL_VOXWORD_IN_CACHE ))
return; return;
FS_FreeSound( word->sfx->cache ); FS_FreeSound( word->sfx->cache );
@@ -191,7 +191,7 @@ void VOX_SetChanVol( channel_t *ch )
{ {
voxword_t *word; voxword_t *word;
if( !ch->is_sentence || ch->sentence_finished ) if( !FBitSet( ch->flags, FL_CHAN_IS_SENTENCE ) || FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ))
return; return;
word = &ch->words[ch->word_index]; word = &ch->words[ch->word_index];
@@ -207,7 +207,7 @@ float VOX_ModifyPitch( channel_t *ch, float pitch )
{ {
voxword_t *word; voxword_t *word;
if( !ch->is_sentence || ch->sentence_finished ) if( !FBitSet( ch->flags, FL_CHAN_IS_SENTENCE ) || FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ))
return pitch; return pitch;
word = &ch->words[ch->word_index]; word = &ch->words[ch->word_index];
@@ -356,10 +356,7 @@ static void VOX_MakeDefaultWordParams( voxword_t *voxword )
*voxword = (voxword_t) { *voxword = (voxword_t) {
.volume = 100, .volume = 100,
.pitch = 100, .pitch = 100,
.start = 0,
.end = 100, .end = 100,
.timecompress = 0,
.in_cache = false,
}; };
} }
@@ -416,19 +413,24 @@ static qboolean VOX_ParseWordParams( char *psz, voxword_t *pvoxword, voxword_t *
i = Q_atoi( sznum ); i = Q_atoi( sznum );
switch( command ) switch( command )
{ {
case 'e': pvoxword->end = i; break; case 'e':
case 'p': pvoxword->pitch = i; break; pvoxword->end = bound( 0, i, 100 );
case 's': pvoxword->start = i; break; break;
case 't': pvoxword->timecompress = i; break; case 'p':
case 'v': pvoxword->volume = i; break; pvoxword->pitch = bound( 0, i, UINT16_MAX );
break;
case 's':
pvoxword->start = bound( 0, i, 100 );
break;
case 't':
pvoxword->timecompress = bound( 0, i, 100 );
break;
case 'v':
pvoxword->volume = bound( 0, i, UINT16_MAX );
break;
} }
} }
// validate some of the parameters
pvoxword->start = bound( 0, pvoxword->start, 100 );
pvoxword->end = bound( 0, pvoxword->end, 100 );
pvoxword->timecompress = bound( 0, pvoxword->timecompress, 100 );
// no actual word but new defaults // no actual word but new defaults
if( Q_strlen( pszsave ) == 0 ) if( Q_strlen( pszsave ) == 0 )
{ {
@@ -494,7 +496,8 @@ void VOX_LoadSound( channel_t *ch, const char *pszin )
qboolean in_cache = false; qboolean in_cache = false;
ch->words[j].sfx = S_FindName( pathbuffer, &in_cache ); ch->words[j].sfx = S_FindName( pathbuffer, &in_cache );
ch->words[j].in_cache = in_cache; if( in_cache )
SetBits( ch->words[j].flags, FL_VOXWORD_IN_CACHE );
j++; j++;
} }
@@ -502,7 +505,7 @@ void VOX_LoadSound( channel_t *ch, const char *pszin )
ch->words[j].sfx = NULL; ch->words[j].sfx = NULL;
ch->sfx = ch->words[0].sfx; ch->sfx = ch->words[0].sfx;
ch->word_index = 0; ch->word_index = 0;
ch->is_sentence = true; SetBits( ch->flags, FL_CHAN_IS_SENTENCE );
VOX_LoadWord( ch ); VOX_LoadWord( ch );
} }

View File

@@ -54,15 +54,17 @@ typedef struct sfx_s
struct sfx_s *hashNext; struct sfx_s *hashNext;
} sfx_t; } sfx_t;
#define FL_VOXWORD_IN_CACHE BIT( 0 ) // if set, it was loaded prior and shouldn't be freed
typedef struct voxword_s typedef struct voxword_s
{ {
sfx_t *sfx; sfx_t *sfx;
uint16_t volume; // volume percent uint16_t volume; // volume percent
uint16_t pitch; // pitch shift percent (keep large for extra chipmunk fun) uint16_t pitch; // pitch shift percent (keep large for extra chipmunk fun)
uint16_t timecompress; // percent of skipped data (speeds up playback without pitch shift) uint8_t timecompress; // percent of skipped data (speeds up playback without pitch shift)
uint16_t start : 7; // percent at which playback starts uint8_t start; // percent at which playback starts
uint16_t end : 7; // percent at which playback ends uint8_t end; // percent at which playback ends
uint16_t in_cache : 1; // if set to 1, it was loaded prior and shouldn't be freed uint8_t flags;
} voxword_t; } voxword_t;
typedef struct snd_format_s typedef struct snd_format_s
@@ -72,19 +74,9 @@ typedef struct snd_format_s
byte channels; byte channels;
} snd_format_t; } snd_format_t;
typedef struct
{
snd_format_t format;
int samples; // mono samples in buffer
int samplepos; // in mono samples
qboolean initialized; // sound engine is active
byte *buffer;
const char *backendName;
} dma_t;
typedef struct rawchan_s typedef struct rawchan_s
{ {
int entnum; short entnum;
short master_vol; short master_vol;
short leftvol; // 0-255 left volume short leftvol; // 0-255 left volume
short rightvol; // 0-255 right volume short rightvol; // 0-255 right volume
@@ -92,31 +84,37 @@ typedef struct rawchan_s
vec3_t origin; // only use if fixed_origin is set vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend; volatile uint s_rawend;
float oldtime; // catch time jumps float oldtime; // catch time jumps
// TODO: add reserved bytes
size_t max_samples; // buffer length size_t max_samples; // buffer length
portable_samplepair_t rawsamples[]; // variable sized portable_samplepair_t rawsamples[]; // variable sized
} rawchan_t; } rawchan_t;
#define FL_CHAN_USE_LOOP BIT( 0 ) // don't loop default and local sounds
#define FL_CHAN_STATIC_SOUND BIT( 1 ) // use origin instead of fetching entnum's origin
#define FL_CHAN_LOCAL_SOUND BIT( 2 ) // it's a local menu sound (not looped, not paused)
#define FL_CHAN_IS_SENTENCE BIT( 3 ) // bit indicating vox sentence
#define FL_CHAN_SENTENCE_FINISHED BIT( 4 ) // if set, finished playing sentence
#define FL_CHAN_FINISHED BIT( 5 ) // if set, finished playing single word
typedef struct channel_s typedef struct channel_s
{ {
char name[16]; // keep sentence name char name[16]; // keep sentence name
sfx_t *sfx; // sfx number sfx_t *sfx; // sfx number
vec3_t origin; // only use if fixed_origin is set vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK) float dist_mult; // distance multiplier (attenuation/clipK)
int entnum; // entity soundsource
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.) int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
uint flags;
short entnum; // entity soundsource
short master_vol; // 0-255 master volume short master_vol; // 0-255 master volume
short leftvol; // 0-255 left volume short leftvol; // 0-255 left volume
short rightvol; // 0-255 right volume short rightvol; // 0-255 right volume
short basePitch; // base pitch percent (100% is normal pitch playback) short basePitch; // base pitch percent (100% is normal pitch playback)
byte use_loop : 1; // don't loop default and local sounds
byte staticsound : 1; // use origin instead of fetching entnum's origin
byte localsound : 1; // it's a local menu sound (not looped, not paused)
byte is_sentence : 1; // bit indicating vox sentence
byte sentence_finished : 1; // if set, finished playing sentence
byte finished : 1; // if set, finished playing single word
byte word_index; byte word_index;
// HACKHACK: count when this channel became inaudible // HACKHACK: count when this channel became inaudible
// to not free it when it could be respatialized soon // to not free it when it could be respatialized soon
#define MAX_CHANNEL_INAUDIBLE_TIME 0.1f #define MAX_CHANNEL_INAUDIBLE_TIME 0.1f
@@ -126,22 +124,42 @@ typedef struct channel_s
double forced_end; double forced_end;
wavdata_t *data; wavdata_t *data;
voxword_t words[CVOXWORDMAX]; voxword_t words[CVOXWORDMAX];
// TODO: add reserved bytes
} channel_t; } channel_t;
typedef struct
{
vec3_t origin; // simorg + view_ofs
vec3_t forward;
vec3_t right;
vec3_t up;
int entnum;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
} listener_t;
typedef int sound_t; typedef int sound_t;
typedef struct snd_globals_s
{
// dma
const char *backend_name;
byte *buffer;
snd_format_t format;
qboolean initialized; // sound engine is active
int samples; // mono samples in buffer
int samplepos; // in mono samples
int paintedtime; // total samples that have been mixed at speed
int soundtime; // total samples that have been played out to hardware at dma speed
// listener (client, camera, etc)
vec3_t origin;
vec3_t forward, right, up;
int entnum;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
// SoundAPI shared pointers
channel_t *const channels;
int max_channels;
int total_channels;
rawchan_t **const raw_channels;
int max_raw_channels;
sound_t ambient_sfx[NUM_AMBIENTS];
qboolean have_ambient_sfx;
} snd_globals_t;
//==================================================================== //====================================================================
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS) #define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
@@ -150,16 +168,8 @@ typedef int sound_t;
#define MAX_RAW_SAMPLES 16384 #define MAX_RAW_SAMPLES 16384
#define SND_CLIP_DISTANCE 1000.0f #define SND_CLIP_DISTANCE 1000.0f
extern sound_t ambient_sfx[NUM_AMBIENTS]; extern int idsp_room;
extern qboolean snd_ambient; extern snd_globals_t snd;
extern channel_t channels[MAX_CHANNELS];
extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
extern int total_channels;
extern int paintedtime;
extern int soundtime;
extern listener_t s_listener;
extern int idsp_room;
extern dma_t dma;
extern convar_t s_musicvolume; extern convar_t s_musicvolume;
extern convar_t s_lerping; extern convar_t s_lerping;

View File

@@ -105,8 +105,8 @@ qboolean SNDDMA_Init( void )
return false; return false;
} }
dma.format.speed = SOUND_DMA_SPEED; snd.format.speed = SOUND_DMA_SPEED;
r = dma.format.speed; r = snd.format.speed;
if( ( err = snd_pcm_hw_params_set_rate_near( s_alsa.pcm_handle, s_alsa.hw_params, &r, &dir ) ) < 0 ) if( ( err = snd_pcm_hw_params_set_rate_near( s_alsa.pcm_handle, s_alsa.hw_params, &r, &dir ) ) < 0 )
{ {
@@ -121,14 +121,14 @@ qboolean SNDDMA_Init( void )
if( dir != 0 ) if( dir != 0 )
{ {
Con_Printf( "ALSA: rate %d not supported, using %d\n", SOUND_DMA_SPEED, r ); Con_Printf( "ALSA: rate %d not supported, using %d\n", SOUND_DMA_SPEED, r );
dma.format.speed = r; snd.format.speed = r;
dir = 0; dir = 0;
} }
} }
dma.format.channels = 2; snd.format.channels = 2;
if( ( err = snd_pcm_hw_params_set_channels(s_alsa.pcm_handle, s_alsa.hw_params, dma.format.channels ) ) < 0 ) if( ( err = snd_pcm_hw_params_set_channels(s_alsa.pcm_handle, s_alsa.hw_params, snd.format.channels ) ) < 0 )
{ {
Con_Printf( "ALSA: cannot set channels %d(%s)\n", 2, snd_strerror( err ) ); Con_Printf( "ALSA: cannot set channels %d(%s)\n", 2, snd_strerror( err ) );
snd_pcm_hw_params_free( s_alsa.hw_params ); snd_pcm_hw_params_free( s_alsa.hw_params );
@@ -162,7 +162,7 @@ qboolean SNDDMA_Init( void )
} }
else else
{ {
// if period is NPOT it cannot be used as dma.samples in Xash3D // if period is NPOT it cannot be used as snd.samples in Xash3D
// and need more space to send buffer partially // and need more space to send buffer partially
samples = 1; samples = 1;
while( samples < p * 4 ) while( samples < p * 4 )
@@ -184,15 +184,15 @@ qboolean SNDDMA_Init( void )
return false; return false;
} }
dma.buffer = Mem_Calloc( sndpool, samples * 2 ); //allocate pcm frame buffer snd.buffer = Mem_Calloc( sndpool, samples * 2 ); //allocate pcm frame buffer
dma.samplepos = 0; snd.samplepos = 0;
dma.samples = samples; snd.samples = samples;
dma.format.width = 2; snd.format.width = 2;
dma.initialized = 1; snd.initialized = 1;
dma.backendName = "ALSA"; snd.backend_name = "ALSA";
snd_pcm_prepare( s_alsa.pcm_handle ); snd_pcm_prepare( s_alsa.pcm_handle );
snd_pcm_writei( s_alsa.pcm_handle, dma.buffer, 2 * s_alsa.period_size ); snd_pcm_writei( s_alsa.pcm_handle, snd.buffer, 2 * s_alsa.period_size );
snd_pcm_start( s_alsa.pcm_handle ); snd_pcm_start( s_alsa.pcm_handle );
return true; return true;
@@ -208,14 +208,14 @@ Closes the ALSA pcm device and frees the dma buffer.
void SNDDMA_Shutdown(void) void SNDDMA_Shutdown(void)
{ {
Con_Printf( "Shutting down audio.\n" ); Con_Printf( "Shutting down audio.\n" );
dma.initialized = false; snd.initialized = false;
if( dma.buffer ) if( snd.buffer )
{ {
snd_pcm_drop( s_alsa.pcm_handle ); snd_pcm_drop( s_alsa.pcm_handle );
snd_pcm_close( s_alsa.pcm_handle ); snd_pcm_close( s_alsa.pcm_handle );
Mem_Free( dma.buffer ); Mem_Free( snd.buffer );
dma.buffer = NULL; snd.buffer = NULL;
} }
} }
@@ -240,38 +240,38 @@ void SNDDMA_Submit( void )
while( avail >= s_alsa.period_size ) while( avail >= s_alsa.period_size )
{ {
int size = dma.samples << 1; int size = snd.samples << 1;
int pos = dma.samplepos << 1; int pos = snd.samplepos << 1;
unsigned long len = s_alsa.period_size * 4; unsigned long len = s_alsa.period_size * 4;
int wrapped = pos + len - size; int wrapped = pos + len - size;
int w; int w;
if( wrapped < 0 ) if( wrapped < 0 )
{ {
w = snd_pcm_writei( s_alsa.pcm_handle, dma.buffer + pos, len / 4 ); w = snd_pcm_writei( s_alsa.pcm_handle, snd.buffer + pos, len / 4 );
if( w < 0 ) if( w < 0 )
{ {
snd_pcm_prepare(s_alsa.pcm_handle); snd_pcm_prepare(s_alsa.pcm_handle);
return; return;
} }
dma.samplepos += len >> 1; snd.samplepos += len >> 1;
} }
else else
{ {
int remaining = size - pos; int remaining = size - pos;
w = snd_pcm_writei( s_alsa.pcm_handle, dma.buffer + pos, remaining / 4 ); w = snd_pcm_writei( s_alsa.pcm_handle, snd.buffer + pos, remaining / 4 );
if( w < 0 ) if( w < 0 )
{ {
snd_pcm_prepare(s_alsa.pcm_handle); snd_pcm_prepare(s_alsa.pcm_handle);
return; return;
} }
w = snd_pcm_writei( s_alsa.pcm_handle, dma.buffer, wrapped / 4 ); w = snd_pcm_writei( s_alsa.pcm_handle, snd.buffer, wrapped / 4 );
if( w < 0 ) if( w < 0 )
{ {
snd_pcm_prepare(s_alsa.pcm_handle); snd_pcm_prepare(s_alsa.pcm_handle);
return; return;
} }
dma.samplepos = wrapped >> 1; snd.samplepos = wrapped >> 1;
} }
avail = snd_pcm_avail_update( s_alsa.pcm_handle ); avail = snd_pcm_avail_update( s_alsa.pcm_handle );
@@ -282,11 +282,11 @@ void SNDDMA_Submit( void )
int s, w, frames; int s, w, frames;
void *start; void *start;
if( !dma.buffer ) if( !snd.buffer )
return; return;
s = dma.samplepos * 2; s = snd.samplepos * 2;
start = (void *)&dma.buffer[s]; start = (void *)&snd.buffer[s];
frames = s_alsa.period_size / 2; frames = s_alsa.period_size / 2;
// write to card // write to card
if( ( w = snd_pcm_writei( s_alsa.pcm_handle, start, frames ) ) < 0) if( ( w = snd_pcm_writei( s_alsa.pcm_handle, start, frames ) ) < 0)
@@ -296,10 +296,10 @@ void SNDDMA_Submit( void )
return; return;
} }
dma.samplepos += w * 2; // mark progress snd.samplepos += w * 2; // mark progress
if(dma.samplepos >= dma.samples) if(snd.samplepos >= snd.samples)
dma.samplepos = 0; // wrap buffer snd.samplepos = 0; // wrap buffer
} }
} }
@@ -324,7 +324,7 @@ between a deactivate and an activate.
*/ */
void SNDDMA_Activate( qboolean active ) void SNDDMA_Activate( qboolean active )
{ {
if( !dma.initialized ) if( !snd.initialized )
return; return;
s_alsa.paused = !active; s_alsa.paused = !active;

View File

@@ -46,38 +46,38 @@ static char sdl_backend_name[32];
static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len ) static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len )
{ {
const int size = dma.samples << 1; const int size = snd.samples << 1;
int pos; int pos;
int wrapped; int wrapped;
if( !dma.buffer ) if( !snd.buffer )
{ {
memset( stream, 0, len ); memset( stream, 0, len );
return; return;
} }
pos = dma.samplepos << 1; pos = snd.samplepos << 1;
if( pos >= size ) if( pos >= size )
pos = dma.samplepos = 0; pos = snd.samplepos = 0;
wrapped = pos + len - size; wrapped = pos + len - size;
if( wrapped < 0 ) if( wrapped < 0 )
{ {
memcpy( stream, dma.buffer + pos, len ); memcpy( stream, snd.buffer + pos, len );
dma.samplepos += len >> 1; snd.samplepos += len >> 1;
} }
else else
{ {
int remaining = size - pos; int remaining = size - pos;
memcpy( stream, dma.buffer + pos, remaining ); memcpy( stream, snd.buffer + pos, remaining );
memcpy( stream + remaining, dma.buffer, wrapped ); memcpy( stream + remaining, snd.buffer, wrapped );
dma.samplepos = wrapped >> 1; snd.samplepos = wrapped >> 1;
} }
if( dma.samplepos >= size ) if( snd.samplepos >= size )
dma.samplepos = 0; snd.samplepos = 0;
} }
/* /*
@@ -131,20 +131,20 @@ qboolean SNDDMA_Init( void )
goto fail; goto fail;
} }
dma.format.speed = obtained.freq; snd.format.speed = obtained.freq;
dma.format.channels = obtained.channels; snd.format.channels = obtained.channels;
dma.format.width = 2; snd.format.width = 2;
samplecount = s_samplecount.value; samplecount = s_samplecount.value;
if( !samplecount ) if( !samplecount )
samplecount = 0x8000; samplecount = 0x8000;
dma.samples = samplecount * obtained.channels; snd.samples = samplecount * obtained.channels;
dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 ); snd.buffer = Mem_Calloc( sndpool, snd.samples * 2 );
dma.samplepos = 0; snd.samplepos = 0;
Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq ); Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq );
Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL" ); Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL" );
dma.initialized = true; snd.initialized = true;
dma.backendName = sdl_backend_name; snd.backend_name = sdl_backend_name;
SNDDMA_Activate( true ); SNDDMA_Activate( true );
@@ -191,7 +191,7 @@ Reset the sound device for exiting
void SNDDMA_Shutdown( void ) void SNDDMA_Shutdown( void )
{ {
Con_Printf( "Shutting down audio.\n" ); Con_Printf( "Shutting down audio.\n" );
dma.initialized = false; snd.initialized = false;
if( sdl_dev ) if( sdl_dev )
{ {
@@ -203,10 +203,10 @@ void SNDDMA_Shutdown( void )
if( SDL_WasInit( SDL_INIT_AUDIO )) if( SDL_WasInit( SDL_INIT_AUDIO ))
SDL_QuitSubSystem( SDL_INIT_AUDIO ); SDL_QuitSubSystem( SDL_INIT_AUDIO );
if( dma.buffer ) if( snd.buffer )
{ {
Mem_Free( dma.buffer ); Mem_Free( snd.buffer );
dma.buffer = NULL; snd.buffer = NULL;
} }
} }
@@ -220,7 +220,7 @@ between a deactivate and an activate.
*/ */
void SNDDMA_Activate( qboolean active ) void SNDDMA_Activate( qboolean active )
{ {
if( !dma.initialized ) if( !snd.initialized )
return; return;
SDL_PauseAudioDevice( sdl_dev, !active ); SDL_PauseAudioDevice( sdl_dev, !active );

View File

@@ -39,32 +39,32 @@ static char sdl_backend_name[32];
static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len ) static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len )
{ {
const int size = dma.samples << 1; const int size = snd.samples << 1;
int pos; int pos;
int wrapped; int wrapped;
pos = dma.samplepos << 1; pos = snd.samplepos << 1;
if( pos >= size ) if( pos >= size )
pos = dma.samplepos = 0; pos = snd.samplepos = 0;
wrapped = pos + len - size; wrapped = pos + len - size;
if( wrapped < 0 ) if( wrapped < 0 )
{ {
memcpy( stream, dma.buffer + pos, len ); memcpy( stream, snd.buffer + pos, len );
dma.samplepos += len >> 1; snd.samplepos += len >> 1;
} }
else else
{ {
int remaining = size - pos; int remaining = size - pos;
memcpy( stream, dma.buffer + pos, remaining ); memcpy( stream, snd.buffer + pos, remaining );
memcpy( stream + remaining, dma.buffer, wrapped ); memcpy( stream + remaining, snd.buffer, wrapped );
dma.samplepos = wrapped >> 1; snd.samplepos = wrapped >> 1;
} }
if( dma.samplepos >= size ) if( snd.samplepos >= size )
dma.samplepos = 0; snd.samplepos = 0;
} }
/* /*
@@ -148,22 +148,22 @@ qboolean SNDDMA_Init( void )
goto fail; goto fail;
} }
dma.format.speed = obtained.freq; snd.format.speed = obtained.freq;
dma.format.channels = obtained.channels; snd.format.channels = obtained.channels;
dma.format.width = 2; snd.format.width = 2;
samplecount = s_samplecount.value; samplecount = s_samplecount.value;
if( !samplecount ) if( !samplecount )
samplecount = 0x8000; samplecount = 0x8000;
dma.samples = samplecount * obtained.channels; snd.samples = samplecount * obtained.channels;
dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 ); snd.buffer = Mem_Calloc( sndpool, snd.samples * 2 );
dma.samplepos = 0; snd.samplepos = 0;
sdl_format = obtained.format; sdl_format = obtained.format;
Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq ); Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq );
Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL (%s)", SDL_GetCurrentAudioDriver( )); Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL (%s)", SDL_GetCurrentAudioDriver( ));
dma.initialized = true; snd.initialized = true;
dma.backendName = sdl_backend_name; snd.backend_name = sdl_backend_name;
SNDDMA_Activate( true ); SNDDMA_Activate( true );
@@ -179,7 +179,7 @@ fail:
============== ==============
SNDDMA_BeginPainting SNDDMA_BeginPainting
Makes sure dma.buffer is valid Makes sure snd.buffer is valid
=============== ===============
*/ */
void SNDDMA_BeginPainting( void ) void SNDDMA_BeginPainting( void )
@@ -210,7 +210,7 @@ Reset the sound device for exiting
void SNDDMA_Shutdown( void ) void SNDDMA_Shutdown( void )
{ {
Con_Printf( "Shutting down audio.\n" ); Con_Printf( "Shutting down audio.\n" );
dma.initialized = false; snd.initialized = false;
if( sdl_dev ) if( sdl_dev )
{ {
@@ -221,10 +221,10 @@ void SNDDMA_Shutdown( void )
SDL_QuitSubSystem( SDL_INIT_AUDIO ); SDL_QuitSubSystem( SDL_INIT_AUDIO );
if( dma.buffer ) if( snd.buffer )
{ {
Mem_Free( dma.buffer ); Mem_Free( snd.buffer );
dma.buffer = NULL; snd.buffer = NULL;
} }
} }
@@ -238,7 +238,7 @@ between a deactivate and an activate.
*/ */
void SNDDMA_Activate( qboolean active ) void SNDDMA_Activate( qboolean active )
{ {
if( !dma.initialized ) if( !snd.initialized )
return; return;
SDL_PauseAudioDevice( sdl_dev, !active ); SDL_PauseAudioDevice( sdl_dev, !active );

View File

@@ -28,35 +28,35 @@ static char sdl_backend_name[32];
static void SDLash_OutputCallback( void *userdata, SDL_AudioStream *stream, int additional_amount, int len ) static void SDLash_OutputCallback( void *userdata, SDL_AudioStream *stream, int additional_amount, int len )
{ {
const int size = dma.samples << 1; const int size = snd.samples << 1;
int pos; int pos;
int wrapped; int wrapped;
(void)userdata; (void)userdata;
(void)additional_amount; (void)additional_amount;
pos = dma.samplepos << 1; pos = snd.samplepos << 1;
if( pos >= size ) if( pos >= size )
pos = dma.samplepos = 0; pos = snd.samplepos = 0;
wrapped = pos + len - size; wrapped = pos + len - size;
if( wrapped < 0 ) if( wrapped < 0 )
{ {
SDL_PutAudioStreamData( stream, dma.buffer + pos, len ); SDL_PutAudioStreamData( stream, snd.buffer + pos, len );
dma.samplepos += len >> 1; snd.samplepos += len >> 1;
} }
else else
{ {
int remaining = size - pos; int remaining = size - pos;
SDL_PutAudioStreamData( stream, dma.buffer + pos, remaining ); SDL_PutAudioStreamData( stream, snd.buffer + pos, remaining );
SDL_PutAudioStreamData( stream, dma.buffer, wrapped ); SDL_PutAudioStreamData( stream, snd.buffer, wrapped );
dma.samplepos = wrapped >> 1; snd.samplepos = wrapped >> 1;
} }
if( dma.samplepos >= size ) if( snd.samplepos >= size )
dma.samplepos = 0; snd.samplepos = 0;
} }
/* /*
@@ -122,18 +122,18 @@ qboolean SNDDMA_Init( void )
return false; return false;
} }
dma.format.speed = SOUND_DMA_SPEED; snd.format.speed = SOUND_DMA_SPEED;
dma.format.channels = 2; snd.format.channels = 2;
dma.format.width = 2; snd.format.width = 2;
int samplecount = s_samplecount.value; int samplecount = s_samplecount.value;
if( !samplecount ) if( !samplecount )
samplecount = 0x8000; samplecount = 0x8000;
dma.samples = samplecount * dma.format.channels; snd.samples = samplecount * snd.format.channels;
dma.buffer = Mem_Calloc( sndpool, dma.samples * dma.format.width ); snd.buffer = Mem_Calloc( sndpool, snd.samples * snd.format.width );
dma.samplepos = 0; snd.samplepos = 0;
dma.initialized = true; snd.initialized = true;
Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL3 (%s)", SDL_GetCurrentAudioDriver( )); Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL3 (%s)", SDL_GetCurrentAudioDriver( ));
dma.backendName = sdl_backend_name; snd.backend_name = sdl_backend_name;
Con_Printf( "Using audio driver: %s @ %d Hz\n", sdl_backend_name, SOUND_DMA_SPEED ); Con_Printf( "Using audio driver: %s @ %d Hz\n", sdl_backend_name, SOUND_DMA_SPEED );
@@ -178,7 +178,7 @@ Reset the sound device for exiting
void SNDDMA_Shutdown( void ) void SNDDMA_Shutdown( void )
{ {
Con_Printf( "Shutting down audio.\n" ); Con_Printf( "Shutting down audio.\n" );
dma.initialized = false; snd.initialized = false;
if( out_stream ) if( out_stream )
{ {
@@ -189,10 +189,10 @@ void SNDDMA_Shutdown( void )
SDL_QuitSubSystem( SDL_INIT_AUDIO ); SDL_QuitSubSystem( SDL_INIT_AUDIO );
if( dma.buffer ) if( snd.buffer )
{ {
Mem_Free( dma.buffer ); Mem_Free( snd.buffer );
dma.buffer = NULL; snd.buffer = NULL;
} }
} }
@@ -206,7 +206,7 @@ between a deactivate and an activate.
*/ */
void SNDDMA_Activate( qboolean active ) void SNDDMA_Activate( qboolean active )
{ {
if( !dma.initialized ) if( !snd.initialized )
return; return;
if( active ) if( active )

View File

@@ -30,8 +30,6 @@ so it can unlock and free the data block after it has been played.
======================================================================= =======================================================================
*/ */
dma_t dma;
void S_Activate( qboolean active ) void S_Activate( qboolean active )
{ {
} }
@@ -86,11 +84,12 @@ Reset the sound device for exiting
void SNDDMA_Shutdown( void ) void SNDDMA_Shutdown( void )
{ {
Con_Printf("Shutting down audio.\n"); Con_Printf("Shutting down audio.\n");
dma.initialized = false; snd.initialized = false;
if (dma.buffer) { if( snd.buffer )
Z_Free(dma.buffer); {
dma.buffer = NULL; Mem_Free( snd.buffer );
snd.buffer = NULL;
} }
} }