From ead50d1c850071a4db3883b692246f8bce46dd15 Mon Sep 17 00:00:00 2001 From: falkTX Date: Thu, 27 May 2021 17:27:49 +0100 Subject: [PATCH] Add CV range flags, implement jack meta-data Signed-off-by: falkTX --- distrho/DistrhoPlugin.hpp | 26 +++++++ distrho/src/DistrhoPluginJack.cpp | 83 +++++++++++++++++++++- distrho/src/DistrhoPluginLV2export.cpp | 95 ++++++++++++++++++++++++-- 3 files changed, 197 insertions(+), 7 deletions(-) diff --git a/distrho/DistrhoPlugin.hpp b/distrho/DistrhoPlugin.hpp index 782cf8c2..45165f3d 100644 --- a/distrho/DistrhoPlugin.hpp +++ b/distrho/DistrhoPlugin.hpp @@ -44,6 +44,32 @@ static const uint32_t kAudioPortIsCV = 0x1; */ static const uint32_t kAudioPortIsSidechain = 0x2; +/** + CV port has bipolar range (-1 to +1, or -5 to +5 if scaled). + This is merely a hint to tell the host what value range to expect. + */ +static const uint32_t kCVPortHasBipolarRange = 0x10; + +/** + CV port has negative unipolar range (0 to +1, or 0 to +10 if scaled). + This is merely a hint to tell the host what value range to expect. + */ +static const uint32_t kCVPortHasNegativeUnipolarRange = 0x20; + +/** + CV port has positive unipolar range (-1 to 0, or -10 to 0 if scaled). + This is merely a hint to tell the host what value range to expect. + */ +static const uint32_t kCVPortHasPositiveUnipolarRange = 0x40; + +/** + CV port has scaled range to match real values (-5 to +5v bipolar, +/-10 to 0v unipolar). + One range flag is required if this flag is set. + + When enabled, this makes the port a mod:CVPort, compatible with the MOD Devices platform. + */ +static const uint32_t kCVPortHasScaledRange = 0x80; + /** @} */ /* ------------------------------------------------------------------------------------------------------------ diff --git a/distrho/src/DistrhoPluginJack.cpp b/distrho/src/DistrhoPluginJack.cpp index 68fa1da2..9dbd9faa 100644 --- a/distrho/src/DistrhoPluginJack.cpp +++ b/distrho/src/DistrhoPluginJack.cpp @@ -25,8 +25,11 @@ #endif #include "jack/jack.h" +#include "jack/metadata.h" #include "jack/midiport.h" #include "jack/transport.h" +#include "jack/uuid.h" +#include "lv2/lv2.h" #ifndef DISTRHO_OS_WINDOWS # include @@ -119,15 +122,18 @@ public: # if DISTRHO_PLUGIN_NUM_INPUTS > 0 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) { - std::snprintf(strBuf, 0xff, "in%i", i+1); - fPortAudioIns[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + const AudioPort& port(fPlugin.getAudioPort(true, i)); + fPortAudioIns[i] = jack_port_register(fClient, port.symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + setAudioPortMetadata(port, fPortAudioIns[i], i); } # endif # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) { std::snprintf(strBuf, 0xff, "out%i", i+1); - fPortAudioOuts[i] = jack_port_register(fClient, strBuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + const AudioPort& port(fPlugin.getAudioPort(false, i)); + fPortAudioOuts[i] = jack_port_register(fClient, port.symbol, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + setAudioPortMetadata(port, fPortAudioOuts[i], i); } # endif #endif @@ -561,6 +567,77 @@ private: # endif #endif + void setAudioPortMetadata(const AudioPort& port, jack_port_t* const jackport, const uint32_t index) + { + DISTRHO_SAFE_ASSERT_RETURN(jackport != nullptr,); + + const jack_uuid_t uuid = jack_port_uuid(jackport); + + if (jack_uuid_empty(uuid)) + return; + + jack_set_property(fClient, uuid, JACK_METADATA_PRETTY_NAME, port.name, "text/plain"); + + { + char strBuf[0xff]; + snprintf(strBuf, sizeof(0xff)-1, "%u", index); + jack_set_property(fClient, uuid, JACK_METADATA_ORDER, strBuf, "http://www.w3.org/2001/XMLSchema#integer"); + } + + if (port.hints & kAudioPortIsCV) + { + jack_set_property(fClient, uuid, JACK_METADATA_SIGNAL_TYPE, "CV", "text/plain"); + } + else + { + jack_set_property(fClient, uuid, JACK_METADATA_SIGNAL_TYPE, "AUDIO", "text/plain"); + return; + } + + // set cv ranges + const bool cvPortScaled = port.hints & kCVPortHasScaledRange; + + if (port.hints & kCVPortHasBipolarRange) + { + if (cvPortScaled) + { + jack_set_property(fClient, uuid, LV2_CORE__minimum, "-5", "http://www.w3.org/2001/XMLSchema#integer"); + jack_set_property(fClient, uuid, LV2_CORE__maximum, "5", "http://www.w3.org/2001/XMLSchema#integer"); + } + else + { + jack_set_property(fClient, uuid, LV2_CORE__minimum, "-1", "http://www.w3.org/2001/XMLSchema#integer"); + jack_set_property(fClient, uuid, LV2_CORE__maximum, "1", "http://www.w3.org/2001/XMLSchema#integer"); + } + } + else if (port.hints & kCVPortHasNegativeUnipolarRange) + { + if (cvPortScaled) + { + jack_set_property(fClient, uuid, LV2_CORE__minimum, "-10", "http://www.w3.org/2001/XMLSchema#integer"); + jack_set_property(fClient, uuid, LV2_CORE__maximum, "0", "http://www.w3.org/2001/XMLSchema#integer"); + } + else + { + jack_set_property(fClient, uuid, LV2_CORE__minimum, "-1", "http://www.w3.org/2001/XMLSchema#integer"); + jack_set_property(fClient, uuid, LV2_CORE__maximum, "0", "http://www.w3.org/2001/XMLSchema#integer"); + } + } + else if (port.hints & kCVPortHasPositiveUnipolarRange) + { + if (cvPortScaled) + { + jack_set_property(fClient, uuid, LV2_CORE__minimum, "0", "http://www.w3.org/2001/XMLSchema#integer"); + jack_set_property(fClient, uuid, LV2_CORE__maximum, "10", "http://www.w3.org/2001/XMLSchema#integer"); + } + else + { + jack_set_property(fClient, uuid, LV2_CORE__minimum, "0", "http://www.w3.org/2001/XMLSchema#integer"); + jack_set_property(fClient, uuid, LV2_CORE__maximum, "1", "http://www.w3.org/2001/XMLSchema#integer"); + } + } + } + // ------------------------------------------------------------------- // Callbacks diff --git a/distrho/src/DistrhoPluginLV2export.cpp b/distrho/src/DistrhoPluginLV2export.cpp index 934e5dfa..ac9e6ce3 100644 --- a/distrho/src/DistrhoPluginLV2export.cpp +++ b/distrho/src/DistrhoPluginLV2export.cpp @@ -22,6 +22,7 @@ #include "lv2/instance-access.h" #include "lv2/midi.h" #include "lv2/options.h" +#include "lv2/parameters.h" #include "lv2/patch.h" #include "lv2/port-props.h" #include "lv2/presets.h" @@ -332,9 +333,7 @@ void lv2_generate_ttl(const char* const basename) pluginString += "@prefix doap: .\n"; pluginString += "@prefix foaf: .\n"; pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; -#ifdef DISTRHO_PLUGIN_BRAND pluginString += "@prefix mod: .\n"; -#endif pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; pluginString += "@prefix patch: <" LV2_PATCH_PREFIX "> .\n"; pluginString += "@prefix rdf: .\n"; @@ -410,13 +409,16 @@ void lv2_generate_ttl(const char* const basename) for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex) { const AudioPort& port(plugin.getAudioPort(true, i)); + const bool cvPortScaled = port.hints & kCVPortHasScaledRange; if (i == 0) pluginString += " lv2:port [\n"; else pluginString += " [\n"; - if (port.hints & kAudioPortIsCV) + if (cvPortScaled) + pluginString += " a lv2:InputPort, lv2:CVPort, mod:CVPort ;\n"; + else if (port.hints & kAudioPortIsCV) pluginString += " a lv2:InputPort, lv2:CVPort ;\n"; else pluginString += " a lv2:InputPort, lv2:AudioPort ;\n"; @@ -428,6 +430,47 @@ void lv2_generate_ttl(const char* const basename) if (port.hints & kAudioPortIsSidechain) pluginString += " lv2:portProperty lv2:isSideChain;\n"; + // set ranges + if (port.hints & kCVPortHasBipolarRange) + { + if (cvPortScaled) + { + pluginString += " lv2:minimum -5.0 ;\n"; + pluginString += " lv2:maximum 5.0 ;\n"; + } + else + { + pluginString += " lv2:minimum -1.0 ;\n"; + pluginString += " lv2:maximum 1.0 ;\n"; + } + } + else if (port.hints & kCVPortHasNegativeUnipolarRange) + { + if (cvPortScaled) + { + pluginString += " lv2:minimum -10.0 ;\n"; + pluginString += " lv2:maximum 0.0 ;\n"; + } + else + { + pluginString += " lv2:minimum -1.0 ;\n"; + pluginString += " lv2:maximum 0.0 ;\n"; + } + } + else if (port.hints & kCVPortHasPositiveUnipolarRange) + { + if (cvPortScaled) + { + pluginString += " lv2:minimum 0.0 ;\n"; + pluginString += " lv2:maximum 10.0 ;\n"; + } + else + { + pluginString += " lv2:minimum 0.0 ;\n"; + pluginString += " lv2:maximum 1.0 ;\n"; + } + } + if (i+1 == DISTRHO_PLUGIN_NUM_INPUTS) pluginString += " ] ;\n"; else @@ -440,13 +483,16 @@ void lv2_generate_ttl(const char* const basename) for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex) { const AudioPort& port(plugin.getAudioPort(false, i)); + const bool cvPortScaled = port.hints & kCVPortHasScaledRange; if (i == 0) pluginString += " lv2:port [\n"; else pluginString += " [\n"; - if (port.hints & kAudioPortIsCV) + if (cvPortScaled) + pluginString += " a lv2:OutputPort, lv2:CVPort, mod:CVPort ;\n"; + else if (port.hints & kAudioPortIsCV) pluginString += " a lv2:OutputPort, lv2:CVPort ;\n"; else pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n"; @@ -458,6 +504,47 @@ void lv2_generate_ttl(const char* const basename) if (port.hints & kAudioPortIsSidechain) pluginString += " lv2:portProperty lv2:isSideChain;\n"; + // set ranges + if (port.hints & kCVPortHasBipolarRange) + { + if (cvPortScaled) + { + pluginString += " lv2:minimum -5.0 ;\n"; + pluginString += " lv2:maximum 5.0 ;\n"; + } + else + { + pluginString += " lv2:minimum -1.0 ;\n"; + pluginString += " lv2:maximum 1.0 ;\n"; + } + } + else if (port.hints & kCVPortHasNegativeUnipolarRange) + { + if (cvPortScaled) + { + pluginString += " lv2:minimum -10.0 ;\n"; + pluginString += " lv2:maximum 0.0 ;\n"; + } + else + { + pluginString += " lv2:minimum -1.0 ;\n"; + pluginString += " lv2:maximum 0.0 ;\n"; + } + } + else if (port.hints & kCVPortHasPositiveUnipolarRange) + { + if (cvPortScaled) + { + pluginString += " lv2:minimum 0.0 ;\n"; + pluginString += " lv2:maximum 10.0 ;\n"; + } + else + { + pluginString += " lv2:minimum 0.0 ;\n"; + pluginString += " lv2:maximum 1.0 ;\n"; + } + } + if (i+1 == DISTRHO_PLUGIN_NUM_OUTPUTS) pluginString += " ] ;\n"; else