V45.2 fix Qin silence (20s audio-thread stall) + SF loop downbeat delay

- SandboxVst2Host::loadSerializedState: queuePreset non-blocking (byte-identical
  echo never matched -> waitApply always burned 20s TIMEOUT on the audio thread;
  VST2 restore runs via runOnMain so every startup silenced ALL audio ~20s = Qin
  'failed that su'). Bridge now holds reloading + defers saveStateJob until the
  child republishes a different chunk (clobber protection, no audio block).
- sf-fx-realtime clear_queue('loop'): truncate old tail to KEEP=4 blocks
  (~21ms) instead of keeping FILL 24 (~128ms) -> wrap downbeat no longer ~110ms
  late; skipFade crossfade masks the truncation jump, seam crossfade recount.
- bump ?v= 202608291721 (app.jsx x2, index.html x2); deploy 3 _internal + dist.
This commit is contained in:
2026-08-29 17:25:32 +07:00
parent 6b26d5db0e
commit f3fd0109a7
8 changed files with 56 additions and 9 deletions
+7 -1
View File
@@ -303,7 +303,13 @@ void SandboxVst2Host::loadSerializedState(const std::string& base64) {
if (base64.empty()) return;
lastPreset_ = base64; // keep for watchdog respawn re-queue
if (!alive_.load() || !ipc_) return;
queuePreset(base64, true); // wait for apply so early saves see the real chunk
// V45.2: non-blocking. The old byte-identical echo wait (memcmp presetOut==input)
// NEVER matched for Qin — the child republishes its own round-trip chunk (differs
// at byte 144) so waitApply always burned the full 20s TIMEOUT. VST2 restore runs
// on the audio thread (runOnMain), so every bridge startup stalled ALL audio 20s —
// the user's first play pressed in that window = silence. Bridge now holds
// reloading + defers saves until the child republishes (see main.cpp doRestore).
queuePreset(base64, false);
std::cerr << "[SandboxVst2Host] presetIn queued ch=" << channel_
<< " (" << base64.size() << "B)" << std::endl;
}