22* Audio Reverberation *
33\******************************************************************************/
44/*
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.
5+ The following code calls MVerb for reverberation.
6+ MVerb was written by Martin Eastwood.
7+ https://github.com/martineastwood/mverb
158*/
169
1710#include " audioreverb.h"
1811
19- void CAudioReverb::Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam, const int iSampleRate, const float fT60 )
12+ void CAudioReverb::Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam )
2013{
21- // store parameters
2214 eAudioChannelConf = eNAudioChannelConf;
2315 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 ();
16+ fMaxShort = static_cast <float > ( _MAXSHORT );
17+ mverb.setParameter ( MVerb<float >::DAMPINGFREQ , 0.5 );
18+ mverb.setParameter ( MVerb<float >::DENSITY , 0.5 );
19+ mverb.setParameter ( MVerb<float >::BANDWIDTHFREQ , 0.5 );
20+ mverb.setParameter ( MVerb<float >::DECAY , 0.5 );
21+ mverb.setParameter ( MVerb<float >::PREDELAY , 0.5 );
22+ mverb.setParameter ( MVerb<float >::GAIN , 1 . );
23+ mverb.setParameter ( MVerb<float >::MIX , 1.0 );
24+ mverb.setParameter ( MVerb<float >::EARLYMIX , 0.5 );
25+ mverb.setParameter ( MVerb<float >::SIZE , 0.75 );
6526}
6627
67- bool CAudioReverb::isPrime ( const int number )
28+ void CAudioReverb::Process ( CVector< int16_t >& vecsStereoInOut, const bool bReverbOnLeftChan, const float fAttenuation )
6829{
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- }
30+ const int numFrames = iStereoBlockSizeSam >> 1 ;
31+
32+ float bufL[numFrames];
33+ float bufR[numFrames];
7734
78- if ( number & 1 )
35+ float * fInput [2 ] = { bufL, bufR };
36+
37+ if ( eAudioChannelConf == CC_STEREO )
7938 {
80- for ( int i = 3 ; i < static_cast < int > ( sqrtf ( static_cast < float > ( number ) ) ) + 1 ; i += 2 )
39+ for ( int i = 0 , j = 0 ; j < numFrames ; i += 2 , j++ )
8140 {
82- if ( ( number % i ) == 0 )
83- {
84- return false ;
85- }
41+ bufL[j] = static_cast <float > ( vecsStereoInOut[i] ) / fMaxShort ;
42+ bufR[j] = static_cast <float > ( vecsStereoInOut[i + 1 ] ) / fMaxShort ;
8643 }
87-
88- return true ; // prime
8944 }
9045 else
9146 {
92- return false ; // even
47+ for ( int i = 0 , j = 0 ; j < numFrames; i += 2 , j++ )
48+ {
49+ bufR[j] = bufL[j] = static_cast <float > ( vecsStereoInOut[i + !bReverbOnLeftChan] ) / fMaxShort ;
50+ }
9351 }
94- }
9552
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- }
53+ mverb.process ( fInput , fInput , numFrames );
11354
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++ )
55+ for ( int i = 0 , j = 0 ; j < numFrames; i += 2 , j++ )
11856 {
119- combCoefficient[i] = powf ( 10 .0f , static_cast <float > ( -3 .0f * combDelays[i].Size () / ( fT60 * iSampleRate ) ) );
57+ vecsStereoInOut[i] = Float2Short ( vecsStereoInOut[i] + bufL[j] * fMaxShort * fAttenuation );
58+ vecsStereoInOut[i + 1 ] = Float2Short ( vecsStereoInOut[i + 1 ] + bufR[j] * fMaxShort * fAttenuation );
12059 }
12160}
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