From ac10994d5c481043e31bdc270bc0b543f01975de Mon Sep 17 00:00:00 2001 From: Volker Fischer Date: Wed, 1 Jan 2014 21:31:22 +0000 Subject: [PATCH] Support for a true stereo reverberation effect --- ChangeLog | 6 ++++ src/client.cpp | 13 ++++--- src/util.cpp | 93 ++++++++++++++++++++++++++++++-------------------- src/util.h | 13 ++++--- 4 files changed, 76 insertions(+), 49 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2c6c23da..4c94155f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 - support for storing/recovering the window positions diff --git a/src/client.cpp b/src/client.cpp index 5ea5c318..75378f8c 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -911,11 +911,8 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) // for stereo always apply reverberation effect on both channels for ( i = 0; i < iStereoBlockSizeSam; i += 2 ) { - // left channel - AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], dRevLev ); - - // right channel - AudioReverbR.ProcessSample ( vecsStereoSndCrd[i + 1], dRevLev ); + // both channels (stereo) + AudioReverbL.ProcessSample ( vecsStereoSndCrd[i], vecsStereoSndCrd[i + 1], dRevLev ); } } else @@ -925,7 +922,8 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) for ( i = 0; i < iStereoBlockSizeSam; i += 2 ) { // 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 @@ -933,7 +931,8 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd ) for ( i = 1; i < iStereoBlockSizeSam; i += 2 ) { // right channel - AudioReverbR.ProcessSample ( vecsStereoSndCrd[i], dRevLev ); + int16_t sRightDummy = 0; // has to be 0 for mono reverb + AudioReverbR.ProcessSample ( vecsStereoSndCrd[i], sRightDummy, dRevLev ); } } } diff --git a/src/util.cpp b/src/util.cpp index f96e21f2..8963a8c3 100755 --- a/src/util.cpp +++ b/src/util.cpp @@ -167,7 +167,7 @@ void CAudioReverb::Init ( const int iSampleRate, int delay, i; // 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; if ( scaler != 1.0 ) @@ -192,16 +192,18 @@ void CAudioReverb::Init ( const int iSampleRate, for ( i = 0; i < 3; i++ ) { - allpassDelays_[i].Init ( lengths[i + 4] ); + allpassDelays[i].Init ( lengths[i + 4] ); } for ( i = 0; i < 4; i++ ) { - combDelays_[i].Init ( lengths[i] ); + combDelays[i].Init ( lengths[i] ); } setT60 ( rT60, iSampleRate ); - allpassCoefficient_ = (double) 0.7; + outLeftDelay.Init ( lengths[7] ); + outRightDelay.Init ( lengths[8] ); + allpassCoefficient = (double) 0.7; Clear(); } @@ -237,13 +239,15 @@ bool CAudioReverb::isPrime ( const int number ) void CAudioReverb::Clear() { // reset and clear all internal state - allpassDelays_[0].Reset ( 0 ); - allpassDelays_[1].Reset ( 0 ); - allpassDelays_[2].Reset ( 0 ); - combDelays_[0].Reset ( 0 ); - combDelays_[1].Reset ( 0 ); - combDelays_[2].Reset ( 0 ); - combDelays_[3].Reset ( 0 ); + allpassDelays[0].Reset ( 0 ); + allpassDelays[1].Reset ( 0 ); + allpassDelays[2].Reset ( 0 ); + combDelays[0].Reset ( 0 ); + combDelays[1].Reset ( 0 ); + combDelays[2].Reset ( 0 ); + combDelays[3].Reset ( 0 ); + outRightDelay.Reset ( 0 ); + outLeftDelay.Reset ( 0 ); } void CAudioReverb::setT60 ( const double rT60, @@ -252,48 +256,63 @@ void CAudioReverb::setT60 ( const double rT60, // set the reverberation T60 decay time for ( int i = 0; i < 4; i++ ) { - combCoefficient_[i] = pow ( (double) 10.0, (double) ( -3.0 * - combDelays_[i].Size() / ( rT60 * iSampleRate ) ) ); + combCoefficient[i] = pow ( (double) 10.0, (double) ( -3.0 * + combDelays[i].Size() / ( rT60 * iSampleRate ) ) ); } } -void CAudioReverb::ProcessSample ( int16_t& input, +void CAudioReverb::ProcessSample ( int16_t& iInputOutputLeft, + int16_t& iInputOutputRight, const double dAttenuation ) { // compute one output sample double temp, temp0, temp1, temp2; - temp = allpassDelays_[0].Get(); - temp0 = allpassCoefficient_ * temp; - temp0 += input; - allpassDelays_[0].Add ( (int) temp0 ); - temp0 = - ( allpassCoefficient_ * temp0 ) + temp; + // 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 ); - temp = allpassDelays_[1].Get(); - temp1 = allpassCoefficient_ * 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 ( (int) temp1 ); - temp1 = - ( allpassCoefficient_ * temp1 ) + temp; + allpassDelays[1].Add ( temp1 ); + temp1 = - ( allpassCoefficient * temp1 ) + temp; - temp = allpassDelays_[2].Get(); - temp2 = allpassCoefficient_ * temp; + temp = allpassDelays[2].Get(); + temp2 = allpassCoefficient * temp; temp2 += temp1; - allpassDelays_[2].Add ( (int) temp2 ); - temp2 = - ( allpassCoefficient_ * temp2 ) + temp; + allpassDelays[2].Add ( temp2 ); + temp2 = - ( allpassCoefficient * temp2 ) + temp; - const double temp3 = temp2 + ( combCoefficient_[0] * combDelays_[0].Get() ); - const double temp4 = temp2 + ( combCoefficient_[1] * combDelays_[1].Get() ); - const double temp5 = temp2 + ( combCoefficient_[2] * combDelays_[2].Get() ); - const double temp6 = temp2 + ( combCoefficient_[3] * combDelays_[3].Get() ); + const double temp3 = temp2 + ( combCoefficient[0] * combDelays[0].Get() ); + const double temp4 = temp2 + ( combCoefficient[1] * combDelays[1].Get() ); + const double temp5 = temp2 + ( combCoefficient[2] * combDelays[2].Get() ); + const double temp6 = temp2 + ( combCoefficient[3] * combDelays[3].Get() ); - combDelays_[0].Add ( (int) temp3 ); - combDelays_[1].Add ( (int) temp4 ); - combDelays_[2].Add ( (int) temp5 ); - combDelays_[3].Add ( (int) temp6 ); + combDelays[0].Add ( temp3 ); + combDelays[1].Add ( temp4 ); + combDelays[2].Add ( temp5 ); + combDelays[3].Add ( temp6 ); + + const double filtout = temp3 + temp4 + temp5 + temp6; + + outLeftDelay.Add ( filtout ); + outRightDelay.Add ( filtout ); // inplace apply the attenuated reverb signal - input = Double2Short ( input + - ( temp3 + temp4 + temp5 + temp6 ) * (double) 0.5 * dAttenuation ); + iInputOutputLeft = Double2Short ( + ( 1.0 - dAttenuation ) * iInputOutputLeft + + 0.5 * dAttenuation * outLeftDelay.Get() ); + + iInputOutputRight = Double2Short ( + ( 1.0 - dAttenuation ) * iInputOutputRight + + 0.5 * dAttenuation * outRightDelay.Get() ); } diff --git a/src/util.h b/src/util.h index 6c2cc970..d9a29c79 100755 --- a/src/util.h +++ b/src/util.h @@ -869,17 +869,20 @@ public: void Init ( const int iSampleRate, const double rT60 = (double) 1.1 ); void Clear(); - void ProcessSample ( int16_t& input, + void ProcessSample ( int16_t& iInputOutputLeft, + int16_t& iInputOutputRight, const double dAttenuation ); protected: void setT60 ( const double rT60, const int iSampleRate ); bool isPrime ( const int number ); - CFIFO allpassDelays_[3]; - CFIFO combDelays_[4]; - double allpassCoefficient_; - double combCoefficient_[4]; + CFIFO allpassDelays[3]; + CFIFO combDelays[4]; + CFIFO outLeftDelay; + CFIFO outRightDelay; + double allpassCoefficient; + double combCoefficient[4]; };