1
Fork 0
cardinal/src/override/plugin.cpp

192 lines
5.1 KiB
C++

/*
* DISTRHO Cardinal Plugin
* Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the LICENSE file.
*/
/**
* This file is an edited version of VCVRack's plugin.cpp
* Copyright (C) 2016-2021 VCV.
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*/
#include <algorithm>
#include <map>
#include <plugin.hpp>
namespace rack {
namespace plugin {
/** Given slug => fallback slug.
Correctly handles bidirectional fallbacks.
To request fallback slugs to be added to this list, open a GitHub issue.
*/
static const std::map<std::string, std::string> pluginSlugFallbacks = {
{"VultModulesFree", "VultModules"},
{"VultModules", "VultModulesFree"},
{"AudibleInstrumentsPreview", "AudibleInstruments"},
// {"", ""},
};
Plugin* getPlugin(const std::string& pluginSlug) {
if (pluginSlug.empty())
return NULL;
auto it = std::find_if(plugins.begin(), plugins.end(), [=](Plugin* p) {
return p->slug == pluginSlug;
});
if (it != plugins.end())
return *it;
return NULL;
}
Plugin* getPluginFallback(const std::string& pluginSlug) {
if (pluginSlug.empty())
return NULL;
// Attempt example plugin
Plugin* p = getPlugin(pluginSlug);
if (p)
return p;
// Attempt fallback plugin slug
auto it = pluginSlugFallbacks.find(pluginSlug);
if (it != pluginSlugFallbacks.end())
return getPlugin(it->second);
return NULL;
}
/** Given slug => fallback slug.
Correctly handles bidirectional fallbacks.
To request fallback slugs to be added to this list, open a GitHub issue.
*/
using PluginModuleSlug = std::tuple<std::string, std::string>;
static const std::map<PluginModuleSlug, PluginModuleSlug> moduleSlugFallbacks = {
{{"Core", "AudioInterface2"}, {"Cardinal", "HostAudio2"}},
{{"Core", "AudioInterface"}, {"Cardinal", "HostAudio8"}},
{{"Core", "AudioInterface16"}, {"Cardinal", "HostAudio8"}},
{{"Core", "MIDIToCVInterface"}, {"Cardinal", "HostMIDI"}},
{{"Core", "MIDICCToCVInterface"}, {"Cardinal", "HostMIDICC"}},
{{"Core", "MIDITriggerToCVInterface"}, {"Cardinal", "HostMIDIGate"}},
{{"Core", "CV-MIDI"}, {"Cardinal", "HostMIDI"}},
{{"Core", "CV-CC"}, {"Cardinal", "HostMIDICC"}},
{{"Core", "CV-Gate"}, {"Cardinal", "HostMIDIGate"}},
{{"Core", "MIDI-Map"}, {"Cardinal", "HostMIDIMap"}},
{{"Core", "Notes"}, {"Cardinal", "TextEditor"}},
{{"Core", "Blank"}, {"Cardinal", "Blank"}},
{{"MindMeld-ShapeMasterPro", "ShapeMasterPro"}, {"MindMeldModular", "ShapeMaster"}},
// {{"", ""}, {"", ""}},
};
Model* getModel(const std::string& pluginSlug, const std::string& modelSlug) {
if (pluginSlug.empty() || modelSlug.empty())
return NULL;
Plugin* p = getPlugin(pluginSlug);
if (!p)
return NULL;
return p->getModel(modelSlug);
}
Model* getModelFallback(const std::string& pluginSlug, const std::string& modelSlug) {
if (pluginSlug.empty() || modelSlug.empty())
return NULL;
// Attempt exact plugin and model
Model* m = getModel(pluginSlug, modelSlug);
if (m)
return m;
// Attempt fallback module
auto it = moduleSlugFallbacks.find(std::make_tuple(pluginSlug, modelSlug));
if (it != moduleSlugFallbacks.end()) {
Model* m = getModel(std::get<0>(it->second), std::get<1>(it->second));
if (m)
return m;
}
// Attempt fallback plugin
auto it2 = pluginSlugFallbacks.find(pluginSlug);
if (it2 != pluginSlugFallbacks.end()) {
Model* m = getModel(it2->second, modelSlug);
if (m)
return m;
}
return NULL;
}
Model* modelFromJson(json_t* moduleJ) {
// Get slugs
json_t* pluginSlugJ = json_object_get(moduleJ, "plugin");
if (!pluginSlugJ)
throw Exception("\"plugin\" property not found in module JSON");
std::string pluginSlug = json_string_value(pluginSlugJ);
pluginSlug = normalizeSlug(pluginSlug);
json_t* modelSlugJ = json_object_get(moduleJ, "model");
if (!modelSlugJ)
throw Exception("\"model\" property not found in module JSON");
std::string modelSlug = json_string_value(modelSlugJ);
modelSlug = normalizeSlug(modelSlug);
// Get Model
Model* model = getModelFallback(pluginSlug, modelSlug);
if (!model)
throw Exception("Could not find module %s/%s", pluginSlug.c_str(), modelSlug.c_str());
return model;
}
bool isSlugValid(const std::string& slug) {
for (char c : slug) {
if (!(std::isalnum(c) || c == '-' || c == '_'))
return false;
}
return true;
}
std::string normalizeSlug(const std::string& slug) {
std::string s;
for (char c : slug) {
if (!(std::isalnum(c) || c == '-' || c == '_'))
continue;
s += c;
}
return s;
}
std::vector<Plugin*> plugins;
} // namespace plugin
} // namespace rack