From a63ef187562c057901a2e8425d91efccc8b62534 Mon Sep 17 00:00:00 2001 From: byrongamatos Date: Wed, 8 Jul 2026 22:07:21 +0200 Subject: [PATCH] audio: replaceIR updates slot name/path so getChainState reflects the swap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replaceProcessor deliberately preserves the target slot's name/path during the prepare/fault window (so a fault in prepareToPlay is blocklisted against the right plugin path). It kept them even on success, so after a successful replaceIR the slot's audio was the new IR but getChainState()/preset-save still reported the OLD IR name+path — a footgun for any consumer that persists a chain read back from getChainState(). Add optional newName/newPath to replaceProcessor, applied under the swap lock ONLY on success (empty = keep, so the sandbox-promotion caller is unchanged). ReplaceIRWorker passes "IR: " + the new path, mirroring LoadIRWorker. Built (npm run build:audio) clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/audio/NodeAddon.cpp | 5 ++++- src/audio/SignalChain.cpp | 8 +++++++- src/audio/SignalChain.h | 7 ++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/audio/NodeAddon.cpp b/src/audio/NodeAddon.cpp index bccb619..971554d 100644 --- a/src/audio/NodeAddon.cpp +++ b/src/audio/NodeAddon.cpp @@ -2499,7 +2499,10 @@ public: processor->prepareToPlay(sr, bs); if (! processor->loadIR(juce::File(juce::String(irPath_)))) { ok_ = false; return; } - ok_ = liveEngine->getSignalChain().replaceProcessor(slotId_, std::move(processor)); + auto name = processor->getIRName(); + ok_ = liveEngine->getSignalChain().replaceProcessor( + slotId_, std::move(processor), + "IR: " + name, juce::String(irPath_)); if (ok_ && gain_ >= 0.0f) liveEngine->getSignalChain().setPostGain(slotId_, gain_); } diff --git a/src/audio/SignalChain.cpp b/src/audio/SignalChain.cpp index 0a42e17..e152948 100644 --- a/src/audio/SignalChain.cpp +++ b/src/audio/SignalChain.cpp @@ -432,7 +432,8 @@ void SignalChain::removeProcessor(int slotId) if (idx >= 0) slots.remove(idx); } -bool SignalChain::replaceProcessor(int slotId, std::unique_ptr processor) +bool SignalChain::replaceProcessor(int slotId, std::unique_ptr processor, + const juce::String& newName, const juce::String& newPath) { if (!processor) return false; @@ -469,6 +470,11 @@ bool SignalChain::replaceProcessor(int slotId, std::unique_ptrprocessor); slot->processor = std::move(staging.processor); + // Swap succeeded: adopt the new identity so getChainState()/preset save + // report the swapped-in processor, not the one it replaced. Only when + // provided — the sandbox-promotion caller passes none and keeps identity. + if (newName.isNotEmpty()) slot->name = newName; + if (newPath.isNotEmpty()) slot->path = newPath; } // Tear the old processor down OUTSIDE the audio lock: releaseResources() (and // a VST3 destructor) can block, and must never stall process() on it. diff --git a/src/audio/SignalChain.h b/src/audio/SignalChain.h index 7495e4d..a3b7d55 100644 --- a/src/audio/SignalChain.h +++ b/src/audio/SignalChain.h @@ -63,7 +63,12 @@ public: // swaps under the audio lock; the old processor is torn down off the lock. // Returns false if the slot is gone or the incoming processor faulted in // prepareToPlay (in which case the existing processor is left untouched). - bool replaceProcessor(int slotId, std::unique_ptr processor); + // The OLD slot name/path are preserved during the prepare/fault window (so a + // fault is blocklisted against the right path); on SUCCESS, if newName/newPath + // are non-empty they replace the slot's identity so getChainState()/preset + // metadata reflect the swapped-in processor (used by replaceIR for cab swaps). + bool replaceProcessor(int slotId, std::unique_ptr processor, + const juce::String& newName = {}, const juce::String& newPath = {}); // Snapshot a slot's state for sandbox promotion, SAFELY. Runs hasEditor() // and getStateInformation() under the audio lock (so they can't race // process()'s processBlock on the same instance) and under the SEH/signal