G2.1: save full instrument state to disk (path/type/preset/transport)

This commit is contained in:
2026-08-16 07:28:17 +07:00
parent 8d9011222a
commit 28441566c2
9 changed files with 212 additions and 2 deletions
@@ -3,6 +3,7 @@
#define NATIVE_INSTRUMENT_ENGINE_H
#include "INativeInstrument.h"
#include "StateStore.h"
#include <sfizz.hpp>
@@ -31,6 +32,9 @@ public:
void pitchBend(uint32_t channel, uint32_t bend14) override;
bool openGUI(void* parentWindowHandle) override;
void closeGUI() override;
// G2.1: expose last bank/program for the state snapshot.
uint32_t bankOf(uint32_t channel) const override;
uint32_t programOf(uint32_t channel) const override;
void processAudioBlock(float* outputL, float* outputR, uint32_t numSamples) override;
private:
@@ -40,6 +44,7 @@ private:
// Per-channel bank select (CC0<<7 | CC32) — programChange phai dung bank
// that (truoc day hardcode bank 0 -> preset o bank != 0 khong chon duoc).
uint32_t bank_[16];
uint32_t program_[16];
};
// sfizz (.sfz)
@@ -97,6 +102,14 @@ public:
// case-insensitive — caller must lowercase before comparing.
std::string pathOf(uint32_t channel);
// G2.1: copy every assigned channel into a state snapshot (channel,
// type, path, VST3 preset blob -> base64, SF2/SF3 bank/program).
// MUST run on the channel worker (captureState enters the plugin);
// takes mu_ for the whole call so the audio loop cannot be inside
// process() on the same instance while its state is captured.
// Channels mid-reload are skipped (their old instance is dying).
bool snapshot(BridgeStateSnapshot& out);
// Mark a channel as rebuilding its VST instance (GUI reopen): the
// real-time loop then skips processAudioBlock for that channel so VST
// teardown never races the audio thread.
@@ -128,6 +141,7 @@ private:
mutable std::mutex mu_;
std::map<uint32_t, std::unique_ptr<INativeInstrument>> channels_;
std::map<uint32_t, std::string> paths_; // last assigned path per channel
std::map<uint32_t, InstrumentType> types_; // last assigned type per channel (G2.1)
// Per-instrument scratch so engines that overwrite (not mix) stay additive.
std::vector<float> scratchL_, scratchR_;
// Channel-level reload flag (see isReloading) — indexed by MIDI channel.