OpenShot Audio Library | OpenShotAudio  0.3.1
juce_Oscillator.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  By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11  Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12  27th April 2017).
13 
14  End User License Agreement: www.juce.com/juce-5-licence
15  Privacy Policy: www.juce.com/juce-5-privacy-policy
16 
17  Or: You may also use this code under the terms of the GPL v3 (see
18  www.gnu.org/licenses).
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 namespace dsp
30 {
31 
37 template <typename SampleType>
39 {
40 public:
44  using NumericType = typename SampleTypeHelpers::ElementType<SampleType>::Type;
45 
47  Oscillator() = default;
48 
54  Oscillator (const std::function<NumericType(NumericType)>& function,
55  size_t lookupTableNumPoints = 0)
56  {
57  initialise (function, lookupTableNumPoints);
58  }
59 
61  bool isInitialised() const noexcept { return static_cast<bool> (generator); }
62 
64  void initialise (const std::function<NumericType(NumericType)>& function,
65  size_t lookupTableNumPoints = 0)
66  {
67  if (lookupTableNumPoints != 0)
68  {
69  auto* table = new LookupTableTransform<NumericType> (function,
72  lookupTableNumPoints);
73 
74  lookupTable.reset (table);
75  generator = [table] (NumericType x) { return (*table) (x); };
76  }
77  else
78  {
79  generator = function;
80  }
81  }
82 
83  //==============================================================================
85  void setFrequency (NumericType newFrequency, bool force = false) noexcept
86  {
87  if (force)
88  {
89  frequency.setCurrentAndTargetValue (newFrequency);
90  return;
91  }
92 
93  frequency.setTargetValue (newFrequency);
94  }
95 
97  NumericType getFrequency() const noexcept { return frequency.getTargetValue(); }
98 
99  //==============================================================================
101  void prepare (const ProcessSpec& spec) noexcept
102  {
103  sampleRate = static_cast<NumericType> (spec.sampleRate);
104  rampBuffer.resize ((int) spec.maximumBlockSize);
105 
106  reset();
107  }
108 
110  void reset() noexcept
111  {
112  phase.reset();
113 
114  if (sampleRate > 0)
115  frequency.reset (sampleRate, 0.05);
116  }
117 
118  //==============================================================================
120  SampleType JUCE_VECTOR_CALLTYPE processSample (SampleType input) noexcept
121  {
122  jassert (isInitialised());
123  auto increment = MathConstants<NumericType>::twoPi * frequency.getNextValue() / sampleRate;
124  return input + generator (phase.advance (increment) - MathConstants<NumericType>::pi);
125  }
126 
128  template <typename ProcessContext>
129  void process (const ProcessContext& context) noexcept
130  {
131  jassert (isInitialised());
132  auto&& outBlock = context.getOutputBlock();
133  auto&& inBlock = context.getInputBlock();
134 
135  // this is an output-only processor
136  jassert (outBlock.getNumSamples() <= static_cast<size_t> (rampBuffer.size()));
137 
138  auto len = outBlock.getNumSamples();
139  auto numChannels = outBlock.getNumChannels();
140  auto inputChannels = inBlock.getNumChannels();
141  auto baseIncrement = MathConstants<NumericType>::twoPi / sampleRate;
142 
143  if (context.isBypassed)
144  context.getOutputBlock().clear();
145 
146  if (frequency.isSmoothing())
147  {
148  auto* buffer = rampBuffer.getRawDataPointer();
149 
150  for (size_t i = 0; i < len; ++i)
151  buffer[i] = phase.advance (baseIncrement * frequency.getNextValue())
153 
154  if (! context.isBypassed)
155  {
156  size_t ch;
157 
158  if (context.usesSeparateInputAndOutputBlocks())
159  {
160  for (ch = 0; ch < jmin (numChannels, inputChannels); ++ch)
161  {
162  auto* dst = outBlock.getChannelPointer (ch);
163  auto* src = inBlock.getChannelPointer (ch);
164 
165  for (size_t i = 0; i < len; ++i)
166  dst[i] = src[i] + generator (buffer[i]);
167  }
168  }
169  else
170  {
171  for (ch = 0; ch < jmin (numChannels, inputChannels); ++ch)
172  {
173  auto* dst = outBlock.getChannelPointer (ch);
174 
175  for (size_t i = 0; i < len; ++i)
176  dst[i] += generator (buffer[i]);
177  }
178  }
179 
180  for (; ch < numChannels; ++ch)
181  {
182  auto* dst = outBlock.getChannelPointer (ch);
183 
184  for (size_t i = 0; i < len; ++i)
185  dst[i] = generator (buffer[i]);
186  }
187  }
188  }
189  else
190  {
191  auto freq = baseIncrement * frequency.getNextValue();
192  auto p = phase;
193 
194  if (context.isBypassed)
195  {
196  frequency.skip (static_cast<int> (len));
197  p.advance (freq * static_cast<NumericType> (len));
198  }
199  else
200  {
201  size_t ch;
202 
203  if (context.usesSeparateInputAndOutputBlocks())
204  {
205  for (ch = 0; ch < jmin (numChannels, inputChannels); ++ch)
206  {
207  p = phase;
208  auto* dst = outBlock.getChannelPointer (ch);
209  auto* src = inBlock.getChannelPointer (ch);
210 
211  for (size_t i = 0; i < len; ++i)
212  dst[i] = src[i] + generator (p.advance (freq) - MathConstants<NumericType>::pi);
213  }
214  }
215  else
216  {
217  for (ch = 0; ch < jmin (numChannels, inputChannels); ++ch)
218  {
219  p = phase;
220  auto* dst = outBlock.getChannelPointer (ch);
221 
222  for (size_t i = 0; i < len; ++i)
223  dst[i] += generator (p.advance (freq) - MathConstants<NumericType>::pi);
224  }
225  }
226 
227  for (; ch < numChannels; ++ch)
228  {
229  p = phase;
230  auto* dst = outBlock.getChannelPointer (ch);
231 
232  for (size_t i = 0; i < len; ++i)
233  dst[i] = generator (p.advance (freq) - MathConstants<NumericType>::pi);
234  }
235  }
236 
237  phase = p;
238  }
239  }
240 
241 private:
242  //==============================================================================
243  std::function<NumericType(NumericType)> generator;
244  std::unique_ptr<LookupTableTransform<NumericType>> lookupTable;
245  Array<NumericType> rampBuffer;
246  SmoothedValue<NumericType> frequency { static_cast<NumericType> (440.0) };
247  NumericType sampleRate = 48000.0;
248  Phase<NumericType> phase;
249 };
250 
251 } // namespace dsp
252 } // namespace juce
int size() const noexcept
Definition: juce_Array.h:215
ElementType * getRawDataPointer() noexcept
Definition: juce_Array.h:310
void resize(int targetNumItems)
Definition: juce_Array.h:670
bool isSmoothing() const noexcept
void setCurrentAndTargetValue(FloatType newValue)
FloatType getTargetValue() const noexcept
FloatType skip(int numSamples) noexcept
FloatType getNextValue() noexcept
void reset(double sampleRate, double rampLengthInSeconds) noexcept
void setTargetValue(FloatType newValue) noexcept
SampleType JUCE_VECTOR_CALLTYPE processSample(SampleType input) noexcept
Oscillator(const std::function< NumericType(NumericType)> &function, size_t lookupTableNumPoints=0)
void prepare(const ProcessSpec &spec) noexcept
bool isInitialised() const noexcept
typename SampleTypeHelpers::ElementType< SampleType >::Type NumericType
void reset() noexcept
NumericType getFrequency() const noexcept
void process(const ProcessContext &context) noexcept
void setFrequency(NumericType newFrequency, bool force=false) noexcept
void initialise(const std::function< NumericType(NumericType)> &function, size_t lookupTableNumPoints=0)
void reset() noexcept
Definition: juce_Phase.h:44
Type advance(Type increment) noexcept
Definition: juce_Phase.h:50