diff --git a/NeuralAmpModeler/NeuralAmpModeler.cpp b/NeuralAmpModeler/NeuralAmpModeler.cpp index 8523ecfb..738717dc 100644 --- a/NeuralAmpModeler/NeuralAmpModeler.cpp +++ b/NeuralAmpModeler/NeuralAmpModeler.cpp @@ -164,7 +164,7 @@ NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info) const auto outputMeterArea = contentArea.GetFromRight(30).GetHShifted(20).GetMidVPadded(100).GetVShifted(-25); // Misc Areas - const auto settingsButtonArea = mainArea.GetFromTRHC(50, 50).GetCentredInside(20, 20); + const auto settingsButtonArea = CornerButtonArea(b); // Model loader button auto loadModelCompletionHandler = [&](const WDL_String& fileName, const WDL_String& path) { @@ -250,7 +250,8 @@ NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info) }, gearSVG)); - pGraphics->AttachControl(new NAMSettingsPageControl(b, backgroundBitmap, style), kCtrlTagSettingsBox)->Hide(true); + pGraphics->AttachControl(new NAMSettingsPageControl(b, backgroundBitmap, crossSVG, style), kCtrlTagSettingsBox) + ->Hide(true); pGraphics->ForAllControlsFunc([](IControl* pControl) { pControl->SetMouseEventsWhenDisabled(true); @@ -377,9 +378,23 @@ void NeuralAmpModeler::OnIdle() if (mNewModelLoadedInDSP) { if (auto* pGraphics = GetUI()) + { pGraphics->GetControlWithTag(kCtrlTagOutNorm)->SetDisabled(!mModel->HasLoudness()); - - mNewModelLoadedInDSP = false; + ModelInfo modelInfo; + modelInfo.sampleRate = mModel->GetEncapsulatedSampleRate(); + modelInfo.knownSampleRate = true; + static_cast(pGraphics->GetControlWithTag(kCtrlTagSettingsBox))->SetModelInfo(modelInfo); + mNewModelLoadedInDSP = false; + } + } + if (mModelCleared) + { + if (auto* pGraphics = GetUI()) + { + pGraphics->GetControlWithTag(kCtrlTagOutNorm)->SetDisabled(false); + static_cast(pGraphics->GetControlWithTag(kCtrlTagSettingsBox))->ClearModelInfo(); + mModelCleared = false; + } } } @@ -534,6 +549,7 @@ void NeuralAmpModeler::_ApplyDSPStaging() mModel = nullptr; mNAMPath.Set(""); mShouldRemoveModel = false; + mModelCleared = true; _UpdateLatency(); } if (mShouldRemoveIR) diff --git a/NeuralAmpModeler/NeuralAmpModeler.h b/NeuralAmpModeler/NeuralAmpModeler.h index a78b0cbd..a391e275 100644 --- a/NeuralAmpModeler/NeuralAmpModeler.h +++ b/NeuralAmpModeler/NeuralAmpModeler.h @@ -268,6 +268,7 @@ class NeuralAmpModeler final : public iplug::Plugin std::atomic mShouldRemoveIR = false; std::atomic mNewModelLoadedInDSP = false; + std::atomic mModelCleared = false; // Tone stack modules std::unique_ptr mToneStack; diff --git a/NeuralAmpModeler/NeuralAmpModelerControls.h b/NeuralAmpModeler/NeuralAmpModelerControls.h index 8abc8d7e..a1fd7d80 100644 --- a/NeuralAmpModeler/NeuralAmpModelerControls.h +++ b/NeuralAmpModeler/NeuralAmpModelerControls.h @@ -10,6 +10,14 @@ using namespace iplug; using namespace igraphics; +// Where the corner button on the plugin (settings, close settings) goes +// :param rect: Rect for the whole plugin's UI +IRECT CornerButtonArea(const IRECT& rect) +{ + const auto mainArea = rect.GetPadded(-20); + return mainArea.GetFromTRHC(50, 50).GetCentredInside(20, 20); +}; + class NAMSquareButtonControl : public ISVGButtonControl { public: @@ -449,7 +457,7 @@ class IContainerBaseWithNamedChildren : public IContainerBase { // Make sure we haven't already used this name assert(mChildNameIndexMap.find(name) == mChildNameIndexMap.end()); - mChildNameIndexMap[name] = (int)mChildNameIndexMap.size(); + mChildNameIndexMap[name] = NChildren(); return AddChildControl(control); }; @@ -464,18 +472,86 @@ class IContainerBaseWithNamedChildren : public IContainerBase std::unordered_map mChildNameIndexMap; }; // class IContainerBaseWithNamedChildren +struct ModelInfo +{ + bool knownSampleRate = false; + double sampleRate = 0.0; +}; + +class ModelInfoControl : public IContainerBaseWithNamedChildren +{ +public: + ModelInfoControl(const IRECT& bounds, const IVStyle& style) + : IContainerBaseWithNamedChildren(bounds) + , mStyle(style) {}; + + void ClearModelInfo() + { + static_cast(GetNamedChild(mControlNames.sampleRate))->SetStr(""); + mHasInfo = false; + }; + + void Hide(bool hide) override + { + // Don't show me unless I have info to show! + IContainerBase::Hide(hide || (!mHasInfo)); + }; + + 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); + }; + + // 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(GetNamedChild(mControlNames.sampleRate))->SetStr(ss.str().c_str()); + mHasInfo = true; + }; + +private: + const IVStyle mStyle; + struct + { + const std::string sampleRate = "sampleRate"; + } mControlNames; + // Do I have info? + bool mHasInfo = false; +}; + class NAMSettingsPageControl : public IContainerBaseWithNamedChildren { public: - NAMSettingsPageControl(const IRECT& bounds, const IBitmap& bitmap, const IVStyle& style) + NAMSettingsPageControl(const IRECT& bounds, const IBitmap& bitmap, ISVG closeSVG, const IVStyle& style) : IContainerBaseWithNamedChildren(bounds) , mAnimationTime(0) , mBitmap(bitmap) , mStyle(style) + , mCloseSVG(closeSVG) { mIgnoreMouse = false; } + void ClearModelInfo() + { + auto* modelInfoControl = static_cast(GetNamedChild(mControlNames.modelInfo)); + assert(modelInfoControl != nullptr); + modelInfoControl->ClearModelInfo(); + } + bool OnKeyDown(float x, float y, const IKeyPress& key) override { if (key.VK == kVK_ESCAPE) @@ -487,8 +563,6 @@ class NAMSettingsPageControl : public IContainerBaseWithNamedChildren return false; } - void OnMouseDown(float x, float y, const IMouseMod& mod) override { HideAnimated(true); } - void HideAnimated(bool hide) { mWillHide = hide; @@ -564,6 +638,16 @@ class NAMSettingsPageControl : public IContainerBaseWithNamedChildren // // }, mStyle, IVColorSwatchControl::ECellLayout::kHorizontal, {kFG}, {""})); + AddNamedChildControl(new ModelInfoControl(GetRECT().GetPadded(-20.0f).GetFromBottom(75.0f).GetFromTop(30.0f), + style.WithValueText(style.valueText.WithAlign(EAlign::Near))), + mControlNames.modelInfo); + + auto closeAction = [&](IControl* pCaller) { + static_cast(pCaller->GetParent())->HideAnimated(true); + }; + AddNamedChildControl( + new NAMSquareButtonControl(CornerButtonArea(GetRECT()), closeAction, mCloseSVG), mControlNames.close); + OnResize(); } @@ -587,10 +671,17 @@ class NAMSettingsPageControl : public IContainerBaseWithNamedChildren } } + void SetModelInfo(const ModelInfo& modelInfo) + { + auto* modelInfoControl = static_cast(GetNamedChild(mControlNames.modelInfo)); + assert(modelInfoControl != nullptr); + modelInfoControl->SetModelInfo(modelInfo); + }; private: IBitmap mBitmap; IVStyle mStyle; + ISVG mCloseSVG; int mAnimationTime = 200; bool mWillHide = false; @@ -601,7 +692,9 @@ class NAMSettingsPageControl : public IContainerBaseWithNamedChildren const std::string bitmap = "bitmap"; const std::string byAuthor = "by author"; const std::string buildInfo = "build info"; + const std::string close = "close"; const std::string development = "development"; + const std::string modelInfo = "model info"; const std::string title = "title"; const std::string website = "website"; } mControlNames; diff --git a/NeuralAmpModeler/ToneStack.h b/NeuralAmpModeler/ToneStack.h index 9a11ec46..1c703406 100644 --- a/NeuralAmpModeler/ToneStack.h +++ b/NeuralAmpModeler/ToneStack.h @@ -43,7 +43,7 @@ class BasicNamToneStack : public AbstractToneStack DSP_SAMPLE** Process(DSP_SAMPLE** inputs, const int numChannels, const int numFrames); virtual void Reset(const double sampleRate, const int maxBlockSize) override; // :param val: Assumed to be between 0 and 10, 5 is "noon" - void SetParam(const std::string name, const double val); + virtual void SetParam(const std::string name, const double val) override; protected: