195 lines
5.1 KiB
C++
195 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.
|
|
*/
|
|
|
|
#include "rack.hpp"
|
|
#include "plugin.hpp"
|
|
|
|
#include "DistrhoUtils.hpp"
|
|
|
|
// Cardinal (built-in)
|
|
#include "Cardinal/src/plugin.hpp"
|
|
|
|
// known terminal modules
|
|
std::vector<Model*> hostTerminalModels;
|
|
|
|
// plugin instances
|
|
Plugin* pluginInstance__Cardinal;
|
|
|
|
namespace rack {
|
|
|
|
namespace asset {
|
|
std::string pluginManifest(const std::string& dirname);
|
|
std::string pluginPath(const std::string& dirname);
|
|
}
|
|
|
|
namespace plugin {
|
|
|
|
struct StaticPluginLoader {
|
|
Plugin* const plugin;
|
|
FILE* file;
|
|
json_t* rootJ;
|
|
|
|
StaticPluginLoader(Plugin* const p, const char* const name)
|
|
: plugin(p),
|
|
file(nullptr),
|
|
rootJ(nullptr)
|
|
{
|
|
#ifdef DEBUG
|
|
DEBUG("Loading plugin module %s", name);
|
|
#endif
|
|
|
|
p->path = asset::pluginPath(name);
|
|
|
|
const std::string manifestFilename = asset::pluginManifest(name);
|
|
|
|
if ((file = std::fopen(manifestFilename.c_str(), "r")) == nullptr)
|
|
{
|
|
d_stderr2("Manifest file %s does not exist", manifestFilename.c_str());
|
|
return;
|
|
}
|
|
|
|
json_error_t error;
|
|
if ((rootJ = json_loadf(file, 0, &error)) == nullptr)
|
|
{
|
|
d_stderr2("JSON parsing error at %s %d:%d %s", manifestFilename.c_str(), error.line, error.column, error.text);
|
|
return;
|
|
}
|
|
|
|
// force ABI, we use static plugins so this doesnt matter as long as it builds
|
|
json_t* const version = json_string((APP_VERSION_MAJOR + ".0").c_str());
|
|
json_object_set(rootJ, "version", version);
|
|
json_decref(version);
|
|
|
|
// Load manifest
|
|
p->fromJson(rootJ);
|
|
|
|
// Reject plugin if slug already exists
|
|
if (Plugin* const existingPlugin = getPlugin(p->slug))
|
|
throw Exception("Plugin %s is already loaded, not attempting to load it again", p->slug.c_str());
|
|
}
|
|
|
|
~StaticPluginLoader()
|
|
{
|
|
if (rootJ != nullptr)
|
|
{
|
|
// Load modules manifest
|
|
json_t* const modulesJ = json_object_get(rootJ, "modules");
|
|
plugin->modulesFromJson(modulesJ);
|
|
|
|
json_decref(rootJ);
|
|
plugins.push_back(plugin);
|
|
}
|
|
|
|
if (file != nullptr)
|
|
std::fclose(file);
|
|
}
|
|
|
|
bool ok() const noexcept
|
|
{
|
|
return rootJ != nullptr;
|
|
}
|
|
|
|
void removeModule(const char* const slugToRemove) const noexcept
|
|
{
|
|
json_t* const modules = json_object_get(rootJ, "modules");
|
|
DISTRHO_SAFE_ASSERT_RETURN(modules != nullptr,);
|
|
|
|
size_t i;
|
|
json_t* v;
|
|
json_array_foreach(modules, i, v)
|
|
{
|
|
if (json_t* const slug = json_object_get(v, "slug"))
|
|
{
|
|
if (const char* const value = json_string_value(slug))
|
|
{
|
|
if (std::strcmp(value, slugToRemove) == 0)
|
|
{
|
|
json_array_remove(modules, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
static void initStatic__Cardinal()
|
|
{
|
|
Plugin* const p = new Plugin;
|
|
pluginInstance__Cardinal = p;
|
|
|
|
const StaticPluginLoader spl(p, "Cardinal");
|
|
if (spl.ok())
|
|
{
|
|
p->addModel(modelHostAudio2);
|
|
p->addModel(modelHostCV);
|
|
p->addModel(modelHostMIDI);
|
|
p->addModel(modelHostMIDICC);
|
|
p->addModel(modelHostMIDIGate);
|
|
p->addModel(modelHostMIDIMap);
|
|
p->addModel(modelHostParameters);
|
|
p->addModel(modelHostParametersMap);
|
|
p->addModel(modelHostTime);
|
|
p->addModel(modelTextEditor);
|
|
#ifdef HAVE_FFTW3F
|
|
p->addModel(modelAudioToCVPitch);
|
|
#else
|
|
spl.removeModule("AudioToCVPitch");
|
|
#endif
|
|
spl.removeModule("AudioFile");
|
|
spl.removeModule("Blank");
|
|
spl.removeModule("Carla");
|
|
spl.removeModule("ExpanderInputMIDI");
|
|
spl.removeModule("ExpanderOutputMIDI");
|
|
spl.removeModule("HostAudio8");
|
|
spl.removeModule("Ildaeil");
|
|
spl.removeModule("MPV");
|
|
spl.removeModule("SassyScope");
|
|
spl.removeModule("glBars");
|
|
|
|
hostTerminalModels = {
|
|
modelHostAudio2,
|
|
modelHostCV,
|
|
modelHostMIDI,
|
|
modelHostMIDICC,
|
|
modelHostMIDIGate,
|
|
modelHostMIDIMap,
|
|
modelHostParameters,
|
|
modelHostParametersMap,
|
|
modelHostTime,
|
|
};
|
|
}
|
|
}
|
|
|
|
void initStaticPlugins()
|
|
{
|
|
initStatic__Cardinal();
|
|
}
|
|
|
|
void destroyStaticPlugins()
|
|
{
|
|
for (Plugin* p : plugins)
|
|
delete p;
|
|
plugins.clear();
|
|
}
|
|
|
|
void updateStaticPluginsDarkMode()
|
|
{
|
|
}
|
|
|
|
}
|
|
}
|