From 64e7ca965e0572c0a52562e8b4e34aca53c657f5 Mon Sep 17 00:00:00 2001 From: JP Cimalando Date: Fri, 1 Nov 2019 19:59:29 +0100 Subject: [PATCH] Port groups proposal --- distrho/DistrhoPlugin.hpp | 41 +++++++++- distrho/src/DistrhoPlugin.cpp | 4 + distrho/src/DistrhoPluginChecks.h | 4 + distrho/src/DistrhoPluginInternal.hpp | 77 ++++++++++++++++++ distrho/src/DistrhoPluginLV2export.cpp | 80 +++++++++++++++++++ dpf.doxygen | 1 + examples/Parameters/DistrhoPluginInfo.h | 13 +-- .../Parameters/ExamplePluginParameters.cpp | 34 ++++++++ 8 files changed, 247 insertions(+), 7 deletions(-) diff --git a/distrho/DistrhoPlugin.hpp b/distrho/DistrhoPlugin.hpp index 9e55c87f..345e829c 100644 --- a/distrho/DistrhoPlugin.hpp +++ b/distrho/DistrhoPlugin.hpp @@ -100,6 +100,10 @@ static const uint32_t kParameterIsTrigger = 0x20 | kParameterIsBoolean; /** @} */ +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS +static const int32_t kPortGroupDefault = -1; +#endif + /* ------------------------------------------------------------------------------------------------------------ * Base Plugin structs */ @@ -136,13 +140,21 @@ struct AudioPort { */ String symbol; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + int32_t group; +#endif + /** Default constructor for a regular audio port. */ AudioPort() noexcept : hints(0x0), name(), - symbol() {} + symbol() +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + , group(kPortGroupDefault) +#endif + {} }; /** @@ -404,6 +416,10 @@ struct Parameter { */ String symbol; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + uint32_t group; +#endif + /** The unit of this parameter.@n This means something like "dB", "kHz" and "ms".@n @@ -450,6 +466,9 @@ struct Parameter { name(), shortName(), symbol(), +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + group(kPortGroupDefault), +#endif unit(), ranges(), enumValues(), @@ -464,6 +483,9 @@ struct Parameter { name(n), shortName(), symbol(s), +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + group(kPortGroupDefault), +#endif unit(u), ranges(def, min, max), enumValues(), @@ -486,6 +508,9 @@ struct Parameter { name = "Bypass"; shortName = "Bypass"; symbol = "dpf_bypass"; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + group = kPortGroupDefault; +#endif unit = ""; midiCC = 0; ranges.def = 0.0f; @@ -496,6 +521,16 @@ struct Parameter { } }; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS +/** + Port group. + */ +struct PortGroup { + String name; + String symbol; +}; +#endif + /** MIDI event. */ @@ -812,6 +847,10 @@ protected: */ virtual void initParameter(uint32_t index, Parameter& parameter) = 0; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + virtual void initPortGroup(uint32_t index, PortGroup& pgroup) = 0; +#endif + #if DISTRHO_PLUGIN_WANT_PROGRAMS /** Set the name of the program @a index.@n diff --git a/distrho/src/DistrhoPlugin.cpp b/distrho/src/DistrhoPlugin.cpp index 34598761..0170d935 100644 --- a/distrho/src/DistrhoPlugin.cpp +++ b/distrho/src/DistrhoPlugin.cpp @@ -32,6 +32,10 @@ const AudioPort PluginExporter::sFallbackAudioPort; const ParameterRanges PluginExporter::sFallbackRanges; const ParameterEnumerationValues PluginExporter::sFallbackEnumValues; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS +const PortGroup PluginExporter::sFallbackPortGroup; +#endif + /* ------------------------------------------------------------------------------------------------------------ * Plugin */ diff --git a/distrho/src/DistrhoPluginChecks.h b/distrho/src/DistrhoPluginChecks.h index 69033dee..ce2ec72f 100644 --- a/distrho/src/DistrhoPluginChecks.h +++ b/distrho/src/DistrhoPluginChecks.h @@ -69,6 +69,10 @@ # define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 #endif +#ifndef DISTRHO_PLUGIN_WANT_PORT_GROUPS +# define DISTRHO_PLUGIN_WANT_PORT_GROUPS 0 +#endif + #ifndef DISTRHO_PLUGIN_WANT_PROGRAMS # define DISTRHO_PLUGIN_WANT_PROGRAMS 0 #endif diff --git a/distrho/src/DistrhoPluginInternal.hpp b/distrho/src/DistrhoPluginInternal.hpp index c2f2aa3c..58be2ffb 100644 --- a/distrho/src/DistrhoPluginInternal.hpp +++ b/distrho/src/DistrhoPluginInternal.hpp @@ -19,6 +19,8 @@ #include "../DistrhoPlugin.hpp" +#include + START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- @@ -51,6 +53,11 @@ struct Plugin::PrivateData { uint32_t parameterOffset; Parameter* parameters; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + PortGroup* portGroups; + uint32_t portGroupCount; +#endif + #if DISTRHO_PLUGIN_WANT_PROGRAMS uint32_t programCount; String* programNames; @@ -85,6 +92,10 @@ struct Plugin::PrivateData { parameterCount(0), parameterOffset(0), parameters(nullptr), +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + portGroups(nullptr), + portGroupCount(0), +#endif #if DISTRHO_PLUGIN_WANT_PROGRAMS programCount(0), programNames(nullptr), @@ -138,6 +149,14 @@ struct Plugin::PrivateData { parameters = nullptr; } +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + if (portGroups != nullptr) + { + delete[] portGroups; + portGroups = nullptr; + } +#endif + #if DISTRHO_PLUGIN_WANT_PROGRAMS if (programNames != nullptr) { @@ -203,6 +222,36 @@ public: for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) fPlugin->initParameter(i, fData->parameters[i]); +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + std::set portGroupIndices; + + for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) + portGroupIndices.insert(fData->audioPorts[i].group); + + for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) + portGroupIndices.insert(fData->parameters[i].group); + + int32_t upperPortGroupIndex = kPortGroupDefault; + if (!portGroupIndices.empty()) + upperPortGroupIndex = *portGroupIndices.rbegin(); + + if (upperPortGroupIndex != kPortGroupDefault) + { + uint32_t portGroupCount = upperPortGroupIndex + 1; + + fData->portGroups = new PortGroup[portGroupCount]; + fData->portGroupCount = portGroupCount; + + for (std::set::iterator pos = portGroupIndices.begin(); + pos != portGroupIndices.end(); ++pos) + { + int32_t index = *pos; + if (index != kPortGroupDefault) + fPlugin->initPortGroup(index, fData->portGroups[index]); + } + } +#endif + #if DISTRHO_PLUGIN_WANT_PROGRAMS for (uint32_t i=0, count=fData->programCount; i < count; ++i) fPlugin->initProgramName(i, fData->programNames[i]); @@ -440,6 +489,30 @@ public: fPlugin->setParameterValue(index, value); } +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + int32_t getParameterGroupIndex(uint32_t index) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, kPortGroupDefault); + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, kPortGroupDefault); + + return fData->parameters[index].group; + } + + const PortGroup& getPortGroup(uint32_t groupIndex) const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && groupIndex < fData->portGroupCount, sFallbackPortGroup); + + return fData->portGroups[groupIndex]; + } + + uint32_t getPortGroupCount() const noexcept + { + DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); + + return fData->portGroupCount; + } +#endif + #if DISTRHO_PLUGIN_WANT_PROGRAMS uint32_t getProgramCount() const noexcept { @@ -677,6 +750,10 @@ private: static const ParameterRanges sFallbackRanges; static const ParameterEnumerationValues sFallbackEnumValues; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + static const PortGroup sFallbackPortGroup; +#endif + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter) DISTRHO_PREVENT_HEAP_ALLOCATION }; diff --git a/distrho/src/DistrhoPluginLV2export.cpp b/distrho/src/DistrhoPluginLV2export.cpp index c074109b..13f37746 100644 --- a/distrho/src/DistrhoPluginLV2export.cpp +++ b/distrho/src/DistrhoPluginLV2export.cpp @@ -23,6 +23,7 @@ #include "lv2/midi.h" #include "lv2/options.h" #include "lv2/patch.h" +#include "lv2/port-groups.h" #include "lv2/port-props.h" #include "lv2/presets.h" #include "lv2/resize-port.h" @@ -337,6 +338,9 @@ void lv2_generate_ttl(const char* const basename) #endif pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; pluginString += "@prefix patch: <" LV2_PATCH_PREFIX "> .\n"; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + pluginString += "@prefix pg: <" LV2_PORT_GROUPS_PREFIX "> .\n"; +#endif pluginString += "@prefix rdf: .\n"; pluginString += "@prefix rdfs: .\n"; #if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT @@ -428,6 +432,14 @@ void lv2_generate_ttl(const char* const basename) if (port.hints & kAudioPortIsSidechain) pluginString += " lv2:portProperty lv2:isSideChain;\n"; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + if (port.group != kPortGroupDefault) + { + const PortGroup &pgroup = plugin.getPortGroup(port.group); + pluginString += " pg:group <" DISTRHO_PLUGIN_URI "#portGroup_" + pgroup.symbol + "> ;\n"; + } +#endif + if (i+1 == DISTRHO_PLUGIN_NUM_INPUTS) pluginString += " ] ;\n"; else @@ -458,6 +470,14 @@ void lv2_generate_ttl(const char* const basename) if (port.hints & kAudioPortIsSidechain) pluginString += " lv2:portProperty lv2:isSideChain;\n"; +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + if (port.group != kPortGroupDefault) + { + const PortGroup &pgroup = plugin.getPortGroup(port.group); + pluginString += " pg:group <" DISTRHO_PLUGIN_URI "#portGroup_" + pgroup.symbol + "> ;\n"; + } +#endif + if (i+1 == DISTRHO_PLUGIN_NUM_OUTPUTS) pluginString += " ] ;\n"; else @@ -694,6 +714,16 @@ void lv2_generate_ttl(const char* const basename) pluginString += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ,\n"; pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomable "> ;\n"; } + +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + // group + int32_t pgroupIndex = plugin.getParameterGroupIndex(i); + if (pgroupIndex != kPortGroupDefault) + { + const PortGroup &pgroup = plugin.getPortGroup(pgroupIndex); + pluginString += " pg:group <" DISTRHO_PLUGIN_URI "#portGroup_" + pgroup.symbol + "> ;\n"; + } +#endif } // ! designated if (i+1 == count) @@ -758,6 +788,56 @@ void lv2_generate_ttl(const char* const basename) pluginString += " lv2:minorVersion " + String(minorVersion) + " .\n"; } +#if DISTRHO_PLUGIN_WANT_PORT_GROUPS + // port groups + { + uint32_t count = plugin.getPortGroupCount(); + + for (int32_t pgroupIndex = 0; (uint32_t)pgroupIndex < count; ++pgroupIndex) + { + const PortGroup& pgroup = plugin.getPortGroup(pgroupIndex); + + DISTRHO_SAFE_ASSERT_CONTINUE(!pgroup.symbol.isEmpty()); + + pluginString += "\n<" DISTRHO_PLUGIN_URI "#portGroup_" + pgroup.symbol + ">\n"; + + bool isInput = false; + bool isOutput = false; + + for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS && !isInput; ++i) + isInput = plugin.getAudioPort(true, i).group == pgroupIndex; + + for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS && !isOutput; ++i) + isOutput = plugin.getAudioPort(false, i).group == pgroupIndex; + + for (uint32_t i=0, count=plugin.getParameterCount(); i < count && (!isInput || !isOutput); ++i) + { + if (plugin.getParameterGroupIndex(i) == pgroupIndex) + { + isInput = isInput || plugin.isParameterInput(i); + isOutput = isOutput || plugin.isParameterOutput(i); + } + } + + pluginString += " a "; + if (isInput && !isOutput) + pluginString += "pg:InputGroup"; + else if (isOutput && !isInput) + pluginString += "pg:OutputGroup"; + else + pluginString += "pg:Group"; + pluginString += " ;\n"; + +#if 0 + pluginString += " rdfs:label \"" + pgroup.name + "\" ;\n"; +#else + pluginString += " lv2:name \"" + pgroup.name + "\" ;\n"; +#endif + pluginString += " lv2:symbol \"" + pgroup.symbol + "\" .\n"; + } + } +#endif + pluginFile << pluginString << std::endl; pluginFile.close(); std::cout << " done!" << std::endl; diff --git a/dpf.doxygen b/dpf.doxygen index 2516e934..3804409b 100644 --- a/dpf.doxygen +++ b/dpf.doxygen @@ -258,6 +258,7 @@ PREDEFINED = DOXYGEN \ DISTRHO_PLUGIN_WANT_MIDI_INPUT=1 \ DISTRHO_PLUGIN_WANT_MIDI_OUTPUT=1 \ DISTRHO_PLUGIN_WANT_PROGRAMS=1 \ + DISTRHO_PLUGIN_WANT_PORT_GROUPS=1 \ DISTRHO_PLUGIN_WANT_STATE=1 \ DISTRHO_PLUGIN_WANT_TIMEPOS=1 \ DISTRHO_PLUGIN_WANT_FULL_STATE=1 \ diff --git a/examples/Parameters/DistrhoPluginInfo.h b/examples/Parameters/DistrhoPluginInfo.h index 72bd3450..a470ea5e 100644 --- a/examples/Parameters/DistrhoPluginInfo.h +++ b/examples/Parameters/DistrhoPluginInfo.h @@ -21,11 +21,12 @@ #define DISTRHO_PLUGIN_NAME "Parameters" #define DISTRHO_PLUGIN_URI "http://distrho.sf.net/examples/Parameters" -#define DISTRHO_PLUGIN_HAS_UI 1 -#define DISTRHO_PLUGIN_IS_RT_SAFE 1 -#define DISTRHO_PLUGIN_NUM_INPUTS 2 -#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 -#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 -#define DISTRHO_UI_USER_RESIZABLE 1 +#define DISTRHO_PLUGIN_HAS_UI 1 +#define DISTRHO_PLUGIN_IS_RT_SAFE 1 +#define DISTRHO_PLUGIN_NUM_INPUTS 2 +#define DISTRHO_PLUGIN_NUM_OUTPUTS 2 +#define DISTRHO_PLUGIN_WANT_PORT_GROUPS 1 +#define DISTRHO_PLUGIN_WANT_PROGRAMS 1 +#define DISTRHO_UI_USER_RESIZABLE 1 #endif // DISTRHO_PLUGIN_INFO_H_INCLUDED diff --git a/examples/Parameters/ExamplePluginParameters.cpp b/examples/Parameters/ExamplePluginParameters.cpp index ea6ec6d1..b900de99 100644 --- a/examples/Parameters/ExamplePluginParameters.cpp +++ b/examples/Parameters/ExamplePluginParameters.cpp @@ -104,6 +104,13 @@ The plugin will be treated as an effect, but it will not change the host audio." /* -------------------------------------------------------------------------------------------------------- * Init */ + enum + { + kPortGroupTop, + kPortGroupMiddle, + kPortGroupBottom, + }; + /** Initialize the parameter @a index. This function will be called once, shortly after the plugin is created. @@ -137,30 +144,39 @@ The plugin will be treated as an effect, but it will not change the host audio." { case 0: parameter.name = "top-left"; + parameter.group = kPortGroupTop; break; case 1: parameter.name = "top-center"; + parameter.group = kPortGroupTop; break; case 2: parameter.name = "top-right"; + parameter.group = kPortGroupTop; break; case 3: parameter.name = "middle-left"; + parameter.group = kPortGroupMiddle; break; case 4: parameter.name = "middle-center"; + parameter.group = kPortGroupMiddle; break; case 5: parameter.name = "middle-right"; + parameter.group = kPortGroupMiddle; break; case 6: parameter.name = "bottom-left"; + parameter.group = kPortGroupBottom; break; case 7: parameter.name = "bottom-center"; + parameter.group = kPortGroupBottom; break; case 8: parameter.name = "bottom-right"; + parameter.group = kPortGroupBottom; break; } @@ -171,6 +187,24 @@ The plugin will be treated as an effect, but it will not change the host audio." parameter.symbol.replace('-', '_'); } + void initPortGroup(uint32_t index, PortGroup& pgroup) override + { + switch (index) { + case kPortGroupTop: + pgroup.name = "Top"; + pgroup.symbol = "top"; + break; + case kPortGroupMiddle: + pgroup.name = "Middle"; + pgroup.symbol = "middle"; + break; + case kPortGroupBottom: + pgroup.name = "Bottom"; + pgroup.symbol = "bottom"; + break; + } + } + /** Set the name of the program @a index. This function will be called once, shortly after the plugin is created.