OpenShot Audio Library | OpenShotAudio  0.3.0
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,
71  MathConstants<NumericType>::pi,
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
FloatType getNextValue() noexcept
FloatType getTargetValue() const noexcept
void reset() noexcept
Definition: juce_Phase.h:44
typename SampleTypeHelpers::ElementType< SampleType >::Type NumericType
FloatType skip(int numSamples) noexcept
void reset(double sampleRate, double rampLengthInSeconds) noexcept
void setFrequency(NumericType newFrequency, bool force=false) noexcept
bool isSmoothing() const noexcept
void resize(int targetNumItems)
Definition: juce_Array.h:670
bool isInitialised() const noexcept
Type advance(Type increment) noexcept
Definition: juce_Phase.h:50
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
int size() const noexcept
Definition: juce_Array.h:215
void reset() noexcept
ElementType * getRawDataPointer() noexcept
Definition: juce_Array.h:310
void setTargetValue(FloatType newValue) noexcept
NumericType getFrequency() const noexcept
void setCurrentAndTargetValue(FloatType newValue)
void process(const ProcessContext &context) noexcept
void initialise(const std::function< NumericType(NumericType)> &function, size_t lookupTableNumPoints=0)