clean up the reverberation and panning code in the client
This commit is contained in:
parent
0d77ccdcc4
commit
4c94633c1a
4 changed files with 117 additions and 176 deletions
142
src/client.cpp
142
src/client.cpp
|
@ -889,8 +889,9 @@ void CClient::Init()
|
||||||
iNumAudioChannels );
|
iNumAudioChannels );
|
||||||
|
|
||||||
// init reverberation
|
// init reverberation
|
||||||
AudioReverbL.Init ( SYSTEM_SAMPLE_RATE_HZ );
|
AudioReverb.Init ( eAudioChannelConf,
|
||||||
AudioReverbR.Init ( SYSTEM_SAMPLE_RATE_HZ );
|
iStereoBlockSizeSam,
|
||||||
|
SYSTEM_SAMPLE_RATE_HZ );
|
||||||
|
|
||||||
// init the sound card conversion buffers
|
// init the sound card conversion buffers
|
||||||
if ( bSndCrdConversionBufferRequired )
|
if ( bSndCrdConversionBufferRequired )
|
||||||
|
@ -973,118 +974,41 @@ void CClient::ProcessAudioDataIntern ( CVector<int16_t>& vecsStereoSndCrd )
|
||||||
// add reverberation effect if activated
|
// add reverberation effect if activated
|
||||||
if ( iReverbLevel != 0 )
|
if ( iReverbLevel != 0 )
|
||||||
{
|
{
|
||||||
// calculate attenuation amplification factor
|
AudioReverb.Process ( vecsStereoSndCrd,
|
||||||
const double dRevLev = static_cast<double> ( iReverbLevel ) / AUD_REVERB_MAX / 4;
|
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 )
|
if ( eAudioChannelConf == CC_STEREO )
|
||||||
{
|
{
|
||||||
// for stereo always apply reverberation effect on both channels
|
// for stereo only apply pan attenuation on one channel (same as pan in the server)
|
||||||
for ( i = 0; i < iStereoBlockSizeSam; i += 2 )
|
const double dGainL = std::min ( 0.5, 1 - dPan ) * 2;
|
||||||
{
|
const double dGainR = std::min ( 0.5, dPan ) * 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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
||||||
{
|
{
|
||||||
// for the sum make sure we have more bits available (cast to
|
// note that the gain is always <= 1, therefore a simple cast is
|
||||||
// int32), after the normalization by 2, the result will fit
|
// ok since we never can get an overload
|
||||||
// into the old size so that cast to int16 is safe
|
vecsStereoSndCrd[j + 1] = static_cast<int16_t> ( dGainR * vecsStereoSndCrd[j + 1] );
|
||||||
vecsStereoSndCrd[i] = static_cast<int16_t> (
|
vecsStereoSndCrd[j] = static_cast<int16_t> ( dGainL * vecsStereoSndCrd[j] );
|
||||||
( 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] );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// mono and mono-in/stereo out mode
|
// for mono implement a cross-fade between channels and mix them
|
||||||
// make sure that in the middle position the two channels are
|
const double dGainL = 1 - dPan;
|
||||||
// amplified by 1/2, if the pan is set to one channel, this
|
const double dGainR = dPan;
|
||||||
// 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;
|
|
||||||
|
|
||||||
const double dAmplFactMono = 0.5 + static_cast<double> (
|
for ( i = 0, j = 0; i < iMonoBlockSizeSam; i++, j += 2 )
|
||||||
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 )
|
vecsStereoSndCrd[i] = Double2Short (
|
||||||
{
|
dGainL * vecsStereoSndCrd[j] + dGainR * vecsStereoSndCrd[j + 1] );
|
||||||
// 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] );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
// for muted stream we have to add our local data here
|
||||||
if ( bMuteOutStream )
|
if ( bMuteOutStream )
|
||||||
{
|
{
|
||||||
|
|
|
@ -151,8 +151,7 @@ public:
|
||||||
void SetReverbOnLeftChan ( const bool bIL )
|
void SetReverbOnLeftChan ( const bool bIL )
|
||||||
{
|
{
|
||||||
bReverbOnLeftChan = bIL;
|
bReverbOnLeftChan = bIL;
|
||||||
AudioReverbL.Clear();
|
AudioReverb.Clear();
|
||||||
AudioReverbR.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDoAutoSockBufSize ( const bool bValue );
|
void SetDoAutoSockBufSize ( const bool bValue );
|
||||||
|
@ -354,8 +353,7 @@ protected:
|
||||||
int iAudioInFader;
|
int iAudioInFader;
|
||||||
bool bReverbOnLeftChan;
|
bool bReverbOnLeftChan;
|
||||||
int iReverbLevel;
|
int iReverbLevel;
|
||||||
CAudioReverb AudioReverbL;
|
CAudioReverb AudioReverb;
|
||||||
CAudioReverb AudioReverbR;
|
|
||||||
|
|
||||||
int iSndCrdPrefFrameSizeFactor;
|
int iSndCrdPrefFrameSizeFactor;
|
||||||
int iSndCrdFrameSizeFactor;
|
int iSndCrdFrameSizeFactor;
|
||||||
|
|
127
src/util.cpp
127
src/util.cpp
|
@ -165,20 +165,24 @@ uint32_t CCRC::GetCRC()
|
||||||
three series allpass units, followed by four parallel comb filters, and two
|
three series allpass units, followed by four parallel comb filters, and two
|
||||||
decorrelation delay lines in parallel at the output.
|
decorrelation delay lines in parallel at the output.
|
||||||
*/
|
*/
|
||||||
void CAudioReverb::Init ( const int iSampleRate,
|
void CAudioReverb::Init ( const EAudChanConf eNAudioChannelConf,
|
||||||
const double rT60 )
|
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
|
// delay lengths for 44100 Hz sample rate
|
||||||
int lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
|
int lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
|
||||||
const double scaler = static_cast<double> ( iSampleRate ) / 44100.0;
|
const double scaler = static_cast<double> ( iSampleRate ) / 44100.0;
|
||||||
|
|
||||||
if ( scaler != 1.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 )
|
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] );
|
allpassDelays[i].Init ( lengths[i + 4] );
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( i = 0; i < 4; i++ )
|
for ( int i = 0; i < 4; i++ )
|
||||||
{
|
{
|
||||||
combDelays[i].Init ( lengths[i] );
|
combDelays[i].Init ( lengths[i] );
|
||||||
combFilters[i].setPole ( 0.2 );
|
combFilters[i].setPole ( 0.2 );
|
||||||
|
@ -285,58 +289,81 @@ double CAudioReverb::COnePole::Calc ( const double dIn )
|
||||||
return dLastSample;
|
return dLastSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAudioReverb::ProcessSample ( int16_t& iInputOutputLeft,
|
void CAudioReverb::Process ( CVector<int16_t>& vecsStereoInOut,
|
||||||
int16_t& iInputOutputRight,
|
const bool bReverbOnLeftChan,
|
||||||
const double dAttenuation )
|
const double dAttenuation )
|
||||||
{
|
{
|
||||||
// compute one output sample
|
double dMixedInput, temp, temp0, temp1, temp2;
|
||||||
double temp, temp0, temp1, temp2;
|
|
||||||
|
|
||||||
// we sum up the stereo input channels (in case mono input is used, a zero
|
for ( int i = 0; i < iStereoBlockSizeSam; i += 2 )
|
||||||
// shall be input for the right channel)
|
{
|
||||||
const double dMixedInput = 0.5 * ( iInputOutputLeft + iInputOutputRight );
|
// 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();
|
temp = allpassDelays[0].Get();
|
||||||
temp0 = allpassCoefficient * temp;
|
temp0 = allpassCoefficient * temp;
|
||||||
temp0 += dMixedInput;
|
temp0 += dMixedInput;
|
||||||
allpassDelays[0].Add ( temp0 );
|
allpassDelays[0].Add ( temp0 );
|
||||||
temp0 = - ( allpassCoefficient * temp0 ) + temp;
|
temp0 = - ( allpassCoefficient * temp0 ) + temp;
|
||||||
|
|
||||||
temp = allpassDelays[1].Get();
|
temp = allpassDelays[1].Get();
|
||||||
temp1 = allpassCoefficient * temp;
|
temp1 = allpassCoefficient * temp;
|
||||||
temp1 += temp0;
|
temp1 += temp0;
|
||||||
allpassDelays[1].Add ( 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 ( temp2 );
|
allpassDelays[2].Add ( temp2 );
|
||||||
temp2 = - ( allpassCoefficient * temp2 ) + temp;
|
temp2 = - ( allpassCoefficient * temp2 ) + temp;
|
||||||
|
|
||||||
const double temp3 = temp2 + combFilters[0].Calc ( combCoefficient[0] * combDelays[0].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 temp4 = temp2 + combFilters[1].Calc ( combCoefficient[1] * combDelays[1].Get() );
|
||||||
const double temp5 = temp2 + combFilters[2].Calc ( combCoefficient[2] * combDelays[2].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 temp6 = temp2 + combFilters[3].Calc ( combCoefficient[3] * combDelays[3].Get() );
|
||||||
|
|
||||||
combDelays[0].Add ( temp3 );
|
combDelays[0].Add ( temp3 );
|
||||||
combDelays[1].Add ( temp4 );
|
combDelays[1].Add ( temp4 );
|
||||||
combDelays[2].Add ( temp5 );
|
combDelays[2].Add ( temp5 );
|
||||||
combDelays[3].Add ( temp6 );
|
combDelays[3].Add ( temp6 );
|
||||||
|
|
||||||
const double filtout = temp3 + temp4 + temp5 + temp6;
|
const double filtout = temp3 + temp4 + temp5 + temp6;
|
||||||
|
|
||||||
outLeftDelay.Add ( filtout );
|
outLeftDelay.Add ( filtout );
|
||||||
outRightDelay.Add ( filtout );
|
outRightDelay.Add ( filtout );
|
||||||
|
|
||||||
// inplace apply the attenuated reverb signal
|
// inplace apply the attenuated reverb signal (for stereo always apply
|
||||||
iInputOutputLeft = Double2Short (
|
// reverberation effect on both channels)
|
||||||
( 1.0 - dAttenuation ) * iInputOutputLeft +
|
if ( ( eAudioChannelConf == CC_STEREO ) || bReverbOnLeftChan )
|
||||||
0.5 * dAttenuation * outLeftDelay.Get() );
|
{
|
||||||
|
vecsStereoInOut[i] = Double2Short (
|
||||||
|
( 1.0 - dAttenuation ) * vecsStereoInOut[i] +
|
||||||
|
0.5 * dAttenuation * outLeftDelay.Get() );
|
||||||
|
}
|
||||||
|
|
||||||
iInputOutputRight = Double2Short (
|
if ( ( eAudioChannelConf == CC_STEREO ) || !bReverbOnLeftChan )
|
||||||
( 1.0 - dAttenuation ) * iInputOutputRight +
|
{
|
||||||
0.5 * dAttenuation * outRightDelay.Get() );
|
vecsStereoInOut[i + 1] = Double2Short (
|
||||||
|
( 1.0 - dAttenuation ) * vecsStereoInOut[i + 1] +
|
||||||
|
0.5 * dAttenuation * outRightDelay.Get() );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
18
src/util.h
18
src/util.h
|
@ -694,8 +694,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
double UpdateCurLevel ( double dCurLevel,
|
double UpdateCurLevel ( double dCurLevel,
|
||||||
const short& sMax );
|
const short& sMax );
|
||||||
|
|
||||||
double dCurLevelL;
|
double dCurLevelL;
|
||||||
double dCurLevelR;
|
double dCurLevelR;
|
||||||
|
@ -1098,11 +1098,15 @@ class CAudioReverb
|
||||||
public:
|
public:
|
||||||
CAudioReverb() {}
|
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 Clear();
|
||||||
void ProcessSample ( int16_t& iInputOutputLeft,
|
void Process ( CVector<int16_t>& vecsStereoInOut,
|
||||||
int16_t& iInputOutputRight,
|
const bool bReverbOnLeftChan,
|
||||||
const double dAttenuation );
|
const double dAttenuation );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setT60 ( const double rT60, const int iSampleRate );
|
void setT60 ( const double rT60, const int iSampleRate );
|
||||||
|
@ -1122,6 +1126,8 @@ protected:
|
||||||
double dLastSample;
|
double dLastSample;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EAudChanConf eAudioChannelConf;
|
||||||
|
int iStereoBlockSizeSam;
|
||||||
CFIFO<double> allpassDelays[3];
|
CFIFO<double> allpassDelays[3];
|
||||||
CFIFO<double> combDelays[4];
|
CFIFO<double> combDelays[4];
|
||||||
COnePole combFilters[4];
|
COnePole combFilters[4];
|
||||||
|
|
Loading…
Reference in a new issue