OpenShot Audio Library | OpenShotAudio  0.3.0
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 
23 namespace juce
24 {
25 
26 //==============================================================================
38 class Reverb
39 {
40 public:
41  //==============================================================================
42  Reverb()
43  {
45  setSampleRate (44100.0);
46  }
47 
48  //==============================================================================
50  struct Parameters
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 
69  void setParameters (const Parameters& newParams)
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 
191 private:
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 processStereo(float *const left, float *const right, const int numSamples) noexcept
const Parameters & getParameters() const noexcept
void setSampleRate(const double sampleRate)
void processMono(float *const samples, const int numSamples) noexcept
void setParameters(const Parameters &newParams)