Support for a true stereo reverberation effect

This commit is contained in:
Volker Fischer 2014-01-01 21:31:22 +00:00
parent 963f1f7849
commit ac10994d5c
4 changed files with 76 additions and 49 deletions

View file

@ -1,3 +1,9 @@
3.3.4
- true stereo reverberation effect (previously it was a mono reverberation
effect on both stereo channels)
3.3.3 3.3.3
- support for storing/recovering the window positions - support for storing/recovering the window positions

View file

@ -911,11 +911,8 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
// for stereo always apply reverberation effect on both channels // for stereo always apply reverberation effect on both channels
for ( i = 0; i < iStereoBlockSizeSam; i += 2 ) for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
{ {
// left channel // both channels (stereo)
AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], dRevLev ); AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], vecsStereoSndCrd[i + 1], dRevLev );
// right channel
AudioReverbR.ProcessSample ( vecsStereoSndCrd[i + 1], dRevLev );
} }
} }
else else
@ -925,7 +922,8 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
for ( i = 0; i < iStereoBlockSizeSam; i += 2 ) for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
{ {
// left channel // left channel
AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], dRevLev ); int16_t sRightDummy = 0; // has to be 0 for mono reverb
AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], sRightDummy, dRevLev );
} }
} }
else else
@ -933,7 +931,8 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
for ( i = 1; i < iStereoBlockSizeSam; i += 2 ) for ( i = 1; i < iStereoBlockSizeSam; i += 2 )
{ {
// right channel // right channel
AudioReverbR.ProcessSample ( vecsStereoSndCrd[i], dRevLev ); int16_t sRightDummy = 0; // has to be 0 for mono reverb
AudioReverbR.ProcessSample ( vecsStereoSndCrd[i], sRightDummy, dRevLev );
} }
} }
} }

View file

@ -167,7 +167,7 @@ void CAudioReverb::Init ( const int iSampleRate,
int delay, i; int delay, i;
// delay lengths for 44100 Hz sample rate // delay lengths for 44100 Hz sample rate
int lengths[9] = { 1777, 1847, 1993, 2137, 389, 127, 43, 211, 179 }; int lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
const double scaler = (double) iSampleRate / 44100.0; const double scaler = (double) iSampleRate / 44100.0;
if ( scaler != 1.0 ) if ( scaler != 1.0 )
@ -192,16 +192,18 @@ void CAudioReverb::Init ( const int iSampleRate,
for ( i = 0; i < 3; i++ ) for ( i = 0; i < 3; i++ )
{ {
allpassDelays_[i].Init ( lengths[i + 4] ); allpassDelays[i].Init ( lengths[i + 4] );
} }
for ( i = 0; i < 4; i++ ) for ( i = 0; i < 4; i++ )
{ {
combDelays_[i].Init ( lengths[i] ); combDelays[i].Init ( lengths[i] );
} }
setT60 ( rT60, iSampleRate ); setT60 ( rT60, iSampleRate );
allpassCoefficient_ = (double) 0.7; outLeftDelay.Init ( lengths[7] );
outRightDelay.Init ( lengths[8] );
allpassCoefficient = (double) 0.7;
Clear(); Clear();
} }
@ -237,13 +239,15 @@ bool CAudioReverb::isPrime ( const int number )
void CAudioReverb::Clear() void CAudioReverb::Clear()
{ {
// reset and clear all internal state // reset and clear all internal state
allpassDelays_[0].Reset ( 0 ); allpassDelays[0].Reset ( 0 );
allpassDelays_[1].Reset ( 0 ); allpassDelays[1].Reset ( 0 );
allpassDelays_[2].Reset ( 0 ); allpassDelays[2].Reset ( 0 );
combDelays_[0].Reset ( 0 ); combDelays[0].Reset ( 0 );
combDelays_[1].Reset ( 0 ); combDelays[1].Reset ( 0 );
combDelays_[2].Reset ( 0 ); combDelays[2].Reset ( 0 );
combDelays_[3].Reset ( 0 ); combDelays[3].Reset ( 0 );
outRightDelay.Reset ( 0 );
outLeftDelay.Reset ( 0 );
} }
void CAudioReverb::setT60 ( const double rT60, void CAudioReverb::setT60 ( const double rT60,
@ -252,48 +256,63 @@ void CAudioReverb::setT60 ( const double rT60,
// set the reverberation T60 decay time // set the reverberation T60 decay time
for ( int i = 0; i < 4; i++ ) for ( int i = 0; i < 4; i++ )
{ {
combCoefficient_[i] = pow ( (double) 10.0, (double) ( -3.0 * combCoefficient[i] = pow ( (double) 10.0, (double) ( -3.0 *
combDelays_[i].Size() / ( rT60 * iSampleRate ) ) ); combDelays[i].Size() / ( rT60 * iSampleRate ) ) );
} }
} }
void CAudioReverb::ProcessSample ( int16_t& input, void CAudioReverb::ProcessSample ( int16_t& iInputOutputLeft,
int16_t& iInputOutputRight,
const double dAttenuation ) const double dAttenuation )
{ {
// compute one output sample // compute one output sample
double temp, temp0, temp1, temp2; double temp, temp0, temp1, temp2;
temp = allpassDelays_[0].Get(); // we sum up the stereo input channels (in case mono input is used, a zero
temp0 = allpassCoefficient_ * temp; // shall be input for the right channel)
temp0 += input; const double dMixedInput = 0.5 * ( iInputOutputLeft + iInputOutputRight );
allpassDelays_[0].Add ( (int) temp0 );
temp0 = - ( allpassCoefficient_ * temp0 ) + temp;
temp = allpassDelays_[1].Get(); temp = allpassDelays[0].Get();
temp1 = allpassCoefficient_ * temp; temp0 = allpassCoefficient * temp;
temp0 += dMixedInput;
allpassDelays[0].Add ( temp0 );
temp0 = - ( allpassCoefficient * temp0 ) + temp;
temp = allpassDelays[1].Get();
temp1 = allpassCoefficient * temp;
temp1 += temp0; temp1 += temp0;
allpassDelays_[1].Add ( (int) temp1 ); allpassDelays[1].Add ( temp1 );
temp1 = - ( allpassCoefficient_ * temp1 ) + temp; temp1 = - ( allpassCoefficient * temp1 ) + temp;
temp = allpassDelays_[2].Get(); temp = allpassDelays[2].Get();
temp2 = allpassCoefficient_ * temp; temp2 = allpassCoefficient * temp;
temp2 += temp1; temp2 += temp1;
allpassDelays_[2].Add ( (int) temp2 ); allpassDelays[2].Add ( temp2 );
temp2 = - ( allpassCoefficient_ * temp2 ) + temp; temp2 = - ( allpassCoefficient * temp2 ) + temp;
const double temp3 = temp2 + ( combCoefficient_[0] * combDelays_[0].Get() ); const double temp3 = temp2 + ( combCoefficient[0] * combDelays[0].Get() );
const double temp4 = temp2 + ( combCoefficient_[1] * combDelays_[1].Get() ); const double temp4 = temp2 + ( combCoefficient[1] * combDelays[1].Get() );
const double temp5 = temp2 + ( combCoefficient_[2] * combDelays_[2].Get() ); const double temp5 = temp2 + ( combCoefficient[2] * combDelays[2].Get() );
const double temp6 = temp2 + ( combCoefficient_[3] * combDelays_[3].Get() ); const double temp6 = temp2 + ( combCoefficient[3] * combDelays[3].Get() );
combDelays_[0].Add ( (int) temp3 ); combDelays[0].Add ( temp3 );
combDelays_[1].Add ( (int) temp4 ); combDelays[1].Add ( temp4 );
combDelays_[2].Add ( (int) temp5 ); combDelays[2].Add ( temp5 );
combDelays_[3].Add ( (int) temp6 ); combDelays[3].Add ( temp6 );
const double filtout = temp3 + temp4 + temp5 + temp6;
outLeftDelay.Add ( filtout );
outRightDelay.Add ( filtout );
// inplace apply the attenuated reverb signal // inplace apply the attenuated reverb signal
input = Double2Short ( input + iInputOutputLeft = Double2Short (
( temp3 + temp4 + temp5 + temp6 ) * (double) 0.5 * dAttenuation ); ( 1.0 - dAttenuation ) * iInputOutputLeft +
0.5 * dAttenuation * outLeftDelay.Get() );
iInputOutputRight = Double2Short (
( 1.0 - dAttenuation ) * iInputOutputRight +
0.5 * dAttenuation * outRightDelay.Get() );
} }

View file

@ -869,17 +869,20 @@ public:
void Init ( const int iSampleRate, const double rT60 = (double) 1.1 ); void Init ( const int iSampleRate, const double rT60 = (double) 1.1 );
void Clear(); void Clear();
void ProcessSample ( int16_t& input, void ProcessSample ( int16_t& iInputOutputLeft,
int16_t& iInputOutputRight,
const double dAttenuation ); const double dAttenuation );
protected: protected:
void setT60 ( const double rT60, const int iSampleRate ); void setT60 ( const double rT60, const int iSampleRate );
bool isPrime ( const int number ); bool isPrime ( const int number );
CFIFO<int> allpassDelays_[3]; CFIFO<double> allpassDelays[3];
CFIFO<int> combDelays_[4]; CFIFO<double> combDelays[4];
double allpassCoefficient_; CFIFO<double> outLeftDelay;
double combCoefficient_[4]; CFIFO<double> outRightDelay;
double allpassCoefficient;
double combCoefficient[4];
}; };