From 729c985eaf1b870a6d814d2646fbe1a04807a6a0 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Mon, 6 Apr 2026 06:00:40 +0500 Subject: [PATCH] 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. --- engine/client/avi/avi_ffmpeg.c | 12 +- engine/client/cl_frame.c | 2 +- engine/client/s_load.c | 17 +- engine/client/s_main.c | 493 +++++++++++++++------------------ engine/client/s_mix.c | 74 ++--- engine/client/s_stream.c | 28 +- engine/client/s_vox.c | 45 +-- engine/client/sound.h | 106 +++---- engine/platform/linux/s_alsa.c | 62 ++--- engine/platform/sdl1/s_sdl1.c | 48 ++-- engine/platform/sdl2/s_sdl2.c | 48 ++-- engine/platform/sdl3/s_sdl3.c | 46 +-- engine/platform/stub/s_stub.c | 11 +- 13 files changed, 486 insertions(+), 506 deletions(-) diff --git a/engine/client/avi/avi_ffmpeg.c b/engine/client/avi/avi_ffmpeg.c index d77f7e39..a569e370 100644 --- a/engine/client/avi/avi_ffmpeg.c +++ b/engine/client/avi/avi_ffmpeg.c @@ -255,9 +255,9 @@ static void AVI_StreamAudio( movie_state_t *Avi ) rawchan_t *ch = NULL; // 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; ch = S_FindRawChannel( Avi->entnum, true ); @@ -268,14 +268,14 @@ static void AVI_StreamAudio( movie_state_t *Avi ) ch->master_vol = Avi->volume; ch->dist_mult = (Avi->attn / SND_CLIP_DISTANCE); - if( ch->s_rawend < soundtime ) - ch->s_rawend = soundtime; + if( ch->s_rawend < snd.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; - 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); if( file_samples <= 1 ) return; // no more samples need diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index 68a4d9cd..dcd27323 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -1381,7 +1381,7 @@ qboolean CL_GetEntitySpatialization( channel_t *ch ) if( ch->entnum == 0 ) { - ch->staticsound = true; + SetBits( ch->flags, FL_CHAN_STATIC_SOUND ); return true; // static sound } diff --git a/engine/client/s_load.c b/engine/client/s_load.c index 4dbed9e3..bba2e84e 100644 --- a/engine/client/s_load.c +++ b/engine/client/s_load.c @@ -152,7 +152,7 @@ sfx_t *S_FindName( const char *pname, qboolean *pfInCache ) uint i, hash; string name; - if( COM_StringEmptyOrNULL( pname ) || !dma.initialized ) + if( COM_StringEmptyOrNULL( pname ) || !snd.initialized ) return NULL; if( Q_strlen( pname ) >= sizeof( sfx->name )) @@ -247,7 +247,7 @@ void S_BeginRegistration( void ) { int i; - snd_ambient = false; + snd.have_ambient_sfx = false; // check for automatic ambient sounds for( i = 0; i < NUM_AMBIENTS; i++ ) @@ -255,8 +255,9 @@ void S_BeginRegistration( void ) if( !GI->ambientsound[i][0] ) continue; // empty slot - ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] ); - if( ambient_sfx[i] ) snd_ambient = true; // allow auto-ambients + snd.ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] ); + if( snd.ambient_sfx[i] ) + snd.have_ambient_sfx = true; // allow auto-ambients } s_registering = true; @@ -273,7 +274,7 @@ void S_EndRegistration( void ) sfx_t *sfx; int i; - if( !s_registering || !dma.initialized ) + if( !s_registering || !snd.initialized ) return; // free any sounds not from this registration sequence @@ -306,7 +307,7 @@ sound_t S_RegisterSound( const char *name ) { sfx_t *sfx; - if( COM_StringEmptyOrNULL( name ) || !dma.initialized ) + if( COM_StringEmptyOrNULL( name ) || !snd.initialized ) return -1; if( S_TestSoundChar( name, '!' )) @@ -330,7 +331,7 @@ sound_t S_RegisterSound( const char *name ) sfx_t *S_GetSfxByHandle( sound_t handle ) { - if( !dma.initialized ) + if( !snd.initialized ) return NULL; // create new sfx @@ -369,7 +370,7 @@ void S_FreeSounds( void ) sfx_t *sfx; int i; - if( !dma.initialized ) + if( !snd.initialized ) return; // stop all sounds diff --git a/engine/client/s_main.c b/engine/client/s_main.c index b2f0888c..c57a6722 100644 --- a/engine/client/s_main.c +++ b/engine/client/s_main.c @@ -31,19 +31,18 @@ struct int in_seconds; } soundfade; -dma_t dma; poolhandle_t sndpool; -sound_t ambient_sfx[NUM_AMBIENTS]; -qboolean snd_ambient = false; qboolean snd_fade_sequence = false; -listener_t s_listener; -channel_t channels[MAX_CHANNELS]; -rawchan_t *raw_channels[MAX_RAW_CHANNELS]; -int total_channels; - -int soundtime; // sample PAIRS -int paintedtime; // sample PAIRS +// this confuses the shit out of qt creator parser +// and good luck if you rely on shitty old msvc +snd_globals_t snd = +{ + .channels = (channel_t[MAX_CHANNELS]){}, + .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" ); 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" ); 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_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( 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)" ); @@ -158,7 +156,7 @@ S_IsClient */ 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->name[0] = '\0'; - ch->use_loop = false; - ch->is_sentence = false; + ch->flags = 0; ch->forced_end = ch->sample = 0.0; ch->data = NULL; - ch->finished = false; SND_CloseMouth( ch ); } @@ -240,7 +236,7 @@ static qboolean SND_FStreamIsPlaying( sfx_t *sfx ) { for( int i = NUM_AMBIENTS; i < MAX_DYNAMIC_CHANNELS; i++ ) { - if( channels[i].sfx == sfx ) + if( snd.channels[i].sfx == sfx ) return true; } return false; @@ -257,14 +253,14 @@ static int SND_GetChannelTimeLeft( const channel_t *ch ) { int remaining; - if( ch->finished || !ch->sfx || !ch->sfx->cache ) + if( FBitSet( ch->flags, FL_CHAN_FINISHED ) || !ch->sfx || !ch->sfx->cache ) 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; - if( ch->sentence_finished ) + if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ) ) return 0; // current word @@ -294,7 +290,7 @@ static int SND_GetChannelTimeLeft( const channel_t *ch ) else { 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 ); } @@ -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++ ) { - channel_t *ch = &channels[ch_idx]; + channel_t *ch = &snd.channels[ch_idx]; // Never override a streaming sound that is currently playing or // 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 ) return NULL; - if( channels[first_to_die].sfx ) + if( snd.channels[first_to_die].sfx ) { // 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 )) { - 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 ) { @@ -381,10 +377,10 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean } // 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; // 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; - if( VectorCompare( pos, channels[i].origin ) && channels[i].sfx == sfx ) + if( VectorCompare( pos, snd.channels[i].origin ) && snd.channels[i].sfx == sfx ) break; } - if( i < total_channels ) + if( i < snd.total_channels ) { // reuse an empty static sound channel - ch = &channels[i]; + ch = &snd.channels[i]; } else { // 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__ ); return NULL; } // get a channel for the static sound - ch = &channels[total_channels]; - total_channels++; + ch = &snd.channels[snd.total_channels]; + snd.total_channels++; } 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( !sfx ) { - if( !ch->is_sentence ) + if( !FBitSet( ch->flags, FL_CHAN_IS_SENTENCE )) return false; } 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 ) { - channel_t *ch; - int i; + // This is a sentence name. + // 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. - // 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. + channel_t *ch = &snd.channels[i]; - for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ ) - { - 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 )) + if( S_MaybeAlterChannel( ch, entnum, channel, flags, is_sentence ? NULL : sfx, pitch, vol )) return true; } + // channel not found return false; } @@ -554,7 +537,7 @@ static void SND_Spatialize( channel_t *ch ) return; } - if( !ch->staticsound ) + if( !FBitSet( ch->flags, FL_CHAN_STATIC_SOUND )) { if( !CL_GetEntitySpatialization( ch )) { @@ -567,11 +550,11 @@ static void SND_Spatialize( channel_t *ch ) // source_vec is vector from listener to sound source // player sounds come from 1' in front of player 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 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 )) { @@ -610,7 +593,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv int vol, ch_idx; qboolean bIgnore = false; - if( !dma.initialized ) return; + if( !snd.initialized ) return; sfx = S_GetSfxByHandle( handle ); 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 ); // pick a channel to play on - if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( pos, sfx ); - else target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); + if( chan == CHAN_STATIC ) + target_chan = SND_PickStaticChannel( pos, sfx ); + else + target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); 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 )); VectorCopy( pos, target_chan->origin ); - target_chan->staticsound = ( ent == 0 ) ? true : false; - target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true; - target_chan->localsound = (flags & SND_LOCALSOUND) ? true : false; + + if( ent == 0 ) + 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->master_vol = vol; target_chan->entnum = ent; target_chan->entchannel = chan; target_chan->basePitch = pitch; - target_chan->is_sentence = false; target_chan->sfx = sfx; pSource = NULL; @@ -723,7 +714,7 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float qboolean bIgnore = false; int vol; - if( !dma.initialized ) return; + if( !snd.initialized ) return; sfx = S_GetSfxByHandle( handle ); 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 // pick a channel to play on - if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( pos, sfx ); - else target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); + if( chan == CHAN_STATIC ) + target_chan = SND_PickStaticChannel( pos, sfx ); + else + target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); 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 )); VectorCopy( pos, target_chan->origin ); - target_chan->staticsound = ( ent == 0 ) ? true : false; - target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true; - target_chan->localsound = (flags & SND_LOCALSOUND) ? true : false; + + if( ent == 0 ) + 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->master_vol = vol; target_chan->entnum = ent; target_chan->entchannel = chan; target_chan->basePitch = pitch; - target_chan->is_sentence = false; target_chan->sfx = sfx; 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 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; 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; int vol, fvox = 0; - if( !dma.initialized ) return; + if( !snd.initialized ) return; sfx = S_GetSfxByHandle( handle ); 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 pSource = S_LoadSound( sfx ); ch->sfx = sfx; - ch->is_sentence = false; + ClearBits( ch->flags, FL_CHAN_IS_SENTENCE ); 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; // never update positions if source entity is 0 - ch->staticsound = ( ent == 0 ) ? true : false; - ch->use_loop = (flags & SND_STOP_LOOPING) ? false : true; - ch->localsound = (flags & SND_LOCALSOUND) ? true : false; + if( ent == 0 ) SetBits( ch->flags, FL_CHAN_STATIC_SOUND ); + else ClearBits( ch->flags, FL_CHAN_STATIC_SOUND ); + + 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->dist_mult = (attn / SND_CLIP_DISTANCE); ch->entchannel = CHAN_STATIC; @@ -914,9 +919,9 @@ void S_StartLocalSound( const char *name, float volume, qboolean reliable ) if( reliable ) channel = CHAN_STATIC; - if( !dma.initialized ) return; + if( !snd.initialized ) return; 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 sounds_left = size; - int i; - if( !dma.initialized ) + if( !snd.initialized ) 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] ) - { - 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; + const channel_t *ch = &snd.channels[i]; - sounds_left--; - pout++; - } + if( ch->entchannel != CHAN_STATIC || !ch->sfx || !ch->sfx->name[0] ) + 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 ); @@ -972,31 +980,35 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size ) int sounds_left = size; int i, looped; - if( !dma.initialized ) + if( !snd.initialized ) 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 - 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 - 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 < 0) ? 0 : 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->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; + 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 < 0) ? 0 : ch->entnum; + VectorCopy( ch->origin, pout->origin ); + pout->volume = (float)ch->master_vol / 255.0f; + pout->attenuation = ch->dist_mult * SND_CLIP_DISTANCE; + pout->pitch = ch->basePitch; + pout->channel = ch->entchannel; + pout->wordIndex = ch->word_index; + pout->samplePos = ch->sample; + pout->forcedEnd = ch->forced_end; pout->looping = looped; sounds_left--; @@ -1013,18 +1025,14 @@ S_InitAmbientChannels */ static void S_InitAmbientChannels( void ) { - int ambient_channel; - channel_t *chan; - - for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) + for( int i = 0; i < NUM_AMBIENTS; i++ ) { - chan = &channels[ambient_channel]; + channel_t *ch = &snd.channels[i]; - chan->staticsound = true; - chan->use_loop = true; - chan->entchannel = CHAN_STATIC; - chan->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE); - chan->basePitch = PITCH_NORM; + SetBits( ch->flags, FL_CHAN_USE_LOOP | FL_CHAN_STATIC_SOUND ); + ch->entchannel = CHAN_STATIC; + ch->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE); + ch->basePitch = PITCH_NORM; } } @@ -1037,27 +1045,27 @@ static void S_UpdateAmbientSounds( void ) { int ambient_channel; - if( !snd_ambient ) + if( !snd.have_ambient_sfx ) return; // calc ambient sound levels if( !cl.worldmodel ) 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 ) { - for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) - channels[ambient_channel].sfx = NULL; + for( int i = 0; i < NUM_AMBIENTS; i++ ) + snd.channels[i].sfx = NULL; 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]; - chan->sfx = S_GetSfxByHandle( ambient_sfx[ambient_channel] ); + channel_t *chan = &snd.channels[i]; + chan->sfx = S_GetSfxByHandle( snd.ambient_sfx[i] ); // ambient is unused if( !chan->sfx ) @@ -1116,9 +1124,9 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create ) int best = -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 ) { @@ -1132,7 +1140,7 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create ) if( ch->entnum == entnum ) return ch; - time = ch->s_rawend - paintedtime; + time = ch->s_rawend - snd.paintedtime; if( time < best_time ) { best = i; @@ -1150,14 +1158,14 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create ) if( best < 0 ) return NULL; // no free slots - if( !raw_channels[best] ) + if( !snd.raw_channels[best] ) { size_t raw_samples = MAX_RAW_SAMPLES; - 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] = Mem_Calloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * raw_samples ); + snd.raw_channels[best]->max_samples = raw_samples; } - ch = raw_channels[best]; + ch = snd.raw_channels[best]; ch->entnum = entnum; ch->s_rawend = 0; @@ -1174,8 +1182,8 @@ uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint ma uint fracstep, samplefrac; uint src, dst; - if( rawend < paintedtime ) - rawend = paintedtime; + if( rawend < snd.paintedtime ) + rawend = snd.paintedtime; fracstep = ((double) rate / (double)SOUND_DMA_SPEED) * (double)(1 << S_RAW_SAMPLES_PRECISION_BITS); samplefrac = 0; @@ -1262,14 +1270,14 @@ static void S_FreeIdleRawChannels( void ) { 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->s_rawend >= paintedtime ) + if( ch->s_rawend >= snd.paintedtime ) continue; if( ch->entnum > 0 ) @@ -1280,9 +1288,9 @@ static void S_FreeIdleRawChannels( void ) 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 ); } } @@ -1297,9 +1305,9 @@ static void S_ClearRawChannels( void ) { 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; ch->s_rawend = 0; @@ -1314,14 +1322,14 @@ S_SpatializeRawChannels */ 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 ) continue; - if( ch->s_rawend < paintedtime ) + if( ch->s_rawend < snd.paintedtime ) { ch->leftvol = ch->rightvol = 0; continue; @@ -1339,11 +1347,11 @@ static void S_SpatializeRawChannels( void ) { 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 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 if( ch->dist_mult <= 0.0f ) dot = 0.0f; @@ -1366,16 +1374,9 @@ S_FreeRawChannels */ static void S_FreeRawChannels( void ) { - int i; - // free raw samples - for( i = 0; i < MAX_RAW_CHANNELS; i++ ) - { - if( raw_channels[i] ) - Mem_Free( raw_channels[i] ); - } - - memset( raw_channels, 0, sizeof( raw_channels )); + for( int i = 0; i < snd.max_raw_channels; i++ ) + Mem_Free2( &snd.raw_channels[i] ); } //============================================================================= @@ -1390,8 +1391,10 @@ static void S_ClearBuffer( void ) S_ClearRawChannels(); SNDDMA_BeginPainting (); - if( dma.buffer ) - memset( dma.buffer, 0, dma.samples * 2 ); + + if( snd.buffer ) + memset( snd.buffer, 0, snd.samples * 2 ); + SNDDMA_Submit (); S_ClearBuffers( PAINTBUFFER_SIZE ); @@ -1408,7 +1411,7 @@ void GAME_EXPORT S_StopSound( int entnum, int channel, const char *soundname ) { sfx_t *sfx; - if( !dma.initialized ) return; + if( !snd.initialized ) return; sfx = S_FindName( soundname, NULL ); S_AlterChannel( entnum, channel, sfx, 0, 0, SND_STOP ); } @@ -1422,19 +1425,21 @@ void S_StopAllSounds( qboolean ambient ) { int i; - if( !dma.initialized ) return; - total_channels = MAX_DYNAMIC_CHANNELS; // no statics + if( !snd.initialized ) return; + 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; - S_FreeChannel( &channels[i] ); + if( !snd.channels[i].sfx ) + continue; + + S_FreeChannel( &snd.channels[i] ); } SX_ClearState(); // clear all the channels - memset( channels, 0, sizeof( channels )); + memset( snd.channels, 0, sizeof( snd.channels[0] ) * snd.max_channels ); // restart the ambient sounds if( ambient ) S_InitAmbientChannels (); @@ -1459,22 +1464,22 @@ static int S_GetSoundtime( void ) static int buffers, oldsamplepos; int samplepos, fullsamples; - fullsamples = dma.samples / 2; + fullsamples = snd.samples / 2; // it is possible to miscount buffers // if it has wrapped twice between // calls to S_Update. Oh well. - samplepos = dma.samplepos; + samplepos = snd.samplepos; if( samplepos < oldsamplepos ) { buffers++; // buffer wrapped - if( paintedtime > 0x40000000 ) + if( snd.paintedtime > 0x40000000 ) { // time to chop things off to avoid 32 bit limits buffers = 0; - paintedtime = fullsamples; + snd.paintedtime = fullsamples; S_StopAllSounds( true ); } } @@ -1492,25 +1497,25 @@ static void S_UpdateChannels( void ) SNDDMA_BeginPainting(); - if( !dma.buffer ) return; + if( !snd.buffer ) return; // updates DMA time - soundtime = S_GetSoundtime(); + snd.soundtime = S_GetSoundtime(); // soundtime - total samples that have been played out to hardware at dmaspeed // paintedtime - total samples that have been mixed at speed // endtime - target for samples in mixahead buffer at speed - endtime = soundtime + s_mixahead.value * SOUND_DMA_SPEED; - samps = dma.samples >> 1; + endtime = snd.soundtime + s_mixahead.value * SOUND_DMA_SPEED; + samps = snd.samples >> 1; - if((int)(endtime - soundtime) > samps ) - endtime = soundtime + samps; + if((int)(endtime - snd.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 // boundaries of 4 samples. this is important when upsampling from 11khz -> 44khz. - endtime -= ( endtime - paintedtime ) & 0x3; + endtime -= ( endtime - snd.paintedtime ) & 0x3; } S_PaintChannels( endtime ); @@ -1527,7 +1532,7 @@ Don't let sound skip if going slow */ void S_ExtraUpdate( void ) { - if( !dma.initialized ) return; + if( !snd.initialized ) return; 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 )) return; - VectorCopy( rvp->vieworigin, s_listener.origin ); - AngleVectors( rvp->viewangles, s_listener.forward, s_listener.right, s_listener.up ); - s_listener.entnum = rvp->viewentity; // can be camera entity too + VectorCopy( rvp->vieworigin, snd.origin ); + AngleVectors( rvp->viewangles, snd.forward, snd.right, snd.up ); + 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 ) { - int i, j, total; - channel_t *ch, *combine; - con_nprint_t info; - - if( !dma.initialized ) return; + if( !snd.initialized ) return; // if the loading plaque is up, clear everything // out to make sure we aren't looping a dirty @@ -1575,55 +1576,15 @@ void SND_UpdateSound( void ) // update general area ambient sound sources S_UpdateAmbientSounds(); - combine = NULL; - // 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; - SND_Spatialize( ch ); // respatialize channel + channel_t *ch = &snd.channels[i]; - if( !ch->leftvol && !ch->rightvol ) + if( !ch->sfx ) continue; - // try to combine static sounds with a previous channel of the same - // 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; - } - } + SND_Spatialize( ch ); // respatialize channel } S_SpatializeRawChannels(); @@ -1631,26 +1592,33 @@ void SND_UpdateSound( void ) // debugging output if( s_show.value != 0.0f ) { - info.color[0] = 1.0f; - 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++ ) + con_nprint_t info = { - if( ch->sfx && ( ch->leftvol || ch->rightvol )) - { - info.index = total; - Con_NXPrintf( &info, "chan %i, pos (%.f %.f %.f) ent %i, lv%3i rv%3i %s\n", + .color[0] = 1.0f, + .color[1] = 0.6f, + .color[2] = 0.0f, + .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 ); - total++; - } + + info.index++; } + int total = info.index - 1; VectorSet( info.color, 1.0f, 1.0f, 1.0f ); 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 (); @@ -1880,12 +1848,12 @@ S_SoundInfo_f */ 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 samples\n", dma.samples ); + Con_Printf( "%5d samples\n", snd.samples ); Con_Printf( "%5d bits/sample\n", 16 ); 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 (); } @@ -1931,7 +1899,6 @@ qboolean S_Init( void ) Cvar_RegisterVariable( &s_lerping ); Cvar_RegisterVariable( &s_ambient_level ); Cvar_RegisterVariable( &s_ambient_fade ); - Cvar_RegisterVariable( &s_combine_sounds ); Cvar_RegisterVariable( &snd_mute_losefocus ); Cvar_RegisterVariable( &s_test ); Cvar_RegisterVariable( &s_samplecount ); @@ -1959,7 +1926,7 @@ qboolean S_Init( void ) Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" ); sndpool = Mem_AllocPool( "Sound Zone" ); - dma.backendName = "None"; + snd.backend_name = "None"; if( !SNDDMA_Init( )) { Con_Printf( "Audio: sound system can't be initialized\n" ); @@ -1967,11 +1934,11 @@ qboolean S_Init( void ) return false; } - soundtime = 0; - paintedtime = 0; + snd.soundtime = 0; + snd.paintedtime = 0; // clear ambient sounds - memset( ambient_sfx, 0, sizeof( ambient_sfx )); + memset( snd.ambient_sfx, 0, sizeof( snd.ambient_sfx )); SX_Init (); S_StopAllSounds ( true ); @@ -1986,7 +1953,7 @@ qboolean S_Init( void ) // ======================================================================= void S_Shutdown( void ) { - if( !dma.initialized ) return; + if( !snd.initialized ) return; Cmd_RemoveCommand( "play" ); Cmd_RemoveCommand( "playvol" ); diff --git a/engine/client/s_mix.c b/engine/client/s_mix.c index c58c77f3..fd64c6e5 100644 --- a/engine/client/s_mix.c +++ b/engine/client/s_mix.c @@ -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 ) { - if( chan->finished ) + if( FBitSet( chan->flags, FL_CHAN_FINISHED )) return 0; // 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 ) { - chan->finished = true; + SetBits( chan->flags, FL_CHAN_FINISHED ); 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 if( timecompress >= 100 ) { - chan->finished = true; + SetBits( chan->flags, FL_CHAN_FINISHED ); 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 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 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 if( num_samples > 0 ) - chan->finished = true; + SetBits( chan->flags, FL_CHAN_FINISHED ); // total amount of samples mixed return offset - initial_offset; @@ -206,10 +206,10 @@ static int VOX_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, { int offset = 0; - if( chan->sentence_finished ) + if( FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED )) 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 ); @@ -217,13 +217,13 @@ static int VOX_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, num_samples -= outputCount; // if we finished load a next word - if( chan->finished ) + if( FBitSet( chan->flags, FL_CHAN_FINISHED )) { VOX_FreeWord( chan ); chan->word_index++; VOX_LoadWord( chan ); - if( !chan->sentence_finished ) + if( !FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED )) 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 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 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 ) 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 ) continue; 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 } - 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 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 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( 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 ) 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( 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 - 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++; - if( ch->is_sentence ) + if( FBitSet( ch->flags, FL_CHAN_IS_SENTENCE )) { VOX_MixChannelToBuffer( dst, ch, num_samples, rate, pitch ); - if( ch->sentence_finished ) + if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED )) S_FreeChannel( ch ); } else { S_MixChannelToBuffer( dst, ch, num_samples, rate, pitch, 0, 0 ); - if( ch->finished ) + if( FBitSet( ch->flags, FL_CHAN_FINISHED )) 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 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 ) 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 ); } - if( dma.format.speed >= SOUND_44k ) + if( snd.format.speed >= SOUND_44k ) { if( num_mixed_channels > 0 ) S_UpsampleBuffer( roombuffer, count / ( SOUND_44k / SOUND_22k )); @@ -402,10 +402,10 @@ static int S_MixRawChannels( int end ) return 0; // 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 - rawchan_t *ch = raw_channels[i]; + rawchan_t *ch = snd.raw_channels[i]; if( !ch ) continue; @@ -434,7 +434,7 @@ static int S_MixRawChannels( int end ) uint stop = (end < ch->s_rawend) ? end : ch->s_rawend; 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].right += ( ch->rawsamples[j & mask].right * ch->rightvol ) >> 8; @@ -443,8 +443,8 @@ static int S_MixRawChannels( int end ) if( ch->entnum > 0 ) { cl_entity_t *ent = CL_GetEntityByIndex( ch->entnum ); - int pos = paintedtime & ( ch->max_samples - 1 ); - int count = bound( 0, ch->max_samples - pos, stop - paintedtime ); + int pos = snd.paintedtime & ( ch->max_samples - 1 ); + int count = bound( 0, ch->max_samples - pos, stop - snd.paintedtime ); if( ent ) 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 ) { const int *snd_p = (const int *)src; - const int sampleMask = ((dma.samples >> 1) - 1); - int lpaintedtime = paintedtime; + const int sampleMask = ((snd.samples >> 1) - 1); + int lpaintedtime = snd.paintedtime; SNDDMA_BeginPainting (); @@ -496,9 +496,9 @@ static void S_TransferPaintBuffer( const portable_samplepair_t *src, int endtime // handle recirculating buffer issues 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 ) snd_linear_count = endtime - lpaintedtime; @@ -526,14 +526,14 @@ void S_PaintChannels( int endtime ) { int gain = S_GetMasterVolume() * 256; - while( paintedtime < endtime ) + while( snd.paintedtime < endtime ) { // if paintbuffer is smaller than DMA buffer int end = endtime; - if( end - paintedtime > PAINTBUFFER_SIZE ) - end = paintedtime + PAINTBUFFER_SIZE; + if( end - snd.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 ); @@ -550,6 +550,6 @@ void S_PaintChannels( int endtime ) // transfer out according to DMA format S_TransferPaintBuffer( paintbuffer, end ); - paintedtime = end; + snd.paintedtime = end; } } diff --git a/engine/client/s_stream.c b/engine/client/s_stream.c index b691bf4c..8e1dd9aa 100644 --- a/engine/client/s_stream.c +++ b/engine/client/s_stream.c @@ -92,7 +92,7 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, int { S_StopBackgroundTrack(); - if( !dma.initialized ) return; + if( !snd.initialized ) return; // check for special symbols if( introTrack && *introTrack == '*' ) @@ -132,9 +132,9 @@ S_StopBackgroundTrack */ 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; FS_FreeStream( s_bgTrack.stream ); @@ -149,7 +149,7 @@ S_StreamSetPause */ 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; rawchan_t *ch = NULL; - if( !dma.initialized || !s_bgTrack.stream || s_listener.streaming ) + if( !snd.initialized || !s_bgTrack.stream || snd.streaming ) return; // 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; if( !cl.background ) @@ -218,14 +218,14 @@ void S_StreamBackgroundTrack( void ) Assert( ch != NULL ); // see how many samples should be copied into the raw buffer - if( ch->s_rawend < soundtime ) - ch->s_rawend = soundtime; + if( ch->s_rawend < snd.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; - 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 fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED ); @@ -283,9 +283,9 @@ S_StartStreaming */ void S_StartStreaming( void ) { - if( !dma.initialized ) return; + if( !snd.initialized ) return; // begin streaming movie soundtrack - s_listener.streaming = true; + snd.streaming = true; } /* @@ -295,6 +295,6 @@ S_StopStreaming */ void S_StopStreaming( void ) { - if( !dma.initialized ) return; - s_listener.streaming = false; + if( !snd.initialized ) return; + snd.streaming = false; } diff --git a/engine/client/s_vox.c b/engine/client/s_vox.c index 3eb3942a..3f87501c 100644 --- a/engine/client/s_vox.c +++ b/engine/client/s_vox.c @@ -140,7 +140,7 @@ static void S_TrimStartEndTimes( channel_t *ch, wavdata_t *wav, int start, int e 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 ) return; @@ -155,7 +155,7 @@ void VOX_LoadWord( channel_t *ch ) if( !data ) return; - ch->sentence_finished = false; + ClearBits( ch->flags, FL_CHAN_SENTENCE_FINISHED ); ch->data = data; 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 ch->sample = ch->forced_end = 0.0; - ch->finished = false; + ClearBits( ch->flags, FL_CHAN_FINISHED ); ch->data = NULL; 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]; - if( !word->sfx || word->in_cache ) + if( !word->sfx || FBitSet( word->flags, FL_VOXWORD_IN_CACHE )) return; FS_FreeSound( word->sfx->cache ); @@ -191,7 +191,7 @@ void VOX_SetChanVol( channel_t *ch ) { 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; word = &ch->words[ch->word_index]; @@ -207,7 +207,7 @@ float VOX_ModifyPitch( channel_t *ch, float pitch ) { 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; word = &ch->words[ch->word_index]; @@ -356,10 +356,7 @@ static void VOX_MakeDefaultWordParams( voxword_t *voxword ) *voxword = (voxword_t) { .volume = 100, .pitch = 100, - .start = 0, .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 ); switch( command ) { - case 'e': pvoxword->end = i; break; - case 'p': pvoxword->pitch = i; break; - case 's': pvoxword->start = i; break; - case 't': pvoxword->timecompress = i; break; - case 'v': pvoxword->volume = i; break; + case 'e': + pvoxword->end = bound( 0, i, 100 ); + break; + case 'p': + 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 if( Q_strlen( pszsave ) == 0 ) { @@ -494,7 +496,8 @@ void VOX_LoadSound( channel_t *ch, const char *pszin ) qboolean in_cache = false; 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++; } @@ -502,7 +505,7 @@ void VOX_LoadSound( channel_t *ch, const char *pszin ) ch->words[j].sfx = NULL; ch->sfx = ch->words[0].sfx; ch->word_index = 0; - ch->is_sentence = true; + SetBits( ch->flags, FL_CHAN_IS_SENTENCE ); VOX_LoadWord( ch ); } diff --git a/engine/client/sound.h b/engine/client/sound.h index 47962b13..7051bc9b 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -54,15 +54,17 @@ typedef struct sfx_s struct sfx_s *hashNext; } sfx_t; +#define FL_VOXWORD_IN_CACHE BIT( 0 ) // if set, it was loaded prior and shouldn't be freed + typedef struct voxword_s { - sfx_t *sfx; - uint16_t volume; // volume percent - 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) - uint16_t start : 7; // percent at which playback starts - uint16_t end : 7; // percent at which playback ends - uint16_t in_cache : 1; // if set to 1, it was loaded prior and shouldn't be freed + sfx_t *sfx; + uint16_t volume; // volume percent + uint16_t pitch; // pitch shift percent (keep large for extra chipmunk fun) + uint8_t timecompress; // percent of skipped data (speeds up playback without pitch shift) + uint8_t start; // percent at which playback starts + uint8_t end; // percent at which playback ends + uint8_t flags; } voxword_t; typedef struct snd_format_s @@ -72,19 +74,9 @@ typedef struct snd_format_s byte channels; } 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 { - int entnum; + short entnum; short master_vol; short leftvol; // 0-255 left 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 volatile uint s_rawend; float oldtime; // catch time jumps + + // TODO: add reserved bytes + size_t max_samples; // buffer length portable_samplepair_t rawsamples[]; // variable sized } 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 { 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 float dist_mult; // distance multiplier (attenuation/clipK) - int entnum; // entity soundsource int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.) + uint flags; + short entnum; // entity soundsource short master_vol; // 0-255 master volume short leftvol; // 0-255 left volume short rightvol; // 0-255 right volume 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; + // HACKHACK: count when this channel became inaudible // to not free it when it could be respatialized soon #define MAX_CHANNEL_INAUDIBLE_TIME 0.1f @@ -126,22 +124,42 @@ typedef struct channel_s double forced_end; wavdata_t *data; voxword_t words[CVOXWORDMAX]; + + // TODO: add reserved bytes } 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 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) @@ -150,16 +168,8 @@ typedef int sound_t; #define MAX_RAW_SAMPLES 16384 #define SND_CLIP_DISTANCE 1000.0f -extern sound_t ambient_sfx[NUM_AMBIENTS]; -extern qboolean snd_ambient; -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 int idsp_room; +extern snd_globals_t snd; extern convar_t s_musicvolume; extern convar_t s_lerping; diff --git a/engine/platform/linux/s_alsa.c b/engine/platform/linux/s_alsa.c index 2c6524ef..dac0d4fc 100644 --- a/engine/platform/linux/s_alsa.c +++ b/engine/platform/linux/s_alsa.c @@ -105,8 +105,8 @@ qboolean SNDDMA_Init( void ) return false; } - dma.format.speed = SOUND_DMA_SPEED; - r = dma.format.speed; + snd.format.speed = SOUND_DMA_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 ) { @@ -121,14 +121,14 @@ qboolean SNDDMA_Init( void ) if( dir != 0 ) { Con_Printf( "ALSA: rate %d not supported, using %d\n", SOUND_DMA_SPEED, r ); - dma.format.speed = r; + snd.format.speed = r; 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 ) ); snd_pcm_hw_params_free( s_alsa.hw_params ); @@ -162,7 +162,7 @@ qboolean SNDDMA_Init( void ) } 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 samples = 1; while( samples < p * 4 ) @@ -184,15 +184,15 @@ qboolean SNDDMA_Init( void ) return false; } - dma.buffer = Mem_Calloc( sndpool, samples * 2 ); //allocate pcm frame buffer - dma.samplepos = 0; - dma.samples = samples; - dma.format.width = 2; - dma.initialized = 1; - dma.backendName = "ALSA"; + snd.buffer = Mem_Calloc( sndpool, samples * 2 ); //allocate pcm frame buffer + snd.samplepos = 0; + snd.samples = samples; + snd.format.width = 2; + snd.initialized = 1; + snd.backend_name = "ALSA"; 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 ); return true; @@ -208,14 +208,14 @@ Closes the ALSA pcm device and frees the dma buffer. void SNDDMA_Shutdown(void) { 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_close( s_alsa.pcm_handle ); - Mem_Free( dma.buffer ); - dma.buffer = NULL; + Mem_Free( snd.buffer ); + snd.buffer = NULL; } } @@ -240,38 +240,38 @@ void SNDDMA_Submit( void ) while( avail >= s_alsa.period_size ) { - int size = dma.samples << 1; - int pos = dma.samplepos << 1; + int size = snd.samples << 1; + int pos = snd.samplepos << 1; unsigned long len = s_alsa.period_size * 4; int wrapped = pos + len - size; int w; 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 ) { snd_pcm_prepare(s_alsa.pcm_handle); return; } - dma.samplepos += len >> 1; + snd.samplepos += len >> 1; } else { 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 ) { snd_pcm_prepare(s_alsa.pcm_handle); 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 ) { snd_pcm_prepare(s_alsa.pcm_handle); return; } - dma.samplepos = wrapped >> 1; + snd.samplepos = wrapped >> 1; } avail = snd_pcm_avail_update( s_alsa.pcm_handle ); @@ -282,11 +282,11 @@ void SNDDMA_Submit( void ) int s, w, frames; void *start; - if( !dma.buffer ) + if( !snd.buffer ) return; - s = dma.samplepos * 2; - start = (void *)&dma.buffer[s]; + s = snd.samplepos * 2; + start = (void *)&snd.buffer[s]; frames = s_alsa.period_size / 2; // write to card if( ( w = snd_pcm_writei( s_alsa.pcm_handle, start, frames ) ) < 0) @@ -296,10 +296,10 @@ void SNDDMA_Submit( void ) return; } - dma.samplepos += w * 2; // mark progress + snd.samplepos += w * 2; // mark progress - if(dma.samplepos >= dma.samples) - dma.samplepos = 0; // wrap buffer + if(snd.samplepos >= snd.samples) + snd.samplepos = 0; // wrap buffer } } @@ -324,7 +324,7 @@ between a deactivate and an activate. */ void SNDDMA_Activate( qboolean active ) { - if( !dma.initialized ) + if( !snd.initialized ) return; s_alsa.paused = !active; diff --git a/engine/platform/sdl1/s_sdl1.c b/engine/platform/sdl1/s_sdl1.c index 86180d9a..03de7e5b 100644 --- a/engine/platform/sdl1/s_sdl1.c +++ b/engine/platform/sdl1/s_sdl1.c @@ -46,38 +46,38 @@ static char sdl_backend_name[32]; 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 wrapped; - if( !dma.buffer ) + if( !snd.buffer ) { memset( stream, 0, len ); return; } - pos = dma.samplepos << 1; + pos = snd.samplepos << 1; if( pos >= size ) - pos = dma.samplepos = 0; + pos = snd.samplepos = 0; wrapped = pos + len - size; if( wrapped < 0 ) { - memcpy( stream, dma.buffer + pos, len ); - dma.samplepos += len >> 1; + memcpy( stream, snd.buffer + pos, len ); + snd.samplepos += len >> 1; } else { int remaining = size - pos; - memcpy( stream, dma.buffer + pos, remaining ); - memcpy( stream + remaining, dma.buffer, wrapped ); - dma.samplepos = wrapped >> 1; + memcpy( stream, snd.buffer + pos, remaining ); + memcpy( stream + remaining, snd.buffer, wrapped ); + snd.samplepos = wrapped >> 1; } - if( dma.samplepos >= size ) - dma.samplepos = 0; + if( snd.samplepos >= size ) + snd.samplepos = 0; } /* @@ -131,20 +131,20 @@ qboolean SNDDMA_Init( void ) goto fail; } - dma.format.speed = obtained.freq; - dma.format.channels = obtained.channels; - dma.format.width = 2; + snd.format.speed = obtained.freq; + snd.format.channels = obtained.channels; + snd.format.width = 2; samplecount = s_samplecount.value; if( !samplecount ) samplecount = 0x8000; - dma.samples = samplecount * obtained.channels; - dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 ); - dma.samplepos = 0; + snd.samples = samplecount * obtained.channels; + snd.buffer = Mem_Calloc( sndpool, snd.samples * 2 ); + snd.samplepos = 0; Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq ); Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL" ); - dma.initialized = true; - dma.backendName = sdl_backend_name; + snd.initialized = true; + snd.backend_name = sdl_backend_name; SNDDMA_Activate( true ); @@ -191,7 +191,7 @@ Reset the sound device for exiting void SNDDMA_Shutdown( void ) { Con_Printf( "Shutting down audio.\n" ); - dma.initialized = false; + snd.initialized = false; if( sdl_dev ) { @@ -203,10 +203,10 @@ void SNDDMA_Shutdown( void ) if( SDL_WasInit( SDL_INIT_AUDIO )) SDL_QuitSubSystem( SDL_INIT_AUDIO ); - if( dma.buffer ) + if( snd.buffer ) { - Mem_Free( dma.buffer ); - dma.buffer = NULL; + Mem_Free( snd.buffer ); + snd.buffer = NULL; } } @@ -220,7 +220,7 @@ between a deactivate and an activate. */ void SNDDMA_Activate( qboolean active ) { - if( !dma.initialized ) + if( !snd.initialized ) return; SDL_PauseAudioDevice( sdl_dev, !active ); diff --git a/engine/platform/sdl2/s_sdl2.c b/engine/platform/sdl2/s_sdl2.c index 96b19f43..53183bc6 100644 --- a/engine/platform/sdl2/s_sdl2.c +++ b/engine/platform/sdl2/s_sdl2.c @@ -39,32 +39,32 @@ static char sdl_backend_name[32]; 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 wrapped; - pos = dma.samplepos << 1; + pos = snd.samplepos << 1; if( pos >= size ) - pos = dma.samplepos = 0; + pos = snd.samplepos = 0; wrapped = pos + len - size; if( wrapped < 0 ) { - memcpy( stream, dma.buffer + pos, len ); - dma.samplepos += len >> 1; + memcpy( stream, snd.buffer + pos, len ); + snd.samplepos += len >> 1; } else { int remaining = size - pos; - memcpy( stream, dma.buffer + pos, remaining ); - memcpy( stream + remaining, dma.buffer, wrapped ); - dma.samplepos = wrapped >> 1; + memcpy( stream, snd.buffer + pos, remaining ); + memcpy( stream + remaining, snd.buffer, wrapped ); + snd.samplepos = wrapped >> 1; } - if( dma.samplepos >= size ) - dma.samplepos = 0; + if( snd.samplepos >= size ) + snd.samplepos = 0; } /* @@ -148,22 +148,22 @@ qboolean SNDDMA_Init( void ) goto fail; } - dma.format.speed = obtained.freq; - dma.format.channels = obtained.channels; - dma.format.width = 2; + snd.format.speed = obtained.freq; + snd.format.channels = obtained.channels; + snd.format.width = 2; samplecount = s_samplecount.value; if( !samplecount ) samplecount = 0x8000; - dma.samples = samplecount * obtained.channels; - dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 ); - dma.samplepos = 0; + snd.samples = samplecount * obtained.channels; + snd.buffer = Mem_Calloc( sndpool, snd.samples * 2 ); + snd.samplepos = 0; sdl_format = obtained.format; 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( )); - dma.initialized = true; - dma.backendName = sdl_backend_name; + snd.initialized = true; + snd.backend_name = sdl_backend_name; SNDDMA_Activate( true ); @@ -179,7 +179,7 @@ fail: ============== SNDDMA_BeginPainting -Makes sure dma.buffer is valid +Makes sure snd.buffer is valid =============== */ void SNDDMA_BeginPainting( void ) @@ -210,7 +210,7 @@ Reset the sound device for exiting void SNDDMA_Shutdown( void ) { Con_Printf( "Shutting down audio.\n" ); - dma.initialized = false; + snd.initialized = false; if( sdl_dev ) { @@ -221,10 +221,10 @@ void SNDDMA_Shutdown( void ) SDL_QuitSubSystem( SDL_INIT_AUDIO ); - if( dma.buffer ) + if( snd.buffer ) { - Mem_Free( dma.buffer ); - dma.buffer = NULL; + Mem_Free( snd.buffer ); + snd.buffer = NULL; } } @@ -238,7 +238,7 @@ between a deactivate and an activate. */ void SNDDMA_Activate( qboolean active ) { - if( !dma.initialized ) + if( !snd.initialized ) return; SDL_PauseAudioDevice( sdl_dev, !active ); diff --git a/engine/platform/sdl3/s_sdl3.c b/engine/platform/sdl3/s_sdl3.c index af001939..458146aa 100644 --- a/engine/platform/sdl3/s_sdl3.c +++ b/engine/platform/sdl3/s_sdl3.c @@ -28,35 +28,35 @@ static char sdl_backend_name[32]; 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 wrapped; (void)userdata; (void)additional_amount; - pos = dma.samplepos << 1; + pos = snd.samplepos << 1; if( pos >= size ) - pos = dma.samplepos = 0; + pos = snd.samplepos = 0; wrapped = pos + len - size; if( wrapped < 0 ) { - SDL_PutAudioStreamData( stream, dma.buffer + pos, len ); - dma.samplepos += len >> 1; + SDL_PutAudioStreamData( stream, snd.buffer + pos, len ); + snd.samplepos += len >> 1; } else { int remaining = size - pos; - SDL_PutAudioStreamData( stream, dma.buffer + pos, remaining ); - SDL_PutAudioStreamData( stream, dma.buffer, wrapped ); - dma.samplepos = wrapped >> 1; + SDL_PutAudioStreamData( stream, snd.buffer + pos, remaining ); + SDL_PutAudioStreamData( stream, snd.buffer, wrapped ); + snd.samplepos = wrapped >> 1; } - if( dma.samplepos >= size ) - dma.samplepos = 0; + if( snd.samplepos >= size ) + snd.samplepos = 0; } /* @@ -122,18 +122,18 @@ qboolean SNDDMA_Init( void ) return false; } - dma.format.speed = SOUND_DMA_SPEED; - dma.format.channels = 2; - dma.format.width = 2; + snd.format.speed = SOUND_DMA_SPEED; + snd.format.channels = 2; + snd.format.width = 2; int samplecount = s_samplecount.value; if( !samplecount ) samplecount = 0x8000; - dma.samples = samplecount * dma.format.channels; - dma.buffer = Mem_Calloc( sndpool, dma.samples * dma.format.width ); - dma.samplepos = 0; - dma.initialized = true; + snd.samples = samplecount * snd.format.channels; + snd.buffer = Mem_Calloc( sndpool, snd.samples * snd.format.width ); + snd.samplepos = 0; + snd.initialized = true; 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 ); @@ -178,7 +178,7 @@ Reset the sound device for exiting void SNDDMA_Shutdown( void ) { Con_Printf( "Shutting down audio.\n" ); - dma.initialized = false; + snd.initialized = false; if( out_stream ) { @@ -189,10 +189,10 @@ void SNDDMA_Shutdown( void ) SDL_QuitSubSystem( SDL_INIT_AUDIO ); - if( dma.buffer ) + if( snd.buffer ) { - Mem_Free( dma.buffer ); - dma.buffer = NULL; + Mem_Free( snd.buffer ); + snd.buffer = NULL; } } @@ -206,7 +206,7 @@ between a deactivate and an activate. */ void SNDDMA_Activate( qboolean active ) { - if( !dma.initialized ) + if( !snd.initialized ) return; if( active ) diff --git a/engine/platform/stub/s_stub.c b/engine/platform/stub/s_stub.c index 6bd96966..bb89ecfa 100644 --- a/engine/platform/stub/s_stub.c +++ b/engine/platform/stub/s_stub.c @@ -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 ) { } @@ -86,11 +84,12 @@ Reset the sound device for exiting void SNDDMA_Shutdown( void ) { Con_Printf("Shutting down audio.\n"); - dma.initialized = false; + snd.initialized = false; - if (dma.buffer) { - Z_Free(dma.buffer); - dma.buffer = NULL; + if( snd.buffer ) + { + Mem_Free( snd.buffer ); + snd.buffer = NULL; } }