OpenShot Audio Library | OpenShotAudio 0.4.0
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) 2022 - Raw Material Software Limited
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 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011)
135 jassert (left != nullptr && right != nullptr);
136
137 for (int i = 0; i < numSamples; ++i)
138 {
139 // NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
140 const float input = (left[i] + right[i]) * gain;
141 float outL = 0, outR = 0;
142
143 const float damp = damping.getNextValue();
144 const float feedbck = feedback.getNextValue();
145
146 for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
147 {
148 outL += comb[0][j].process (input, damp, feedbck);
149 outR += comb[1][j].process (input, damp, feedbck);
150 }
151
152 for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
153 {
154 outL = allPass[0][j].process (outL);
155 outR = allPass[1][j].process (outR);
156 }
157
158 const float dry = dryGain.getNextValue();
159 const float wet1 = wetGain1.getNextValue();
160 const float wet2 = wetGain2.getNextValue();
161
162 left[i] = outL * wet1 + outR * wet2 + left[i] * dry;
163 right[i] = outR * wet1 + outL * wet2 + right[i] * dry;
164 }
165 JUCE_END_IGNORE_WARNINGS_MSVC
166 }
167
169 void processMono (float* const samples, const int numSamples) noexcept
170 {
171 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011)
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 JUCE_END_IGNORE_WARNINGS_MSVC
194 }
195
196private:
197 //==============================================================================
198 static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; }
199
200 void updateDamping() noexcept
201 {
202 const float roomScaleFactor = 0.28f;
203 const float roomOffset = 0.7f;
204 const float dampScaleFactor = 0.4f;
205
206 if (isFrozen (parameters.freezeMode))
207 setDamping (0.0f, 1.0f);
208 else
209 setDamping (parameters.damping * dampScaleFactor,
210 parameters.roomSize * roomScaleFactor + roomOffset);
211 }
212
213 void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept
214 {
215 damping.setTargetValue (dampingToUse);
216 feedback.setTargetValue (roomSizeToUse);
217 }
218
219 //==============================================================================
220 class CombFilter
221 {
222 public:
223 CombFilter() noexcept {}
224
225 void setSize (const int size)
226 {
227 if (size != bufferSize)
228 {
229 bufferIndex = 0;
230 buffer.malloc (size);
231 bufferSize = size;
232 }
233
234 clear();
235 }
236
237 void clear() noexcept
238 {
239 last = 0;
240 buffer.clear ((size_t) bufferSize);
241 }
242
243 float process (const float input, const float damp, const float feedbackLevel) noexcept
244 {
245 const float output = buffer[bufferIndex];
246 last = (output * (1.0f - damp)) + (last * damp);
247 JUCE_UNDENORMALISE (last);
248
249 float temp = input + (last * feedbackLevel);
250 JUCE_UNDENORMALISE (temp);
251 buffer[bufferIndex] = temp;
252 bufferIndex = (bufferIndex + 1) % bufferSize;
253 return output;
254 }
255
256 private:
257 HeapBlock<float> buffer;
258 int bufferSize = 0, bufferIndex = 0;
259 float last = 0.0f;
260
261 JUCE_DECLARE_NON_COPYABLE (CombFilter)
262 };
263
264 //==============================================================================
265 class AllPassFilter
266 {
267 public:
268 AllPassFilter() noexcept {}
269
270 void setSize (const int size)
271 {
272 if (size != bufferSize)
273 {
274 bufferIndex = 0;
275 buffer.malloc (size);
276 bufferSize = size;
277 }
278
279 clear();
280 }
281
282 void clear() noexcept
283 {
284 buffer.clear ((size_t) bufferSize);
285 }
286
287 float process (const float input) noexcept
288 {
289 const float bufferedValue = buffer [bufferIndex];
290 float temp = input + (bufferedValue * 0.5f);
291 JUCE_UNDENORMALISE (temp);
292 buffer [bufferIndex] = temp;
293 bufferIndex = (bufferIndex + 1) % bufferSize;
294 return bufferedValue - input;
295 }
296
297 private:
298 HeapBlock<float> buffer;
299 int bufferSize = 0, bufferIndex = 0;
300
301 JUCE_DECLARE_NON_COPYABLE (AllPassFilter)
302 };
303
304 //==============================================================================
305 enum { numCombs = 8, numAllPasses = 4, numChannels = 2 };
306
307 Parameters parameters;
308 float gain;
309
310 CombFilter comb [numChannels][numCombs];
311 AllPassFilter allPass [numChannels][numAllPasses];
312
313 SmoothedValue<float> damping, feedback, dryGain, wetGain1, wetGain2;
314
315 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb)
316};
317
318} // 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