From 27d7a0fa77efd70662be629834afc5b0f43ca525 Mon Sep 17 00:00:00 2001 From: Durgesh Date: Fri, 24 Feb 2023 14:20:07 -0500 Subject: [PATCH 1/5] Fixing FFMpeg Streaming. Need to compile FFMpeg libs with xcbgrab option --- Server/CMakeLists.txt | 2 +- Server/Source/ScreenRecorder.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Server/CMakeLists.txt b/Server/CMakeLists.txt index a74fa15..8996147 100644 --- a/Server/CMakeLists.txt +++ b/Server/CMakeLists.txt @@ -75,7 +75,7 @@ target_link_libraries(AudioGridderServer PRIVATE ${SENTRY_LIBRARIES}) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - target_link_libraries(AudioGridderServer PRIVATE X11 Xtst) + target_link_libraries(AudioGridderServer PRIVATE X11 Xtst xcb xcb-shm xcb-xfixes xcb-shape) target_compile_definitions(AudioGridderServer PRIVATE JUCE_LINUX=1) endif() diff --git a/Server/Source/ScreenRecorder.cpp b/Server/Source/ScreenRecorder.cpp index 02b2b54..ecb1cca 100644 --- a/Server/Source/ScreenRecorder.cpp +++ b/Server/Source/ScreenRecorder.cpp @@ -87,6 +87,9 @@ void ScreenRecorder::initialize(ScreenRecorder::EncoderMode encMode, EncoderQual askForScreenRecordingPermission(); m_inputFmtName = "avfoundation"; m_inputStreamUrl = String(getCaptureDeviceIndex()) + ":none"; +#elif defined JUCE_LINUX + m_inputFmtName = "x11grab"; + m_inputStreamUrl = ":0.0"; #else m_inputFmtName = "gdigrab"; m_inputStreamUrl = "desktop"; @@ -291,11 +294,14 @@ bool ScreenRecorder::prepareInput() { #endif int ret; - - logln("opening input format " << m_inputFmtName << ": " << m_inputStreamUrl); + String streamUrl = m_inputStreamUrl; +#ifdef JUCE_LINUX + streamUrl = streamUrl << "+" << m_captureRect.getX() << "," << m_captureRect.getY(); +#endif + logln("opening input format " << m_inputFmtName << ": " << streamUrl); m_captureFmtCtx = avformat_alloc_context(); - ret = avformat_open_input(&m_captureFmtCtx, m_inputStreamUrl.getCharPointer(), m_inputFmt, &opts); + ret = avformat_open_input(&m_captureFmtCtx, streamUrl.getCharPointer(), m_inputFmt, &opts); if (ret != 0) { logError("prepareInput: avformat_open_input failed: err = " + String(ret)); return false; From 7652253075d67daaa82ffee4f10801af3bd930f7 Mon Sep 17 00:00:00 2001 From: Durgesh Kumar Date: Sun, 26 Feb 2023 12:47:47 -0500 Subject: [PATCH 2/5] LV2 plugin support rough draft changes to support LV2 plugin formats --- Server/CMakeLists.txt | 1 + Server/Source/PluginListComponent.cpp | 3 ++- Server/Source/Processor.cpp | 3 ++- Server/Source/Processor.hpp | 2 +- Server/Source/Server.cpp | 14 ++++++++++++++ Server/Source/Server.hpp | 4 ++++ 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Server/CMakeLists.txt b/Server/CMakeLists.txt index 8996147..6260faa 100644 --- a/Server/CMakeLists.txt +++ b/Server/CMakeLists.txt @@ -45,6 +45,7 @@ target_compile_definitions(AudioGridderServer PRIVATE AG_SENTRY_CRASHPAD_PATH="${AG_SENTRY_CRASHPAD_PATH}" JUCE_PLUGINHOST_VST3=1 JUCE_PLUGINHOST_VST=${AG_PLUGINHOST_VST} + JUCE_PLUGINHOST_LV2=1 JUCE_WEB_BROWSER=0 JUCE_USE_CURL=0 JUCE_MODAL_LOOPS_PERMITTED=1 diff --git a/Server/Source/PluginListComponent.cpp b/Server/Source/PluginListComponent.cpp index 54a9fe1..d4530fe 100644 --- a/Server/Source/PluginListComponent.cpp +++ b/Server/Source/PluginListComponent.cpp @@ -59,7 +59,8 @@ class PluginListComponent::TableModel : public TableListBoxModel { File f(name); String type; - if (f.getFileExtension().toLowerCase() == ".vst" || f.getFileExtension().toLowerCase() == ".vst3") { + if (f.getFileExtension().toLowerCase() == ".lv2" || f.getFileExtension().toLowerCase() == ".vst" || + f.getFileExtension().toLowerCase() == ".vst3") { name = f.getFileNameWithoutExtension(); type = f.getFileExtension().toUpperCase().substring(1); } else if (f.getFileExtension().toLowerCase() == ".dll") { diff --git a/Server/Source/Processor.cpp b/Server/Source/Processor.cpp index c749ef0..c77880c 100644 --- a/Server/Source/Processor.cpp +++ b/Server/Source/Processor.cpp @@ -49,6 +49,7 @@ Processor::Processor(ProcessorChain& chain, const String& id, double sampleRate, m_isClient(isClient), m_fmt(id.startsWith("VST3") ? VST3 : id.startsWith("VST") ? VST + : id.startsWith("LV2") ? LV2 : AU) { initAsyncFunctors(); @@ -93,7 +94,7 @@ String Processor::convertJUCEtoAGPluginID(const String& id) { if ((pos = id.indexOfChar(0, '-')) > -1) { format = id.substring(0, pos); - if (format != "AudioUnit" && format != "VST" && format != "VST3") { + if (format != "AudioUnit" && format != "VST" && format != "VST3" && format != "LV2") { return {}; } name = id.substring(pos + 1); diff --git a/Server/Source/Processor.hpp b/Server/Source/Processor.hpp index f2bd1e3..8fb0a9c 100644 --- a/Server/Source/Processor.hpp +++ b/Server/Source/Processor.hpp @@ -221,7 +221,7 @@ class Processor : public LogTagDelegate, public std::enable_shared_from_this m_lastPosition = {0, 0}; - enum FormatType { VST, VST3, AU }; + enum FormatType { VST, VST3, AU, LV2 }; FormatType m_fmt; std::shared_ptr getPlugin(int channel) { diff --git a/Server/Source/Server.cpp b/Server/Source/Server.cpp index 5b2ee40..7c2e0a0 100644 --- a/Server/Source/Server.cpp +++ b/Server/Source/Server.cpp @@ -119,6 +119,20 @@ void Server::loadConfig() { } m_vstNoStandardFolders = jsonGetValue(cfg, "VSTNoStandardFolders", false); logln("include VST standard folders is " << (m_vstNoStandardFolders ? "disabled" : "enabled")); + + m_enableLV2 = jsonGetValue(cfg, "LV2", m_enableLV2); + logln("LV2 support " << (m_enableLV2 ? "enabled" : "disabled")); + m_lv2Folders.clear(); + if (jsonHasValue(cfg, "LV2Folders") && cfg["LV2Folders"].size() > 0) { + logln("LV2 custom folders:"); + for (auto& s : cfg["LV2Folders"]) { + if (s.get().length() > 0) { + logln(" " << s.get()); + m_lv2Folders.add(s.get()); + } + } + } + m_screenCapturingFFmpeg = jsonGetValue(cfg, "ScreenCapturingFFmpeg", m_screenCapturingFFmpeg); String encoder = "webp"; m_screenCapturingFFmpegEncMode = ScreenRecorder::WEBP; diff --git a/Server/Source/Server.hpp b/Server/Source/Server.hpp index cfa8219..f185b0f 100644 --- a/Server/Source/Server.hpp +++ b/Server/Source/Server.hpp @@ -49,6 +49,8 @@ class Server : public Thread, public LogTag { void setEnableVST3(bool b) { m_enableVST3 = b; } bool getEnableVST2() const { return m_enableVST2; } void setEnableVST2(bool b) { m_enableVST2 = b; } + bool getEnableLV2() const { return m_enableLV2; } + void setEnableLV2(bool b) { m_enableLV2 = b; } const StringArray& getVST3Folders() const { return m_vst3Folders; } void setVST3Folders(const StringArray& folders) { m_vst3Folders = folders; } const StringArray& getVST2Folders() const { return m_vst2Folders; } @@ -154,6 +156,7 @@ class Server : public Thread, public LogTag { bool m_enableAU = true; bool m_enableVST3 = true; bool m_enableVST2 = true; + bool m_enableLV2 = true; float m_screenJpgQuality = 0.9f; bool m_screenDiffDetection = true; bool m_screenCapturingOff = false; @@ -171,6 +174,7 @@ class Server : public Thread, public LogTag { ScreenRecorder::EncoderQuality m_screenCapturingFFmpegQuality = ScreenRecorder::ENC_QUALITY_MEDIUM; StringArray m_vst3Folders; StringArray m_vst2Folders; + StringArray m_lv2Folders; bool m_vstNoStandardFolders; bool m_scanForPlugins = true; bool m_crashReporting = true; From e8026fcb4d2fe9cb192b0cf1f57eba08498f868f Mon Sep 17 00:00:00 2001 From: Durgesh Kumar Date: Thu, 9 Mar 2023 04:18:01 -0500 Subject: [PATCH 3/5] LV2 plugin support Tested with chowmatrix.lv2 plugin --- Server/Source/Processor.cpp | 6 +++++ Server/Source/Server.cpp | 44 +++++++++++++++++++++++++++++++++++-- Server/Source/Server.hpp | 2 ++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/Server/Source/Processor.cpp b/Server/Source/Processor.cpp index c77880c..08353f9 100644 --- a/Server/Source/Processor.cpp +++ b/Server/Source/Processor.cpp @@ -308,6 +308,12 @@ std::shared_ptr Processor::loadPlugin(const PluginDescripti String err2; AudioPluginFormatManager plugmgr; plugmgr.addDefaultFormats(); +#if JUCE_PLUGINHOST_LV2 + if (plugdesc.pluginFormatName == "LV2") { + AudioPluginFormat* fmt = new LV2PluginFormat(); + plugmgr.addFormat(fmt); + } +#endif std::shared_ptr inst; runOnMsgThreadSync([&] { traceScope(); diff --git a/Server/Source/Server.cpp b/Server/Source/Server.cpp index 3bd6f99..9c5fc36 100644 --- a/Server/Source/Server.cpp +++ b/Server/Source/Server.cpp @@ -198,6 +198,11 @@ void Server::saveConfig() { for (auto& f : m_vst2Folders) { j["VST2Folders"].push_back(f.toStdString()); } + j["LV2"] = m_enableLV2; + j["LV2Folders"] = json::array(); + for (auto& f : m_lv2Folders) { + j["LV2Folders"].push_back(f.toStdString()); + } j["VSTNoStandardFolders"] = m_vstNoStandardFolders; j["ScreenCapturingFFmpeg"] = m_screenCapturingFFmpeg; switch (m_screenCapturingFFmpegEncMode) { @@ -265,6 +270,10 @@ void Server::loadKnownPluginList() { #endif } else if (desc.pluginFormatName == "VST3") { fmt = std::make_unique(); +#if JUCE_PLUGINHOST_LV2 + } else if (desc.pluginFormatName == "LV2") { + fmt = std::make_unique(); +#endif } if (nullptr != fmt) { @@ -559,6 +568,10 @@ bool Server::scanPlugin(const String& id, const String& format, int srvId, bool #if JUCE_MAC } else if (!format.compare("AudioUnit")) { fmt = std::make_unique(); +#endif +#if JUCE_PLUGINHOST_LV2 + } else if (!format.compare("LV2")) { + fmt = std::make_unique(); #endif } else { return false; @@ -832,7 +845,7 @@ void Server::scanForPlugins(const std::vector& include) { traceScope(); logln("scanning for plugins..."); std::vector> fmts; - size_t fmtAU = 0, fmtVST = 0, fmtVST3 = 0; + size_t fmtAU = 0, fmtVST = 0, fmtVST3 = 0, fmtLV2 = 0; #if JUCE_MAC if (m_enableAU) { @@ -850,6 +863,12 @@ void Server::scanForPlugins(const std::vector& include) { fmts.push_back(std::make_unique()); } #endif +#if JUCE_PLUGINHOST_LV2 + if (m_enableLV2) { + fmtLV2 = fmts.size(); + fmts.push_back(std::make_unique()); + } +#endif std::set neverSeenList = m_pluginExclude; std::set newBlacklistedPlugins; @@ -877,13 +896,27 @@ void Server::scanForPlugins(const std::vector& include) { std::atomic progress{0}; StringArray fileOrIds; + KnownPluginList pluginList; for (auto& fmt : fmts) { FileSearchPath searchPaths; if (fmt->getName().compare("AudioUnit") && !m_vstNoStandardFolders) { searchPaths = fmt->getDefaultLocationsToSearch(); } - if (!fmt->getName().compare("VST3")) { + if (fmt->getName().compare("LV2")) { + searchPaths = fmt->getDefaultLocationsToSearch(); + for (auto& f : m_lv2Folders) { + searchPaths.addIfNotAlreadyThere(f); + } + logln("LV2 search paths " << searchPaths.toString()); + File x(".\aax.txt"); + PluginDirectoryScanner scanner(pluginList, *fmts[fmtLV2], searchPaths, true, x); + String nextPlug; + while (scanner.scanNextFile(true, nextPlug)) { + logln("LV2 search: " << nextPlug); + } + + } else if (!fmt->getName().compare("VST3")) { for (auto& f : m_vst3Folders) { searchPaths.addIfNotAlreadyThere(f); } @@ -901,9 +934,16 @@ void Server::scanForPlugins(const std::vector& include) { auto& fileOrId = fileOrIds.getReference(idx); auto name = getPluginName(fileOrId, false); auto type = getPluginType(fileOrId); + std::unique_ptr pluginDesc = pluginList.getTypeForFile(fileOrId); + if (type == "unknown" && pluginDesc != nullptr) { + type = pluginDesc->pluginFormatName; + logln("Id " << fileOrId << " name " << name << " type " << type); + } + auto* fmt = type == "au" ? fmts[fmtAU].get() : type == "vst3" ? fmts[fmtVST3].get() : type == "vst" ? fmts[fmtVST].get() + : type == "LV2" ? fmts[fmtLV2].get() : nullptr; if (nullptr == fmt) { diff --git a/Server/Source/Server.hpp b/Server/Source/Server.hpp index 12c1ee9..d0774fc 100644 --- a/Server/Source/Server.hpp +++ b/Server/Source/Server.hpp @@ -51,6 +51,8 @@ class Server : public Thread, public LogTag { void setEnableVST2(bool b) { m_enableVST2 = b; } bool getEnableLV2() const { return m_enableLV2; } void setEnableLV2(bool b) { m_enableLV2 = b; } + const StringArray& getLV2Folders() const { return m_lv2Folders; } + void setLV2Folders(const StringArray& folders) { m_lv2Folders = folders; } const StringArray& getVST3Folders() const { return m_vst3Folders; } void setVST3Folders(const StringArray& folders) { m_vst3Folders = folders; } const StringArray& getVST2Folders() const { return m_vst2Folders; } From 6a5abdc6947ac6c296a2adf1d6e141efe2ef34eb Mon Sep 17 00:00:00 2001 From: Andreas Pohl Date: Mon, 13 Mar 2023 16:16:16 +0100 Subject: [PATCH 4/5] Server: Allinged LV2 integration with other formats --- Common/Source/Utils.hpp | 34 +++++++++++++++++++----------- Server/Source/Server.cpp | 45 ++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 41 deletions(-) diff --git a/Common/Source/Utils.hpp b/Common/Source/Utils.hpp index 81a8b67..f2e4976 100644 --- a/Common/Source/Utils.hpp +++ b/Common/Source/Utils.hpp @@ -646,27 +646,37 @@ inline int getLayoutNumChannels(const AudioProcessor::BusesLayout& l, bool isInp } #endif -inline String getPluginType(const String& id) { +inline String getPluginType(const String& id, const PluginDescription* pdesc) { String type; - File f(id); - if (f.exists()) { - if (f.getFileExtension().toLowerCase() == ".dll") { - type = "vst"; + if (pdesc != nullptr) { + if (pdesc->pluginFormatName == "AudioUnit") { + type = "au"; } else { - type = f.getFileExtension().toLowerCase().substring(1); + type = pdesc->pluginFormatName.toLowerCase(); } - } else if (id.startsWith("AudioUnit")) { - type = "au"; } else { - type = "unknown"; + File f(id); + if (f.exists()) { + if (f.getFileExtension().toLowerCase() == ".dll") { + type = "vst"; + } else { + type = f.getFileExtension().toLowerCase().substring(1); + } + } else if (id.startsWith("AudioUnit")) { + type = "au"; + } else { + type = "lv2"; + } } return type; } -inline String getPluginName(const String& id, bool withType = true) { +inline String getPluginName(const String& id, const PluginDescription* pdesc, bool withType = true) { String name; File f(id); - if (f.exists()) { + if (pdesc != nullptr) { + name = pdesc->name; + } else if (f.exists()) { name = f.getFileNameWithoutExtension(); #if JUCE_MAC && AG_SERVER } else if (id.startsWith("AudioUnit")) { @@ -677,7 +687,7 @@ inline String getPluginName(const String& id, bool withType = true) { name = id; } if (withType) { - name << " (" << getPluginType(id) << ")"; + name << " (" << getPluginType(id, pdesc) << ")"; } return name; } diff --git a/Server/Source/Server.cpp b/Server/Source/Server.cpp index 9c5fc36..df3270a 100644 --- a/Server/Source/Server.cpp +++ b/Server/Source/Server.cpp @@ -900,30 +900,21 @@ void Server::scanForPlugins(const std::vector& include) { for (auto& fmt : fmts) { FileSearchPath searchPaths; - if (fmt->getName().compare("AudioUnit") && !m_vstNoStandardFolders) { + if (fmt->getName() != "AudioUnit" && (!fmt->getName().startsWith("VST") || !m_vstNoStandardFolders)) { searchPaths = fmt->getDefaultLocationsToSearch(); } - if (fmt->getName().compare("LV2")) { - searchPaths = fmt->getDefaultLocationsToSearch(); - for (auto& f : m_lv2Folders) { - searchPaths.addIfNotAlreadyThere(f); - } - logln("LV2 search paths " << searchPaths.toString()); - File x(".\aax.txt"); - PluginDirectoryScanner scanner(pluginList, *fmts[fmtLV2], searchPaths, true, x); - String nextPlug; - while (scanner.scanNextFile(true, nextPlug)) { - logln("LV2 search: " << nextPlug); - } - - } else if (!fmt->getName().compare("VST3")) { + if (fmt->getName() == "VST3") { for (auto& f : m_vst3Folders) { searchPaths.addIfNotAlreadyThere(f); } - } else if (!fmt->getName().compare("VST")) { + } else if (fmt->getName() == "VST") { for (auto& f : m_vst2Folders) { searchPaths.addIfNotAlreadyThere(f); } + } else if (fmt->getName() == "LV2") { + for (auto& f : m_lv2Folders) { + searchPaths.addIfNotAlreadyThere(f); + } } searchPaths.removeRedundantPaths(); searchPaths.removeNonExistentPaths(); @@ -932,18 +923,14 @@ void Server::scanForPlugins(const std::vector& include) { for (int idx = 0; idx < fileOrIds.size(); idx++) { auto& fileOrId = fileOrIds.getReference(idx); - auto name = getPluginName(fileOrId, false); - auto type = getPluginType(fileOrId); - std::unique_ptr pluginDesc = pluginList.getTypeForFile(fileOrId); - if (type == "unknown" && pluginDesc != nullptr) { - type = pluginDesc->pluginFormatName; - logln("Id " << fileOrId << " name " << name << " type " << type); - } + auto pluginDesc = m_pluginList.getTypeForFile(fileOrId); + auto name = getPluginName(fileOrId, pluginDesc.get(), false); + auto type = getPluginType(fileOrId, pluginDesc.get()); auto* fmt = type == "au" ? fmts[fmtAU].get() : type == "vst3" ? fmts[fmtVST3].get() : type == "vst" ? fmts[fmtVST].get() - : type == "LV2" ? fmts[fmtLV2].get() + : type == "lv2" ? fmts[fmtLV2].get() : nullptr; if (nullptr == fmt) { @@ -951,9 +938,8 @@ void Server::scanForPlugins(const std::vector& include) { continue; } - auto plugindesc = m_pluginList.getTypeForFile(fileOrId); bool excluded = shouldExclude(name, fileOrId, include); - if ((nullptr == plugindesc || fmt->pluginNeedsRescanning(*plugindesc)) && + if ((nullptr == pluginDesc || fmt->pluginNeedsRescanning(*pluginDesc)) && !m_pluginList.getBlacklistedFiles().contains(fileOrId) && newBlacklistedPlugins.count(fileOrId) == 0 && !excluded) { ScanThread* scanThread = nullptr; @@ -969,7 +955,7 @@ void Server::scanForPlugins(const std::vector& include) { } } while (scanThread == nullptr); - String splashName = getPluginName(fileOrId); + String splashName = getPluginName(fileOrId, pluginDesc.get()); progress = (float)idx / fileOrIds.size() * 100.0f; @@ -1053,7 +1039,8 @@ void Server::processScanResults(int id, std::set& newBlacklistedPlugins) for (auto& p : plist.getBlacklistedFiles()) { if (!m_pluginList.getBlacklistedFiles().contains(p)) { m_pluginList.addToBlacklist(p); - newBlacklistedPlugins.insert(getPluginName(p)); + auto pdesc = plist.getTypeForIdentifierString(p); + newBlacklistedPlugins.insert(getPluginName(p, pdesc.get())); } } @@ -1076,7 +1063,7 @@ void Server::processScanResults(int id, std::set& newBlacklistedPlugins) deadmanFile.readLines(lines); for (auto& line : lines) { - newBlacklistedPlugins.insert(getPluginName(line)); + newBlacklistedPlugins.insert(getPluginName(line, nullptr)); } deadmanFile.deleteFile(); From fa674bc3d7d718b0caefbaee2682a63f7f98c5cf Mon Sep 17 00:00:00 2001 From: Andreas Pohl Date: Mon, 13 Mar 2023 16:18:00 +0100 Subject: [PATCH 5/5] Server: Added LV2 settings --- Server/Source/ServerSettingsWindow.cpp | 38 ++++++++++++++++++++++++++ Server/Source/ServerSettingsWindow.hpp | 7 +++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Server/Source/ServerSettingsWindow.cpp b/Server/Source/ServerSettingsWindow.cpp index 85a9910..c6043e6 100644 --- a/Server/Source/ServerSettingsWindow.cpp +++ b/Server/Source/ServerSettingsWindow.cpp @@ -243,6 +243,39 @@ ServerSettingsWindow::ServerSettingsWindow(App* app) tooltip.clear(); row++; + label = std::make_unique