mirror of
https://github.com/got-feedBack/feedBack-desktop.git
synced 2026-08-10 18:59:55 +00:00
fix(audio): accept standard base64 for IR/NAM slot state (was silently dropped) (#88)
MemoryBlock::fromBase64Encoding only parses JUCE's proprietary
"<size>.<alphabet>" format and returns false on standard RFC-4648 base64 —
which is what the Python-side plugins (rig_builder) emit for per-slot state.
That silent false meant LoadPresetWorker/SetSlotState never called setState()
for those slots, so IR stages lost their per-stage `gain` (cab loudness makeup,
amp-trim impulse compensation) on every chain load.
Add decodeStateBlob(): JUCE format first (engine-native saves unchanged), then
a standard-base64 fallback via juce::Base64 — gated to IR/NAM slots only, whose
processors take exactly the JSON these states carry ({"irPath","gain"} /
{"modelPath",...}). VST slots keep the JUCE-only decode: their plugin-emitted
blobs are metadata wrappers, not real setStateInformation() chunks.
Co-authored-by: Jafz2001 <ignacio.fritis@mundotelecomunicaciones.cl>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Jafz2001
Claude Fable 5
parent
3e3f1f868c
commit
b2be91808c
+38
-3
@@ -54,6 +54,32 @@ static void cancelAllPendingLoads();
|
||||
static std::shared_ptr<AudioEngine> engine;
|
||||
static std::mutex engineMutex;
|
||||
|
||||
// Decode a state blob that may be in EITHER base64 flavour. JUCE's
|
||||
// MemoryBlock::fromBase64Encoding only understands JUCE's own proprietary
|
||||
// format ("<size>.<juce-alphabet>") and returns false for standard RFC-4648
|
||||
// base64 — which is what the Python-side plugins (rig_builder et al.) emit
|
||||
// for per-slot state. That silent false meant setState() was never called
|
||||
// for those slots: IR stages lost their per-stage `gain` (the cab loudness
|
||||
// makeup and amp trims never reached the engine). Try the JUCE format first
|
||||
// (engine-native saves), then fall back to standard b64.
|
||||
//
|
||||
// `allowStandard` is only set for IR/NAM slots: their processors take a JSON
|
||||
// state ({"irPath","gain"} / model path), which is exactly what the plugins
|
||||
// emit. VST slots keep the JUCE-only decode — their plugin-emitted blobs are
|
||||
// metadata wrappers, not real setStateInformation() chunks, and feeding those
|
||||
// to a VST3 for the first time would be an unasked-for behaviour change.
|
||||
static bool decodeStateBlob(const juce::String& s, juce::MemoryBlock& mb,
|
||||
bool allowStandard)
|
||||
{
|
||||
if (mb.fromBase64Encoding(s) && mb.getSize() > 0)
|
||||
return true;
|
||||
if (!allowStandard)
|
||||
return false;
|
||||
mb.reset();
|
||||
juce::MemoryOutputStream mo(mb, false);
|
||||
return juce::Base64::convertFromBase64(mo, s) && mb.getSize() > 0;
|
||||
}
|
||||
|
||||
static std::shared_ptr<AudioEngine> snapshotEngine()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(engineMutex);
|
||||
@@ -3079,8 +3105,12 @@ static Napi::Value SetSlotState(const Napi::CallbackInfo& info)
|
||||
{
|
||||
int slotId = info[0].As<Napi::Number>().Int32Value();
|
||||
auto base64 = info[1].As<Napi::String>().Utf8Value();
|
||||
const auto* slot = liveEngine->getSignalChain().getSlot(slotId);
|
||||
const bool allowStandard = slot != nullptr
|
||||
&& (slot->type == ProcessorSlot::Type::IR
|
||||
|| slot->type == ProcessorSlot::Type::NAM);
|
||||
juce::MemoryBlock mb;
|
||||
if (mb.fromBase64Encoding(juce::String(base64)) && mb.getSize() > 0)
|
||||
if (decodeStateBlob(juce::String(base64), mb, allowStandard))
|
||||
liveEngine->getSignalChain().setSlotState(slotId, mb);
|
||||
}
|
||||
return info.Env().Undefined();
|
||||
@@ -3305,11 +3335,16 @@ public:
|
||||
liveEngine->getSignalChain().setBranchSrc(slotId, (int)slotObj->getProperty("branchSrc"));
|
||||
}
|
||||
|
||||
// Restore processor state
|
||||
// Restore processor state (JUCE-format base64; IR/NAM slots also
|
||||
// accept standard base64 — see decodeStateBlob: their plugin-
|
||||
// emitted JSON states were silently dropped before, so IR stages
|
||||
// never got their per-stage gain).
|
||||
if (stateB64.isNotEmpty() && slotId >= 0)
|
||||
{
|
||||
const bool allowStandard = type == (int)ProcessorSlot::Type::IR
|
||||
|| type == (int)ProcessorSlot::Type::NAM;
|
||||
juce::MemoryBlock state;
|
||||
if (state.fromBase64Encoding(stateB64))
|
||||
if (decodeStateBlob(stateB64, state, allowStandard))
|
||||
{
|
||||
auto* slot = const_cast<ProcessorSlot*>(liveEngine->getSignalChain().getSlot(slotId));
|
||||
if (slot) slot->setState(state);
|
||||
|
||||
Reference in New Issue
Block a user