| @@ -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 | |||
| @@ -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 */ | |||
| @@ -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 | |||
| @@ -19,6 +19,8 @@ | |||
| #include "../DistrhoPlugin.hpp" | |||
| #include <set> | |||
| 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<int32_t> 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<int32_t>::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 | |||
| }; | |||
| @@ -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: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"; | |||
| pluginString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\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; | |||
| @@ -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 \ | |||
| @@ -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 | |||
| @@ -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. | |||