Skip to content

Commit

Permalink
use known_audio_plugins.json to store information about installed plu…
Browse files Browse the repository at this point in the history
…gins

(instead of having a separate file for each plugin to avoid possible name conflicts, the user may have the same plugin installed in several different locations)
  • Loading branch information
RomanPudashkin committed Jul 4, 2023
1 parent 13bd0e9 commit 8e1faa4
Show file tree
Hide file tree
Showing 15 changed files with 154 additions and 139 deletions.
4 changes: 2 additions & 2 deletions src/diagnostics/internal/diagnosticfileswriter.cpp
Expand Up @@ -34,9 +34,8 @@ mu::Ret DiagnosticFilesWriter::writeDiagnosticFiles(const path_t& destinationPat
{
TRACEFUNC;

static const std::vector<std::string> DIRS_TO_WRITE {
const std::vector<std::string> DIRS_TO_WRITE {
"logs",
"audio_plugins",
"plugins",
"workspaces",
};
Expand All @@ -61,6 +60,7 @@ mu::Ret DiagnosticFilesWriter::writeDiagnosticFiles(const path_t& destinationPat
const std::vector<std::string> FILES_TO_WRITE {
"shortcuts.xml",
"midi_mappings.xml",
"known_audio_plugins.json",
};

for (const std::string& fileName : FILES_TO_WRITE) {
Expand Down
2 changes: 1 addition & 1 deletion src/framework/audio/audiomodule.cpp
Expand Up @@ -214,7 +214,7 @@ void AudioModule::onInit(const framework::IApplication::RunMode& mode)
for (const io::path_t& p : paths) {
pr->reg("soundfonts", p);
}
pr->reg("audio_plugins", m_configuration->knownAudioPluginsDir());
pr->reg("known_audio_plugins", m_configuration->knownAudioPluginsFilePath());
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/framework/audio/audiotypes.h
Expand Up @@ -186,15 +186,15 @@ struct AudioPluginInfo {
int errorCode = 0;
};

inline AudioPluginType audioPluginTypeFromCategoriesString(const std::string& categoriesStr)
inline AudioPluginType audioPluginTypeFromCategoriesString(const String& categoriesStr)
{
static const std::map<std::string, AudioPluginType> STRING_TO_PLUGIN_TYPE_MAP = {
{ "Fx", AudioPluginType::Fx },
{ "Instrument", AudioPluginType::Instrument },
static const std::map<String, AudioPluginType> STRING_TO_PLUGIN_TYPE_MAP = {
{ u"Fx", AudioPluginType::Fx },
{ u"Instrument", AudioPluginType::Instrument },
};

for (auto it = STRING_TO_PLUGIN_TYPE_MAP.cbegin(); it != STRING_TO_PLUGIN_TYPE_MAP.cend(); ++it) {
if (categoriesStr.find(it->first) != std::string::npos) {
if (categoriesStr.contains(it->first)) {
return it->second;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/framework/audio/iaudioconfiguration.h
Expand Up @@ -70,7 +70,7 @@ class IAudioConfiguration : MODULE_EXPORT_INTERFACE
virtual async::Notification synthesizerStateChanged() const = 0;
virtual async::Notification synthesizerStateGroupChanged(const std::string& groupName) const = 0;

virtual io::path_t knownAudioPluginsDir() const = 0;
virtual io::path_t knownAudioPluginsFilePath() const = 0;
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/framework/audio/internal/audioconfiguration.cpp
Expand Up @@ -260,9 +260,9 @@ async::Notification AudioConfiguration::synthesizerStateGroupChanged(const std::
return m_synthesizerStateGroupChanged[gname];
}

io::path_t AudioConfiguration::knownAudioPluginsDir() const
io::path_t AudioConfiguration::knownAudioPluginsFilePath() const
{
return globalConfiguration()->userAppDataPath() + "/audio_plugins";
return globalConfiguration()->userAppDataPath() + "/known_audio_plugins.json";
}

io::path_t AudioConfiguration::stateFilePath() const
Expand Down
2 changes: 1 addition & 1 deletion src/framework/audio/internal/audioconfiguration.h
Expand Up @@ -70,7 +70,7 @@ class AudioConfiguration : public IAudioConfiguration
async::Notification synthesizerStateChanged() const override;
async::Notification synthesizerStateGroupChanged(const std::string& groupName) const override;

io::path_t knownAudioPluginsDir() const override;
io::path_t knownAudioPluginsFilePath() const override;

private:
async::Channel<io::paths_t> m_soundFontDirsChanged;
Expand Down
129 changes: 67 additions & 62 deletions src/framework/audio/internal/plugins/knownaudiopluginsregister.cpp
Expand Up @@ -38,7 +38,7 @@ static JsonObject attributesToJson(const AudioResourceAttributes& attributes)
JsonObject result;

for (auto it = attributes.cbegin(); it != attributes.cend(); ++it) {
if (it->second == audio::PLAYBACK_SETUP_DATA_ATTRIBUTE) {
if (it->first == audio::PLAYBACK_SETUP_DATA_ATTRIBUTE) {
continue;
}

Expand All @@ -54,10 +54,17 @@ static JsonObject metaToJson(const AudioResourceMeta& meta)

result.set("id", meta.id);
result.set("type", mu::value(RESOURCE_TYPE_TO_STRING_MAP, meta.type, "Undefined"));
result.set("vendor", meta.vendor);
result.set("attributes", attributesToJson(meta.attributes));
result.set("hasNativeEditorSupport", meta.hasNativeEditorSupport);

if (!meta.vendor.empty()) {
result.set("vendor", meta.vendor);
}

JsonObject attributesJson = attributesToJson(meta.attributes);
if (!attributesJson.empty()) {
result.set("attributes", attributesJson);
}

return result;
}

Expand All @@ -79,9 +86,13 @@ static AudioResourceMeta metaFromJson(const JsonObject& object)
result.id = object.value("id").toStdString();
result.type = mu::key(RESOURCE_TYPE_TO_STRING_MAP, object.value("type").toStdString());
result.vendor = object.value("vendor").toStdString();
result.attributes = attributesFromJson(object.value("attributes").toObject());
result.hasNativeEditorSupport = object.value("hasNativeEditorSupport").toBool();

JsonValue attributes = object.value("attributes");
if (attributes.isObject()) {
result.attributes = attributesFromJson(attributes.toObject());
}

return result;
}
}
Expand All @@ -90,50 +101,45 @@ mu::Ret KnownAudioPluginsRegister::load()
{
TRACEFUNC;

io::path_t knownAudioPluginsDir = configuration()->knownAudioPluginsDir();
m_loaded = false;
m_pluginInfoMap.clear();
m_pluginPaths.clear();

if (!fileSystem()->exists(knownAudioPluginsDir)) {
fileSystem()->makePath(knownAudioPluginsDir);
io::path_t knownAudioPluginsPath = configuration()->knownAudioPluginsFilePath();
if (!fileSystem()->exists(knownAudioPluginsPath)) {
m_loaded = true;
return make_ok();
}

RetVal<io::paths_t> paths = fileSystem()->scanFiles(knownAudioPluginsDir,
{ "*.json" },
io::ScanMode::FilesInCurrentDir);
if (!paths.ret) {
return paths.ret;
RetVal<ByteArray> file = fileSystem()->readFile(knownAudioPluginsPath);
if (!file.ret) {
return file.ret;
}

m_pluginInfoMap.clear();
m_pluginPaths.clear();

for (const io::path_t& infoPath : paths.val) {
RetVal<ByteArray> file = fileSystem()->readFile(infoPath);
if (!file.ret) {
LOGE() << file.ret.toString();
continue;
}
std::string err;
JsonDocument json = JsonDocument::fromJson(file.val, &err);
if (!err.empty()) {
return Ret(static_cast<int>(Ret::Code::UnknownError), err);
}

std::string err;
JsonDocument json = JsonDocument::fromJson(file.val, &err);
if (!err.empty()) {
LOGE() << err;
continue;
}
JsonArray array = json.rootArray();

JsonObject object = json.rootObject();
for (size_t i = 0; i < array.size(); ++i) {
JsonObject object = array.at(i).toObject();

AudioPluginInfo info;
info.meta = metaFromJson(object.value("meta").toObject());
info.meta.attributes.insert({ audio::PLAYBACK_SETUP_DATA_ATTRIBUTE, mpe::GENERIC_SETUP_DATA_STRING });
info.type = audioPluginTypeFromCategoriesString(info.meta.attributeVal(audio::CATEGORIES_ATTRIBUTE).toStdString());
info.meta.attributes.emplace(audio::PLAYBACK_SETUP_DATA_ATTRIBUTE, mpe::GENERIC_SETUP_DATA_STRING);
info.type = audioPluginTypeFromCategoriesString(info.meta.attributeVal(audio::CATEGORIES_ATTRIBUTE));
info.path = object.value("path").toString();
info.enabled = object.value("enabled").toBool();
info.errorCode = object.value("errorCode").toInt();

m_pluginInfoMap[info.meta.id] = info;
m_pluginPaths.insert(info.path);
m_pluginInfoMap.emplace(info.meta.id, std::move(info));
}

m_loaded = true;
return make_ok();
}

Expand Down Expand Up @@ -177,60 +183,59 @@ bool KnownAudioPluginsRegister::exists(const AudioResourceId& resourceId) const

mu::Ret KnownAudioPluginsRegister::registerPlugin(const AudioPluginInfo& info)
{
TRACEFUNC;

JsonObject obj;
obj.set("meta", metaToJson(info.meta));
obj.set("path", info.path.toStdString());
obj.set("enabled", info.enabled);

if (info.errorCode != 0) {
obj.set("errorCode", info.errorCode);
}

io::path_t path = pluginInfoPath(info.meta.vendor, info.meta.id);
Ret ret = fileSystem()->writeFile(path, JsonDocument(obj).toJson());
if (!ret) {
return ret;
IF_ASSERT_FAILED(m_loaded) {
return false;
}

m_pluginInfoMap[info.meta.id] = info;
m_pluginPaths.insert(info.path);

return make_ok();
Ret ret = writePluginsInfo();
return ret;
}

mu::Ret KnownAudioPluginsRegister::unregisterPlugin(const AudioResourceId& resourceId)
{
TRACEFUNC;
IF_ASSERT_FAILED(m_loaded) {
return false;
}

if (!exists(resourceId)) {
return make_ok();
}

AudioPluginInfo info = m_pluginInfoMap[resourceId];
io::path_t path = pluginInfoPath(info.meta.vendor, resourceId);

Ret ret = fileSystem()->remove(path);
if (!ret) {
return ret;
}

mu::remove(m_pluginInfoMap, resourceId);
mu::remove(m_pluginPaths, info.path);

return make_ok();
Ret ret = writePluginsInfo();
return ret;
}

mu::io::path_t KnownAudioPluginsRegister::pluginInfoPath(const AudioResourceVendor& vendor, const AudioResourceId& resourceId) const
mu::Ret KnownAudioPluginsRegister::writePluginsInfo()
{
io::path_t fileName;
TRACEFUNC;

JsonArray array;

for (const auto& pair : m_pluginInfoMap) {
const AudioPluginInfo& info = pair.second;

if (vendor.empty()) {
fileName = io::escapeFileName(resourceId);
} else {
fileName = io::escapeFileName(vendor + "_" + resourceId);
JsonObject obj;
obj.set("meta", metaToJson(info.meta));
obj.set("path", info.path.toStdString());
obj.set("enabled", info.enabled);

if (info.errorCode != 0) {
obj.set("errorCode", info.errorCode);
}

array << obj;
}

return configuration()->knownAudioPluginsDir() + "/" + fileName + ".json";
io::path_t knownAudioPluginsPath = configuration()->knownAudioPluginsFilePath();
Ret ret = fileSystem()->writeFile(knownAudioPluginsPath, JsonDocument(array).toJson());

return ret;
}
Expand Up @@ -48,9 +48,10 @@ class KnownAudioPluginsRegister : public IKnownAudioPluginsRegister
Ret unregisterPlugin(const AudioResourceId& resourceId) override;

private:
mu::io::path_t pluginInfoPath(const AudioResourceVendor& vendor, const AudioResourceId& resourceId) const;
Ret writePluginsInfo();

std::unordered_map<AudioResourceId, AudioPluginInfo> m_pluginInfoMap;
bool m_loaded = false;
std::map<AudioResourceId, AudioPluginInfo> m_pluginInfoMap;
std::set<io::path_t> m_pluginPaths;
};
}
Expand Down
Expand Up @@ -129,7 +129,7 @@ mu::Ret RegisterAudioPluginsScenario::registerPlugin(const io::path_t& pluginPat

for (const AudioResourceMeta& meta : metaList.val) {
AudioPluginInfo info;
info.type = audioPluginTypeFromCategoriesString(meta.attributeVal(audio::CATEGORIES_ATTRIBUTE).toStdString());
info.type = audioPluginTypeFromCategoriesString(meta.attributeVal(audio::CATEGORIES_ATTRIBUTE));
info.meta = meta;
info.path = pluginPath;
info.enabled = true;
Expand All @@ -153,6 +153,12 @@ mu::Ret RegisterAudioPluginsScenario::registerFailedPlugin(const io::path_t& plu

AudioPluginInfo info;
info.meta.id = io::filename(pluginPath).toStdString();

std::string ext = io::suffix(pluginPath);
if (ext.find("vst") != std::string::npos) {
info.meta.type = AudioResourceType::VstPlugin;
}

info.path = pluginPath;
info.enabled = false;
info.errorCode = failCode;
Expand Down

0 comments on commit 8e1faa4

Please sign in to comment.