Loading...
Searching...
No Matches
juce_Oscillator.h
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce::dsp
{
template <typename SampleType>
class Oscillator
{
public:
using NumericType = typename SampleTypeHelpers::ElementType<SampleType>::Type;
Oscillator() = default;
Oscillator (const std::function<NumericType (NumericType)>& function,
size_t lookupTableNumPoints = 0)
{
initialise (function, lookupTableNumPoints);
}
bool isInitialised() const noexcept { return static_cast<bool> (generator); }
void initialise (const std::function<NumericType (NumericType)>& function,
size_t lookupTableNumPoints = 0)
{
if (lookupTableNumPoints != 0)
{
auto* table = new LookupTableTransform<NumericType> (function,
-MathConstants<NumericType>::pi,
MathConstants<NumericType>::pi,
lookupTableNumPoints);
lookupTable.reset (table);
generator = [table] (NumericType x) { return (*table) (x); };
}
else
{
generator = function;
}
}
//==============================================================================
void setFrequency (NumericType newFrequency, bool force = false) noexcept
{
if (force)
{
frequency.setCurrentAndTargetValue (newFrequency);
return;
}
frequency.setTargetValue (newFrequency);
}
NumericType getFrequency() const noexcept { return frequency.getTargetValue(); }
//==============================================================================
void prepare (const ProcessSpec& spec) noexcept
{
sampleRate = static_cast<NumericType> (spec.sampleRate);
rampBuffer.resize ((int) spec.maximumBlockSize);
reset();
}
void reset() noexcept
{
phase.reset();
if (sampleRate > 0)
frequency.reset (sampleRate, 0.05);
}
//==============================================================================
SampleType JUCE_VECTOR_CALLTYPE processSample (SampleType input) noexcept
{
jassert (isInitialised());
auto increment = MathConstants<NumericType>::twoPi * frequency.getNextValue() / sampleRate;
return input + generator (phase.advance (increment) - MathConstants<NumericType>::pi);
}
template <typename ProcessContext>
void process (const ProcessContext& context) noexcept
{
jassert (isInitialised());
auto&& outBlock = context.getOutputBlock();
auto&& inBlock = context.getInputBlock();
// this is an output-only processor
jassert (outBlock.getNumSamples() <= static_cast<size_t> (rampBuffer.size()));
auto len = outBlock.getNumSamples();
auto numChannels = outBlock.getNumChannels();
auto inputChannels = inBlock.getNumChannels();
auto baseIncrement = MathConstants<NumericType>::twoPi / sampleRate;
if (context.isBypassed)
context.getOutputBlock().clear();
if (frequency.isSmoothing())
{
auto* buffer = rampBuffer.getRawDataPointer();
for (size_t i = 0; i < len; ++i)
buffer[i] = phase.advance (baseIncrement * frequency.getNextValue())
- MathConstants<NumericType>::pi;
if (! context.isBypassed)
{
size_t ch;
if (context.usesSeparateInputAndOutputBlocks())
{
for (ch = 0; ch < jmin (numChannels, inputChannels); ++ch)
{
auto* dst = outBlock.getChannelPointer (ch);
auto* src = inBlock.getChannelPointer (ch);
for (size_t i = 0; i < len; ++i)
dst[i] = src[i] + generator (buffer[i]);
}
}
else
{
for (ch = 0; ch < jmin (numChannels, inputChannels); ++ch)
{
auto* dst = outBlock.getChannelPointer (ch);
for (size_t i = 0; i < len; ++i)
dst[i] += generator (buffer[i]);
}
}
for (; ch < numChannels; ++ch)
{
auto* dst = outBlock.getChannelPointer (ch);
for (size_t i = 0; i < len; ++i)
dst[i] = generator (buffer[i]);
}
}
}
else
{
auto freq = baseIncrement * frequency.getNextValue();
auto p = phase;
if (context.isBypassed)
{
frequency.skip (static_cast<int> (len));
p.advance (freq * static_cast<NumericType> (len));
}
else
{
size_t ch;
if (context.usesSeparateInputAndOutputBlocks())
{
for (ch = 0; ch < jmin (numChannels, inputChannels); ++ch)
{
p = phase;
auto* dst = outBlock.getChannelPointer (ch);
auto* src = inBlock.getChannelPointer (ch);
for (size_t i = 0; i < len; ++i)
dst[i] = src[i] + generator (p.advance (freq) - MathConstants<NumericType>::pi);
}
}
else
{
for (ch = 0; ch < jmin (numChannels, inputChannels); ++ch)
{
p = phase;
auto* dst = outBlock.getChannelPointer (ch);
for (size_t i = 0; i < len; ++i)
dst[i] += generator (p.advance (freq) - MathConstants<NumericType>::pi);
}
}
for (; ch < numChannels; ++ch)
{
p = phase;
auto* dst = outBlock.getChannelPointer (ch);
for (size_t i = 0; i < len; ++i)
dst[i] = generator (p.advance (freq) - MathConstants<NumericType>::pi);
}
}
phase = p;
}
}
private:
//==============================================================================
std::function<NumericType (NumericType)> generator;
std::unique_ptr<LookupTableTransform<NumericType>> lookupTable;
Array<NumericType> rampBuffer;
SmoothedValue<NumericType> frequency { static_cast<NumericType> (440.0) };
NumericType sampleRate = 48000.0;
Phase<NumericType> phase;
};
} // namespace juce::dsp
juce::Array
Definition juce_Array.h:56
juce::SmoothedValue
Definition juce_SmoothedValue.h:227
juce::dsp::LookupTableTransform
Definition juce_LookupTable.h:173
juce::dsp::Oscillator::processSample
SampleType JUCE_VECTOR_CALLTYPE processSample(SampleType input) noexcept
Definition juce_Oscillator.h:117
juce::dsp::Oscillator::Oscillator
Oscillator(const std::function< NumericType(NumericType)> &function, size_t lookupTableNumPoints=0)
Definition juce_Oscillator.h:51
juce::dsp::Oscillator::Oscillator
Oscillator()=default
juce::dsp::Oscillator::prepare
void prepare(const ProcessSpec &spec) noexcept
Definition juce_Oscillator.h:98
juce::dsp::Oscillator::isInitialised
bool isInitialised() const noexcept
Definition juce_Oscillator.h:58
juce::dsp::Oscillator::NumericType
typename SampleTypeHelpers::ElementType< SampleType >::Type NumericType
Definition juce_Oscillator.h:41
juce::dsp::Oscillator::reset
void reset() noexcept
Definition juce_Oscillator.h:107
juce::dsp::Oscillator::getFrequency
NumericType getFrequency() const noexcept
Definition juce_Oscillator.h:94
juce::dsp::Oscillator::process
void process(const ProcessContext &context) noexcept
Definition juce_Oscillator.h:126
juce::dsp::Oscillator::setFrequency
void setFrequency(NumericType newFrequency, bool force=false) noexcept
Definition juce_Oscillator.h:82
juce::dsp::Oscillator::initialise
void initialise(const std::function< NumericType(NumericType)> &function, size_t lookupTableNumPoints=0)
Definition juce_Oscillator.h:61
juce::MathConstants::twoPi
static constexpr FloatType twoPi
Definition juce_MathsFunctions.h:144
juce::MathConstants::pi
static constexpr FloatType pi
Definition juce_MathsFunctions.h:141
juce::dsp::ProcessSpec
Definition juce_ProcessContext.h:36