@@ -185,6 +185,29 @@ START_NAMESPACE_DISTRHO | |||||
#endif | #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 */ | * 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. | Parameter ranges. | ||||
This is used to set the default, minimum and maximum values of a parameter. | This is used to set the default, minimum and maximum values of a parameter. | ||||
@@ -670,6 +727,12 @@ protected: | |||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* Init */ | * 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. | Initialize the parameter @a index. | ||||
This function will be called once, shortly after the plugin is created. | 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 */ | * Static fallback data, see DistrhoPluginInternal.hpp */ | ||||
const d_string PluginExporter::sFallbackString; | const d_string PluginExporter::sFallbackString; | ||||
const AudioPort PluginExporter::sFallbackAudioPort; | |||||
const ParameterRanges PluginExporter::sFallbackRanges; | 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) | Plugin::Plugin(const uint32_t parameterCount, const uint32_t programCount, const uint32_t stateCount) | ||||
: pData(new PrivateData()) | : 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) | if (parameterCount > 0) | ||||
{ | { | ||||
pData->parameterCount = parameterCount; | pData->parameterCount = parameterCount; | ||||
@@ -104,6 +109,27 @@ bool Plugin::d_writeMidiEvent(const MidiEvent& /*midiEvent*/) noexcept | |||||
} | } | ||||
#endif | #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) */ | * Callbacks (optional) */ | ||||
@@ -38,6 +38,10 @@ extern double d_lastSampleRate; | |||||
struct Plugin::PrivateData { | struct Plugin::PrivateData { | ||||
bool isProcessing; | bool isProcessing; | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||||
AudioPort* audioPorts; | |||||
#endif | |||||
uint32_t parameterCount; | uint32_t parameterCount; | ||||
Parameter* parameters; | Parameter* parameters; | ||||
@@ -65,6 +69,9 @@ struct Plugin::PrivateData { | |||||
PrivateData() noexcept | PrivateData() noexcept | ||||
: isProcessing(false), | : isProcessing(false), | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||||
audioPorts(nullptr), | |||||
#endif | |||||
parameterCount(0), | parameterCount(0), | ||||
parameters(nullptr), | parameters(nullptr), | ||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | #if DISTRHO_PLUGIN_WANT_PROGRAMS | ||||
@@ -88,6 +95,14 @@ struct Plugin::PrivateData { | |||||
~PrivateData() noexcept | ~PrivateData() noexcept | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||||
if (audioPorts != nullptr) | |||||
{ | |||||
delete[] audioPorts; | |||||
audioPorts = nullptr; | |||||
} | |||||
#endif | |||||
if (parameters != nullptr) | if (parameters != nullptr) | ||||
{ | { | ||||
delete[] parameters; | delete[] parameters; | ||||
@@ -132,6 +147,16 @@ public: | |||||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fData != 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) | for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) | ||||
fPlugin->d_initParameter(i, fData->parameters[i]); | fPlugin->d_initParameter(i, fData->parameters[i]); | ||||
@@ -211,6 +236,21 @@ public: | |||||
} | } | ||||
#endif | #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 | uint32_t getParameterCount() const noexcept | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); | DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0); | ||||
@@ -458,6 +498,7 @@ private: | |||||
// Static fallback data, see DistrhoPlugin.cpp | // Static fallback data, see DistrhoPlugin.cpp | ||||
static const d_string sFallbackString; | static const d_string sFallbackString; | ||||
static const AudioPort sFallbackAudioPort; | |||||
static const ParameterRanges sFallbackRanges; | static const ParameterRanges sFallbackRanges; | ||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginExporter) | ||||
@@ -109,6 +109,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
# else | # else | ||||
manifestString += " ui:binary <" + pluginDLL + "." DISTRHO_DLL_EXTENSION "> ;\n"; | manifestString += " ui:binary <" + pluginDLL + "." DISTRHO_DLL_EXTENSION "> ;\n"; | ||||
#endif | #endif | ||||
manifestString += "\n"; | |||||
manifestString += " lv2:extensionData ui:idleInterface ,\n"; | manifestString += " lv2:extensionData ui:idleInterface ,\n"; | ||||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | # if DISTRHO_PLUGIN_WANT_PROGRAMS | ||||
manifestString += " ui:showInterface ,\n"; | manifestString += " ui:showInterface ,\n"; | ||||
@@ -116,9 +117,11 @@ void lv2_generate_ttl(const char* const basename) | |||||
# else | # else | ||||
manifestString += " ui:showInterface ;\n"; | manifestString += " ui:showInterface ;\n"; | ||||
# endif | # endif | ||||
manifestString += "\n"; | |||||
manifestString += " lv2:optionalFeature ui:noUserResize ,\n"; | manifestString += " lv2:optionalFeature ui:noUserResize ,\n"; | ||||
manifestString += " ui:resize ,\n"; | manifestString += " ui:resize ,\n"; | ||||
manifestString += " ui:touch ;\n"; | manifestString += " ui:touch ;\n"; | ||||
manifestString += "\n"; | |||||
# if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | # if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
manifestString += " lv2:requiredFeature <" LV2_DATA_ACCESS_URI "> ,\n"; | manifestString += " lv2:requiredFeature <" LV2_DATA_ACCESS_URI "> ,\n"; | ||||
manifestString += " <" LV2_INSTANCE_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 | #if DISTRHO_PLUGIN_NUM_INPUTS > 0 | ||||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex) | for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex) | ||||
{ | { | ||||
const AudioPort& port(plugin.getAudioPort(true, i)); | |||||
if (i == 0) | if (i == 0) | ||||
pluginString += " lv2:port [\n"; | pluginString += " lv2:port [\n"; | ||||
else | else | ||||
pluginString += " [\n"; | 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: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) | if (i+1 == DISTRHO_PLUGIN_NUM_INPUTS) | ||||
pluginString += " ] ;\n\n"; | |||||
pluginString += " ] ;\n"; | |||||
else | else | ||||
pluginString += " ] ,\n"; | pluginString += " ] ,\n"; | ||||
} | } | ||||
@@ -226,18 +238,27 @@ void lv2_generate_ttl(const char* const basename) | |||||
#if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | ||||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex) | for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex) | ||||
{ | { | ||||
const AudioPort& port(plugin.getAudioPort(false, i)); | |||||
if (i == 0) | if (i == 0) | ||||
pluginString += " lv2:port [\n"; | pluginString += " lv2:port [\n"; | ||||
else | else | ||||
pluginString += " [\n"; | 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: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) | if (i+1 == DISTRHO_PLUGIN_NUM_OUTPUTS) | ||||
pluginString += " ] ;\n\n"; | |||||
pluginString += " ] ;\n"; | |||||
else | else | ||||
pluginString += " ] ,\n"; | pluginString += " ] ,\n"; | ||||
} | } | ||||