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
+61
View File
@@ -587,6 +587,67 @@ std::string Vst3Instrument::serializeState() const {
#endif
}
// G2.3: base64 decode (RFC 4648). Empty / invalid -> false.
static int b64val(unsigned char c) {
if (c >= 'A' && c <= 'Z') return c - 'A';
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
if (c >= '0' && c <= '9') return c - '0' + 52;
if (c == '+') return 62;
if (c == '/') return 63;
return -1;
}
static bool base64Decode(const std::string& in, std::vector<uint8_t>& out) {
out.clear();
out.reserve((in.size() / 4) * 3);
uint32_t acc = 0;
int bits = 0;
for (unsigned char ch : in) {
if (ch == '=' || ch == '\n' || ch == '\r' || ch == ' ') continue;
int v = b64val(ch);
if (v < 0) return false;
acc = (acc << 6) | (uint32_t)v;
bits += 6;
if (bits >= 8) {
bits -= 8;
out.push_back((uint8_t)((acc >> bits) & 0xFF));
}
}
return true;
}
// G2.3: restore a preset previously saved by serializeState() (base64 of
// [4B BE componentLen][component][4B BE controllerLen][controller]).
// Decodes into the saved-state buffers and applies them to the live instance.
void Vst3Instrument::loadSerializedState(const std::string& base64) {
#ifndef HAVE_VST3SDK
(void)base64;
return;
#else
std::vector<uint8_t> blob;
if (!base64Decode(base64, blob) || blob.size() < 8) {
std::cerr << "[Vst3Instrument] loadSerializedState: bad base64 ch=" << channel_ << std::endl;
return;
}
auto read32 = [&blob](size_t off) -> uint32_t {
return ((uint32_t)blob[off] << 24) | ((uint32_t)blob[off + 1] << 16) |
((uint32_t)blob[off + 2] << 8) | (uint32_t)blob[off + 3];
};
size_t off = 0;
uint32_t clen = read32(off); off += 4;
if (off + clen > blob.size()) { std::cerr << "[Vst3Instrument] loadSerializedState: bad compLen" << std::endl; return; }
savedComponentState_.assign(blob.begin() + off, blob.begin() + off + clen);
off += clen;
if (off + 4 > blob.size()) { std::cerr << "[Vst3Instrument] loadSerializedState: bad ctrlLen" << std::endl; return; }
uint32_t klen = read32(off); off += 4;
if (off + klen > blob.size()) { std::cerr << "[Vst3Instrument] loadSerializedState: bad ctrlLen" << std::endl; return; }
savedControllerState_.assign(blob.begin() + off, blob.begin() + off + klen);
std::cout << "[Vst3Instrument] loaded serialized state ch=" << channel_
<< " component=" << savedComponentState_.size()
<< " controller=" << savedControllerState_.size() << std::endl;
restoreState();
#endif
}
// G0.4: restore the captured state onto the freshly loaded instance.
void Vst3Instrument::restoreState() {
#ifndef HAVE_VST3SDK