From d92b3a730cea8ad3bf1ed5f7271a0cacbbae2669 Mon Sep 17 00:00:00 2001 From: TheEVolk Date: Wed, 8 Apr 2026 14:02:10 +0300 Subject: [PATCH] engine: client: adapt sound api to snd globals --- common/sound_api.h | 131 ++++++++++++++++++++++++++++++++++------ engine/client/cl_game.c | 2 +- engine/client/s_main.c | 32 ++-------- engine/client/sound.h | 115 ----------------------------------- 4 files changed, 120 insertions(+), 160 deletions(-) diff --git a/common/sound_api.h b/common/sound_api.h index 04161b49..6a9094c3 100644 --- a/common/sound_api.h +++ b/common/sound_api.h @@ -37,23 +37,118 @@ For more information, please refer to typedef int sound_t; -struct dma_api_s; -struct listener_s; - -// Forward decls (full def in engine/client/sound.h) -struct channel_s; -struct rawchan_s; -struct portable_samplepair_s; - -// Engine-owned state: client reads only. Filled by engine, passed to pfnS_Init. -typedef struct snd_interface_state_s +typedef struct portable_samplepair_s { - const struct listener_s *listener; - const struct channel_s *channels; // &channels[0], contiguous - int total_channels; - struct rawchan_s *const *raw_channels; // rawchan_t*[] - int max_raw_channels; -} snd_interface_state_t; + int left; + int right; +} portable_samplepair_t; + +typedef struct sfx_s +{ + char name[MAX_QPATH]; + wavdata_t *cache; + + int servercount; + uint hashValue; + struct sfx_s *hashNext; +} sfx_t; + +typedef struct voxword_s +{ + 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 channel_s +{ + char name[16]; // keep sentence name + sfx_t *sfx; // sfx number + + vec3_t origin; // only use if fixed_origin is set + float dist_mult; // distance multiplier (attenuation/clipK) + + 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 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 + float inauduble_free_time; + + double sample; + double forced_end; + wavdata_t *data; + voxword_t *words; // dynamically allocated, (num_words + 1) entries, null sfx terminates + + uintptr_t engine_reserved[8]; // only for engine developers + uintptr_t game_reserved[8]; // free space for game developers +} channel_t; + +typedef struct rawchan_s +{ + short entnum; + short master_vol; + short leftvol; // 0-255 left volume + short rightvol; // 0-255 right volume + float dist_mult; // distance multiplier (attenuation/clipK) + vec3_t origin; // only use if fixed_origin is set + volatile uint s_rawend; + float oldtime; // catch time jumps + + uintptr_t engine_reserved[8]; // only for engine developers + uintptr_t game_reserved[8]; // free space for game developers + + size_t max_samples; // buffer length + portable_samplepair_t rawsamples[]; // variable sized +} rawchan_t; + +typedef struct snd_format_s +{ + uint speed; + byte width; + byte channels; +} snd_format_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; // API from engine to client (client calls these) typedef struct sound_api_s @@ -67,11 +162,11 @@ typedef struct sound_interface_s { int version; - qboolean (*pfnS_Init)( snd_interface_state_t *state ); + qboolean (*pfnS_Init)( snd_globals_t *globals ); void (*pfnS_Shutdown)( void ); void (*pfnS_UpdateSound)( void ); /* Full paint: endtime (sample pairs), dma buffer, paintedtime in/out. Client does mix + transfer to dma.buffer. */ - void (*pfnS_PaintChannels)( int endtime, struct dma_api_s *dma, int *paintedtime ); + void (*pfnS_PaintChannels)( int endtime ); void (*pfnS_UpdateChannel)( int ch_idx, const struct channel_s *ch, sound_t handle ); // ch=NULL -> channel freed void (*pfnS_UpdateRawChannel)( int raw_idx, struct rawchan_s *ch ); // ch=NULL -> channel freed void (*pfnS_Spatialize)( struct channel_s *ch ); diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 1116b6cf..2b9d7c43 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -101,11 +101,11 @@ static const dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and high { "HUD_VoiceStatus", (void **)&clgame.dllFuncs.pfnVoiceStatus }, { "HUD_ChatInputPosition", (void **)&clgame.dllFuncs.pfnChatInputPosition }, { "HUD_GetRenderInterface", (void **)&clgame.dllFuncs.pfnGetRenderInterface }, // Xash3D ext -{ "HUD_GetSoundInterface", (void **)&clgame.dllFuncs.pfnGetSoundInterface }, // Xash3D ext { "HUD_ClipMoveToEntity", (void **)&clgame.dllFuncs.pfnClipMoveToEntity }, // Xash3D ext { "IN_ClientTouchEvent", (void **)&clgame.dllFuncs.pfnTouchEvent}, // Xash3D FWGS ext { "IN_ClientMoveEvent", (void **)&clgame.dllFuncs.pfnMoveEvent}, // Xash3D FWGS ext { "IN_ClientLookEvent", (void **)&clgame.dllFuncs.pfnLookEvent}, // Xash3D FWGS ext +{ "HUD_GetSoundInterface", (void **)&clgame.dllFuncs.pfnGetSoundInterface }, // Xash3D ext }; static void pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc ); diff --git a/engine/client/s_main.c b/engine/client/s_main.c index 33d2ef96..349b8392 100644 --- a/engine/client/s_main.c +++ b/engine/client/s_main.c @@ -44,8 +44,6 @@ snd_globals_t snd = .max_raw_channels = MAX_RAW_CHANNELS, }; -static snd_interface_state_t s_sndState; - 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" ); static CVAR_DEFINE( s_mixahead, "_snd_mixahead", "0.12", FCVAR_FILTERABLE, "how much sound to mix ahead of time" ); @@ -185,7 +183,7 @@ S_FreeChannel */ void S_FreeChannel( channel_t *ch ) { - S_NotifyChannelUpdate( ch - channels, NULL, -1 ); + S_NotifyChannelUpdate( ch - snd.channels, NULL, -1 ); // free the currently loaded word's audio cache before nuking the channel if( ch->words ) @@ -735,7 +733,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv } } - S_NotifyChannelUpdate( target_chan - channels, target_chan, handle ); + S_NotifyChannelUpdate( target_chan - snd.channels, target_chan, handle ); // Init client entity mouth movement vars SND_InitMouth( ent, chan ); @@ -851,7 +849,7 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float target_chan->sample = sample; target_chan->forced_end = end; - S_NotifyChannelUpdate( target_chan - channels, target_chan, handle ); + S_NotifyChannelUpdate( target_chan - snd.channels, target_chan, handle ); // Init client entity mouth movement vars SND_InitMouth( ent, chan ); @@ -946,7 +944,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa ch->entchannel = CHAN_STATIC; ch->basePitch = pitch; - S_NotifyChannelUpdate( ch - channels, ch, handle ); + S_NotifyChannelUpdate( ch - snd.channels, ch, handle ); SND_Spatialize( ch ); } @@ -1564,9 +1562,8 @@ static void S_UpdateChannels( void ) endtime -= ( endtime - snd.paintedtime ) & 0x3; } - s_sndState.total_channels = total_channels; if( clgame.soundFuncs.pfnS_PaintChannels ) - clgame.soundFuncs.pfnS_PaintChannels( endtime, &dma, &paintedtime ); + clgame.soundFuncs.pfnS_PaintChannels( endtime ); else S_PaintChannels( endtime ); @@ -1938,21 +1935,6 @@ static void S_VoiceRecordStop_f( void ) Voice_RecordStop(); } -/* -================ -S_FillSndState -================ -*/ -static void S_FillSndState( snd_interface_state_t *st ) -{ - memset( st, 0, sizeof( *st )); - st->listener = &s_listener; - st->channels = channels; - st->total_channels = total_channels; - st->raw_channels = raw_channels; - st->max_raw_channels = MAX_RAW_CHANNELS; -} - static const sound_api_t s_clientSoundAPI = { CL_GetEntitySpatialization, S_GetSfxByHandle, @@ -1967,8 +1949,6 @@ static qboolean S_InitSoundAPI( void ) { // make sure what sound functions is cleared memset( &clgame.soundFuncs, 0, sizeof( clgame.soundFuncs )); - - S_FillSndState( &s_sndState ); if( clgame.dllFuncs.pfnGetSoundInterface ) { @@ -2050,7 +2030,7 @@ qboolean S_Init( void ) S_InitSoundAPI(); if( clgame.soundFuncs.pfnS_Init ) - clgame.soundFuncs.pfnS_Init( &s_sndState ); + clgame.soundFuncs.pfnS_Init( &snd ); return true; } diff --git a/engine/client/sound.h b/engine/client/sound.h index a596f2f4..95eaebd7 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -39,129 +39,14 @@ extern poolhandle_t sndpool; #define CLIP16( x ) bound( SHRT_MIN + 8, x, SHRT_MAX - 8 ) -typedef struct portable_samplepair_s -{ - int left; - int right; -} portable_samplepair_t; - -typedef struct sfx_s -{ - char name[MAX_QPATH]; - wavdata_t *cache; - - int servercount; - uint hashValue; - 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) - 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 -{ - uint speed; - byte width; - byte channels; -} snd_format_t; - -typedef struct rawchan_s -{ - short entnum; - short master_vol; - short leftvol; // 0-255 left volume - short rightvol; // 0-255 right volume - float dist_mult; // distance multiplier (attenuation/clipK) - vec3_t origin; // only use if fixed_origin is set - volatile uint s_rawend; - float oldtime; // catch time jumps - - uintptr_t engine_reserved[8]; // only for engine developers - uintptr_t game_reserved[8]; // free space for game developers - - 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_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 - - vec3_t origin; // only use if fixed_origin is set - float dist_mult; // distance multiplier (attenuation/clipK) - - 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 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 - float inauduble_free_time; - - double sample; - double forced_end; - wavdata_t *data; - voxword_t *words; // dynamically allocated, (num_words + 1) entries, null sfx terminates - - uintptr_t engine_reserved[8]; // only for engine developers - uintptr_t game_reserved[8]; // free space for game developers -} channel_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)