Here is the code, all except my first variable, is taken directly from the DSP Tutorial;
//==============================================================================
template <typename Type>
class CustomOscillator
{
public:
//==============================================================================
CustomOscillator() {
auto& osc = processorChain.template get<oscIndex>(); // [5]
osc.initialise ([] (Type x) { return std::sin (x); }, OscillatorResolution); // [6]
}
//==============================================================================
void setFrequency (Type newValue, bool force = false)
{
auto& osc = processorChain.template get<oscIndex>();
osc.setFrequency (newValue, force); // [7]
}
//==============================================================================
void setLevel (Type newValue)
{
auto& gain = processorChain.template get<gainIndex>();
gain.setGainLinear (newValue); // [8]
}
//==============================================================================
void reset() noexcept {
processorChain.reset(); // [4]
}
//==============================================================================
template <typename ProcessContext>
void process (const ProcessContext& context) noexcept
{
processorChain.process (context); // [9]
}
//==============================================================================
void prepare (const juce::dsp::ProcessSpec& spec)
{
processorChain.prepare (spec); // [3]
}
private:
//==============================================================================
enum
{
oscIndex,
gainIndex
}; // [2]
juce::dsp::ProcessorChain<juce::dsp::Oscillator<Type>, juce::dsp::Gain<Type>> processorChain; // [1]
};
//==============================================================================
class Voice : public juce::MPESynthesiserVoice
{
public:
Voice()
{
auto& masterGain = processorChain.get<masterGainIndex>();
masterGain.setGainLinear (0.7f);
}
//==============================================================================
void prepare (const juce::dsp::ProcessSpec& spec)
{
tempBlock = juce::dsp::AudioBlock<float> (heapBlock, spec.numChannels, spec.maximumBlockSize);
processorChain.prepare (spec);
}
//==============================================================================
void noteStarted() override
{
auto velocity = getCurrentlyPlayingNote().noteOnVelocity.asUnsignedFloat();
auto freqHz = (float) getCurrentlyPlayingNote().getFrequencyInHertz();
processorChain.get<osc1Index>().setFrequency (freqHz, true);
processorChain.get<osc1Index>().setLevel (velocity);
}
//==============================================================================
void notePitchbendChanged() override
{
auto freqHz = (float) getCurrentlyPlayingNote().getFrequencyInHertz();
processorChain.get<osc1Index>().setFrequency (freqHz);
}
//==============================================================================
void noteStopped (bool) override
{
clearCurrentNote();
}
//==============================================================================
void notePressureChanged() override {}
void noteTimbreChanged() override {}
void noteKeyStateChanged() override {}
//==============================================================================
void renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override
{
auto block = tempBlock.getSubBlock (0, (size_t) numSamples);
block.clear();
juce::dsp::ProcessContextReplacing<float> context (block);
processorChain.process (context);
juce::dsp::AudioBlock<float> (outputBuffer)
.getSubBlock ((size_t) startSample, (size_t) numSamples)
.add (tempBlock);
}
private:
//==============================================================================
juce::HeapBlock<char> heapBlock;
juce::dsp::AudioBlock<float> tempBlock;
enum
{
osc1Index,
masterGainIndex
};
juce::dsp::ProcessorChain<CustomOscillator<float>, juce::dsp::Gain<float>> processorChain;
static constexpr size_t lfoUpdateRate = 100;
};
//==============================================================================
class AudioEngine : public juce::MPESynthesiser
{
public:
static constexpr auto maxNumVoices = 64;
//==============================================================================
AudioEngine()
{
for (auto i = 0; i < maxNumVoices; ++i)
addVoice (new Voice);
setVoiceStealingEnabled (true);
}
//==============================================================================
void prepare (const juce::dsp::ProcessSpec& spec) noexcept
{
setCurrentPlaybackSampleRate (spec.sampleRate);
for (auto* v : voices)
dynamic_cast<Voice*> (v)->prepare (spec);
}
private:
//==============================================================================
void renderNextSubBlock (AudioBuffer<float>& outputAudio, int startSample, int numSamples) override
{
MPESynthesiser::renderNextSubBlock (outputAudio, startSample, numSamples);
}
};
//==============================================================================
template <typename SampleType>
class AudioBufferQueue
{
public:
//==============================================================================
static constexpr size_t order = 9;
static constexpr size_t bufferSize = 1U << order;
static constexpr size_t numBuffers = 5;
//==============================================================================
void push (const SampleType* dataToPush, size_t numSamples)
{
jassert (numSamples <= bufferSize);
int start1, size1, start2, size2;
abstractFifo.prepareToWrite (1, start1, size1, start2, size2);
jassert (size1 <= 1);
jassert (size2 == 0);
if (size1 > 0)
FloatVectorOperations::copy (buffers[(size_t) start1].data(), dataToPush, (int) jmin (bufferSize, numSamples));
abstractFifo.finishedWrite (size1);
}
//==============================================================================
void pop (SampleType* outputBuffer)
{
int start1, size1, start2, size2;
abstractFifo.prepareToRead (1, start1, size1, start2, size2);
jassert (size1 <= 1);
jassert (size2 == 0);
if (size1 > 0)
FloatVectorOperations::copy (outputBuffer, buffers[(size_t) start1].data(), (int) bufferSize);
abstractFifo.finishedRead (size1);
}
private:
//==============================================================================
AbstractFifo abstractFifo { numBuffers };
std::array<std::array<SampleType, bufferSize>, numBuffers> buffers;
};