| @@ -185,6 +185,29 @@ START_NAMESPACE_DISTRHO | |||
| #endif | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * Audio Port Hints */ | |||
| /** | |||
| @defgroup AudioPortHints Audio Port Hints | |||
| Various audio port hints. | |||
| @see AudioPort::hints | |||
| @{ | |||
| */ | |||
| /** | |||
| Audio port can be used as control voltage (LV2 only). | |||
| */ | |||
| static const uint32_t kAudioPortIsCV = 0x1; | |||
| /** | |||
| Audio port should be used as sidechan (LV2 only). | |||
| */ | |||
| static const uint32_t kAudioPortIsSidechain = 0x2; | |||
| /** @} */ | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * Parameter Hints */ | |||
| @@ -243,6 +266,40 @@ static const uint32_t kParameterIsCV = 0x20; | |||
| @{ | |||
| */ | |||
| /** | |||
| Audio Port. | |||
| */ | |||
| struct AudioPort { | |||
| /** | |||
| Hints describing this audio port. | |||
| @see AudioPortHints | |||
| */ | |||
| uint32_t hints; | |||
| /** | |||
| The name of this audio port. | |||
| An audio port name can contain any character, but hosts might have a hard time with non-ascii ones. | |||
| The name doesn't have to be unique within a plugin instance, but it's recommended. | |||
| */ | |||
| d_string name; | |||
| /** | |||
| The symbol of this audio port. | |||
| An audio port symbol is a short restricted name used as a machine and human readable identifier. | |||
| The first character must be one of _, a-z or A-Z and subsequent characters can be from _, a-z, A-Z and 0-9. | |||
| @note: Audio port and parameter symbols MUST be unique within a plugin instance. | |||
| */ | |||
| d_string symbol; | |||
| /** | |||
| Default constructor for a regular audio port. | |||
| */ | |||
| AudioPort() noexcept | |||
| : hints(0x0), | |||
| name(), | |||
| symbol() {} | |||
| }; | |||
| /** | |||
| Parameter ranges. | |||
| This is used to set the default, minimum and maximum values of a parameter. | |||
| @@ -670,6 +727,12 @@ protected: | |||
| /* -------------------------------------------------------------------------------------------------------- | |||
| * Init */ | |||
| /** | |||
| Initialize the audio port @a index. | |||
| This function will be called once, shortly after the plugin is created. | |||
| */ | |||
| virtual void d_initAudioPort(bool input, uint32_t index, AudioPort& port); | |||
| /** | |||
| Initialize the parameter @a index. | |||
| This function will be called once, shortly after the plugin is created. | |||
| @@ -28,6 +28,7 @@ double d_lastSampleRate = 0.0; | |||
| * Static fallback data, see DistrhoPluginInternal.hpp */ | |||
| const d_string PluginExporter::sFallbackString; | |||
| const AudioPort PluginExporter::sFallbackAudioPort; | |||
| const ParameterRanges PluginExporter::sFallbackRanges; | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| @@ -36,6 +37,10 @@ const ParameterRanges PluginExporter::sFallbackRanges; | |||
| Plugin::Plugin(const uint32_t parameterCount, const uint32_t programCount, const uint32_t stateCount) | |||
| : pData(new PrivateData()) | |||
| { | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| pData->audioPorts = new AudioPort[DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
| #endif | |||
| if (parameterCount > 0) | |||
| { | |||
| pData->parameterCount = parameterCount; | |||
| @@ -104,6 +109,27 @@ bool Plugin::d_writeMidiEvent(const MidiEvent& /*midiEvent*/) noexcept | |||
| } | |||
| #endif | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * Init */ | |||
| void Plugin::d_initAudioPort(bool input, uint32_t index, AudioPort& port) | |||
| { | |||
| if (port.hints & kAudioPortIsCV) | |||
| { | |||
| port.name = input ? "CV Input " : "CV Output "; | |||
| port.name += d_string(index+1); | |||
| port.symbol = input ? "cv_in_" : "cv_out_"; | |||
| port.symbol += d_string(index+1); | |||
| } | |||
| else | |||
| { | |||
| port.name = input ? "Audio Input " : "Audio Output "; | |||
| port.name += d_string(index+1); | |||
| port.symbol = input ? "audio_in_" : "audio_out_"; | |||
| port.symbol += d_string(index+1); | |||
| } | |||
| } | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * Callbacks (optional) */ | |||
| @@ -38,6 +38,10 @@ extern double d_lastSampleRate; | |||
| struct Plugin::PrivateData { | |||
| bool isProcessing; | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| AudioPort* audioPorts; | |||
| #endif | |||
| uint32_t parameterCount; | |||
| Parameter* parameters; | |||
| @@ -65,6 +69,9 @@ struct Plugin::PrivateData { | |||
| PrivateData() noexcept | |||
| : isProcessing(false), | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| audioPorts(nullptr), | |||
| #endif | |||
| parameterCount(0), | |||
| parameters(nullptr), | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| @@ -88,6 +95,14 @@ struct Plugin::PrivateData { | |||
| ~PrivateData() noexcept | |||
| { | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| if (audioPorts != nullptr) | |||
| { | |||
| delete[] audioPorts; | |||
| audioPorts = nullptr; | |||
| } | |||
| #endif | |||
| if (parameters != nullptr) | |||
| { | |||
| delete[] parameters; | |||
| @@ -132,6 +147,16 @@ public: | |||
| DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| { | |||
| uint32_t j=0; | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j) | |||
| fPlugin->d_initAudioPort(true, i, fData->audioPorts[j]); | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j) | |||
| fPlugin->d_initAudioPort(false, i, fData->audioPorts[j]); | |||
| } | |||
| #endif | |||
| for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) | |||
| fPlugin->d_initParameter(i, fData->parameters[i]); | |||
| @@ -211,6 +236,21 @@ public: | |||
| } | |||
| #endif | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| const AudioPort& getAudioPort(const bool input, const uint32_t index) const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort); | |||
| if (input) { | |||
| DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_INPUTS, sFallbackAudioPort); | |||
| } else { | |||
| DISTRHO_SAFE_ASSERT_RETURN(index < DISTRHO_PLUGIN_NUM_OUTPUTS, sFallbackAudioPort); | |||
| } | |||
| return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)]; | |||
| } | |||
| #endif | |||
| uint32_t getParameterCount() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); | |||
| @@ -458,6 +498,7 @@ private: | |||
| // Static fallback data, see DistrhoPlugin.cpp | |||
| static const d_string sFallbackString; | |||
| static const AudioPort sFallbackAudioPort; | |||
| static const ParameterRanges sFallbackRanges; | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter) | |||
| @@ -109,6 +109,7 @@ void lv2_generate_ttl(const char* const basename) | |||
| # else | |||
| manifestString += " ui:binary <" + pluginDLL + "." DISTRHO_DLL_EXTENSION "> ;\n"; | |||
| #endif | |||
| manifestString += "\n"; | |||
| manifestString += " lv2:extensionData ui:idleInterface ,\n"; | |||
| # if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| manifestString += " ui:showInterface ,\n"; | |||
| @@ -116,9 +117,11 @@ void lv2_generate_ttl(const char* const basename) | |||
| # else | |||
| manifestString += " ui:showInterface ;\n"; | |||
| # endif | |||
| manifestString += "\n"; | |||
| manifestString += " lv2:optionalFeature ui:noUserResize ,\n"; | |||
| manifestString += " ui:resize ,\n"; | |||
| manifestString += " ui:touch ;\n"; | |||
| manifestString += "\n"; | |||
| # if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| manifestString += " lv2:requiredFeature <" LV2_DATA_ACCESS_URI "> ,\n"; | |||
| manifestString += " <" LV2_INSTANCE_ACCESS_URI "> ,\n"; | |||
| @@ -205,18 +208,27 @@ void lv2_generate_ttl(const char* const basename) | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex) | |||
| { | |||
| const AudioPort& port(plugin.getAudioPort(true, i)); | |||
| if (i == 0) | |||
| pluginString += " lv2:port [\n"; | |||
| else | |||
| pluginString += " [\n"; | |||
| pluginString += " a lv2:InputPort, lv2:AudioPort ;\n"; | |||
| if (port.hints & kAudioPortIsCV) | |||
| pluginString += " a lv2:InputPort, lv2:CVPort ;\n"; | |||
| else | |||
| pluginString += " a lv2:InputPort, lv2:AudioPort ;\n"; | |||
| pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
| pluginString += " lv2:symbol \"lv2_audio_in_" + d_string(i+1) + "\" ;\n"; | |||
| pluginString += " lv2:name \"Audio Input " + d_string(i+1) + "\" ;\n"; | |||
| pluginString += " lv2:symbol \"" + port.symbol + "\" ;\n"; | |||
| pluginString += " lv2:name \"" + port.name + "\" ;\n"; | |||
| if (port.hints & kAudioPortIsSidechain) | |||
| pluginString += " lv2:portProperty lv2:isSideChain;\n"; | |||
| if (i+1 == DISTRHO_PLUGIN_NUM_INPUTS) | |||
| pluginString += " ] ;\n\n"; | |||
| pluginString += " ] ;\n"; | |||
| else | |||
| pluginString += " ] ,\n"; | |||
| } | |||
| @@ -226,18 +238,27 @@ void lv2_generate_ttl(const char* const basename) | |||
| #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex) | |||
| { | |||
| const AudioPort& port(plugin.getAudioPort(false, i)); | |||
| if (i == 0) | |||
| pluginString += " lv2:port [\n"; | |||
| else | |||
| pluginString += " [\n"; | |||
| pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n"; | |||
| if (port.hints & kAudioPortIsCV) | |||
| pluginString += " a lv2:OutputPort, lv2:CVPort ;\n"; | |||
| else | |||
| pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n"; | |||
| pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
| pluginString += " lv2:symbol \"lv2_audio_out_" + d_string(i+1) + "\" ;\n"; | |||
| pluginString += " lv2:name \"Audio Output " + d_string(i+1) + "\" ;\n"; | |||
| pluginString += " lv2:symbol \"" + port.symbol + "\" ;\n"; | |||
| pluginString += " lv2:name \"" + port.name + "\" ;\n"; | |||
| if (port.hints & kAudioPortIsSidechain) | |||
| pluginString += " lv2:portProperty lv2:isSideChain;\n"; | |||
| if (i+1 == DISTRHO_PLUGIN_NUM_OUTPUTS) | |||
| pluginString += " ] ;\n\n"; | |||
| pluginString += " ] ;\n"; | |||
| else | |||
| pluginString += " ] ,\n"; | |||
| } | |||