Support for a true stereo reverberation effect
This commit is contained in:
parent
963f1f7849
commit
ac10994d5c
4 changed files with 76 additions and 49 deletions
|
@ -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
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
93
src/util.cpp
93
src/util.cpp
|
@ -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() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
13
src/util.h
13
src/util.h
|
@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue