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