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+ }
0 commit comments