G2.3: auto-reload instruments from state file after bridge respawn

This commit is contained in:
2026-08-16 07:33:14 +07:00
parent 28441566c2
commit 4faa5a3504
7 changed files with 130 additions and 1 deletions
+57
View File
@@ -1045,6 +1045,63 @@ int main(int argc, char* argv[]) {
else
std::cerr << "[NativeBridge] state save FAILED: " << stateFile << std::endl;
};
// G2.3: auto-reload instruments from the state file after a respawn.
// Runs before the audio loop: read the file once, post one LOAD job per
// saved channel to the UiThread (assign + preset restore), then resume
// transport if the session was PLAYing. Only restores channels that are
// empty (the frontend may already have loaded some by the time the state
// file becomes visible). All jobs serialize on g_loadMutex; file IO here
// is startup-only, never in the audio loop.
{
BridgeStateSnapshot snap;
if (StateStore::load(snap, stateFile)) {
std::cout << "[NativeBridge] restoring " << snap.instruments.size()
<< " instruments from " << stateFile << std::endl;
for (const auto& e : snap.instruments) {
uint32_t ch = e.channel & 0xF;
if (e.path.empty() || instruments.get(ch)) continue; // guard: empty channel only
InstrumentType t = (InstrumentType)e.type;
std::string path = e.path;
std::string preset = e.presetBase64;
uint32_t bank = e.bank, program = e.program;
uiWorker.post([&instruments, t, ch, path, preset, bank, program, sampleRate, block]() {
std::lock_guard<std::mutex> lg(g_loadMutex);
bool ok = false;
try {
ok = instruments.assign(ch, t, path, sampleRate, block);
} catch (...) {
std::cerr << "[NativeBridge] restore assign EXCEPTION ch=" << ch
<< " type=" << (int)t << " path=" << path << std::endl;
ok = false;
}
if (ok) {
if (auto* inst = instruments.get(ch)) {
if (t == InstrumentType::VST3 && !preset.empty())
inst->loadSerializedState(preset);
else
inst->selectProgram(ch, bank, program);
}
std::cout << "[NativeBridge] restored ch=" << ch
<< " type=" << (int)t << " " << path << std::endl;
} else {
std::cerr << "[NativeBridge] restore FAILED ch=" << ch
<< " type=" << (int)t << " " << path << std::endl;
}
});
}
if (snap.playing) {
playheadSamples = (uint64_t)snap.playhead;
transportStopped = false;
g_transportPlaying = true;
g_stateDirty = true;
std::cout << "[NativeBridge] restoring transport PLAY playhead="
<< playheadSamples.load() << std::endl;
}
} else {
std::cout << "[NativeBridge] no state file to restore (" << stateFile << ")" << std::endl;
}
}
// 2. REAL-TIME AUDIO PROCESSING ENGINE LOOP
while (true) {