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