openshot-audio  0.1.6
juce_Reverb.h
Go to the documentation of this file.
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2015 - ROLI Ltd.
6 
7  Permission is granted to use this software under the terms of either:
8  a) the GPL v2 (or any later version)
9  b) the Affero GPL v3
10 
11  Details of these licenses can be found at: www.gnu.org/licenses
12 
13  JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
14  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15  A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 
17  ------------------------------------------------------------------------------
18 
19  To release a closed-source product which uses JUCE, commercial licenses are
20  available: visit www.juce.com for more information.
21 
22  ==============================================================================
23 */
24 
25 #ifndef JUCE_REVERB_H_INCLUDED
26 #define JUCE_REVERB_H_INCLUDED
27 
28 
29 //==============================================================================
39 class Reverb
40 {
41 public:
42  //==============================================================================
44  {
46  setSampleRate (44100.0);
47  }
48 
49  //==============================================================================
51  struct Parameters
52  {
54  : roomSize (0.5f),
55  damping (0.5f),
56  wetLevel (0.33f),
57  dryLevel (0.4f),
58  width (1.0f),
59  freezeMode (0)
60  {}
61 
62  float roomSize;
63  float damping;
64  float wetLevel;
65  float dryLevel;
66  float width;
67  float freezeMode;
69  };
70 
71  //==============================================================================
73  const Parameters& getParameters() const noexcept { return parameters; }
74 
79  void setParameters (const Parameters& newParams)
80  {
81  const float wetScaleFactor = 3.0f;
82  const float dryScaleFactor = 2.0f;
83 
84  const float wet = newParams.wetLevel * wetScaleFactor;
85  dryGain.setValue (newParams.dryLevel * dryScaleFactor);
86  wetGain1.setValue (0.5f * wet * (1.0f + newParams.width));
87  wetGain2.setValue (0.5f * wet * (1.0f - newParams.width));
88 
89  gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f;
90  parameters = newParams;
91  updateDamping();
92  }
93 
94  //==============================================================================
98  void setSampleRate (const double sampleRate)
99  {
100  jassert (sampleRate > 0);
101 
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;
106 
107  for (int i = 0; i < numCombs; ++i)
108  {
109  comb[0][i].setSize ((intSampleRate * combTunings[i]) / 44100);
110  comb[1][i].setSize ((intSampleRate * (combTunings[i] + stereoSpread)) / 44100);
111  }
112 
113  for (int i = 0; i < numAllPasses; ++i)
114  {
115  allPass[0][i].setSize ((intSampleRate * allPassTunings[i]) / 44100);
116  allPass[1][i].setSize ((intSampleRate * (allPassTunings[i] + stereoSpread)) / 44100);
117  }
118 
119  const double smoothTime = 0.01;
120  damping .reset (sampleRate, smoothTime);
121  feedback.reset (sampleRate, smoothTime);
122  dryGain .reset (sampleRate, smoothTime);
123  wetGain1.reset (sampleRate, smoothTime);
124  wetGain2.reset (sampleRate, smoothTime);
125  }
126 
128  void reset()
129  {
130  for (int j = 0; j < numChannels; ++j)
131  {
132  for (int i = 0; i < numCombs; ++i)
133  comb[j][i].clear();
134 
135  for (int i = 0; i < numAllPasses; ++i)
136  allPass[j][i].clear();
137  }
138  }
139 
140  //==============================================================================
142  void processStereo (float* const left, float* const right, const int numSamples) noexcept
143  {
144  jassert (left != nullptr && right != nullptr);
145 
146  for (int i = 0; i < numSamples; ++i)
147  {
148  const float input = (left[i] + right[i]) * gain;
149  float outL = 0, outR = 0;
150 
151  const float damp = damping.getNextValue();
152  const float feedbck = feedback.getNextValue();
153 
154  for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
155  {
156  outL += comb[0][j].process (input, damp, feedbck);
157  outR += comb[1][j].process (input, damp, feedbck);
158  }
159 
160  for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
161  {
162  outL = allPass[0][j].process (outL);
163  outR = allPass[1][j].process (outR);
164  }
165 
166  const float dry = dryGain.getNextValue();
167  const float wet1 = wetGain1.getNextValue();
168  const float wet2 = wetGain2.getNextValue();
169 
170  left[i] = outL * wet1 + outR * wet2 + left[i] * dry;
171  right[i] = outR * wet1 + outL * wet2 + right[i] * dry;
172  }
173  }
174 
176  void processMono (float* const samples, const int numSamples) noexcept
177  {
178  jassert (samples != nullptr);
179 
180  for (int i = 0; i < numSamples; ++i)
181  {
182  const float input = samples[i] * gain;
183  float output = 0;
184 
185  const float damp = damping.getNextValue();
186  const float feedbck = feedback.getNextValue();
187 
188  for (int j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
189  output += comb[0][j].process (input, damp, feedbck);
190 
191  for (int j = 0; j < numAllPasses; ++j) // run the allpass filters in series
192  output = allPass[0][j].process (output);
193 
194  const float dry = dryGain.getNextValue();
195  const float wet1 = wetGain1.getNextValue();
196 
197  samples[i] = output * wet1 + samples[i] * dry;
198  }
199  }
200 
201 private:
202  //==============================================================================
203  static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; }
204 
205  void updateDamping() noexcept
206  {
207  const float roomScaleFactor = 0.28f;
208  const float roomOffset = 0.7f;
209  const float dampScaleFactor = 0.4f;
210 
211  if (isFrozen (parameters.freezeMode))
212  setDamping (0.0f, 1.0f);
213  else
214  setDamping (parameters.damping * dampScaleFactor,
215  parameters.roomSize * roomScaleFactor + roomOffset);
216  }
217 
218  void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept
219  {
220  damping.setValue (dampingToUse);
221  feedback.setValue (roomSizeToUse);
222  }
223 
224  //==============================================================================
225  class CombFilter
226  {
227  public:
228  CombFilter() noexcept : bufferSize (0), bufferIndex (0), last (0) {}
229 
230  void setSize (const int size)
231  {
232  if (size != bufferSize)
233  {
234  bufferIndex = 0;
235  buffer.malloc ((size_t) size);
236  bufferSize = size;
237  }
238 
239  clear();
240  }
241 
242  void clear() noexcept
243  {
244  last = 0;
245  buffer.clear ((size_t) bufferSize);
246  }
247 
248  float process (const float input, const float damp, const float feedbackLevel) noexcept
249  {
250  const float output = buffer[bufferIndex];
251  last = (output * (1.0f - damp)) + (last * damp);
252  JUCE_UNDENORMALISE (last);
253 
254  float temp = input + (last * feedbackLevel);
255  JUCE_UNDENORMALISE (temp);
256  buffer[bufferIndex] = temp;
257  bufferIndex = (bufferIndex + 1) % bufferSize;
258  return output;
259  }
260 
261  private:
263  int bufferSize, bufferIndex;
264  float last;
265 
266  JUCE_DECLARE_NON_COPYABLE (CombFilter)
267  };
268 
269  //==============================================================================
270  class AllPassFilter
271  {
272  public:
273  AllPassFilter() noexcept : bufferSize (0), bufferIndex (0) {}
274 
275  void setSize (const int size)
276  {
277  if (size != bufferSize)
278  {
279  bufferIndex = 0;
280  buffer.malloc ((size_t) size);
281  bufferSize = size;
282  }
283 
284  clear();
285  }
286 
287  void clear() noexcept
288  {
289  buffer.clear ((size_t) bufferSize);
290  }
291 
292  float process (const float input) noexcept
293  {
294  const float bufferedValue = buffer [bufferIndex];
295  float temp = input + (bufferedValue * 0.5f);
296  JUCE_UNDENORMALISE (temp);
297  buffer [bufferIndex] = temp;
298  bufferIndex = (bufferIndex + 1) % bufferSize;
299  return bufferedValue - input;
300  }
301 
302  private:
304  int bufferSize, bufferIndex;
305 
306  JUCE_DECLARE_NON_COPYABLE (AllPassFilter)
307  };
308 
309  //==============================================================================
310  class LinearSmoothedValue
311  {
312  public:
313  LinearSmoothedValue() noexcept
314  : currentValue (0), target (0), step (0), countdown (0), stepsToTarget (0)
315  {
316  }
317 
318  void reset (double sampleRate, double fadeLengthSeconds) noexcept
319  {
320  jassert (sampleRate > 0 && fadeLengthSeconds >= 0);
321  stepsToTarget = (int) std::floor (fadeLengthSeconds * sampleRate);
322  currentValue = target;
323  countdown = 0;
324  }
325 
326  void setValue (float newValue) noexcept
327  {
328  if (target != newValue)
329  {
330  target = newValue;
331  countdown = stepsToTarget;
332 
333  if (countdown <= 0)
334  currentValue = target;
335  else
336  step = (target - currentValue) / (float) countdown;
337  }
338  }
339 
340  float getNextValue() noexcept
341  {
342  if (countdown <= 0)
343  return target;
344 
345  --countdown;
346  currentValue += step;
347  return currentValue;
348  }
349 
350  private:
351  float currentValue, target, step;
352  int countdown, stepsToTarget;
353 
354  JUCE_DECLARE_NON_COPYABLE (LinearSmoothedValue)
355  };
356 
357  //==============================================================================
358  enum { numCombs = 8, numAllPasses = 4, numChannels = 2 };
359 
360  Parameters parameters;
361  float gain;
362 
363  CombFilter comb [numChannels][numCombs];
364  AllPassFilter allPass [numChannels][numAllPasses];
365 
366  LinearSmoothedValue damping, feedback, dryGain, wetGain1, wetGain2;
367 
369 };
370 
371 
372 #endif // JUCE_REVERB_H_INCLUDED
float freezeMode
Definition: juce_Reverb.h:67
float damping
Definition: juce_Reverb.h:63
Reverb()
Definition: juce_Reverb.h:43
void processMono(float *const samples, const int numSamples) noexcept
Definition: juce_Reverb.h:176
#define noexcept
Definition: juce_CompilerSupport.h:141
Parameters() noexcept
Definition: juce_Reverb.h:53
void processStereo(float *const left, float *const right, const int numSamples) noexcept
Definition: juce_Reverb.h:142
#define JUCE_UNDENORMALISE(x)
#define const
JOCTET * buffer
Definition: juce_JPEGLoader.cpp:302
float roomSize
Definition: juce_Reverb.h:62
Definition: juce_Reverb.h:39
float width
Definition: juce_Reverb.h:66
void setParameters(const Parameters &newParams)
Definition: juce_Reverb.h:79
void reset()
Definition: juce_Reverb.h:128
#define jassert(a)
Definition: juce_PlatformDefs.h:146
float wetLevel
Definition: juce_Reverb.h:64
#define JUCE_DECLARE_NON_COPYABLE(className)
Definition: juce_PlatformDefs.h:191
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
Definition: juce_PlatformDefs.h:198
Definition: juce_HeapBlock.h:90
Definition: juce_Reverb.h:51
const Parameters & getParameters() const noexcept
Definition: juce_Reverb.h:73
void setSampleRate(const double sampleRate)
Definition: juce_Reverb.h:98
float dryLevel
Definition: juce_Reverb.h:65