NeuralAmpModelerPlugin

Plugin for Neural Amp Modeler
Log | Files | Refs | Submodules | README | LICENSE

commit ebd135215ce1041d9766c312f6ab6f77984e2d59
parent ab9ea544f94ee5a003a0bb1f1d54a1294141acb3
Author: Steven Atkinson <steven@atkinson.mn>
Date:   Sun, 28 Jul 2024 16:21:54 -0700

Support loading serialized plug-in states from v0.7.9 (#487)


Diffstat:
MNeuralAmpModeler/NeuralAmpModeler.cpp | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
MNeuralAmpModeler/NeuralAmpModeler.h | 6++++++
2 files changed, 100 insertions(+), 17 deletions(-)

diff --git a/NeuralAmpModeler/NeuralAmpModeler.cpp b/NeuralAmpModeler/NeuralAmpModeler.cpp @@ -1,4 +1,4 @@ -#include <algorithm> // std::clamp +#include <algorithm> // std::clamp, std::min #include <cmath> // pow #include <filesystem> #include <iostream> @@ -400,26 +400,28 @@ bool NeuralAmpModeler::SerializeState(IByteChunk& chunk) const int NeuralAmpModeler::UnserializeState(const IByteChunk& chunk, int startPos) { WDL_String header; - startPos = chunk.GetStr(header, startPos); - // TODO: Handle legacy plugin serialized states. - // if strncmp (header.Get(), "###NeuralAmpModeler###") - //{ - // return UnserializeStateLegacy(header, startPos); // (We'll assume 0.7.9). - //} - WDL_String version; - startPos = chunk.GetStr(version, startPos); - // Version-specific loading here if needed. - // ... - - // Current version loading: - startPos = chunk.GetStr(mNAMPath, startPos); - startPos = chunk.GetStr(mIRPath, startPos); - int retcode = UnserializeParams(chunk, startPos); + int pos = startPos; + pos = chunk.GetStr(header, pos); + // Unseralization: + { + // Handle legacy plugin serialized states: + // In v0.7.9, this was the NAM filepath. So, if we dont' get the expected header, then we can attempt to unserialize + // as v0.7.9: + const char* kExpectedHeader = "###NeuralAmpModeler###"; + if (strcmp(header.Get(), kExpectedHeader) == 0) + { + pos = _UnserializeStateCurrent(chunk, pos); + } + else + { + pos = _UnserializeStateLegacy_0_7_9(chunk, startPos); + } + } if (mNAMPath.GetLength()) _StageModel(mNAMPath); if (mIRPath.GetLength()) _StageIR(mIRPath); - return retcode; + return pos; } void NeuralAmpModeler::OnUIOpen() @@ -804,6 +806,81 @@ void NeuralAmpModeler::_ProcessOutput(iplug::sample** inputs, iplug::sample** ou #endif } +int NeuralAmpModeler::_UnserializeStateCurrent(const IByteChunk& chunk, int pos) +{ + WDL_String version; + pos = chunk.GetStr(version, pos); + // Post-v0.7.9 legacy loading here once needed: + // ... + + // Current version loading: + pos = chunk.GetStr(mNAMPath, pos); + pos = chunk.GetStr(mIRPath, pos); + pos = UnserializeParams(chunk, pos); + return pos; +} + +int NeuralAmpModeler::_UnserializeStateLegacy_0_7_9(const IByteChunk& chunk, int startPos) +{ + WDL_String dir; + int pos = startPos; + pos = chunk.GetStr(mNAMPath, pos); + pos = chunk.GetStr(mIRPath, pos); + auto unserialize = [&](const IByteChunk& chunk, int startPos) { + // cf IPluginBase::UnserializeParams(const IByteChunk& chunk, int startPos) + + // These are the parameter names, in the order that they were serialized in v0.7.9. + std::vector<std::string> oldParamNames{ + "Input", "Gate", "Bass", "Middle", "Treble", "Output", "NoiseGateActive", "ToneStack", "OutNorm", "IRToggle"}; + // These are their current names. + // IF YOU CHANGE THE NAMES OF THE PARAMETERS, THEN YOU NEED TO UPDATE THIS! + std::unordered_map<std::string, std::string> newNames{{"Gate", "Threshold"}}; + auto getParamByOldName = [&, newNames](std::string& oldName) { + std::string name = newNames.find(oldName) != newNames.end() ? newNames.at(oldName) : oldName; + // Could use a map but eh + for (int i = 0; i < kNumParams; i++) + { + IParam* param = GetParam(i); + if (strcmp(param->GetName(), name.c_str()) == 0) + { + return param; + } + } + return (IParam*)nullptr; + }; + TRACE + int pos = startPos; + ENTER_PARAMS_MUTEX + int i = 0; + for (auto it = oldParamNames.begin(); it != oldParamNames.end(); ++it, i++) + { + // Here's the change: instead of assuming that we can iterate through the parameters, we look for the one that now + // holds this info. + // IParam* pParam = mParams.Get(i); + IParam* pParam = getParamByOldName(*it); + + double v = 0.0; + pos = chunk.Get(&v, pos); + // It's possible that future versions will not have all of the params of previous versions. If that's the case, + // then this is a null ptr and we skip it. + if (pParam) + { + pParam->Set(v); + Trace(TRACELOC, "%d %s %f", i, pParam->GetName(), pParam->Value()); + } + else + { + Trace(TRACELOC, "%d NOT-FOUND", i); + } + } + OnParamReset(kPresetRecall); + LEAVE_PARAMS_MUTEX + return pos; + }; + pos = unserialize(chunk, pos); + return pos; +} + void NeuralAmpModeler::_UpdateMeters(sample** inputPointer, sample** outputPointer, const size_t nFrames, const size_t nChansIn, const size_t nChansOut) { diff --git a/NeuralAmpModeler/NeuralAmpModeler.h b/NeuralAmpModeler/NeuralAmpModeler.h @@ -265,6 +265,12 @@ private: // Resetting for models and IRs, called by OnReset void _ResetModelAndIR(const double sampleRate, const int maxBlockSize); + // Unserialize current-version plug-in data: + int _UnserializeStateCurrent(const iplug::IByteChunk& chunk, int startPos); + // Unserialize v0.7.9 legacy data: + int _UnserializeStateLegacy_0_7_9(const iplug::IByteChunk& chunk, int startPos); + // And other legacy unsrializations if/as needed... + // Update level meters // Called within ProcessBlock(). // Assume _ProcessInput() and _ProcessOutput() were run immediately before.