Skip to content

Commit d723bfc

Browse files
authored
Merge pull request #3403 from ann0see/refactoring/moveReverb
2 parents 7258a55 + 8f3a955 commit d723bfc

6 files changed

Lines changed: 269 additions & 247 deletions

File tree

Jamulus.pro

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,8 @@ FORMS_GUI = src/aboutdlgbase.ui \
378378
src/connectdlgbase.ui
379379
}
380380

381-
HEADERS += src/buffer.h \
381+
HEADERS += src/plugins/audioreverb.h \
382+
src/buffer.h \
382383
src/channel.h \
383384
src/global.h \
384385
src/protocol.h \
@@ -486,7 +487,8 @@ HEADERS_OPUS_X86 = libs/opus/celt/x86/celt_lpc_sse.h \
486487
libs/opus/celt/x86/x86cpu.h \
487488
$$files(libs/opus/silk/x86/*.h)
488489

489-
SOURCES += src/buffer.cpp \
490+
SOURCES += src/plugins/audioreverb.cpp \
491+
src/buffer.cpp \
490492
src/channel.cpp \
491493
src/main.cpp \
492494
src/protocol.cpp \

src/client.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "socket.h"
3939
#include "channel.h"
4040
#include "util.h"
41+
#include "plugins/audioreverb.h"
4142
#include "buffer.h"
4243
#include "signalhandler.h"
4344

src/plugins/audioreverb.cpp

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/******************************************************************************\
2+
* Audio Reverberation *
3+
\******************************************************************************/
4+
/*
5+
The following code is based on "JCRev: John Chowning's reverberator class"
6+
by Perry R. Cook and Gary P. Scavone, 1995 - 2004
7+
which is in "The Synthesis ToolKit in C++ (STK)"
8+
http://ccrma.stanford.edu/software/stk
9+
10+
Original description:
11+
This class is derived from the CLM JCRev function, which is based on the use
12+
of networks of simple allpass and comb delay filters. This class implements
13+
three series allpass units, followed by four parallel comb filters, and two
14+
decorrelation delay lines in parallel at the output.
15+
*/
16+
17+
#include "audioreverb.h"
18+
19+
void CAudioReverb::Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam, const int iSampleRate, const float fT60 )
20+
{
21+
// store parameters
22+
eAudioChannelConf = eNAudioChannelConf;
23+
iStereoBlockSizeSam = iNStereoBlockSizeSam;
24+
25+
// delay lengths for 44100 Hz sample rate
26+
int lengths[9] = { 1116, 1356, 1422, 1617, 225, 341, 441, 211, 179 };
27+
const float scaler = static_cast<float> ( iSampleRate ) / 44100.0f;
28+
29+
if ( scaler != 1.0f )
30+
{
31+
for ( int i = 0; i < 9; i++ )
32+
{
33+
int delay = static_cast<int> ( floorf ( scaler * lengths[i] ) );
34+
35+
if ( ( delay & 1 ) == 0 )
36+
{
37+
delay++;
38+
}
39+
40+
while ( !isPrime ( delay ) )
41+
{
42+
delay += 2;
43+
}
44+
45+
lengths[i] = delay;
46+
}
47+
}
48+
49+
for ( int i = 0; i < 3; i++ )
50+
{
51+
allpassDelays[i].Init ( lengths[i + 4] );
52+
}
53+
54+
for ( int i = 0; i < 4; i++ )
55+
{
56+
combDelays[i].Init ( lengths[i] );
57+
combFilters[i].setPole ( 0.2f );
58+
}
59+
60+
setT60 ( fT60, iSampleRate );
61+
outLeftDelay.Init ( lengths[7] );
62+
outRightDelay.Init ( lengths[8] );
63+
allpassCoefficient = 0.7f;
64+
Clear();
65+
}
66+
67+
bool CAudioReverb::isPrime ( const int number )
68+
{
69+
/*
70+
Returns true if argument value is prime. Taken from "class Effect" in
71+
"STK abstract effects parent class".
72+
*/
73+
if ( number == 2 )
74+
{
75+
return true;
76+
}
77+
78+
if ( number & 1 )
79+
{
80+
for ( int i = 3; i < static_cast<int> ( sqrtf ( static_cast<float> ( number ) ) ) + 1; i += 2 )
81+
{
82+
if ( ( number % i ) == 0 )
83+
{
84+
return false;
85+
}
86+
}
87+
88+
return true; // prime
89+
}
90+
else
91+
{
92+
return false; // even
93+
}
94+
}
95+
96+
void CAudioReverb::Clear()
97+
{
98+
// reset and clear all internal state
99+
allpassDelays[0].Reset ( 0 );
100+
allpassDelays[1].Reset ( 0 );
101+
allpassDelays[2].Reset ( 0 );
102+
combDelays[0].Reset ( 0 );
103+
combDelays[1].Reset ( 0 );
104+
combDelays[2].Reset ( 0 );
105+
combDelays[3].Reset ( 0 );
106+
combFilters[0].Reset();
107+
combFilters[1].Reset();
108+
combFilters[2].Reset();
109+
combFilters[3].Reset();
110+
outRightDelay.Reset ( 0 );
111+
outLeftDelay.Reset ( 0 );
112+
}
113+
114+
void CAudioReverb::setT60 ( const float fT60, const int iSampleRate )
115+
{
116+
// set the reverberation T60 decay time
117+
for ( int i = 0; i < 4; i++ )
118+
{
119+
combCoefficient[i] = powf ( 10.0f, static_cast<float> ( -3.0f * combDelays[i].Size() / ( fT60 * iSampleRate ) ) );
120+
}
121+
}
122+
123+
void CAudioReverb::COnePole::setPole ( const float fPole )
124+
{
125+
// calculate IIR filter coefficients based on the pole value
126+
fA = -fPole;
127+
fB = 1.0f - fPole;
128+
}
129+
130+
float CAudioReverb::COnePole::Calc ( const float fIn )
131+
{
132+
// calculate IIR filter
133+
fLastSample = fB * fIn - fA * fLastSample;
134+
135+
return fLastSample;
136+
}
137+
138+
void CAudioReverb::Process ( CVector<int16_t>& vecsStereoInOut, const bool bReverbOnLeftChan, const float fAttenuation )
139+
{
140+
float fMixedInput, temp, temp0, temp1, temp2;
141+
142+
for ( int i = 0; i < iStereoBlockSizeSam; i += 2 )
143+
{
144+
// we sum up the stereo input channels (in case mono input is used, a zero
145+
// shall be input for the right channel)
146+
if ( eAudioChannelConf == CC_STEREO )
147+
{
148+
fMixedInput = 0.5f * ( vecsStereoInOut[i] + vecsStereoInOut[i + 1] );
149+
}
150+
else
151+
{
152+
if ( bReverbOnLeftChan )
153+
{
154+
fMixedInput = vecsStereoInOut[i];
155+
}
156+
else
157+
{
158+
fMixedInput = vecsStereoInOut[i + 1];
159+
}
160+
}
161+
162+
temp = allpassDelays[0].Get();
163+
temp0 = allpassCoefficient * temp;
164+
temp0 += fMixedInput;
165+
allpassDelays[0].Add ( temp0 );
166+
temp0 = -( allpassCoefficient * temp0 ) + temp;
167+
168+
temp = allpassDelays[1].Get();
169+
temp1 = allpassCoefficient * temp;
170+
temp1 += temp0;
171+
allpassDelays[1].Add ( temp1 );
172+
temp1 = -( allpassCoefficient * temp1 ) + temp;
173+
174+
temp = allpassDelays[2].Get();
175+
temp2 = allpassCoefficient * temp;
176+
temp2 += temp1;
177+
allpassDelays[2].Add ( temp2 );
178+
temp2 = -( allpassCoefficient * temp2 ) + temp;
179+
180+
const float temp3 = temp2 + combFilters[0].Calc ( combCoefficient[0] * combDelays[0].Get() );
181+
const float temp4 = temp2 + combFilters[1].Calc ( combCoefficient[1] * combDelays[1].Get() );
182+
const float temp5 = temp2 + combFilters[2].Calc ( combCoefficient[2] * combDelays[2].Get() );
183+
const float temp6 = temp2 + combFilters[3].Calc ( combCoefficient[3] * combDelays[3].Get() );
184+
185+
combDelays[0].Add ( temp3 );
186+
combDelays[1].Add ( temp4 );
187+
combDelays[2].Add ( temp5 );
188+
combDelays[3].Add ( temp6 );
189+
190+
const float filtout = temp3 + temp4 + temp5 + temp6;
191+
192+
outLeftDelay.Add ( filtout );
193+
outRightDelay.Add ( filtout );
194+
195+
// inplace apply the attenuated reverb signal (for stereo always apply
196+
// reverberation effect on both channels)
197+
if ( ( eAudioChannelConf == CC_STEREO ) || bReverbOnLeftChan )
198+
{
199+
vecsStereoInOut[i] = Float2Short ( ( 1.0f - fAttenuation ) * vecsStereoInOut[i] + 0.5f * fAttenuation * outLeftDelay.Get() );
200+
}
201+
202+
if ( ( eAudioChannelConf == CC_STEREO ) || !bReverbOnLeftChan )
203+
{
204+
vecsStereoInOut[i + 1] = Float2Short ( ( 1.0f - fAttenuation ) * vecsStereoInOut[i + 1] + 0.5f * fAttenuation * outRightDelay.Get() );
205+
}
206+
}
207+
}

src/plugins/audioreverb.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/******************************************************************************\
2+
* Audio Reverberation *
3+
\******************************************************************************/
4+
/*
5+
The following code is based on "JCRev: John Chowning's reverberator class"
6+
by Perry R. Cook and Gary P. Scavone, 1995 - 2004
7+
which is in "The Synthesis ToolKit in C++ (STK)"
8+
http://ccrma.stanford.edu/software/stk
9+
10+
Original description:
11+
This class is derived from the CLM JCRev function, which is based on the use
12+
of networks of simple allpass and comb delay filters. This class implements
13+
three series allpass units, followed by four parallel comb filters, and two
14+
decorrelation delay lines in parallel at the output.
15+
*/
16+
17+
#pragma once
18+
#include "util.h"
19+
20+
class CAudioReverb
21+
{
22+
public:
23+
CAudioReverb() {}
24+
25+
void Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam, const int iSampleRate, const float fT60 = 1.1f );
26+
27+
void Clear();
28+
void Process ( CVector<int16_t>& vecsStereoInOut, const bool bReverbOnLeftChan, const float fAttenuation );
29+
30+
protected:
31+
void setT60 ( const float fT60, const int iSampleRate );
32+
bool isPrime ( const int number );
33+
34+
class COnePole
35+
{
36+
public:
37+
COnePole() : fA ( 0 ), fB ( 0 ) { Reset(); }
38+
void setPole ( const float fPole );
39+
float Calc ( const float fIn );
40+
void Reset() { fLastSample = 0; }
41+
42+
protected:
43+
float fA;
44+
float fB;
45+
float fLastSample;
46+
};
47+
48+
EAudChanConf eAudioChannelConf;
49+
int iStereoBlockSizeSam;
50+
CFIFO<float> allpassDelays[3];
51+
CFIFO<float> combDelays[4];
52+
COnePole combFilters[4];
53+
CFIFO<float> outLeftDelay;
54+
CFIFO<float> outRightDelay;
55+
float allpassCoefficient;
56+
float combCoefficient[4];
57+
};

0 commit comments

Comments
 (0)