commit 420f438ad084a86341d5dc5d690d57fabcb7cc95
parent dd3ad7a2b5e2b23cc6cc131548f700d814524eb8
Author: Steven Atkinson <steven@atkinson.mn>
Date: Sat, 16 Nov 2024 19:18:51 -0600
[FEATURE] Input level calibration (#525)
* Rearrange about info
* Define parameters for input calibration
* No click through ModelInfoControl--just use the 'close' button in the corner
* Settings control: Clean up OnAttached() and set rect for background immediately
* Input calibration controls
* Input calibration controls
* Input calibration
* Disable both the switch and knob when model doesn't have input calibration metadata
* Display I/O calibration levels in model info
* Add tooltip to input calibraiton knob.
* Don't disable mouse events when input calibraiton controls are disabled.
* Set disable state correctly on UI open for input calibration controls
* Input level as text control, still needs cleaning up
* Improve input level graphics, still iffy layout
Diffstat:
8 files changed, 215 insertions(+), 56 deletions(-)
diff --git a/NeuralAmpModeler/NeuralAmpModeler.cpp b/NeuralAmpModeler/NeuralAmpModeler.cpp
@@ -81,6 +81,9 @@ NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info)
GetParam(kEQActive)->InitBool("ToneStack", true);
GetParam(kOutNorm)->InitBool("OutNorm", true);
GetParam(kIRToggle)->InitBool("IRToggle", true);
+ GetParam(kCalibrateInput)->InitBool("CalibrateInput", false);
+ // TODO Double, label "dBu"
+ GetParam(kInputCalibrationLevel)->InitDouble("InputCalibrationLevel", 12.5, -30.0, 30.0, 0.1, "dBu");
mNoiseGateTrigger.AddListener(&mNoiseGateGain);
@@ -116,6 +119,7 @@ NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info)
const auto backgroundBitmap = pGraphics->LoadBitmap(BACKGROUND_FN);
const auto fileBackgroundBitmap = pGraphics->LoadBitmap(FILEBACKGROUND_FN);
+ const auto inputLevelBackgroundBitmap = pGraphics->LoadBitmap(INPUTLEVELBACKGROUND_FN);
const auto linesBitmap = pGraphics->LoadBitmap(LINES_FN);
const auto knobBackgroundBitmap = pGraphics->LoadBitmap(KNOBBACKGROUND_FN);
const auto switchHandleBitmap = pGraphics->LoadBitmap(SLIDESWITCHHANDLE_FN);
@@ -130,9 +134,8 @@ NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info)
// Areas for knobs
const auto knobsPad = 20.0f;
const auto knobsExtraSpaceBelowTitle = 25.0f;
- const auto knobHeight = 120.f;
const auto singleKnobPad = -2.0f;
- const auto knobsArea = contentArea.GetFromTop(knobHeight)
+ const auto knobsArea = contentArea.GetFromTop(NAM_KNOB_HEIGHT)
.GetReducedFromLeft(knobsPad)
.GetReducedFromRight(knobsPad)
.GetVShifted(titleHeight + knobsExtraSpaceBelowTitle);
@@ -250,7 +253,10 @@ NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info)
},
gearSVG));
- pGraphics->AttachControl(new NAMSettingsPageControl(b, backgroundBitmap, crossSVG, style), kCtrlTagSettingsBox)
+ pGraphics
+ ->AttachControl(new NAMSettingsPageControl(
+ b, backgroundBitmap, inputLevelBackgroundBitmap, switchHandleBitmap, crossSVG, style),
+ kCtrlTagSettingsBox)
->Hide(true);
pGraphics->ForAllControlsFunc([](IControl* pControl) {
@@ -258,7 +264,8 @@ NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info)
pControl->SetMouseOverWhenDisabled(true);
});
- pGraphics->GetControlWithTag(kCtrlTagOutNorm)->SetMouseEventsWhenDisabled(false);
+ // pGraphics->GetControlWithTag(kCtrlTagOutNorm)->SetMouseEventsWhenDisabled(false);
+ // pGraphics->GetControlWithTag(kCtrlTagCalibrateInput)->SetMouseEventsWhenDisabled(false);
};
}
@@ -381,9 +388,19 @@ void NeuralAmpModeler::OnIdle()
{
pGraphics->GetControlWithTag(kCtrlTagOutNorm)->SetDisabled(!mModel->HasLoudness());
ModelInfo modelInfo;
- modelInfo.sampleRate = mModel->GetEncapsulatedSampleRate();
- modelInfo.knownSampleRate = true;
+ modelInfo.sampleRate.known = true;
+ modelInfo.sampleRate.value = mModel->GetEncapsulatedSampleRate();
+ modelInfo.inputCalibrationLevel.known = mModel->HasInputLevel();
+ modelInfo.inputCalibrationLevel.value = mModel->HasInputLevel() ? mModel->GetInputLevel() : 0.0;
+ modelInfo.outputCalibrationLevel.known = mModel->HasOutputLevel();
+ modelInfo.outputCalibrationLevel.value = mModel->HasOutputLevel() ? mModel->GetOutputLevel() : 0.0;
+
static_cast<NAMSettingsPageControl*>(pGraphics->GetControlWithTag(kCtrlTagSettingsBox))->SetModelInfo(modelInfo);
+
+ const bool disableInputCalibrationControls = !mModel->HasInputLevel();
+ pGraphics->GetControlWithTag(kCtrlTagCalibrateInput)->SetDisabled(disableInputCalibrationControls);
+ pGraphics->GetControlWithTag(kCtrlTagInputCalibrationLevel)->SetDisabled(disableInputCalibrationControls);
+
mNewModelLoadedInDSP = false;
}
}
@@ -461,13 +478,25 @@ void NeuralAmpModeler::OnUIOpen()
}
if (mModel != nullptr)
- GetUI()->GetControlWithTag(kCtrlTagOutNorm)->SetDisabled(!mModel->HasLoudness());
+ {
+ auto* pGraphics = GetUI();
+ assert(pGraphics != nullptr);
+ pGraphics->GetControlWithTag(kCtrlTagOutNorm)->SetDisabled(!mModel->HasLoudness());
+ const bool disableInputCalibrationControls = !mModel->HasInputLevel();
+ pGraphics->GetControlWithTag(kCtrlTagCalibrateInput)->SetDisabled(disableInputCalibrationControls);
+ pGraphics->GetControlWithTag(kCtrlTagInputCalibrationLevel)->SetDisabled(disableInputCalibrationControls);
+ }
}
void NeuralAmpModeler::OnParamChange(int paramIdx)
{
switch (paramIdx)
{
+ // Changes to the input gain
+ case kCalibrateInput:
+ case kInputCalibrationLevel:
+ case kInputLevel: _SetInputGain(); break;
+ // Tone stack:
case kToneBass: mToneStack->SetParam("bass", GetParam(paramIdx)->Value()); break;
case kToneMid: mToneStack->SetParam("middle", GetParam(paramIdx)->Value()); break;
case kToneTreble: mToneStack->SetParam("treble", GetParam(paramIdx)->Value()); break;
@@ -487,7 +516,7 @@ void NeuralAmpModeler::OnParamChangeUI(int paramIdx, EParamSource source)
case kEQActive:
pGraphics->ForControlInGroup("EQ_KNOBS", [active](IControl* pControl) { pControl->SetDisabled(!active); });
break;
- case kIRToggle: pGraphics->GetControlWithTag(kCtrlTagIRFileBrowser)->SetDisabled(!active);
+ case kIRToggle: pGraphics->GetControlWithTag(kCtrlTagIRFileBrowser)->SetDisabled(!active); break;
default: break;
}
}
@@ -551,6 +580,7 @@ void NeuralAmpModeler::_ApplyDSPStaging()
mShouldRemoveModel = false;
mModelCleared = true;
_UpdateLatency();
+ _SetInputGain();
}
if (mShouldRemoveIR)
{
@@ -566,6 +596,7 @@ void NeuralAmpModeler::_ApplyDSPStaging()
mStagedModel = nullptr;
mNewModelLoadedInDSP = true;
_UpdateLatency();
+ _SetInputGain();
}
if (mStagedIR != nullptr)
{
@@ -651,6 +682,17 @@ void NeuralAmpModeler::_ResetModelAndIR(const double sampleRate, const int maxBl
}
}
+void NeuralAmpModeler::_SetInputGain()
+{
+ iplug::sample inputGainDB = GetParam(kInputLevel)->Value();
+ // Input calibration
+ if ((mModel != nullptr) && (mModel->HasInputLevel()) && GetParam(kCalibrateInput)->Bool())
+ {
+ inputGainDB += GetParam(kInputCalibrationLevel)->Value() - mModel->GetInputLevel();
+ }
+ mInputGain = DBToAmp(inputGainDB);
+}
+
std::string NeuralAmpModeler::_StageModel(const WDL_String& modelPath)
{
WDL_String previousNAMPath = mNAMPath;
@@ -787,13 +829,12 @@ void NeuralAmpModeler::_ProcessInput(iplug::sample** inputs, const size_t nFrame
}
// On the standalone, we can probably assume that the user has plugged into only one input and they expect it to be
- // carried straight through. Don't apply any division over nCahnsIn because we're just "catching anything out there."
+ // carried straight through. Don't apply any division over nChansIn because we're just "catching anything out there."
// However, in a DAW, it's probably something providing stereo, and we want to take the average in order to avoid
- // doubling the loudness.
-#ifdef APP_API
- const double gain = pow(10.0, GetParam(kInputLevel)->Value() / 20.0);
-#else
- const double gain = pow(10.0, GetParam(kInputLevel)->Value() / 20.0) / (float)nChansIn;
+ // doubling the loudness. (This would change w/ double mono processing)
+ double gain = mInputGain;
+#ifndef APP_API
+ gain /= (float)nChansIn;
#endif
// Assume _PrepareBuffers() was already called
for (size_t c = 0; c < nChansIn; c++)
diff --git a/NeuralAmpModeler/NeuralAmpModeler.h b/NeuralAmpModeler/NeuralAmpModeler.h
@@ -41,6 +41,9 @@ enum EParams
kEQActive,
kOutNorm,
kIRToggle,
+ // Input calibration
+ kCalibrateInput,
+ kInputCalibrationLevel,
kNumParams
};
@@ -54,6 +57,8 @@ enum ECtrlTags
kCtrlTagOutputMeter,
kCtrlTagSettingsBox,
kCtrlTagOutNorm,
+ kCtrlTagCalibrateInput,
+ kCtrlTagInputCalibrationLevel,
kNumCtrlTags
};
@@ -102,7 +107,17 @@ public:
// Get the other information from the encapsulated NAM so that we can tell the outside world about what we're
// holding.
if (mEncapsulated->HasLoudness())
+ {
SetLoudness(mEncapsulated->GetLoudness());
+ }
+ if (mEncapsulated->HasInputLevel())
+ {
+ SetInputLevel(mEncapsulated->GetInputLevel());
+ }
+ if (mEncapsulated->HasOutputLevel())
+ {
+ SetOutputLevel(mEncapsulated->GetOutputLevel());
+ }
// NOTE: prewarm samples doesn't mean anything--we can prewarm the encapsulated model as it likes and be good to
// go.
@@ -228,6 +243,8 @@ private:
// Resetting for models and IRs, called by OnReset
void _ResetModelAndIR(const double sampleRate, const int maxBlockSize);
+ void _SetInputGain();
+
// Unserialize current-version plug-in data:
int _UnserializeStateCurrent(const iplug::IByteChunk& chunk, int startPos);
// Unserialize v0.7.9 legacy data:
@@ -253,6 +270,9 @@ private:
iplug::sample** mInputPointers = nullptr;
iplug::sample** mOutputPointers = nullptr;
+ // Input and (soon) output gain
+ iplug::sample mInputGain = 1.0;
+
// Noise gates
dsp::noise_gate::Trigger mNoiseGateTrigger;
dsp::noise_gate::Gain mNoiseGateGain;
diff --git a/NeuralAmpModeler/NeuralAmpModelerControls.h b/NeuralAmpModeler/NeuralAmpModelerControls.h
@@ -6,6 +6,8 @@
#include "IControls.h"
#define PLUG() static_cast<PLUG_CLASS_NAME*>(GetDelegate())
+#define NAM_KNOB_HEIGHT 120.0f
+#define NAM_SWTICH_HEIGHT 50.0f
using namespace iplug;
using namespace igraphics;
@@ -453,12 +455,12 @@ public:
~IContainerBaseWithNamedChildren() = default;
protected:
- IControl* AddNamedChildControl(IControl* control, std::string name)
+ IControl* AddNamedChildControl(IControl* control, std::string name, int ctrlTag = kNoTag, const char* group = "")
{
// Make sure we haven't already used this name
assert(mChildNameIndexMap.find(name) == mChildNameIndexMap.end());
mChildNameIndexMap[name] = NChildren();
- return AddChildControl(control);
+ return AddChildControl(control, ctrlTag, group);
};
IControl* GetNamedChild(std::string name)
@@ -472,10 +474,18 @@ private:
std::unordered_map<std::string, int> mChildNameIndexMap;
}; // class IContainerBaseWithNamedChildren
+
+struct PossiblyKnownParameter
+{
+ bool known = false;
+ double value = 0.0;
+};
+
struct ModelInfo
{
- bool knownSampleRate = false;
- double sampleRate = 0.0;
+ PossiblyKnownParameter sampleRate;
+ PossiblyKnownParameter inputCalibrationLevel;
+ PossiblyKnownParameter outputCalibrationLevel;
};
class ModelInfoControl : public IContainerBaseWithNamedChildren
@@ -499,26 +509,37 @@ public:
void OnAttached() override
{
- AddChildControl(new IVLabelControl(GetRECT().GetGridCell(0, 0, 2, 1), "Model information:", mStyle));
- AddNamedChildControl(new IVLabelControl(GetRECT().GetGridCell(1, 0, 2, 1), "", mStyle), mControlNames.sampleRate);
+ AddChildControl(new IVLabelControl(GetRECT().SubRectVertical(4, 0), "Model information:", mStyle));
+ AddNamedChildControl(new IVLabelControl(GetRECT().SubRectVertical(4, 1), "", mStyle), mControlNames.sampleRate);
+ // AddNamedChildControl(
+ // new IVLabelControl(GetRECT().SubRectVertical(4, 2), "", mStyle), mControlNames.inputCalibrationLevel);
+ // AddNamedChildControl(
+ // new IVLabelControl(GetRECT().SubRectVertical(4, 3), "", mStyle), mControlNames.outputCalibrationLevel);
};
- // Click through me
- void OnMouseDown(float x, float y, const IMouseMod& mod) override { GetParent()->OnMouseDown(x, y, mod); }
-
void SetModelInfo(const ModelInfo& modelInfo)
{
- std::stringstream ss;
- ss << "Sample rate: ";
- if (modelInfo.knownSampleRate)
- {
- ss << (int)modelInfo.sampleRate;
- }
- else
- {
- ss << "(Unknown)";
- }
- static_cast<IVLabelControl*>(GetNamedChild(mControlNames.sampleRate))->SetStr(ss.str().c_str());
+ auto SetControlStr = [&](const std::string& name, const PossiblyKnownParameter& p, const std::string& units,
+ const std::string& childName) {
+ std::stringstream ss;
+ ss << name << ": ";
+ if (p.known)
+ {
+ ss << p.value << " " << units;
+ }
+ else
+ {
+ ss << "(Unknown)";
+ }
+ static_cast<IVLabelControl*>(GetNamedChild(childName))->SetStr(ss.str().c_str());
+ };
+
+ SetControlStr("Sample rate", modelInfo.sampleRate, "Hz", mControlNames.sampleRate);
+ // SetControlStr(
+ // "Input calibration level", modelInfo.inputCalibrationLevel, "dBu", mControlNames.inputCalibrationLevel);
+ // SetControlStr(
+ // "Output calibration level", modelInfo.outputCalibrationLevel, "dBu", mControlNames.outputCalibrationLevel);
+
mHasInfo = true;
};
@@ -527,6 +548,8 @@ private:
struct
{
const std::string sampleRate = "sampleRate";
+ // const std::string inputCalibrationLevel = "inputCalibrationLevel";
+ // const std::string outputCalibrationLevel = "outputCalibrationLevel";
} mControlNames;
// Do I have info?
bool mHasInfo = false;
@@ -535,10 +558,13 @@ private:
class NAMSettingsPageControl : public IContainerBaseWithNamedChildren
{
public:
- NAMSettingsPageControl(const IRECT& bounds, const IBitmap& bitmap, ISVG closeSVG, const IVStyle& style)
+ NAMSettingsPageControl(const IRECT& bounds, const IBitmap& bitmap, const IBitmap& inputLevelBackgroundBitmap,
+ const IBitmap& switchBitmap, ISVG closeSVG, const IVStyle& style)
: IContainerBaseWithNamedChildren(bounds)
, mAnimationTime(0)
, mBitmap(bitmap)
+ , mInputLevelBackgroundBitmap(inputLevelBackgroundBitmap)
+ , mSwitchBitmap(switchBitmap)
, mStyle(style)
, mCloseSVG(closeSVG)
{
@@ -609,16 +635,41 @@ public:
const auto style = mStyle.WithDrawFrame(false).WithValueText(text);
const IVStyle leftStyle = style.WithValueText(leftText);
- // This'll get fixed on OnResize; FIXME
- AddNamedChildControl(new IBitmapControl(IRECT(), mBitmap), mControlNames.bitmap)->SetIgnoreMouse(true);
- AddNamedChildControl(
- new IVLabelControl(GetRECT().GetPadded(-(pad + 10.0f)).GetFromTop(50.0f), "SETTINGS", titleStyle),
- mControlNames.title);
+ AddNamedChildControl(new IBitmapControl(GetRECT(), mBitmap), mControlNames.bitmap)->SetIgnoreMouse(true);
+ const auto titleArea = GetRECT().GetPadded(-(pad + 10.0f)).GetFromTop(50.0f);
+ AddNamedChildControl(new IVLabelControl(titleArea, "SETTINGS", titleStyle), mControlNames.title);
+
+ // Attach input/output calibration controls
+ {
+ const float height = NAM_KNOB_HEIGHT + NAM_SWTICH_HEIGHT + 10.0f;
+ const float width = titleArea.W();
+ const auto inputOutputArea = titleArea.GetFromBottom(height).GetTranslated(0.0f, height);
+ const auto inputArea = inputOutputArea.GetFromLeft(0.5f * width);
+ // const auto outputArea = inputOutputArea.GetFromRight(0.5f * width);
+
+ const float knobWidth = 87.0f; // HACK based on looking at the main page knobs.
+ const auto inputLevelArea =
+ inputArea.GetFromTop(NAM_KNOB_HEIGHT).GetFromBottom(25.0f).GetMidHPadded(0.5f * knobWidth);
+ const auto inputSwitchArea = inputArea.GetFromBottom(NAM_SWTICH_HEIGHT).GetMidHPadded(0.5f * knobWidth);
+
+ auto* inputLevelControl = AddNamedChildControl(
+ new InputLevelControl(inputLevelArea, kInputCalibrationLevel, mInputLevelBackgroundBitmap, text),
+ mControlNames.inputCalibrationLevel, kCtrlTagInputCalibrationLevel);
+ inputLevelControl->SetTooltip(
+ "The analog level, in dBu RMS, that corresponds to digital level of 0 dBFS peak in the host as its signal "
+ "enters this plugin.");
+ AddNamedChildControl(
+ new NAMSwitchControl(inputSwitchArea, kCalibrateInput, "Calibrate Input", mStyle, mSwitchBitmap),
+ mControlNames.calibrateInput, kCtrlTagCalibrateInput);
+
+ // TODO output--raw, normalized, calibrated
+ }
const float halfWidth = PLUG_WIDTH / 2.0f - pad;
const auto bottomArea = GetRECT().GetPadded(-pad).GetFromBottom(78.0f);
- const auto modelInfoArea = bottomArea.GetFromLeft(halfWidth).GetFromTop(30.0f);
- const auto aboutArea = bottomArea.GetFromRight(halfWidth);
+ const float lineHeight = 15.0f;
+ const auto modelInfoArea = bottomArea.GetFromLeft(halfWidth).GetFromTop(4 * lineHeight);
+ const auto aboutArea = bottomArea.GetFromRight(halfWidth).GetFromTop(5 * lineHeight);
AddNamedChildControl(new ModelInfoControl(modelInfoArea, leftStyle), mControlNames.modelInfo);
AddNamedChildControl(new AboutControl(aboutArea, leftStyle, leftText), mControlNames.about);
@@ -631,15 +682,6 @@ public:
OnResize();
}
- void OnResize() override
- {
- if (NChildren())
- {
- GetNamedChild(mControlNames.bitmap)->SetTargetAndDrawRECTs(mRECT);
- // Rework this later, but resizing on the main page needs to happen too.
- }
- }
-
void SetModelInfo(const ModelInfo& modelInfo)
{
auto* modelInfoControl = static_cast<ModelInfoControl*>(GetNamedChild(mControlNames.modelInfo));
@@ -649,6 +691,8 @@ public:
private:
IBitmap mBitmap;
+ IBitmap mInputLevelBackgroundBitmap;
+ IBitmap mSwitchBitmap;
IVStyle mStyle;
ISVG mCloseSVG;
int mAnimationTime = 200;
@@ -667,6 +711,51 @@ private:
const std::string title = "Title";
} mControlNames;
+ class InputLevelControl : public IEditableTextControl
+ {
+ public:
+ InputLevelControl(const IRECT& bounds, int paramIdx, const IBitmap& bitmap, const IText& text = DEFAULT_TEXT,
+ const IColor& BGColor = DEFAULT_BGCOLOR)
+ : IEditableTextControl(bounds, "", text, BGColor)
+ , mBitmap(bitmap)
+ {
+ SetParamIdx(paramIdx);
+ };
+
+ void Draw(IGraphics& g) override
+ {
+ g.DrawFittedBitmap(mBitmap, mRECT);
+ ITextControl::Draw(g);
+ };
+
+ void SetValueFromUserInput(double normalizedValue, int valIdx) override
+ {
+ IControl::SetValueFromUserInput(normalizedValue, valIdx);
+ const std::string s = ConvertToString(normalizedValue);
+ OnTextEntryCompletion(s.c_str(), valIdx);
+ };
+
+ void SetValueFromDelegate(double normalizedValue, int valIdx) override
+ {
+ IControl::SetValueFromDelegate(normalizedValue, valIdx);
+ const std::string s = ConvertToString(normalizedValue);
+ OnTextEntryCompletion(s.c_str(), valIdx);
+ };
+
+ private:
+ std::string ConvertToString(const double normalizedValue)
+ {
+ const double naturalValue = GetParam()->FromNormalized(normalizedValue);
+ // And make the value to display
+ std::stringstream ss;
+ ss << naturalValue << " dBu";
+ std::string s = ss.str();
+ return s;
+ };
+
+ IBitmap mBitmap;
+ };
+
class AboutControl : public IContainerBase
{
public:
@@ -682,14 +771,14 @@ private:
buildInfoStr.SetFormatted(100, "Version %s %s %s", verStr.Get(), PLUG()->GetArchStr(), PLUG()->GetAPIStr());
- AddChildControl(new IVLabelControl(GetRECT().GetGridCell(0, 0, 5, 1), "NEURAL AMP MODELER", mStyle));
- AddChildControl(new IVLabelControl(GetRECT().GetGridCell(1, 0, 5, 1), "By Steven Atkinson", mStyle));
- AddChildControl(new IVLabelControl(GetRECT().GetGridCell(2, 0, 5, 1), buildInfoStr.Get(), mStyle));
- AddChildControl(new IURLControl(GetRECT().GetGridCell(3, 0, 5, 1),
+ AddChildControl(new IVLabelControl(GetRECT().SubRectVertical(5, 0), "NEURAL AMP MODELER", mStyle));
+ AddChildControl(new IVLabelControl(GetRECT().SubRectVertical(5, 1), "By Steven Atkinson", mStyle));
+ AddChildControl(new IVLabelControl(GetRECT().SubRectVertical(5, 2), buildInfoStr.Get(), mStyle));
+ AddChildControl(new IURLControl(GetRECT().SubRectVertical(5, 3),
"Plug-in development: Steve Atkinson, Oli Larkin, ... ",
"https://github.com/sdatkinson/NeuralAmpModelerPlugin/graphs/contributors", mText,
COLOR_TRANSPARENT, PluginColors::HELP_TEXT_MO, PluginColors::HELP_TEXT_CLICKED));
- AddChildControl(new IURLControl(GetRECT().GetGridCell(4, 0, 5, 1), "www.neuralampmodeler.com",
+ AddChildControl(new IURLControl(GetRECT().SubRectVertical(5, 4), "www.neuralampmodeler.com",
"https://www.neuralampmodeler.com", mText, COLOR_TRANSPARENT,
PluginColors::HELP_TEXT_MO, PluginColors::HELP_TEXT_CLICKED));
};
diff --git a/NeuralAmpModeler/config.h b/NeuralAmpModeler/config.h
@@ -77,6 +77,9 @@
#define FILEBACKGROUND_FN "FileBackground.png"
#define FILEBACKGROUND2X_FN "FileBackground@2x.png"
#define FILEBACKGROUND3X_FN "FileBackground@3x.png"
+#define INPUTLEVELBACKGROUND_FN "InputLevelBackground.png"
+#define INPUTLEVELBACKGROUND2X_FN "InputLevelBackground@2x.png"
+#define INPUTLEVELBACKGROUND3X_FN "InputLevelBackground@3x.png"
#define LINES_FN "Lines.png"
#define LINES2X_FN "Lines@2x.png"
#define LINES3X_FN "Lines@3x.png"
diff --git a/NeuralAmpModeler/resources/img/InputLevelBackground.png b/NeuralAmpModeler/resources/img/InputLevelBackground.png
Binary files differ.
diff --git a/NeuralAmpModeler/resources/img/InputLevelBackground@2x.png b/NeuralAmpModeler/resources/img/InputLevelBackground@2x.png
Binary files differ.
diff --git a/NeuralAmpModeler/resources/img/InputLevelBackground@3x.png b/NeuralAmpModeler/resources/img/InputLevelBackground@3x.png
Binary files differ.
diff --git a/NeuralAmpModeler/resources/main.rc b/NeuralAmpModeler/resources/main.rc
@@ -168,6 +168,9 @@ BEGIN
"FILEBACKGROUND_FN PNG FILEBACKGROUND_FN\r\n"
"FILEBACKGROUND2X_FN PNG FILEBACKGROUND2X_FN\r\n"
"FILEBACKGROUND3X_FN PNG FILEBACKGROUND3X_FN\r\n"
+ "INPUTLEVELBACKGROUND_FN PNG INPUTLEVELBACKGROUND_FN\r\n"
+ "INPUTLEVELBACKGROUND2X_FN PNG INPUTLEVELBACKGROUND2X_FN\r\n"
+ "INPUTLEVELBACKGROUND3X_FN PNG INPUTLEVELBACKGROUND3X_FN\r\n"
"LINES_FN PNG LINES_FN\r\n"
"LINES2X_FN PNG LINES2X_FN\r\n"
"LINES3X_FN PNG LINES3X_FN\r\n"
@@ -275,6 +278,9 @@ KNOBBACKGROUND3X_FN PNG KNOBBACKGROUND3X_FN
FILEBACKGROUND_FN PNG FILEBACKGROUND_FN
FILEBACKGROUND2X_FN PNG FILEBACKGROUND2X_FN
FILEBACKGROUND3X_FN PNG FILEBACKGROUND3X_FN
+INPUTLEVELBACKGROUND_FN PNG INPUTLEVELBACKGROUND_FN
+INPUTLEVELBACKGROUND2X_FN PNG INPUTLEVELBACKGROUND2X_FN
+INPUTLEVELBACKGROUND3X_FN PNG INPUTLEVELBACKGROUND3X_FN
LINES_FN PNG LINES_FN
LINES2X_FN PNG LINES2X_FN
LINES3X_FN PNG LINES3X_FN