Skip to content

Commit 172daf1

Browse files
committed
Use MVerb by Martin Eastwood for reverberation
1 parent 55e0d62 commit 172daf1

7 files changed

Lines changed: 48 additions & 221 deletions

File tree

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "libs/oboe"]
22
path = libs/oboe
33
url = ../../google/oboe.git
4+
[submodule "libs/mverb"]
5+
path = libs/mverb
6+
url = https://github.com/martineastwood/mverb.git

Jamulus.pro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,8 @@ HEADERS += src/plugins/audioreverb.h \
403403
src/recorder/jamrecorder.h \
404404
src/recorder/creaperproject.h \
405405
src/recorder/cwavestream.h \
406-
src/signalhandler.h
406+
src/signalhandler.h \
407+
libs/mverb/MVerb.h
407408

408409
!contains(CONFIG, "serveronly") {
409410
HEADERS += src/client.h \

libs/mverb

Submodule mverb added at 9f9512e

src/client.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1345,7 +1345,7 @@ void CClient::Init()
13451345
Channel.SetAudioStreamProperties ( eAudioCompressionType, iCeltNumCodedBytes, iSndCrdFrameSizeFactor, iNumAudioChannels );
13461346

13471347
// init reverberation
1348-
AudioReverb.Init ( eAudioChannelConf, iStereoBlockSizeSam, SYSTEM_SAMPLE_RATE_HZ );
1348+
AudioReverb.Init ( eAudioChannelConf, iStereoBlockSizeSam );
13491349

13501350
// init the sound card conversion buffers
13511351
if ( bSndCrdConversionBufferRequired )

src/client.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,7 @@ class CClient : public QObject
192192
void SetReverbLevel ( const int iNL ) { iReverbLevel = iNL; }
193193

194194
bool IsReverbOnLeftChan() const { return bReverbOnLeftChan; }
195-
void SetReverbOnLeftChan ( const bool bIL )
196-
{
197-
bReverbOnLeftChan = bIL;
198-
AudioReverb.Clear();
199-
}
195+
void SetReverbOnLeftChan ( const bool bIL ) { bReverbOnLeftChan = bIL; }
200196

201197
void SetDoAutoSockBufSize ( const bool bValue );
202198
bool GetDoAutoSockBufSize() const { return Channel.GetDoAutoSockBufSize(); }

src/plugins/audioreverb.cpp

Lines changed: 33 additions & 180 deletions
Original file line numberDiff line numberDiff line change
@@ -2,206 +2,59 @@
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-
}

src/plugins/audioreverb.h

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,29 @@
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
#pragma once
1811
#include "util.h"
12+
#include "libs/mverb/MVerb.h"
1913

2014
class CAudioReverb
2115
{
2216
public:
2317
CAudioReverb() {}
2418

25-
void Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam, const int iSampleRate, const float fT60 = 1.1f );
19+
void Init ( const EAudChanConf eNAudioChannelConf, const int iNStereoBlockSizeSam );
2620

2721
void Clear();
2822
void Process ( CVector<int16_t>& vecsStereoInOut, const bool bReverbOnLeftChan, const float fAttenuation );
2923

3024
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-
};
25+
MVerb<float> mverb;
4726

4827
EAudChanConf eAudioChannelConf;
4928
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];
29+
float fMaxShort;
5730
};

0 commit comments

Comments
 (0)