Files
NeuralSynth/Source/AudioEngine.h
2025-10-22 16:57:19 +00:00

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);
}
};