mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-15 21:50:59 +01:00
engine: client: voice: implemented automatic gain control
This commit is contained in:
parent
c5d7e3c783
commit
ae97eae42f
@ -8,6 +8,8 @@ voice_state_t voice;
|
||||
CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_ARCHIVE, "enable voice chat" );
|
||||
CVAR_DEFINE_AUTO( voice_loopback, "0", 0, "loopback voice back to the speaker" );
|
||||
CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_ARCHIVE, "incoming voice volume scale" );
|
||||
CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_ARCHIVE, "automatic voice gain control (average)" );
|
||||
CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
|
||||
CVAR_DEFINE_AUTO( voice_inputfromfile, "0", 0, "input voice from voice_input.wav" );
|
||||
|
||||
static const char* Voice_GetBandwidthTypeName( int bandwidthType )
|
||||
@ -46,6 +48,8 @@ void Voice_RegisterCvars( void )
|
||||
Cvar_RegisterVariable( &voice_enable );
|
||||
Cvar_RegisterVariable( &voice_loopback );
|
||||
Cvar_RegisterVariable( &voice_scale );
|
||||
Cvar_RegisterVariable( &voice_avggain );
|
||||
Cvar_RegisterVariable( &voice_maxgain );
|
||||
Cvar_RegisterVariable( &voice_inputfromfile );
|
||||
Cmd_AddClientCommand( "voice_codecinfo", Voice_CodecInfo_f );
|
||||
}
|
||||
@ -60,6 +64,47 @@ static uint Voice_GetFrameSize( float durationMsec )
|
||||
return voice.channels * voice.width * (( float )voice.samplerate / ( 1000.0f / durationMsec ));
|
||||
}
|
||||
|
||||
static void Voice_ApplyGainAdjust( opus_int16 *samples, int count )
|
||||
{
|
||||
float gain, modifiedMax;
|
||||
int average, adjustedSample;
|
||||
int blockOffset = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int i;
|
||||
int localMax = 0;
|
||||
int localSum = 0;
|
||||
int blockSize = Q_min( count - ( blockOffset + voice.autogain.block_size ), voice.autogain.block_size );
|
||||
|
||||
if( blockSize < 1 )
|
||||
break;
|
||||
|
||||
for( i = 0; i < blockSize; ++i )
|
||||
{
|
||||
int sample = samples[blockOffset + i];
|
||||
if( abs( sample ) > localMax ) {
|
||||
localMax = abs( sample );
|
||||
}
|
||||
localSum += sample;
|
||||
|
||||
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
|
||||
adjustedSample = Q_min( 32767, Q_max(( int )( sample * gain ), -32768 ));
|
||||
samples[blockOffset + i] = adjustedSample;
|
||||
}
|
||||
|
||||
if( blockOffset % voice.autogain.block_size == 0 )
|
||||
{
|
||||
average = localSum / blockSize;
|
||||
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
||||
voice.autogain.current_gain = voice.autogain.next_gain * voice_scale.value;
|
||||
voice.autogain.next_gain = Q_min( 32767.0f / modifiedMax, voice_maxgain.value ) * voice_scale.value;
|
||||
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( voice.autogain.block_size - 1 );
|
||||
}
|
||||
blockOffset += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
// parameters currently unused
|
||||
qboolean Voice_Init( const char *pszCodecName, int quality )
|
||||
{
|
||||
@ -75,6 +120,7 @@ qboolean Voice_Init( const char *pszCodecName, int quality )
|
||||
voice.width = 2;
|
||||
voice.samplerate = SOUND_48k;
|
||||
voice.frame_size = Voice_GetFrameSize( 20.0f );
|
||||
voice.autogain.block_size = 128;
|
||||
|
||||
if ( !VoiceCapture_Init() )
|
||||
{
|
||||
@ -155,6 +201,8 @@ uint Voice_GetCompressedData( byte *out, uint maxsize, uint *frames )
|
||||
{
|
||||
int bytes;
|
||||
|
||||
// adjust gain before encoding
|
||||
Voice_ApplyGainAdjust((opus_int16*)voice.input_buffer + ofs, voice.frame_size);
|
||||
bytes = opus_encode( voice.encoder, (const opus_int16*)(voice.input_buffer + ofs), voice.frame_size / voice.width, out + size, maxsize );
|
||||
memmove( voice.input_buffer, voice.input_buffer + voice.frame_size, sizeof( voice.input_buffer ) - voice.frame_size );
|
||||
voice.input_buffer_pos -= voice.frame_size;
|
||||
@ -316,5 +364,5 @@ void Voice_StartChannel( uint samples, byte *data, int entnum )
|
||||
{
|
||||
SND_ForceInitMouth( entnum );
|
||||
Voice_Status( entnum, true );
|
||||
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, voice.channels, data, 128.0f * voice_scale.value );
|
||||
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, voice.channels, data, 255 );
|
||||
}
|
||||
|
@ -39,6 +39,14 @@ typedef struct voice_state_s
|
||||
byte output_buffer[MAX_RAW_SAMPLES];
|
||||
byte decompress_buffer[MAX_RAW_SAMPLES];
|
||||
fs_offset_t input_buffer_pos;
|
||||
|
||||
// automatic gain control
|
||||
struct {
|
||||
int block_size;
|
||||
float current_gain;
|
||||
float next_gain;
|
||||
float gain_multiplier;
|
||||
} autogain;
|
||||
} voice_state_t;
|
||||
|
||||
extern voice_state_t voice;
|
||||
|
Loading…
Reference in New Issue
Block a user