2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #ifndef __JUCE_REVERB_JUCEHEADER__
27 #define __JUCE_REVERB_JUCEHEADER__
30 //==============================================================================
32 Performs a simple reverb effect on a stream of audio data.
34 This is a simple stereo reverb, based on the technique and tunings used in FreeVerb.
35 Use setSampleRate() to prepare it, and then call processStereo() or processMono() to
36 apply the reverb to your audio data.
38 @see ReverbAudioSource
43 //==============================================================================
46 setParameters (Parameters());
47 setSampleRate (44100.0);
50 //==============================================================================
51 /** Holds the parameters being used by a Reverb object. */
63 float roomSize
; /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */
64 float damping
; /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */
65 float wetLevel
; /**< Wet level, 0 to 1.0 */
66 float dryLevel
; /**< Dry level, 0 to 1.0 */
67 float width
; /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */
68 float freezeMode
; /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5
69 put the reverb into a continuous feedback loop. */
72 //==============================================================================
73 /** Returns the reverb's current parameters. */
74 const Parameters
& getParameters() const noexcept
{ return parameters
; }
76 /** Applies a new set of parameters to the reverb.
77 Note that this doesn't attempt to lock the reverb, so if you call this in parallel with
78 the process method, you may get artifacts.
80 void setParameters (const Parameters
& newParams
)
82 const float wetScaleFactor
= 3.0f
;
83 const float dryScaleFactor
= 2.0f
;
85 const float wet
= newParams
.wetLevel
* wetScaleFactor
;
86 wet1
= wet
* (newParams
.width
* 0.5f
+ 0.5f
);
87 wet2
= wet
* (1.0f
- newParams
.width
) * 0.5f
;
88 dry
= newParams
.dryLevel
* dryScaleFactor
;
89 gain
= isFrozen (newParams
.freezeMode
) ? 0.0f
: 0.015f
;
90 parameters
= newParams
;
91 shouldUpdateDamping
= true;
94 //==============================================================================
95 /** Sets the sample rate that will be used for the reverb.
96 You must call this before the process methods, in order to tell it the correct sample rate.
98 void setSampleRate (const double sampleRate
)
100 jassert (sampleRate
> 0);
102 static const short combTunings
[] = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 }; // (at 44100Hz)
103 static const short allPassTunings
[] = { 556, 441, 341, 225 };
104 const int stereoSpread
= 23;
105 const int intSampleRate
= (int) sampleRate
;
108 for (i
= 0; i
< numCombs
; ++i
)
110 comb
[0][i
].setSize ((intSampleRate
* combTunings
[i
]) / 44100);
111 comb
[1][i
].setSize ((intSampleRate
* (combTunings
[i
] + stereoSpread
)) / 44100);
114 for (i
= 0; i
< numAllPasses
; ++i
)
116 allPass
[0][i
].setSize ((intSampleRate
* allPassTunings
[i
]) / 44100);
117 allPass
[1][i
].setSize ((intSampleRate
* (allPassTunings
[i
] + stereoSpread
)) / 44100);
120 shouldUpdateDamping
= true;
123 /** Clears the reverb's buffers. */
126 for (int j
= 0; j
< numChannels
; ++j
)
129 for (i
= 0; i
< numCombs
; ++i
)
132 for (i
= 0; i
< numAllPasses
; ++i
)
133 allPass
[j
][i
].clear();
137 //==============================================================================
138 /** Applies the reverb to two stereo channels of audio data. */
139 void processStereo (float* const left
, float* const right
, const int numSamples
) noexcept
141 jassert (left
!= nullptr && right
!= nullptr);
143 if (shouldUpdateDamping
)
146 for (int i
= 0; i
< numSamples
; ++i
)
148 const float input
= (left
[i
] + right
[i
]) * gain
;
149 float outL
= 0, outR
= 0;
152 for (j
= 0; j
< numCombs
; ++j
) // accumulate the comb filters in parallel
154 outL
+= comb
[0][j
].process (input
);
155 outR
+= comb
[1][j
].process (input
);
158 for (j
= 0; j
< numAllPasses
; ++j
) // run the allpass filters in series
160 outL
= allPass
[0][j
].process (outL
);
161 outR
= allPass
[1][j
].process (outR
);
164 left
[i
] = outL
* wet1
+ outR
* wet2
+ left
[i
] * dry
;
165 right
[i
] = outR
* wet1
+ outL
* wet2
+ right
[i
] * dry
;
169 /** Applies the reverb to a single mono channel of audio data. */
170 void processMono (float* const samples
, const int numSamples
) noexcept
172 jassert (samples
!= nullptr);
174 if (shouldUpdateDamping
)
177 for (int i
= 0; i
< numSamples
; ++i
)
179 const float input
= samples
[i
] * gain
;
183 for (j
= 0; j
< numCombs
; ++j
) // accumulate the comb filters in parallel
184 output
+= comb
[0][j
].process (input
);
186 for (j
= 0; j
< numAllPasses
; ++j
) // run the allpass filters in series
187 output
= allPass
[0][j
].process (output
);
189 samples
[i
] = output
* wet1
+ input
* dry
;
194 //==============================================================================
195 Parameters parameters
;
197 volatile bool shouldUpdateDamping
;
198 float gain
, wet1
, wet2
, dry
;
200 inline static bool isFrozen (const float freezeMode
) noexcept
{ return freezeMode
>= 0.5f
; }
202 void updateDamping() noexcept
204 const float roomScaleFactor
= 0.28f
;
205 const float roomOffset
= 0.7f
;
206 const float dampScaleFactor
= 0.4f
;
208 shouldUpdateDamping
= false;
210 if (isFrozen (parameters
.freezeMode
))
211 setDamping (1.0f
, 0.0f
);
213 setDamping (parameters
.damping
* dampScaleFactor
,
214 parameters
.roomSize
* roomScaleFactor
+ roomOffset
);
217 void setDamping (const float dampingToUse
, const float roomSizeToUse
) noexcept
219 for (int j
= 0; j
< numChannels
; ++j
)
220 for (int i
= numCombs
; --i
>= 0;)
221 comb
[j
][i
].setFeedbackAndDamp (roomSizeToUse
, dampingToUse
);
224 //==============================================================================
228 CombFilter() noexcept
: bufferSize (0), bufferIndex (0) {}
230 void setSize (const int size
)
232 if (size
!= bufferSize
)
235 buffer
.malloc (size
);
242 void clear() noexcept
245 buffer
.clear (bufferSize
);
248 void setFeedbackAndDamp (const float f
, const float d
) noexcept
255 inline float process (const float input
) noexcept
257 const float output
= buffer
[bufferIndex
];
258 last
= (output
* damp2
) + (last
* damp1
);
259 JUCE_UNDENORMALISE (last
);
261 float temp
= input
+ (last
* feedback
);
262 JUCE_UNDENORMALISE (temp
);
263 buffer
[bufferIndex
] = temp
;
264 bufferIndex
= (bufferIndex
+ 1) % bufferSize
;
269 HeapBlock
<float> buffer
;
270 int bufferSize
, bufferIndex
;
271 float feedback
, last
, damp1
, damp2
;
273 JUCE_DECLARE_NON_COPYABLE (CombFilter
);
276 //==============================================================================
280 AllPassFilter() noexcept
: bufferSize (0), bufferIndex (0) {}
282 void setSize (const int size
)
284 if (size
!= bufferSize
)
287 buffer
.malloc (size
);
294 void clear() noexcept
296 buffer
.clear (bufferSize
);
299 inline float process (const float input
) noexcept
301 const float bufferedValue
= buffer
[bufferIndex
];
302 float temp
= input
+ (bufferedValue
* 0.5f
);
303 JUCE_UNDENORMALISE (temp
);
304 buffer
[bufferIndex
] = temp
;
305 bufferIndex
= (bufferIndex
+ 1) % bufferSize
;
306 return bufferedValue
- input
;
310 HeapBlock
<float> buffer
;
311 int bufferSize
, bufferIndex
;
313 JUCE_DECLARE_NON_COPYABLE (AllPassFilter
);
316 enum { numCombs
= 8, numAllPasses
= 4, numChannels
= 2 };
318 CombFilter comb
[numChannels
][numCombs
];
319 AllPassFilter allPass
[numChannels
][numAllPasses
];
321 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb
);
325 #endif // __JUCE_REVERB_JUCEHEADER__