OpenShot Library | libopenshot-audio 0.2.0
juce_Reverb.h
1
2/** @weakgroup juce_audio_basics-utilities
3 * @{
4 */
5/*
6 ==============================================================================
7
8 This file is part of the JUCE library.
9 Copyright (c) 2017 - ROLI Ltd.
10
11 JUCE is an open source library subject to commercial or open-source
12 licensing.
13
14 The code included in this file is provided under the terms of the ISC license
15 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16 To use, copy, modify, and/or distribute this software for any purpose with or
17 without fee is hereby granted provided that the above copyright notice and
18 this permission notice appear in all copies.
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29
30//==============================================================================
31/**
32 Performs a simple reverb effect on a stream of audio data.
33
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.
37
38 @see ReverbAudioSource
39
40 @tags{Audio}
41*/
42class Reverb
43{
44public:
45 //==============================================================================
46 Reverb()
47 {
49 setSampleRate (44100.0);
50 }
51
52 //==============================================================================
53 /** Holds the parameters being used by a Reverb object. */
55 {
56 float roomSize = 0.5f; /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */
57 float damping = 0.5f; /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */
58 float wetLevel = 0.33f; /**< Wet level, 0 to 1.0 */
59 float dryLevel = 0.4f; /**< Dry level, 0 to 1.0 */
60 float width = 1.0f; /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */
61 float freezeMode = 0.0f; /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5
62 put the reverb into a continuous feedback loop. */
63 };
64
65 //==============================================================================
66 /** Returns the reverb's current parameters. */
67 const Parameters& getParameters() const noexcept { return parameters; }
68
69 /** Applies a new set of parameters to the reverb.
70 Note that this doesn't attempt to lock the reverb, so if you call this in parallel with
71 the process method, you may get artifacts.
72 */
73 void setParameters (const Parameters& newParams)
74 {
75 const float wetScaleFactor = 3.0f;
76 const float dryScaleFactor = 2.0f;
77
78 const float wet = newParams.wetLevel * wetScaleFactor;
79 dryGain.setTargetValue (newParams.dryLevel * dryScaleFactor);
80 wetGain1.setTargetValue (0.5f * wet * (1.0f + newParams.width));
81 wetGain2.setTargetValue (0.5f * wet * (1.0f - newParams.width));
82
83 gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f;
84 parameters = newParams;
85 updateDamping();
86 }
87
88 //==============================================================================
89 /** Sets the sample rate that will be used for the reverb.
90 You must call this before the process methods, in order to tell it the correct sample rate.
91 */
92 void setSampleRate (const double sampleRate)
93 {
94 jassert (sampleRate > 0);
95
96 static const short combTunings[] = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 }; // (at 44100Hz)
97 static const short allPassTunings[] = { 556, 441, 341, 225 };
98 const int stereoSpread = 23;
99 const int intSampleRate = (int) sampleRate;
100
101 for (int i = 0; i < numCombs; ++i)
102 {
103 comb[0][i].setSize ((intSampleRate * combTunings[i]) / 44100);
104 comb[1][i].setSize ((intSampleRate * (combTunings[i] + stereoSpread)) / 44100);
105 }
106
107 for (int i = 0; i < numAllPasses; ++i)
108 {
109 allPass[0][i].setSize ((intSampleRate * allPassTunings[i]) / 44100);
110 allPass[1][i].setSize ((intSampleRate * (allPassTunings[i] + stereoSpread)) / 44100);
111 }
112
113 const double smoothTime = 0.01;
114 damping .reset (sampleRate, smoothTime);
115 feedback.reset (sampleRate, smoothTime);
116 dryGain .reset (sampleRate, smoothTime);
117 wetGain1.reset (sampleRate, smoothTime);
118 wetGain2.reset (sampleRate, smoothTime);
119 }
120
121 /** Clears the reverb's buffers. */
122 void reset()
123 {
124 for (int j = 0; j < numChannels; ++j)
125 {
126 for (int i = 0; i < numCombs; ++i)
127 comb[j][i].clear();
128
129 for (int i = 0; i < numAllPasses; ++i)
130 allPass[j][i].clear();
131 }
132 }
133
134 //==============================================================================
135 /** Applies the reverb to two stereo channels of audio data. */
136 void processStereo (float* const left, float* const right, const int numSamples) noexcept
137 {
138 jassert (left != nullptr && right != nullptr);
139
140 for (int i = 0; i < numSamples; ++i)
141 {
142 const float input = (left[i] + right[i]) * gain;
143 float outL = 0, outR = 0;
144
145 const float damp = damping.getNextValue();
146 const float feedbck = feedback.getNextValue();
147
148 for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
149 {
150 outL += comb[0][j].process (input, damp, feedbck);
151 outR += comb[1][j].process (input, damp, feedbck);
152 }
153
154 for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
155 {
156 outL = allPass[0][j].process (outL);
157 outR = allPass[1][j].process (outR);
158 }
159
160 const float dry = dryGain.getNextValue();
161 const float wet1 = wetGain1.getNextValue();
162 const float wet2 = wetGain2.getNextValue();
163
164 left[i] = outL * wet1 + outR * wet2 + left[i] * dry;
165 right[i] = outR * wet1 + outL * wet2 + right[i] * dry;
166 }
167 }
168
169 /** Applies the reverb to a single mono channel of audio data. */
170 void processMono (float* const samples, const int numSamples) noexcept
171 {
172 jassert (samples != nullptr);
173
174 for (int i = 0; i < numSamples; ++i)
175 {
176 const float input = samples[i] * gain;
177 float output = 0;
178
179 const float damp = damping.getNextValue();
180 const float feedbck = feedback.getNextValue();
181
182 for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
183 output += comb[0][j].process (input, damp, feedbck);
184
185 for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
186 output = allPass[0][j].process (output);
187
188 const float dry = dryGain.getNextValue();
189 const float wet1 = wetGain1.getNextValue();
190
191 samples[i] = output * wet1 + samples[i] * dry;
192 }
193 }
194
195private:
196 //==============================================================================
197 static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; }
198
199 void updateDamping() noexcept
200 {
201 const float roomScaleFactor = 0.28f;
202 const float roomOffset = 0.7f;
203 const float dampScaleFactor = 0.4f;
204
205 if (isFrozen (parameters.freezeMode))
206 setDamping (0.0f, 1.0f);
207 else
208 setDamping (parameters.damping * dampScaleFactor,
209 parameters.roomSize * roomScaleFactor + roomOffset);
210 }
211
212 void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept
213 {
214 damping.setTargetValue (dampingToUse);
215 feedback.setTargetValue (roomSizeToUse);
216 }
217
218 //==============================================================================
219 class CombFilter
220 {
221 public:
222 CombFilter() noexcept {}
223
224 void setSize (const int size)
225 {
226 if (size != bufferSize)
227 {
228 bufferIndex = 0;
229 buffer.malloc (size);
230 bufferSize = size;
231 }
232
233 clear();
234 }
235
236 void clear() noexcept
237 {
238 last = 0;
239 buffer.clear ((size_t) bufferSize);
240 }
241
242 float process (const float input, const float damp, const float feedbackLevel) noexcept
243 {
244 const float output = buffer[bufferIndex];
245 last = (output * (1.0f - damp)) + (last * damp);
246 JUCE_UNDENORMALISE (last);
247
248 float temp = input + (last * feedbackLevel);
249 JUCE_UNDENORMALISE (temp);
250 buffer[bufferIndex] = temp;
251 bufferIndex = (bufferIndex + 1) % bufferSize;
252 return output;
253 }
254
255 private:
256 HeapBlock<float> buffer;
257 int bufferSize = 0, bufferIndex = 0;
258 float last = 0.0f;
259
260 JUCE_DECLARE_NON_COPYABLE (CombFilter)
261 };
262
263 //==============================================================================
264 class AllPassFilter
265 {
266 public:
267 AllPassFilter() noexcept {}
268
269 void setSize (const int size)
270 {
271 if (size != bufferSize)
272 {
273 bufferIndex = 0;
274 buffer.malloc (size);
275 bufferSize = size;
276 }
277
278 clear();
279 }
280
281 void clear() noexcept
282 {
283 buffer.clear ((size_t) bufferSize);
284 }
285
286 float process (const float input) noexcept
287 {
288 const float bufferedValue = buffer [bufferIndex];
289 float temp = input + (bufferedValue * 0.5f);
290 JUCE_UNDENORMALISE (temp);
291 buffer [bufferIndex] = temp;
292 bufferIndex = (bufferIndex + 1) % bufferSize;
293 return bufferedValue - input;
294 }
295
296 private:
297 HeapBlock<float> buffer;
298 int bufferSize = 0, bufferIndex = 0;
299
300 JUCE_DECLARE_NON_COPYABLE (AllPassFilter)
301 };
302
303 //==============================================================================
304 enum { numCombs = 8, numAllPasses = 4, numChannels = 2 };
305
306 Parameters parameters;
307 float gain;
308
309 CombFilter comb [numChannels][numCombs];
310 AllPassFilter allPass [numChannels][numAllPasses];
311
312 SmoothedValue<float> damping, feedback, dryGain, wetGain1, wetGain2;
313
314 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb)
315};
316
317} // namespace juce
318
319/** @}*/
Performs a simple reverb effect on a stream of audio data.
Definition juce_Reverb.h:43
void processMono(float *const samples, const int numSamples) noexcept
Applies the reverb to a single mono channel of audio data.
void reset()
Clears the reverb's buffers.
void processStereo(float *const left, float *const right, const int numSamples) noexcept
Applies the reverb to two stereo channels of audio data.
void setParameters(const Parameters &newParams)
Applies a new set of parameters to the reverb.
Definition juce_Reverb.h:73
const Parameters & getParameters() const noexcept
Returns the reverb's current parameters.
Definition juce_Reverb.h:67
void setSampleRate(const double sampleRate)
Sets the sample rate that will be used for the reverb.
Definition juce_Reverb.h:92
FloatType getNextValue() noexcept
Compute the next value.
void reset(double sampleRate, double rampLengthInSeconds) noexcept
Reset to a new sample rate and ramp length.
void setTargetValue(FloatType newValue) noexcept
Set the next value to ramp towards.
float roomSize
Room size, 0 to 1.0, where 1.0 is big, 0 is small.
Definition juce_Reverb.h:56
float width
Reverb width, 0 to 1.0, where 1.0 is very wide.
Definition juce_Reverb.h:60
float dryLevel
Dry level, 0 to 1.0.
Definition juce_Reverb.h:59
float wetLevel
Wet level, 0 to 1.0.
Definition juce_Reverb.h:58
float freezeMode
Freeze mode - values < 0.5 are "normal" mode, values > 0.5 put the reverb into a continuous feedback ...
Definition juce_Reverb.h:61
float damping
Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped.
Definition juce_Reverb.h:57
Holds the parameters being used by a Reverb object.
Definition juce_Reverb.h:55