clean up the reverberation and panning code in the client

This commit is contained in:
Volker Fischer 2020-06-12 18:26:34 +02:00
parent 0d77ccdcc4
commit 4c94633c1a
4 changed files with 117 additions and 176 deletions

View File

@ -889,8 +889,9 @@ void CClient::Init()
iNumAudioChannels );
// init reverberation
AudioReverbL.Init ( SYSTEM_SAMPLE_RATE_HZ );
AudioReverbR.Init ( SYSTEM_SAMPLE_RATE_HZ );
AudioReverb.Init ( eAudioChannelConf,
iStereoBlockSizeSam,
SYSTEM_SAMPLE_RATE_HZ );
// init the sound card conversion buffers
if ( bSndCrdConversionBufferRequired )
@ -973,118 +974,41 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
// add reverberation effect if activated
if ( iReverbLevel != 0 )
{
// calculate attenuation amplification factor
const double dRevLev = static_cast<double> ( iReverbLevel ) / AUD_REVERB_MAX / 4;
AudioReverb.Process ( vecsStereoSndCrd,
bReverbOnLeftChan,
static_cast<double> ( iReverbLevel ) / AUD_REVERB_MAX / 4 );
}
// apply pan (audio fader) and mix mono signals
if ( !( ( iAudioInFader == AUD_FADER_IN_MIDDLE ) && ( eAudioChannelConf == CC_STEREO ) ) )
{
// calculate pan gain in the range 0 to 1, where 0.5 is the middle position
const double dPan = static_cast<double> ( iAudioInFader ) / AUD_FADER_IN_MAX;
if ( eAudioChannelConf == CC_STEREO )
{
// for stereo always apply reverberation effect on both channels
for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
{
// both channels (stereo)
AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], vecsStereoSndCrd[i + 1], dRevLev );
}
}
else
{
// mono and mono-in/stereo out mode
if ( bReverbOnLeftChan )
{
for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
{
// left channel
int16_t sRightDummy = 0; // has to be 0 for mono reverb
AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], sRightDummy, dRevLev );
}
}
else
{
for ( i = 1; i < iStereoBlockSizeSam; i += 2 )
{
// right channel
int16_t sRightDummy = 0; // has to be 0 for mono reverb
AudioReverbR.ProcessSample ( vecsStereoSndCrd[i], sRightDummy, dRevLev );
}
}
}
}
// for stereo only apply pan attenuation on one channel (same as pan in the server)
const double dGainL = std::min ( 0.5, 1 - dPan ) * 2;
const double dGainR = std::min ( 0.5, dPan ) * 2;
// mix both signals depending on the fading setting, convert
// from double to short
if ( iAudioInFader == AUD_FADER_IN_MIDDLE )
{
// no action require if fader is in the middle and stereo is used
if ( eAudioChannelConf != CC_STEREO )
{
// mix channels together (store result in first half of the vector)
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{
// for the sum make sure we have more bits available (cast to
// int32), after the normalization by 2, the result will fit
// into the old size so that cast to int16 is safe
vecsStereoSndCrd[i] = static_cast<int16_t> (
( static_cast<int32_t> ( vecsStereoSndCrd[j] ) + vecsStereoSndCrd[j + 1] ) / 2 );
}
}
}
else
{
if ( eAudioChannelConf == CC_STEREO )
{
// stereo
const double dAttFactStereo = static_cast<double> (
AUD_FADER_IN_MIDDLE - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / AUD_FADER_IN_MIDDLE;
if ( iAudioInFader > AUD_FADER_IN_MIDDLE )
{
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{
// attenuation on right channel
vecsStereoSndCrd[j + 1] = Double2Short ( dAttFactStereo * vecsStereoSndCrd[j + 1] );
}
}
else
{
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{
// attenuation on left channel
vecsStereoSndCrd[j] = Double2Short ( dAttFactStereo * vecsStereoSndCrd[j] );
}
// note that the gain is always <= 1, therefore a simple cast is
// ok since we never can get an overload
vecsStereoSndCrd[j + 1] = static_cast<int16_t> ( dGainR * vecsStereoSndCrd[j + 1] );
vecsStereoSndCrd[j] = static_cast<int16_t> ( dGainL * vecsStereoSndCrd[j] );
}
}
else
{
// mono and mono-in/stereo out mode
// make sure that in the middle position the two channels are
// amplified by 1/2, if the pan is set to one channel, this
// channel should have an amplification of 1
const double dAttFactMono = static_cast<double> (
AUD_FADER_IN_MIDDLE - abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / AUD_FADER_IN_MIDDLE / 2;
// for mono implement a cross-fade between channels and mix them
const double dGainL = 1 - dPan;
const double dGainR = dPan;
const double dAmplFactMono = 0.5 + static_cast<double> (
abs ( AUD_FADER_IN_MIDDLE - iAudioInFader ) ) / AUD_FADER_IN_MIDDLE / 2;
if ( iAudioInFader > AUD_FADER_IN_MIDDLE )
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{
// attenuation on right channel (store result in first half
// of the vector)
vecsStereoSndCrd[i] = Double2Short (
dAmplFactMono * vecsStereoSndCrd[j] +
dAttFactMono * vecsStereoSndCrd[j + 1] );
}
}
else
{
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
{
// attenuation on left channel (store result in first half
// of the vector)
vecsStereoSndCrd[i] = Double2Short (
dAmplFactMono * vecsStereoSndCrd[j + 1] +
dAttFactMono * vecsStereoSndCrd[j] );
}
vecsStereoSndCrd[i] = Double2Short (
dGainL * vecsStereoSndCrd[j] + dGainR * vecsStereoSndCrd[j + 1] );
}
}
}
@ -1175,20 +1099,6 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
}
}
/*
// TEST
// fid=fopen('c:\\temp\test2.dat','r');x=fread(fid,'int16');fclose(fid);
static FILE* pFileDelay = fopen("c:\\temp\\test2.dat", "wb");
short sData[2];
for (i = 0; i < iMonoBlockSizeSam; i++)
{
sData[0] = (short) vecsStereoSndCrd[i];
fwrite(&sData, size_t(2), size_t(1), pFileDelay);
}
fflush(pFileDelay);
*/
// for muted stream we have to add our local data here
if ( bMuteOutStream )
{

View File

@ -151,8 +151,7 @@ public:
void SetReverbOnLeftChan ( const bool bIL )
{
bReverbOnLeftChan = bIL;
AudioReverbL.Clear();
AudioReverbR.Clear();
AudioReverb.Clear();
}
void SetDoAutoSockBufSize ( const bool bValue );
@ -354,8 +353,7 @@ protected:
int iAudioInFader;
bool bReverbOnLeftChan;
int iReverbLevel;
CAudioReverb AudioReverbL;
CAudioReverb AudioReverbR;
CAudioReverb AudioReverb;
int iSndCrdPrefFrameSizeFactor;
int iSndCrdFrameSizeFactor;

View File

@ -165,20 +165,24 @@ uint32_t CCRC::GetCRC()
three series allpass units, followed by four parallel comb filters, and two
decorrelation delay lines in parallel at the output.
*/
void CAudioReverb::Init ( const int iSampleRate,
const double rT60 )
void CAudioReverb::Init ( const EAudChanConf eNAudioChannelConf,
const int iNStereoBlockSizeSam,
const int iSampleRate,
const double rT60 )
{
int delay, i;
// store paramters
eAudioChannelConf = eNAudioChannelConf;
iStereoBlockSizeSam = iNStereoBlockSizeSam;
// delay lengths for 44100 Hz sample rate
int lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
const double scaler = static_cast<double> ( iSampleRate ) / 44100.0;
int lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
const double scaler = static_cast<double> ( iSampleRate ) / 44100.0;
if ( scaler != 1.0 )
{
for ( i = 0; i < 9; i++ )
for ( int i = 0; i < 9; i++ )
{
delay = static_cast<int> ( floor ( scaler * lengths[i] ) );
int delay = static_cast<int> ( floor ( scaler * lengths[i] ) );
if ( ( delay & 1 ) == 0 )
{
@ -194,12 +198,12 @@ void CAudioReverb::Init ( const int iSampleRate,
}
}
for ( i = 0; i < 3; i++ )
for ( int i = 0; i < 3; i++ )
{
allpassDelays[i].Init ( lengths[i + 4] );
}
for ( i = 0; i < 4; i++ )
for ( int i = 0; i < 4; i++ )
{
combDelays[i].Init ( lengths[i] );
combFilters[i].setPole ( 0.2 );
@ -285,58 +289,81 @@ double CAudioReverb::COnePole::Calc ( const double dIn )
return dLastSample;
}
void CAudioReverb::ProcessSample ( int16_t& iInputOutputLeft,
int16_t& iInputOutputRight,
const double dAttenuation )
void CAudioReverb::Process ( CVector<int16_t>& vecsStereoInOut,
const bool bReverbOnLeftChan,
const double dAttenuation )
{
// compute one output sample
double temp, temp0, temp1, temp2;
double dMixedInput, temp, temp0, temp1, temp2;
// we sum up the stereo input channels (in case mono input is used, a zero
// shall be input for the right channel)
const double dMixedInput = 0.5 * ( iInputOutputLeft + iInputOutputRight );
for ( int i = 0; i < iStereoBlockSizeSam; i += 2 )
{
// we sum up the stereo input channels (in case mono input is used, a zero
// shall be input for the right channel)
if ( eAudioChannelConf == CC_STEREO )
{
dMixedInput = 0.5 * ( vecsStereoInOut[i] + vecsStereoInOut[i + 1] );
}
else
{
if ( bReverbOnLeftChan )
{
dMixedInput = vecsStereoInOut[i];
}
else
{
dMixedInput = vecsStereoInOut[i + 1];
}
}
temp = allpassDelays[0].Get();
temp0 = allpassCoefficient * temp;
temp0 += dMixedInput;
allpassDelays[0].Add ( temp0 );
temp0 = - ( allpassCoefficient * temp0 ) + temp;
temp = allpassDelays[0].Get();
temp0 = allpassCoefficient * temp;
temp0 += dMixedInput;
allpassDelays[0].Add ( temp0 );
temp0 = - ( allpassCoefficient * temp0 ) + temp;
temp = allpassDelays[1].Get();
temp1 = allpassCoefficient * temp;
temp1 += temp0;
allpassDelays[1].Add ( temp1 );
temp1 = - ( allpassCoefficient * temp1 ) + temp;
temp = allpassDelays[1].Get();
temp1 = allpassCoefficient * temp;
temp1 += temp0;
allpassDelays[1].Add ( temp1 );
temp1 = - ( allpassCoefficient * temp1 ) + temp;
temp = allpassDelays[2].Get();
temp2 = allpassCoefficient * temp;
temp2 += temp1;
allpassDelays[2].Add ( temp2 );
temp2 = - ( allpassCoefficient * temp2 ) + temp;
temp = allpassDelays[2].Get();
temp2 = allpassCoefficient * temp;
temp2 += temp1;
allpassDelays[2].Add ( temp2 );
temp2 = - ( allpassCoefficient * temp2 ) + temp;
const double temp3 = temp2 + combFilters[0].Calc ( combCoefficient[0] * combDelays[0].Get() );
const double temp4 = temp2 + combFilters[1].Calc ( combCoefficient[1] * combDelays[1].Get() );
const double temp5 = temp2 + combFilters[2].Calc ( combCoefficient[2] * combDelays[2].Get() );
const double temp6 = temp2 + combFilters[3].Calc ( combCoefficient[3] * combDelays[3].Get() );
const double temp3 = temp2 + combFilters[0].Calc ( combCoefficient[0] * combDelays[0].Get() );
const double temp4 = temp2 + combFilters[1].Calc ( combCoefficient[1] * combDelays[1].Get() );
const double temp5 = temp2 + combFilters[2].Calc ( combCoefficient[2] * combDelays[2].Get() );
const double temp6 = temp2 + combFilters[3].Calc ( combCoefficient[3] * combDelays[3].Get() );
combDelays[0].Add ( temp3 );
combDelays[1].Add ( temp4 );
combDelays[2].Add ( temp5 );
combDelays[3].Add ( temp6 );
combDelays[0].Add ( temp3 );
combDelays[1].Add ( temp4 );
combDelays[2].Add ( temp5 );
combDelays[3].Add ( temp6 );
const double filtout = temp3 + temp4 + temp5 + temp6;
const double filtout = temp3 + temp4 + temp5 + temp6;
outLeftDelay.Add ( filtout );
outRightDelay.Add ( filtout );
outLeftDelay.Add ( filtout );
outRightDelay.Add ( filtout );
// inplace apply the attenuated reverb signal
iInputOutputLeft = Double2Short (
( 1.0 - dAttenuation ) * iInputOutputLeft +
0.5 * dAttenuation * outLeftDelay.Get() );
// inplace apply the attenuated reverb signal (for stereo always apply
// reverberation effect on both channels)
if ( ( eAudioChannelConf == CC_STEREO ) || bReverbOnLeftChan )
{
vecsStereoInOut[i] = Double2Short (
( 1.0 - dAttenuation ) * vecsStereoInOut[i] +
0.5 * dAttenuation * outLeftDelay.Get() );
}
iInputOutputRight = Double2Short (
( 1.0 - dAttenuation ) * iInputOutputRight +
0.5 * dAttenuation * outRightDelay.Get() );
if ( ( eAudioChannelConf == CC_STEREO ) || !bReverbOnLeftChan )
{
vecsStereoInOut[i + 1] = Double2Short (
( 1.0 - dAttenuation ) * vecsStereoInOut[i + 1] +
0.5 * dAttenuation * outRightDelay.Get() );
}
}
}

View File

@ -694,8 +694,8 @@ public:
}
protected:
double UpdateCurLevel ( double dCurLevel,
const short& sMax );
double UpdateCurLevel ( double dCurLevel,
const short& sMax );
double dCurLevelL;
double dCurLevelR;
@ -1098,11 +1098,15 @@ class CAudioReverb
public:
CAudioReverb() {}
void Init ( const int iSampleRate, const double rT60 = 1.1 );
void Init ( const EAudChanConf eNAudioChannelConf,
const int iNStereoBlockSizeSam,
const int iSampleRate,
const double rT60 = 1.1 );
void Clear();
void ProcessSample ( int16_t& iInputOutputLeft,
int16_t& iInputOutputRight,
const double dAttenuation );
void Process ( CVector<int16_t>& vecsStereoInOut,
const bool bReverbOnLeftChan,
const double dAttenuation );
protected:
void setT60 ( const double rT60, const int iSampleRate );
@ -1122,6 +1126,8 @@ protected:
double dLastSample;
};
EAudChanConf eAudioChannelConf;
int iStereoBlockSizeSam;
CFIFO<double> allpassDelays[3];
CFIFO<double> combDelays[4];
COnePole combFilters[4];