// native_bridge/include/NativeInstrumentEngine.h #ifndef NATIVE_INSTRUMENT_ENGINE_H #define NATIVE_INSTRUMENT_ENGINE_H #include "INativeInstrument.h" #include #include #include #include #include // FluidSynth (.sf2 / .sf3) class FluidSynthInstrument : public INativeInstrument { public: FluidSynthInstrument(); ~FluidSynthInstrument() override; bool loadSoundFontFile(const std::string& path, double sampleRate); bool init(double sampleRate, uint32_t maxBlockSize) override; void selectProgram(uint32_t channel, uint32_t bank, uint32_t program) override; void noteOn(uint32_t channel, uint32_t pitch, float velocity, uint32_t sampleOffset) override; void noteOff(uint32_t channel, uint32_t pitch, uint32_t sampleOffset) override; void controlChange(uint32_t channel, uint32_t cc, uint32_t value) override; void programChange(uint32_t channel, uint32_t program) override; void pitchBend(uint32_t channel, uint32_t bend14) override; bool openGUI(void* parentWindowHandle) override; void closeGUI() override; void processAudioBlock(float* outputL, float* outputR, uint32_t numSamples) override; private: void* settings; // fluid_settings_t* void* synth; // fluid_synth_t* int sfontId; }; // sfizz (.sfz) class SfizzInstrument : public INativeInstrument { public: bool loadSfzFile(const std::string& path, double sampleRate); bool init(double sampleRate, uint32_t maxBlockSize) override; void selectProgram(uint32_t channel, uint32_t bank, uint32_t program) override; void noteOn(uint32_t channel, uint32_t pitch, float velocity, uint32_t sampleOffset) override; void noteOff(uint32_t channel, uint32_t pitch, uint32_t sampleOffset) override; void controlChange(uint32_t channel, uint32_t cc, uint32_t value) override; void programChange(uint32_t channel, uint32_t program) override; void pitchBend(uint32_t channel, uint32_t bend14) override; bool openGUI(void* parentWindowHandle) override; void closeGUI() override; void processAudioBlock(float* outputL, float* outputR, uint32_t numSamples) override; private: sfizz::Synth sfizzSynth; }; // Multi-instrument host (A10): one engine instance per MIDI channel, so two // tracks can play two different soundfonts/VSTs simultaneously. All channels // render into the same output block (mixed), keyed by evt.channel. class InstrumentEngineManager { public: // Create (or replace) the instrument on `channel` for `path`. // Returns false if the type is unsupported or the file fails to load. bool assign(uint32_t channel, InstrumentType type, const std::string& path, double sampleRate, uint32_t blockSize); INativeInstrument* get(uint32_t channel); // Flush every sounding note on every assigned channel. void allNotesOff(); // Zero L/R then sum each assigned instrument into it. void renderAll(float* outputL, float* outputR, uint32_t numSamples); size_t count() const { return channels_.size(); } private: static std::unique_ptr create_instrument(InstrumentType type); std::map> channels_; // Per-instrument scratch so engines that overwrite (not mix) stay additive. std::vector scratchL_, scratchR_; }; #endif // NATIVE_INSTRUMENT_ENGINE_H