Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backward-compatible unserialization to v0.7.3 #532

Merged
merged 6 commits into from
Nov 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Include [Closing words](https://docs.github.com/en/issues/tracking-your-work-wit
- [ ] Does the VST3 plugin pass all of the unit tests in the [VST3PluginTestHost](https://steinbergmedia.github.io/vst3_dev_portal/pages/What+is+the+VST+3+SDK/Plug-in+Test+Host.html)? (Download it as part of the VST3 SDK [here](https://www.steinberg.net/developers/).)
- [ ] Windows
- [ ] macOS
- [ ] Does your PR add, remove, or rename any plugin parameters?
- [ ] If yes, then have you ensured that older versions of the plug-in load correctly? (Usually, this means writing a new legacy unserialization function like [`_UnserializeStateLegacy_0_7_9`](https://github.com/sdatkinson/NeuralAmpModelerPlugin/blob/f755918e3f325f28658700ca954f8a47ec58d021/NeuralAmpModeler/NeuralAmpModeler.cpp#L823).)
- [ ] Does your PR add, remove, or rename any plugin parameters? If yes...
- [ ] Have you ensured that the plug-in unserializes correctly?
- [ ] Have you ensured that _older_ versions of the plug-in load correctly? (See [`Unserialization.cpp`](https://github.com/sdatkinson/NeuralAmpModelerPlugin/blob/main/NeuralAmpModeler/Unserialization.cpp).)

115 changes: 20 additions & 95 deletions NeuralAmpModeler/NeuralAmpModeler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ EMsgBoxResult _ShowMessageBox(iplug::igraphics::IGraphics* pGraphics, const char
#endif
}

const std::string kCalibrateInputParamName = "CalibrateInput";
const bool kDefaultCalibrateInput = false;
const std::string kInputCalibrationLevelParamName = "InputCalibrationLevel";
const double kDefaultInputCalibrationLevel = 12.0;


NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info)
: Plugin(info, MakeConfig(kNumParams, kNumPresets))
Expand All @@ -85,8 +90,9 @@ NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info)
GetParam(kEQActive)->InitBool("ToneStack", true);
GetParam(kOutputMode)->InitEnum("OutputMode", 1, {"Raw", "Normalized", "Calibrated"}); // TODO DRY w/ control
GetParam(kIRToggle)->InitBool("IRToggle", true);
GetParam(kCalibrateInput)->InitBool("CalibrateInput", false);
GetParam(kInputCalibrationLevel)->InitDouble("InputCalibrationLevel", 12.5, -30.0, 30.0, 0.1, "dBu");
GetParam(kCalibrateInput)->InitBool(kCalibrateInputParamName.c_str(), kDefaultCalibrateInput);
GetParam(kInputCalibrationLevel)
->InitDouble(kInputCalibrationLevelParamName.c_str(), kDefaultInputCalibrationLevel, -60.0, 60.0, 0.1, "dBu");

mNoiseGateTrigger.AddListener(&mNoiseGateGain);

Expand Down Expand Up @@ -413,29 +419,20 @@ bool NeuralAmpModeler::SerializeState(IByteChunk& chunk) const

int NeuralAmpModeler::UnserializeState(const IByteChunk& chunk, int startPos)
{
// Look for the expected header. If it's there, then we'll know what to do.
WDL_String header;
int pos = startPos;
pos = chunk.GetStr(header, pos);
// Unseralization:

const char* kExpectedHeader = "###NeuralAmpModeler###";
if (strcmp(header.Get(), kExpectedHeader) == 0)
{
// 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);
}
return _UnserializeStateWithKnownVersion(chunk, pos);
}
else
{
return _UnserializeStateWithUnknownVersion(chunk, startPos);
}
if (mNAMPath.GetLength())
_StageModel(mNAMPath);
if (mIRPath.GetLength())
_StageIR(mIRPath);
return pos;
}

void NeuralAmpModeler::OnUIOpen()
Expand Down Expand Up @@ -857,81 +854,6 @@ 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::_UpdateControlsFromModel()
{
if (mModel == nullptr)
Expand Down Expand Up @@ -985,3 +907,6 @@ void NeuralAmpModeler::_UpdateMeters(sample** inputPointer, sample** outputPoint
mInputSender.ProcessBlock(inputPointer, (int)nFrames, kCtrlTagInputMeter, nChansHack);
mOutputSender.ProcessBlock(outputPointer, (int)nFrames, kCtrlTagOutputMeter, nChansHack);
}

// HACK
#include "Unserialization.cpp"
14 changes: 8 additions & 6 deletions NeuralAmpModeler/NeuralAmpModeler.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "AudioDSPTools/dsp/wav.h"
#include "AudioDSPTools/dsp/ResamplingContainer/ResamplingContainer.h"

#include "Colors.h"
#include "ToneStack.h"

#include "IPlug_include_in_plug_hdr.h"
Expand Down Expand Up @@ -150,7 +151,7 @@ class ResamplingNAM : public nam::DSP

int GetLatency() const { return NeedToResample() ? mResampler.GetLatency() : 0; };

void Reset(const double sampleRate, const int maxBlockSize)
void Reset(const double sampleRate, const int maxBlockSize) override
{
mExpectedSampleRate = sampleRate;
mMaxExternalBlockSize = maxBlockSize;
Expand Down Expand Up @@ -244,11 +245,12 @@ class NeuralAmpModeler final : public iplug::Plugin
void _SetInputGain();
void _SetOutputGain();

// 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...
// See: Unserialization.cpp
void _UnserializeApplyConfig(nlohmann::json& config);
// 0.7.9 and later
int _UnserializeStateWithKnownVersion(const iplug::IByteChunk& chunk, int startPos);
// Hopefully 0.7.3-0.7.8, but no gurantees
int _UnserializeStateWithUnknownVersion(const iplug::IByteChunk& chunk, int startPos);

// Update all controls that depend on a model
void _UpdateControlsFromModel();
Expand Down
Loading
Loading