Signed-off-by: falkTX <falktx@falktx.com>pull/281/head
@@ -44,6 +44,32 @@ static const uint32_t kAudioPortIsCV = 0x1; | |||||
*/ | */ | ||||
static const uint32_t kAudioPortIsSidechain = 0x2; | 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; | |||||
/** @} */ | /** @} */ | ||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
@@ -25,8 +25,11 @@ | |||||
#endif | #endif | ||||
#include "jack/jack.h" | #include "jack/jack.h" | ||||
#include "jack/metadata.h" | |||||
#include "jack/midiport.h" | #include "jack/midiport.h" | ||||
#include "jack/transport.h" | #include "jack/transport.h" | ||||
#include "jack/uuid.h" | |||||
#include "lv2/lv2.h" | |||||
#ifndef DISTRHO_OS_WINDOWS | #ifndef DISTRHO_OS_WINDOWS | ||||
# include <signal.h> | # include <signal.h> | ||||
@@ -119,15 +122,18 @@ public: | |||||
# if DISTRHO_PLUGIN_NUM_INPUTS > 0 | # if DISTRHO_PLUGIN_NUM_INPUTS > 0 | ||||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i) | 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 | # endif | ||||
# if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | ||||
for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | ||||
{ | { | ||||
std::snprintf(strBuf, 0xff, "out%i", i+1); | 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 | ||||
#endif | #endif | ||||
@@ -561,6 +567,77 @@ private: | |||||
# endif | # endif | ||||
#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 | // Callbacks | ||||
@@ -22,6 +22,7 @@ | |||||
#include "lv2/instance-access.h" | #include "lv2/instance-access.h" | ||||
#include "lv2/midi.h" | #include "lv2/midi.h" | ||||
#include "lv2/options.h" | #include "lv2/options.h" | ||||
#include "lv2/parameters.h" | |||||
#include "lv2/patch.h" | #include "lv2/patch.h" | ||||
#include "lv2/port-props.h" | #include "lv2/port-props.h" | ||||
#include "lv2/presets.h" | #include "lv2/presets.h" | ||||
@@ -332,9 +333,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | ||||
pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"; | pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"; | ||||
pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | ||||
#ifdef DISTRHO_PLUGIN_BRAND | |||||
pluginString += "@prefix mod: <http://moddevices.com/ns/mod#> .\n"; | pluginString += "@prefix mod: <http://moddevices.com/ns/mod#> .\n"; | ||||
#endif | |||||
pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | ||||
pluginString += "@prefix patch: <" LV2_PATCH_PREFIX "> .\n"; | pluginString += "@prefix patch: <" LV2_PATCH_PREFIX "> .\n"; | ||||
pluginString += "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"; | pluginString += "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\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) | for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex) | ||||
{ | { | ||||
const AudioPort& port(plugin.getAudioPort(true, i)); | const AudioPort& port(plugin.getAudioPort(true, i)); | ||||
const bool cvPortScaled = port.hints & kCVPortHasScaledRange; | |||||
if (i == 0) | if (i == 0) | ||||
pluginString += " lv2:port [\n"; | pluginString += " lv2:port [\n"; | ||||
else | else | ||||
pluginString += " [\n"; | 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"; | pluginString += " a lv2:InputPort, lv2:CVPort ;\n"; | ||||
else | else | ||||
pluginString += " a lv2:InputPort, lv2:AudioPort ;\n"; | pluginString += " a lv2:InputPort, lv2:AudioPort ;\n"; | ||||
@@ -428,6 +430,47 @@ void lv2_generate_ttl(const char* const basename) | |||||
if (port.hints & kAudioPortIsSidechain) | if (port.hints & kAudioPortIsSidechain) | ||||
pluginString += " lv2:portProperty lv2:isSideChain;\n"; | 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) | if (i+1 == DISTRHO_PLUGIN_NUM_INPUTS) | ||||
pluginString += " ] ;\n"; | pluginString += " ] ;\n"; | ||||
else | 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) | for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex) | ||||
{ | { | ||||
const AudioPort& port(plugin.getAudioPort(false, i)); | const AudioPort& port(plugin.getAudioPort(false, i)); | ||||
const bool cvPortScaled = port.hints & kCVPortHasScaledRange; | |||||
if (i == 0) | if (i == 0) | ||||
pluginString += " lv2:port [\n"; | pluginString += " lv2:port [\n"; | ||||
else | else | ||||
pluginString += " [\n"; | 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"; | pluginString += " a lv2:OutputPort, lv2:CVPort ;\n"; | ||||
else | else | ||||
pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n"; | pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n"; | ||||
@@ -458,6 +504,47 @@ void lv2_generate_ttl(const char* const basename) | |||||
if (port.hints & kAudioPortIsSidechain) | if (port.hints & kAudioPortIsSidechain) | ||||
pluginString += " lv2:portProperty lv2:isSideChain;\n"; | 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) | if (i+1 == DISTRHO_PLUGIN_NUM_OUTPUTS) | ||||
pluginString += " ] ;\n"; | pluginString += " ] ;\n"; | ||||
else | else | ||||