engine: client: adapt sound api to snd globals

This commit is contained in:
TheEVolk
2026-04-08 14:02:10 +03:00
parent 4345e9e6a6
commit d92b3a730c
4 changed files with 120 additions and 160 deletions

View File

@@ -37,23 +37,118 @@ For more information, please refer to <http://unlicense.org/>
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 );

View File

@@ -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 );

View File

@@ -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;
}

View File

@@ -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)