Skip to content
Draft
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
44 changes: 41 additions & 3 deletions NeuralAmpModeler/NeuralAmpModeler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <cmath> // pow
#include <filesystem>
#include <iostream>
#include <string>
#include <utility>

#include "Colors.h"
Expand Down Expand Up @@ -69,6 +70,23 @@ EMsgBoxResult _ShowMessageBox(iplug::igraphics::IGraphics* pGraphics, const char
#endif
}

std::string _GetModelDisplayName(const nam::dspData& modelData)
{
if (!modelData.metadata.is_object())
{
return "";
}

auto it = modelData.metadata.find("name");
if (it == modelData.metadata.end() || !it->is_string())
{
return "";
}

const std::string name = it->get<std::string>();
return name.empty() ? "" : name;
}

const std::string kCalibrateInputParamName = "CalibrateInput";
const bool kDefaultCalibrateInput = false;
const std::string kInputCalibrationLevelParamName = "InputCalibrationLevel";
Expand Down Expand Up @@ -486,7 +504,7 @@ void NeuralAmpModeler::OnUIOpen()

if (mNAMPath.GetLength())
{
SendControlMsgFromDelegate(kCtrlTagModelFileBrowser, kMsgTagLoadedModel, mNAMPath.GetLength(), mNAMPath.Get());
_SendLoadedModelMessage();
// If it's not loaded yet, then mark as failed.
// If it's yet to be loaded, then the completion handler will set us straight once it runs.
if (mModel == nullptr && mStagedModel == nullptr)
Expand Down Expand Up @@ -599,6 +617,7 @@ void NeuralAmpModeler::_ApplyDSPStaging()
{
mModel = nullptr;
mNAMPath.Set("");
mNAMDisplayName.Set("");
mShouldRemoveModel = false;
mModelCleared = true;
_UpdateLatency();
Expand Down Expand Up @@ -742,13 +761,30 @@ void NeuralAmpModeler::_ApplySlimParamToLoadedNAMs()
apply(mStagedModel.get());
}

void NeuralAmpModeler::_SendLoadedModelMessage()
{
std::string payload(mNAMPath.Get(), mNAMPath.GetLength());
payload.push_back('\0');

if (mNAMDisplayName.GetLength())
{
payload.append(mNAMDisplayName.Get(), mNAMDisplayName.GetLength());
payload.push_back('\0');
}

SendControlMsgFromDelegate(kCtrlTagModelFileBrowser, kMsgTagLoadedModel, static_cast<int>(payload.size()),
payload.data());
}

std::string NeuralAmpModeler::_StageModel(const WDL_String& modelPath)
{
WDL_String previousNAMPath = mNAMPath;
WDL_String previousNAMDisplayName = mNAMDisplayName;
try
{
auto dspPath = std::filesystem::u8path(modelPath.Get());
std::unique_ptr<nam::DSP> model = nam::get_dsp(dspPath);
nam::dspData modelData;
std::unique_ptr<nam::DSP> model = nam::get_dsp(dspPath, modelData);

// Check that the model has 1 input and 1 output channel
if (model->NumInputChannels() != 1)
Expand All @@ -769,7 +805,8 @@ std::string NeuralAmpModeler::_StageModel(const WDL_String& modelPath)
}
mStagedModel = std::move(temp);
mNAMPath = modelPath;
SendControlMsgFromDelegate(kCtrlTagModelFileBrowser, kMsgTagLoadedModel, mNAMPath.GetLength(), mNAMPath.Get());
mNAMDisplayName.Set(_GetModelDisplayName(modelData).c_str());
_SendLoadedModelMessage();
}
catch (std::runtime_error& e)
{
Expand All @@ -780,6 +817,7 @@ std::string NeuralAmpModeler::_StageModel(const WDL_String& modelPath)
mStagedModel = nullptr;
}
mNAMPath = previousNAMPath;
mNAMDisplayName = previousNAMDisplayName;
std::cerr << "Failed to read DSP module" << std::endl;
std::cerr << e.what() << std::endl;
return e.what();
Expand Down
3 changes: 3 additions & 0 deletions NeuralAmpModeler/NeuralAmpModeler.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ class NeuralAmpModeler final : public iplug::Plugin
void _SetInputGain();
void _SetOutputGain();
void _ApplySlimParamToLoadedNAMs();
void _SendLoadedModelMessage();

// See: Unserialization.cpp
void _UnserializeApplyConfig(nlohmann::json& config);
Expand Down Expand Up @@ -316,6 +317,8 @@ class NeuralAmpModeler final : public iplug::Plugin

// Path to model's config.json or model.nam
WDL_String mNAMPath;
// Name from the model metadata, if present.
WDL_String mNAMDisplayName;
// Path to IR (.wav file)
WDL_String mIRPath;

Expand Down
117 changes: 110 additions & 7 deletions NeuralAmpModeler/NeuralAmpModelerControls.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
#pragma once

#include <algorithm> // std::find
#include <cmath> // std::round
#include <cstdio> // FILE, fclose
#include <fstream> // std::ifstream
#include <sstream> // std::stringstream
#include <string> // std::string
#include <string_view> // std::string_view
#include <unordered_map> // std::unordered_map
#include "IControls.h"
#include "IPlugPaths.h"

#include "../NeuralAmpModelerCore/Dependencies/nlohmann/json.hpp"

#ifdef OS_WIN
#include <Windows.h>
#include <Shellapi.h>
Expand Down Expand Up @@ -269,7 +275,6 @@ class NAMFileBrowserControl : public IDirBrowseControlBase
const ISVG& clearSVG, const ISVG& leftSVG, const ISVG& rightSVG, const IBitmap& bitmap,
const ISVG& globeSVG, const char* getButtonLabel, const char* getButtonURL)
: IDirBrowseControlBase(bounds, fileExtension, false, false)
, mClearMsgTag(clearMsgTag)
, mDefaultLabelStr(labelStr)
, mCompletionHandlerFunc(ch)
, mStyle(style.WithColor(kFG, COLOR_TRANSPARENT).WithDrawFrame(false))
Expand All @@ -279,6 +284,8 @@ class NAMFileBrowserControl : public IDirBrowseControlBase
, mLeftSVG(leftSVG)
, mRightSVG(rightSVG)
, mGlobeSVG(globeSVG)
, mClearMsgTag(clearMsgTag)
, mUseModelMetadataNames(std::string_view(fileExtension) == "nam")
, mGetButtonLabel(getButtonLabel)
, mGetButtonURL(getButtonURL)
, mBrowserState(NAMBrowserState::Empty)
Expand Down Expand Up @@ -338,7 +345,7 @@ class NAMFileBrowserControl : public IDirBrowseControlBase
{
ClearPathList();
AddPath(path.Get(), "");
SetupMenu();
SetupMenuWithDisplayNames();
SelectFirstFile();
LoadFileAtCurrentIndex();
}
Expand All @@ -350,7 +357,7 @@ class NAMFileBrowserControl : public IDirBrowseControlBase
{
ClearPathList();
AddPath(path.Get(), "");
SetupMenu();
SetupMenuWithDisplayNames();
SetSelectedFile(fileName.Get());
LoadFileAtCurrentIndex();
}
Expand Down Expand Up @@ -425,6 +432,21 @@ class NAMFileBrowserControl : public IDirBrowseControlBase

void OnMsgFromDelegate(int msgTag, int dataSize, const void* pData) override
{
auto ReadPayloadString = [](const void* payload, int size, int& offset) {
if (payload == nullptr || offset >= size)
{
return std::string();
}

const char* data = reinterpret_cast<const char*>(payload);
const char* begin = data + offset;
const char* end = data + size;
const char* terminator = std::find(begin, end, '\0');
std::string value(begin, terminator);
offset = terminator == end ? size : static_cast<int>(terminator - data) + 1;
return value;
};

switch (msgTag)
{
case kMsgTagLoadFailed:
Expand All @@ -438,16 +460,26 @@ class NAMFileBrowserControl : public IDirBrowseControlBase
case kMsgTagLoadedModel:
case kMsgTagLoadedIR:
{
int offset = 0;
const std::string pathString = ReadPayloadString(pData, dataSize, offset);
const std::string displayName = msgTag == kMsgTagLoadedModel ? ReadPayloadString(pData, dataSize, offset) : "";
WDL_String fileName, directory;
fileName.Set(reinterpret_cast<const char*>(pData));
directory.Set(reinterpret_cast<const char*>(pData));
fileName.Set(pathString.c_str());
directory.Set(pathString.c_str());
directory.remove_filepart(true);

ClearPathList();
AddPath(directory.Get(), "");
SetupMenu();
SetupMenuWithDisplayNames();
SetSelectedFile(fileName.Get());
mFileNameControl->SetLabelAndTooltipEllipsizing(fileName);
if (displayName.empty())
{
mFileNameControl->SetLabelAndTooltipEllipsizing(fileName);
}
else
{
mFileNameControl->SetLabelAndTooltip(displayName.c_str());
}
SetBrowserState(NAMBrowserState::Loaded);
}
break;
Expand All @@ -458,6 +490,75 @@ class NAMFileBrowserControl : public IDirBrowseControlBase
private:
void SelectFirstFile() { mSelectedItemIndex = mFiles.GetSize() ? 0 : -1; }

void SetupMenuWithDisplayNames()
{
SetupMenu();
UpdateModelMenuDisplayNames();
}

std::string GetCachedModelMetadataName(const char* filePath)
{
const std::string key(filePath);
auto cached = mModelMetadataNames.find(key);
if (cached != mModelMetadataNames.end())
{
return cached->second;
}

std::ifstream file(filePath);
if (!file.is_open())
{
mModelMetadataNames[key] = "";
return "";
}

try
{
nlohmann::json modelJson;
file >> modelJson;
const auto metadata = modelJson.find("metadata");
if (metadata != modelJson.end() && metadata->is_object())
{
const auto name = metadata->find("name");
if (name != metadata->end() && name->is_string())
{
mModelMetadataNames[key] = name->get<std::string>();
return mModelMetadataNames[key];
}
}
}
catch (const nlohmann::json::exception&)
{
}

mModelMetadataNames[key] = "";
return "";
}

void UpdateModelMenuDisplayNames()
{
if (!mUseModelMetadataNames)
{
return;
}

for (int itemIdx = 0; itemIdx < mItems.GetSize(); itemIdx++)
{
IPopupMenu::Item* pItem = mItems.Get(itemIdx);
const int fileIdx = pItem->GetTag();
if (fileIdx < 0 || fileIdx >= mFiles.GetSize())
{
continue;
}

const std::string displayName = GetCachedModelMetadataName(mFiles.Get(fileIdx)->Get());
if (!displayName.empty())
{
pItem->SetText(displayName.c_str());
}
}
}

void GetSelectedFileDirectory(WDL_String& path)
{
GetSelectedFile(path);
Expand Down Expand Up @@ -490,6 +591,8 @@ class NAMFileBrowserControl : public IDirBrowseControlBase
IBitmap mBitmap;
ISVG mLoadSVG, mClearSVG, mLeftSVG, mRightSVG, mGlobeSVG;
int mClearMsgTag;
bool mUseModelMetadataNames;
std::unordered_map<std::string, std::string> mModelMetadataNames;

// new members for the "Get" button
const char* mGetButtonLabel;
Expand Down