80 lines
2.7 KiB
C++
80 lines
2.7 KiB
C++
#pragma once
|
|
|
|
#include <JuceHeader.h>
|
|
#include "SynthVoice.h"
|
|
|
|
//==============================================================================
|
|
// MPESynthesiser wrapper that owns voices, installs a catch-all Sound,
|
|
// forwards prepare() to each voice, and renders MIDI blocks.
|
|
class NeuralAudioEngine : public juce::MPESynthesiser
|
|
{
|
|
public:
|
|
static constexpr int maxNumVoices = 8;
|
|
|
|
explicit NeuralAudioEngine (NeuralSharedParams& sp)
|
|
{
|
|
// Call Synthesiser base API explicitly via a base pointer (portable on MSVC).
|
|
auto* base = static_cast<juce::Synthesiser*>(this);
|
|
base->clearVoices();
|
|
base->clearSounds();
|
|
|
|
// Create voices (MPESynthesiser takes ownership)
|
|
for (int i = 0; i < maxNumVoices; ++i)
|
|
addVoice (new NeuralSynthVoice (sp));
|
|
|
|
// Catch-all Sound so any MIDI note/channel is accepted.
|
|
struct AnySound final : public juce::SynthesiserSound
|
|
{
|
|
bool appliesToNote (int) override { return true; }
|
|
bool appliesToChannel (int) override { return true; }
|
|
};
|
|
// Use raw pointer for this JUCE API on your version.
|
|
base->addSound (new AnySound());
|
|
|
|
// Respond to standard MIDI in non-MPE hosts
|
|
enableLegacyMode();
|
|
|
|
setVoiceStealingEnabled (true);
|
|
}
|
|
|
|
// Called from processor::prepareToPlay()
|
|
void prepare (const juce::dsp::ProcessSpec& spec) noexcept
|
|
{
|
|
setCurrentPlaybackSampleRate (spec.sampleRate);
|
|
|
|
for (auto* v : voices)
|
|
if (auto* nv = dynamic_cast<NeuralSynthVoice*> (v))
|
|
nv->prepare (spec);
|
|
}
|
|
|
|
// Forward the MIDI-buffer overload so MIDI is consumed.
|
|
void renderNextBlock (juce::AudioBuffer<float>& outputAudio,
|
|
juce::MidiBuffer& midiMessages,
|
|
int startSample,
|
|
int numSamples)
|
|
{
|
|
juce::MPESynthesiser::renderNextBlock (outputAudio, midiMessages,
|
|
startSample, numSamples);
|
|
}
|
|
|
|
// Utility: apply a lambda to all voices
|
|
template <typename VoiceFunc>
|
|
void applyToVoices (VoiceFunc&& fn) noexcept
|
|
{
|
|
for (auto* v : voices)
|
|
if (auto* nv = dynamic_cast<NeuralSynthVoice*> (v))
|
|
fn (nv);
|
|
}
|
|
|
|
private:
|
|
// Keep base rendering behaviour for the sub-block overload.
|
|
using juce::MPESynthesiser::renderNextSubBlock;
|
|
|
|
void renderNextSubBlock (juce::AudioBuffer<float>& buffer,
|
|
int startSample,
|
|
int numSamples) override
|
|
{
|
|
juce::MPESynthesiser::renderNextSubBlock (buffer, startSample, numSamples);
|
|
}
|
|
};
|