OpenShot Audio Library | OpenShotAudio  0.6.0
juce_ADSR.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 
23 namespace juce
24 {
25 
26 //==============================================================================
40 class JUCE_API ADSR
41 {
42 public:
43  //==============================================================================
44  ADSR()
45  {
46  recalculateRates();
47  }
48 
49  //==============================================================================
55  struct JUCE_API Parameters
56  {
57  Parameters() = default;
58 
59  Parameters (float attackTimeSeconds,
60  float decayTimeSeconds,
61  float sustainLevel,
62  float releaseTimeSeconds)
63  : attack (attackTimeSeconds),
64  decay (decayTimeSeconds),
65  sustain (sustainLevel),
66  release (releaseTimeSeconds)
67  {
68  }
69 
70  float attack = 0.1f, decay = 0.1f, sustain = 1.0f, release = 0.1f;
71  };
72 
80  void setParameters (const Parameters& newParameters)
81  {
82  // need to call setSampleRate() first!
83  jassert (sampleRate > 0.0);
84 
85  parameters = newParameters;
86  recalculateRates();
87  }
88 
93  const Parameters& getParameters() const noexcept { return parameters; }
94 
96  bool isActive() const noexcept { return state != State::idle; }
97 
98  //==============================================================================
103  void setSampleRate (double newSampleRate) noexcept
104  {
105  jassert (newSampleRate > 0.0);
106  sampleRate = newSampleRate;
107  }
108 
109  //==============================================================================
111  void reset() noexcept
112  {
113  envelopeVal = 0.0f;
114  state = State::idle;
115  }
116 
118  void noteOn() noexcept
119  {
120  if (attackRate > 0.0f)
121  {
122  state = State::attack;
123  }
124  else if (decayRate > 0.0f)
125  {
126  envelopeVal = 1.0f;
127  state = State::decay;
128  }
129  else
130  {
131  envelopeVal = parameters.sustain;
132  state = State::sustain;
133  }
134  }
135 
137  void noteOff() noexcept
138  {
139  if (state != State::idle)
140  {
141  if (parameters.release > 0.0f)
142  {
143  releaseRate = (float) (envelopeVal / (parameters.release * sampleRate));
144  state = State::release;
145  }
146  else
147  {
148  reset();
149  }
150  }
151  }
152 
153  //==============================================================================
158  float getNextSample() noexcept
159  {
160  switch (state)
161  {
162  case State::idle:
163  {
164  return 0.0f;
165  }
166 
167  case State::attack:
168  {
169  envelopeVal += attackRate;
170 
171  if (envelopeVal >= 1.0f)
172  {
173  envelopeVal = 1.0f;
174  goToNextState();
175  }
176 
177  break;
178  }
179 
180  case State::decay:
181  {
182  envelopeVal -= decayRate;
183 
184  if (envelopeVal <= parameters.sustain)
185  {
186  envelopeVal = parameters.sustain;
187  goToNextState();
188  }
189 
190  break;
191  }
192 
193  case State::sustain:
194  {
195  envelopeVal = parameters.sustain;
196  break;
197  }
198 
199  case State::release:
200  {
201  envelopeVal -= releaseRate;
202 
203  if (envelopeVal <= 0.0f)
204  goToNextState();
205 
206  break;
207  }
208  }
209 
210  return envelopeVal;
211  }
212 
218  template <typename FloatType>
219  void applyEnvelopeToBuffer (AudioBuffer<FloatType>& buffer, int startSample, int numSamples)
220  {
221  jassert (startSample + numSamples <= buffer.getNumSamples());
222 
223  if (state == State::idle)
224  {
225  buffer.clear (startSample, numSamples);
226  return;
227  }
228 
229  if (state == State::sustain)
230  {
231  buffer.applyGain (startSample, numSamples, parameters.sustain);
232  return;
233  }
234 
235  auto numChannels = buffer.getNumChannels();
236 
237  while (--numSamples >= 0)
238  {
239  auto env = getNextSample();
240 
241  for (int i = 0; i < numChannels; ++i)
242  buffer.getWritePointer (i)[startSample] *= env;
243 
244  ++startSample;
245  }
246  }
247 
248 private:
249  //==============================================================================
250  void recalculateRates() noexcept
251  {
252  auto getRate = [] (float distance, float timeInSeconds, double sr)
253  {
254  return timeInSeconds > 0.0f ? (float) (distance / (timeInSeconds * sr)) : -1.0f;
255  };
256 
257  attackRate = getRate (1.0f, parameters.attack, sampleRate);
258  decayRate = getRate (1.0f - parameters.sustain, parameters.decay, sampleRate);
259  releaseRate = getRate (parameters.sustain, parameters.release, sampleRate);
260 
261  if ((state == State::attack && attackRate <= 0.0f)
262  || (state == State::decay && (decayRate <= 0.0f || envelopeVal <= parameters.sustain))
263  || (state == State::release && releaseRate <= 0.0f))
264  {
265  goToNextState();
266  }
267  }
268 
269  void goToNextState() noexcept
270  {
271  if (state == State::attack)
272  {
273  state = (decayRate > 0.0f ? State::decay : State::sustain);
274  return;
275  }
276 
277  if (state == State::decay)
278  {
279  state = State::sustain;
280  return;
281  }
282 
283  if (state == State::release)
284  reset();
285  }
286 
287  //==============================================================================
288  enum class State { idle, attack, decay, sustain, release };
289 
290  State state = State::idle;
291  Parameters parameters;
292 
293  double sampleRate = 44100.0;
294  float envelopeVal = 0.0f, attackRate = 0.0f, decayRate = 0.0f, releaseRate = 0.0f;
295 };
296 
297 } // namespace juce
void setSampleRate(double newSampleRate) noexcept
Definition: juce_ADSR.h:103
void noteOff() noexcept
Definition: juce_ADSR.h:137
bool isActive() const noexcept
Definition: juce_ADSR.h:96
void reset() noexcept
Definition: juce_ADSR.h:111
float getNextSample() noexcept
Definition: juce_ADSR.h:158
void setParameters(const Parameters &newParameters)
Definition: juce_ADSR.h:80
const Parameters & getParameters() const noexcept
Definition: juce_ADSR.h:93
void noteOn() noexcept
Definition: juce_ADSR.h:118
void applyEnvelopeToBuffer(AudioBuffer< FloatType > &buffer, int startSample, int numSamples)
Definition: juce_ADSR.h:219
Type * getWritePointer(int channelNumber) noexcept
int getNumChannels() const noexcept
int getNumSamples() const noexcept
void applyGain(int channel, int startSample, int numSamples, Type gain) noexcept