Browse Source

Initial support for LV2 params (#811)

* Quick & dirty LV2 params now working, testing waters...
* Support LV2 UIs purely through show interface without complaining
* Small tweak to how DSSI UIs are found, to be more inclusive
* Make water File paths accept paths from CWD, adjust bridges to it
* Add "plugin-wine" make target in cross-compile mingw mode
* Whitespace
* Bump maximum value of LFO speed
* Rename a variable
* Fix build
* Always copy carla-plugin binary when exporting lv2 plugin
* Fix typo
* Do not build external plugins in DEBUG mode
They make bigger binaries, take longer to build and sometimes even fail.
We do not need them in DEBUG mode, since they are assumed to be tested and work well
* Cleanup some water
* Fix leaks and oddities with water Array class
* Make ScopedLocale its own class, apply it everywhere that it fits
* Cleanup
* More cleanup, make lv2 params code not crash carla
* Fake lv2 plugin gui for those with file paths, using first prop

Signed-off-by: falkTX <falktx@gmail.com>
tags/v2.1-alpha2
Filipe Coelho GitHub 5 years ago
parent
commit
efd2441fa1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 401 additions and 107 deletions
  1. +182
    -50
      source/backend/plugin/CarlaPluginLV2.cpp
  2. +12
    -7
      source/includes/lv2_rdf.hpp
  3. +207
    -50
      source/utils/CarlaLv2Utils.hpp

+ 182
- 50
source/backend/plugin/CarlaPluginLV2.cpp View File

@@ -114,6 +114,9 @@ enum CarlaLv2URIDs {
kUridLogNote,
kUridLogTrace,
kUridLogWarning,
kUridPatchSet,
kUridPatchPoperty,
kUridPatchValue,
// time base type
kUridTimePosition,
// time values
@@ -527,7 +530,7 @@ public:
fNeedsUiClose(false),
fLatencyIndex(-1),
fStrictBounds(-1),
fAtomBufferUiIn(),
fAtomBufferEvIn(),
fAtomBufferUiOut(),
fAtomBufferWorkerIn(),
fAtomBufferWorkerResp(),
@@ -542,6 +545,7 @@ public:
fFirstActive(true),
fLastStateChunk(nullptr),
fLastTimeInfo(),
fFilePathURI(),
fExt(),
fUI()
{
@@ -1001,23 +1005,35 @@ public:
CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor != nullptr,);
CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);

// TODO param support
LV2_RDF_PortUnit* portUnit = nullptr;

const int32_t rindex(pData->param.data[parameterId].rindex);
int32_t rindex = pData->param.data[parameterId].rindex;

if (rindex < static_cast<int32_t>(fRdfDescriptor->PortCount))
{
const LV2_RDF_Port* const port(&fRdfDescriptor->Ports[rindex]);
portUnit = &fRdfDescriptor->Ports[rindex].Unit;
}
else
{
rindex -= fRdfDescriptor->PortCount;

if (rindex < static_cast<int32_t>(fRdfDescriptor->ParameterCount))
{
portUnit = &fRdfDescriptor->Parameters[rindex].Unit;
}
}

if (LV2_HAVE_PORT_UNIT_SYMBOL(port->Unit.Hints) && port->Unit.Symbol != nullptr)
if (portUnit != nullptr)
{
if (LV2_HAVE_PORT_UNIT_SYMBOL(portUnit->Hints) && portUnit->Symbol != nullptr)
{
std::strncpy(strBuf, port->Unit.Symbol, STR_MAX);
std::strncpy(strBuf, portUnit->Symbol, STR_MAX);
return;
}

if (LV2_HAVE_PORT_UNIT_UNIT(port->Unit.Hints))
if (LV2_HAVE_PORT_UNIT_UNIT(portUnit->Hints))
{
switch (port->Unit.Unit)
switch (portUnit->Unit)
{
case LV2_PORT_UNIT_BAR:
std::strncpy(strBuf, "bars", STR_MAX);
@@ -1180,9 +1196,50 @@ public:
const float fixedValue(pData->param.getFixedValue(parameterId, value));
fParamBuffers[parameterId] = fixedValue;

if (parameterId >= fRdfDescriptor->PortCount)
if (pData->param.data[parameterId].rindex >= static_cast<int32_t>(fRdfDescriptor->PortCount))
{
// TODO
const uint32_t rparamId = pData->param.data[parameterId].rindex - fRdfDescriptor->PortCount;
CARLA_SAFE_ASSERT_UINT2_RETURN(rparamId < fRdfDescriptor->ParameterCount,
rparamId, fRdfDescriptor->PortCount,);

uint8_t atomBuf[256];
lv2_atom_forge_set_buffer(&fAtomForge, atomBuf, sizeof(atomBuf));

LV2_Atom_Forge_Frame forgeFrame;
lv2_atom_forge_object(&fAtomForge, &forgeFrame, kUridNull, kUridPatchSet);

lv2_atom_forge_key(&fAtomForge, kUridPatchPoperty);
lv2_atom_forge_urid(&fAtomForge, getCustomURID(fRdfDescriptor->Parameters[rparamId].URI));
lv2_atom_forge_key(&fAtomForge, kUridPatchValue);

switch (fRdfDescriptor->Parameters[rparamId].Type)
{
case LV2_PARAMETER_BOOL:
lv2_atom_forge_bool(&fAtomForge, fixedValue > 0.5f);
break;
case LV2_PARAMETER_INT:
lv2_atom_forge_int(&fAtomForge, fixedValue + 0.5f);
break;
case LV2_PARAMETER_LONG:
lv2_atom_forge_long(&fAtomForge, fixedValue + 0.5f);
break;
case LV2_PARAMETER_FLOAT:
lv2_atom_forge_float(&fAtomForge, fixedValue);
break;
case LV2_PARAMETER_DOUBLE:
lv2_atom_forge_double(&fAtomForge, fixedValue);
break;
default:
carla_stderr2("setParameterValue called for invalid parameter, expect issues!");
break;
}

lv2_atom_forge_pop(&fAtomForge, &forgeFrame);

LV2_Atom* const atom((LV2_Atom*)atomBuf);
CARLA_SAFE_ASSERT(atom->size < sizeof(atomBuf));

fAtomBufferEvIn.put(atom, fEventsIn.ctrlIndex);
}

CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback);
@@ -1316,7 +1373,39 @@ public:
{
if (fUI.type == UI::TYPE_NULL)
{
CARLA_SAFE_ASSERT(!yesNo);
if (fFilePathURI.isNotEmpty())
{
const char* const path = pData->engine->runFileCallback(FILE_CALLBACK_OPEN, false, "Open File", "");

if (path != nullptr && path[0] != '\0')
{
carla_stdout("LV2 file path to send: '%s'", path);

uint8_t atomBuf[4096];
lv2_atom_forge_set_buffer(&fAtomForge, atomBuf, sizeof(atomBuf));

LV2_Atom_Forge_Frame forgeFrame;
lv2_atom_forge_object(&fAtomForge, &forgeFrame, kUridNull, kUridPatchSet);

lv2_atom_forge_key(&fAtomForge, kUridPatchPoperty);
lv2_atom_forge_urid(&fAtomForge, getCustomURID(fFilePathURI));

lv2_atom_forge_key(&fAtomForge, kUridPatchValue);
lv2_atom_forge_path(&fAtomForge, path, std::strlen(path));

lv2_atom_forge_pop(&fAtomForge, &forgeFrame);

LV2_Atom* const atom((LV2_Atom*)atomBuf);
CARLA_SAFE_ASSERT(atom->size < sizeof(atomBuf));

fAtomBufferEvIn.put(atom, fEventsIn.ctrlIndex);
}
}
else
{
CARLA_SAFE_ASSERT(!yesNo);
}
pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0.0f, nullptr);
return;
}

@@ -1443,7 +1532,7 @@ public:
if (fUI.handle == nullptr)
{
#ifndef LV2_UIS_ONLY_BRIDGES
if (fUI.type == UI::TYPE_EMBED && fUI.window == nullptr)
if (fUI.type == UI::TYPE_EMBED && fUI.rdfDescriptor->Type != LV2_UI_NONE && fUI.window == nullptr)
{
const char* msg = nullptr;

@@ -1757,16 +1846,20 @@ public:

for (uint32_t i=0; i < fRdfDescriptor->ParameterCount; ++i)
{
const LV2_RDF_Parameter& rdfParam(fRdfDescriptor->Parameters[i]);

if (rdfParam.Range == nullptr)
continue;
if (std::strcmp(rdfParam.Range, LV2_ATOM__Bool) != 0 &&
std::strcmp(rdfParam.Range, LV2_ATOM__Int) != 0 &&
std::strcmp(rdfParam.Range, LV2_ATOM__Float) != 0)
continue;

params += 1;
switch (fRdfDescriptor->Parameters[i].Type)
{
case LV2_PARAMETER_BOOL:
case LV2_PARAMETER_INT:
// case LV2_PARAMETER_LONG:
case LV2_PARAMETER_FLOAT:
case LV2_PARAMETER_DOUBLE:
params += 1;
break;
case LV2_PARAMETER_PATH:
if (fFilePathURI.isEmpty())
fFilePathURI = fRdfDescriptor->Parameters[i].URI;
break;
}
}

if ((pData->options & PLUGIN_OPTION_FORCE_STEREO) != 0 && aIns <= 1 && aOuts <= 1 && fExt.state == nullptr && fExt.worker == nullptr)
@@ -2413,7 +2506,20 @@ public:
for (uint32_t i=0; i < fRdfDescriptor->ParameterCount; ++i)
{
const LV2_RDF_Parameter& rdfParam(fRdfDescriptor->Parameters[i]);
const LV2_RDF_PortPoints portPoints(fRdfDescriptor->Parameters[i].Points);

switch (rdfParam.Type)
{
case LV2_PARAMETER_BOOL:
case LV2_PARAMETER_INT:
// case LV2_PARAMETER_LONG:
case LV2_PARAMETER_FLOAT:
case LV2_PARAMETER_DOUBLE:
break;
default:
continue;
}

const LV2_RDF_PortPoints& portPoints(rdfParam.Points);

const uint32_t j = iCtrl++;
pData->param.data[j].index = static_cast<int32_t>(j);
@@ -2435,7 +2541,7 @@ public:

if (min >= max)
{
carla_stderr2("WARNING - Broken plugin parameter '%s': min >= max", fRdfDescriptor->Parameters[i].Label);
carla_stderr2("WARNING - Broken plugin parameter '%s': min >= max", rdfParam.Label);
max = min + 0.1f;
}

@@ -2458,26 +2564,29 @@ public:
else if (def > max)
def = max;

if (std::strcmp(rdfParam.Range, LV2_ATOM__Bool) == 0)
switch (rdfParam.Type)
{
case LV2_PARAMETER_BOOL:
step = max - min;
stepSmall = step;
stepLarge = step;
pData->param.data[j].hints |= PARAMETER_IS_BOOLEAN;
}
else if (std::strcmp(rdfParam.Range, LV2_ATOM__Int) == 0)
{
break;

case LV2_PARAMETER_INT:
case LV2_PARAMETER_LONG:
step = 1.0f;
stepSmall = 1.0f;
stepLarge = 10.0f;
pData->param.data[j].hints |= PARAMETER_IS_INTEGER;
}
else
{
float range = max - min;
break;
default:
const float range = max - min;
step = range/100.0f;
stepSmall = range/1000.0f;
stepLarge = range/10.0f;
break;
}

if (rdfParam.Input)
@@ -2544,8 +2653,9 @@ public:
fAtomBufferWorkerInTmpData = new uint8_t[fAtomBufferWorkerIn.getSize()];
}

if (fUI.type != UI::TYPE_NULL && fEventsIn.count > 0 && (fEventsIn.data[0].type & CARLA_EVENT_DATA_ATOM) != 0)
fAtomBufferUiIn.createBuffer(eventBufferSize);
if (fRdfDescriptor->ParameterCount > 0 ||
(fUI.type != UI::TYPE_NULL && fEventsIn.count > 0 && (fEventsIn.data[0].type & CARLA_EVENT_DATA_ATOM) != 0))
fAtomBufferEvIn.createBuffer(eventBufferSize);

if (fUI.type != UI::TYPE_NULL && fEventsOut.count > 0 && (fEventsOut.data[0].type & CARLA_EVENT_DATA_ATOM) != 0)
{
@@ -2570,7 +2680,7 @@ public:
if (isRealtimeSafe())
pData->hints |= PLUGIN_IS_RTSAFE;

if (fUI.type != UI::TYPE_NULL)
if (fUI.type != UI::TYPE_NULL || fFilePathURI.isNotEmpty())
{
pData->hints |= PLUGIN_HAS_CUSTOM_UI;

@@ -3132,14 +3242,14 @@ public:
// ----------------------------------------------------------------------------------------------------
// Message Input

if (fAtomBufferUiIn.tryLock())
if (fAtomBufferEvIn.tryLock())
{
if (fAtomBufferUiIn.isDataAvailableForReading())
if (fAtomBufferEvIn.isDataAvailableForReading())
{
const LV2_Atom* atom;
uint32_t j, portIndex;

for (; fAtomBufferUiIn.get(atom, portIndex);)
for (; fAtomBufferEvIn.get(atom, portIndex);)
{
j = (portIndex < fEventsIn.count) ? portIndex : fEventsIn.ctrlIndex;

@@ -3151,7 +3261,7 @@ public:
}
}

fAtomBufferUiIn.unlock();
fAtomBufferEvIn.unlock();
}

if (fExt.worker != nullptr && fAtomBufferWorkerIn.tryLock())
@@ -3628,9 +3738,8 @@ public:
evData.port->writeMidiEvent(currentFrame, static_cast<uint8_t>(ev->body.size), data);
}
}
else //if (ev->body.type == kUridAtomBLANK)
else if (fAtomBufferUiOutTmpData != nullptr)
{
//carla_stdout("Got out event, %s", carla_lv2_urid_unmap(this, ev->body.type));
fAtomBufferUiOut.put(&ev->body, evData.rindex);
}

@@ -4226,7 +4335,7 @@ public:

void uiParameterChange(const uint32_t index, const float value) noexcept override
{
CARLA_SAFE_ASSERT_RETURN(fUI.type != UI::TYPE_NULL,);
CARLA_SAFE_ASSERT_RETURN(fUI.type != UI::TYPE_NULL || fFilePathURI.isNotEmpty(),);
CARLA_SAFE_ASSERT_RETURN(index < pData->param.count,);

if (fUI.type == UI::TYPE_BRIDGE)
@@ -4246,7 +4355,7 @@ public:

void uiMidiProgramChange(const uint32_t index) noexcept override
{
CARLA_SAFE_ASSERT_RETURN(fUI.type != UI::TYPE_NULL,);
CARLA_SAFE_ASSERT_RETURN(fUI.type != UI::TYPE_NULL || fFilePathURI.isNotEmpty(),);
CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count,);

if (fUI.type == UI::TYPE_BRIDGE)
@@ -4263,7 +4372,7 @@ public:

void uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept override
{
CARLA_SAFE_ASSERT_RETURN(fUI.type != UI::TYPE_NULL,);
CARLA_SAFE_ASSERT_RETURN(fUI.type != UI::TYPE_NULL || fFilePathURI.isNotEmpty(),);
CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
CARLA_SAFE_ASSERT_RETURN(velo > 0 && velo < MAX_MIDI_VALUE,);
@@ -4293,7 +4402,7 @@ public:

void uiNoteOff(const uint8_t channel, const uint8_t note) noexcept override
{
CARLA_SAFE_ASSERT_RETURN(fUI.type != UI::TYPE_NULL,);
CARLA_SAFE_ASSERT_RETURN(fUI.type != UI::TYPE_NULL || fFilePathURI.isNotEmpty(),);
CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);

@@ -4817,7 +4926,7 @@ public:
{
CARLA_SAFE_ASSERT_RETURN(fExt.worker != nullptr && fExt.worker->work != nullptr, LV2_WORKER_ERR_UNKNOWN);
CARLA_SAFE_ASSERT_RETURN(fEventsIn.ctrl != nullptr, LV2_WORKER_ERR_UNKNOWN);
carla_stdout("CarlaPluginLV2::handleWorkerSchedule(%i, %p)", size, data);
carla_debug("CarlaPluginLV2::handleWorkerSchedule(%i, %p)", size, data);

if (pData->engine->isOffline())
{
@@ -4835,7 +4944,7 @@ public:
LV2_Worker_Status handleWorkerRespond(const uint32_t size, const void* const data)
{
CARLA_SAFE_ASSERT_RETURN(fExt.worker != nullptr && fExt.worker->work_response != nullptr, LV2_WORKER_ERR_UNKNOWN);
carla_stdout("CarlaPluginLV2::handleWorkerRespond(%i, %p)", size, data);
carla_debug("CarlaPluginLV2::handleWorkerRespond(%i, %p)", size, data);

LV2_Atom atom;
atom.size = size;
@@ -5003,7 +5112,7 @@ public:
index = fEventsIn.ctrlIndex;
}

fAtomBufferUiIn.put(atom, index);
fAtomBufferEvIn.put(atom, index);
} break;

default:
@@ -5759,6 +5868,10 @@ public:

switch (uiType)
{
case LV2_UI_NONE:
carla_stdout("Will use LV2 Show Interface for '%s'", pData->name);
fUI.type = UI::TYPE_EMBED;
break;
case LV2_UI_QT4:
carla_stdout("Will use LV2 Qt4 UI for '%s', NOT!", pData->name);
fUI.type = UI::TYPE_EMBED;
@@ -5922,7 +6035,7 @@ public:
CARLA_SAFE_ASSERT_RETURN(atom != nullptr,);
carla_debug("CarlaPluginLV2::handleTransferAtom(%i, %p)", portIndex, atom);

fAtomBufferUiIn.put(atom, portIndex);
fAtomBufferEvIn.put(atom, portIndex);
}

void handleUridMap(const LV2_URID urid, const char* const uri)
@@ -5970,7 +6083,7 @@ private:
int32_t fLatencyIndex; // -1 if invalid
int fStrictBounds; // -1 unsupported, 0 optional, 1 required

Lv2AtomRingBuffer fAtomBufferUiIn;
Lv2AtomRingBuffer fAtomBufferEvIn;
Lv2AtomRingBuffer fAtomBufferUiOut;
Lv2AtomRingBuffer fAtomBufferWorkerIn;
Lv2AtomRingBuffer fAtomBufferWorkerResp;
@@ -5989,6 +6102,9 @@ private:
void* fLastStateChunk;
EngineTimeInfo fLastTimeInfo;

// if plugin provides path parameter, use it as fake "gui"
CarlaString fFilePathURI;

struct Extensions {
const LV2_Options_Interface* options;
const LV2_State_Interface* state;
@@ -6307,6 +6423,14 @@ private:
if (std::strcmp(uri, LV2_LOG__Warning) == 0)
return kUridLogWarning;

// Patch types
if (std::strcmp(uri, LV2_PATCH__Set) == 0)
return kUridPatchSet;
if (std::strcmp(uri, LV2_PATCH__property) == 0)
return kUridPatchPoperty;
if (std::strcmp(uri, LV2_PATCH__value) == 0)
return kUridPatchValue;

// Time types
if (std::strcmp(uri, LV2_TIME__Position) == 0)
return kUridTimePosition;
@@ -6427,6 +6551,14 @@ private:
case kUridLogWarning:
return LV2_LOG__Warning;

// Patch types
case kUridPatchSet:
return LV2_PATCH__Set;
case kUridPatchPoperty:
return LV2_PATCH__property;
case kUridPatchValue:
return LV2_PATCH__value;

// Time types
case kUridTimePosition:
return LV2_TIME__Position;


+ 12
- 7
source/includes/lv2_rdf.hpp View File

@@ -31,6 +31,15 @@ typedef const char* LV2_URI;
typedef uint32_t LV2_Property;
#define LV2UI_INVALID_PORT_INDEX ((uint32_t)-1)

// Parameter Types
#define LV2_PARAMETER_BOOL 1
#define LV2_PARAMETER_INT 2
#define LV2_PARAMETER_LONG 3
#define LV2_PARAMETER_FLOAT 4
#define LV2_PARAMETER_DOUBLE 5
#define LV2_PARAMETER_PATH 6
#define LV2_PARAMETER_STRING 7

// Port Midi Map Types
#define LV2_PORT_MIDI_MAP_CC 1
#define LV2_PORT_MIDI_MAP_NRPN 2
@@ -215,6 +224,7 @@ typedef uint32_t LV2_Property;
#define LV2_IS_UI_PORT_PROTOCOL_PEAK(x) ((x) == LV2_UI_PORT_PROTOCOL_PEAK)

// UI Types
#define LV2_UI_NONE 0
#define LV2_UI_GTK2 1
#define LV2_UI_GTK3 2
#define LV2_UI_QT4 3
@@ -446,7 +456,7 @@ struct LV2_RDF_Port {
// Parameter
struct LV2_RDF_Parameter {
LV2_URI URI;
LV2_URI Range;
LV2_Property Type;
bool Input;
const char* Label;
const char* Comment;
@@ -457,7 +467,7 @@ struct LV2_RDF_Parameter {

LV2_RDF_Parameter() noexcept
: URI(nullptr),
Range(nullptr),
Type(0),
Input(true),
Label(nullptr),
Comment(nullptr),
@@ -472,11 +482,6 @@ struct LV2_RDF_Parameter {
delete[] URI;
URI = nullptr;
}
if (Range != nullptr)
{
delete[] Range;
Range = nullptr;
}
if (Label != nullptr)
{
delete[] Label;


+ 207
- 50
source/utils/CarlaLv2Utils.hpp View File

@@ -229,6 +229,7 @@ public:
Lilv::Node unit_unit;

// UI Types
Lilv::Node ui;
Lilv::Node ui_gtk2;
Lilv::Node ui_gtk3;
Lilv::Node ui_qt4;
@@ -238,7 +239,6 @@ public:
Lilv::Node ui_x11;
Lilv::Node ui_external;
Lilv::Node ui_externalOld;
Lilv::Node ui_externalOld2;

// Misc
Lilv::Node atom_bufferType;
@@ -365,6 +365,7 @@ public:
unit_symbol (new_uri(LV2_UNITS__symbol)),
unit_unit (new_uri(LV2_UNITS__unit)),

ui (new_uri(LV2_UI__UI)),
ui_gtk2 (new_uri(LV2_UI__GtkUI)),
ui_gtk3 (new_uri(LV2_UI__Gtk3UI)),
ui_qt4 (new_uri(LV2_UI__Qt4UI)),
@@ -374,7 +375,6 @@ public:
ui_x11 (new_uri(LV2_UI__X11UI)),
ui_external (new_uri(LV2_EXTERNAL_UI__Widget)),
ui_externalOld (new_uri(LV2_EXTERNAL_UI_DEPRECATED_URI)),
ui_externalOld2 (new_uri("http://nedko.arnaudov.name/lv2/external_ui/")),

atom_bufferType (new_uri(LV2_ATOM__bufferType)),
atom_sequence (new_uri(LV2_ATOM__Sequence)),
@@ -2153,7 +2153,7 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
else if (std::strcmp(unitUnit, LV2_UNITS__semitone12TET) == 0)
rdfPort->Unit.Unit = LV2_PORT_UNIT_SEMITONE;
else
carla_stderr("lv2_rdf_new(\"%s\") - got unknown unit unit '%s'", uri, unitUnit);
carla_stderr("lv2_rdf_new(\"%s\") - got unknown unit '%s'", uri, unitUnit);
}
}

@@ -2214,7 +2214,6 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)

if (const uint numScalePoints = lilvScalePoints.size())
{
rdfPort->ScalePointCount = numScalePoints;
rdfPort->ScalePoints = new LV2_RDF_PortScalePoint[numScalePoints];

// get all scalepoints and sort them by value
@@ -2234,11 +2233,11 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
}

// now safe to store, sorted by using std::map
uint h = 0;
uint numUsed = 0;
for (LilvScalePointMap::iterator it=sortedpoints.begin(), end=sortedpoints.end(); it != end; ++it)
{
CARLA_SAFE_ASSERT_BREAK(h < numScalePoints);
LV2_RDF_PortScalePoint* const rdfScalePoint(&rdfPort->ScalePoints[h++]);
CARLA_SAFE_ASSERT_BREAK(numUsed < numScalePoints);
LV2_RDF_PortScalePoint* const rdfScalePoint(&rdfPort->ScalePoints[numUsed++]);

const LilvScalePoint* const scalepoint = it->second;

@@ -2248,6 +2247,8 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
rdfScalePoint->Label = carla_strdup(lilv_node_as_string(xlabel));
rdfScalePoint->Value = lilv_node_as_float(xvalue);
}

rdfPort->ScalePointCount = numUsed;
}

lilv_nodes_free(const_cast<LilvNodes*>(lilvScalePoints.me));
@@ -2262,39 +2263,192 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)

if (const uint numParameters = patchWritableNodes.size())
{
rdfDescriptor->ParameterCount = numParameters;
rdfDescriptor->Parameters = new LV2_RDF_Parameter[numParameters];

uint h = 0;
uint numUsed = 0;
LILV_FOREACH(nodes, it, patchWritableNodes)
{
CARLA_SAFE_ASSERT_BREAK(h < numParameters);
CARLA_SAFE_ASSERT_BREAK(numUsed < numParameters);

Lilv::Node patchWritableNode(patchWritableNodes.get(it));
LV2_RDF_Parameter* const rdfParam(&rdfDescriptor->Parameters[h++]);
LV2_RDF_Parameter& rdfParam(rdfDescriptor->Parameters[numUsed++]);

CARLA_SAFE_ASSERT_CONTINUE(patchWritableNode.is_uri());

rdfParam->URI = carla_strdup(patchWritableNode.as_uri());
rdfParam.URI = carla_strdup(patchWritableNode.as_uri());

// ----------------------------------------------------------------------------------------------------
// Set Basics

if (LilvNode* const label = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.rdfs_range.me, nullptr))
if (LilvNode* const rangeNode = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.rdfs_range.me, nullptr))
{
rdfParam->Range = carla_strdup(lilv_node_as_string(label));
const char* const rangeURI = lilv_node_as_string(rangeNode);

/**/ if (std::strcmp(rangeURI, LV2_ATOM__Bool) == 0)
rdfParam.Type = LV2_PARAMETER_BOOL;
else if (std::strcmp(rangeURI, LV2_ATOM__Int) == 0)
rdfParam.Type = LV2_PARAMETER_INT;
else if (std::strcmp(rangeURI, LV2_ATOM__Long) == 0)
rdfParam.Type = LV2_PARAMETER_LONG;
else if (std::strcmp(rangeURI, LV2_ATOM__Float) == 0)
rdfParam.Type = LV2_PARAMETER_FLOAT;
else if (std::strcmp(rangeURI, LV2_ATOM__Double) == 0)
rdfParam.Type = LV2_PARAMETER_DOUBLE;
else if (std::strcmp(rangeURI, LV2_ATOM__Path) == 0)
rdfParam.Type = LV2_PARAMETER_PATH;
else if (std::strcmp(rangeURI, LV2_ATOM__String) == 0)
rdfParam.Type = LV2_PARAMETER_STRING;
else
carla_stderr("lv2_rdf_new(\"%s\") - got unknown parameter type '%s'", uri, rangeURI);

lilv_node_free(rangeNode);
}
if (LilvNode* const label = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.rdfs_label.me, nullptr))

if (LilvNode* const labelNode = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.rdfs_label.me, nullptr))
{
rdfParam->Label = carla_strdup(lilv_node_as_string(label));
rdfParam.Label = carla_strdup(lilv_node_as_string(labelNode));
lilv_node_free(labelNode);
}
if (LilvNode* const comment = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.rdfs_comment.me, nullptr))

if (LilvNode* const commentNode = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.rdfs_comment.me, nullptr))
{
rdfParam->Comment = carla_strdup(lilv_node_as_string(comment));
rdfParam.Comment = carla_strdup(lilv_node_as_string(commentNode));
lilv_node_free(commentNode);
}

// ----------------------------------------------------------------------------------------------------
// Set Port Points

if (LilvNode* const defNode = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.value_default.me, nullptr))
{
rdfParam.Points.Hints |= LV2_PORT_POINT_DEFAULT;
rdfParam.Points.Default = lilv_node_as_float(defNode);
lilv_node_free(defNode);
}

if (LilvNode* const minNode = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.value_minimum.me, nullptr))
{
rdfParam.Points.Hints |= LV2_PORT_POINT_MINIMUM;
rdfParam.Points.Minimum = lilv_node_as_float(minNode);
lilv_node_free(minNode);
}

if (LilvNode* const maxNode = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.value_maximum.me, nullptr))
{
rdfParam.Points.Hints |= LV2_PORT_POINT_MAXIMUM;
rdfParam.Points.Maximum = lilv_node_as_float(maxNode);
lilv_node_free(maxNode);
}

// TODO: MidiMap, Points, Unit;
// ----------------------------------------------------------------------------------------------------
// Set Port Unit

if (LilvNode* const unitUnitNode = lilv_world_get(lv2World.me, patchWritableNode,
lv2World.unit_unit.me, nullptr))
{
if (lilv_node_is_uri(unitUnitNode))
{
if (const char* const unitUnit = lilv_node_as_uri(unitUnitNode))
{
rdfParam.Unit.Hints |= LV2_PORT_UNIT_UNIT;

/**/ if (std::strcmp(unitUnit, LV2_UNITS__bar) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_BAR;
else if (std::strcmp(unitUnit, LV2_UNITS__beat) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_BEAT;
else if (std::strcmp(unitUnit, LV2_UNITS__bpm) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_BPM;
else if (std::strcmp(unitUnit, LV2_UNITS__cent) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_CENT;
else if (std::strcmp(unitUnit, LV2_UNITS__cm) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_CM;
else if (std::strcmp(unitUnit, LV2_UNITS__coef) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_COEF;
else if (std::strcmp(unitUnit, LV2_UNITS__db) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_DB;
else if (std::strcmp(unitUnit, LV2_UNITS__degree) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_DEGREE;
else if (std::strcmp(unitUnit, LV2_UNITS__frame) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_FRAME;
else if (std::strcmp(unitUnit, LV2_UNITS__hz) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_HZ;
else if (std::strcmp(unitUnit, LV2_UNITS__inch) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_INCH;
else if (std::strcmp(unitUnit, LV2_UNITS__khz) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_KHZ;
else if (std::strcmp(unitUnit, LV2_UNITS__km) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_KM;
else if (std::strcmp(unitUnit, LV2_UNITS__m) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_M;
else if (std::strcmp(unitUnit, LV2_UNITS__mhz) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_MHZ;
else if (std::strcmp(unitUnit, LV2_UNITS__midiNote) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_MIDINOTE;
else if (std::strcmp(unitUnit, LV2_UNITS__mile) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_MILE;
else if (std::strcmp(unitUnit, LV2_UNITS__min) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_MIN;
else if (std::strcmp(unitUnit, LV2_UNITS__mm) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_MM;
else if (std::strcmp(unitUnit, LV2_UNITS__ms) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_MS;
else if (std::strcmp(unitUnit, LV2_UNITS__oct) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_OCT;
else if (std::strcmp(unitUnit, LV2_UNITS__pc) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_PC;
else if (std::strcmp(unitUnit, LV2_UNITS__s) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_S;
else if (std::strcmp(unitUnit, LV2_UNITS__semitone12TET) == 0)
rdfParam.Unit.Unit = LV2_PORT_UNIT_SEMITONE;
else
carla_stderr("lv2_rdf_new(\"%s\") - got unknown unit '%s'", uri, unitUnit);
}
}

if (LilvNode* const unitNameNode = lilv_world_get(lv2World.me, unitUnitNode,
lv2World.unit_name.me, nullptr))
{
if (const char* const unitName = lilv_node_as_string(unitNameNode))
{
rdfParam.Unit.Hints |= LV2_PORT_UNIT_NAME;
rdfParam.Unit.Name = carla_strdup(unitName);
}
lilv_node_free(unitNameNode);
}

if (LilvNode* const unitRenderNode = lilv_world_get(lv2World.me, unitUnitNode,
lv2World.unit_render.me, nullptr))
{
if (const char* const unitRender = lilv_node_as_string(unitRenderNode))
{
rdfParam.Unit.Hints |= LV2_PORT_UNIT_RENDER;
rdfParam.Unit.Render = carla_strdup(unitRender);
}
lilv_node_free(unitRenderNode);
}

if (LilvNode* const unitSymbolNode = lilv_world_get(lv2World.me, unitUnitNode,
lv2World.unit_symbol.me, nullptr))
{
if (const char* const unitSymbol = lilv_node_as_string(unitSymbolNode))
{
rdfParam.Unit.Hints |= LV2_PORT_UNIT_SYMBOL;
rdfParam.Unit.Symbol = carla_strdup(unitSymbol);
}
lilv_node_free(unitSymbolNode);
}

lilv_node_free(unitUnitNode);
}
}

rdfDescriptor->ParameterCount = numUsed;
}

lilv_nodes_free(const_cast<LilvNodes*>(patchWritableNodes.me));
@@ -2405,16 +2559,15 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
{
Lilv::Nodes lilvFeatureNodesR(lilvPlugin.get_required_features());

rdfDescriptor->FeatureCount = numFeatures;
rdfDescriptor->Features = new LV2_RDF_Feature[numFeatures];

uint h = 0;
uint numUsed = 0;
LILV_FOREACH(nodes, it, lilvFeatureNodes)
{
CARLA_SAFE_ASSERT_BREAK(h < numFeatures);
CARLA_SAFE_ASSERT_BREAK(numUsed < numFeatures);

Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it));
LV2_RDF_Feature* const rdfFeature(&rdfDescriptor->Features[h++]);
LV2_RDF_Feature* const rdfFeature(&rdfDescriptor->Features[numUsed++]);

rdfFeature->Required = lilvFeatureNodesR.contains(lilvFeatureNode);

@@ -2424,6 +2577,7 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
rdfFeature->URI = nullptr;
}

rdfDescriptor->FeatureCount = numUsed;
lilv_nodes_free(const_cast<LilvNodes*>(lilvFeatureNodesR.me));
}

@@ -2437,16 +2591,15 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)

if (const uint numExtensions = lilvExtensionDataNodes.size())
{
rdfDescriptor->ExtensionCount = numExtensions;
rdfDescriptor->Extensions = new LV2_URI[numExtensions];

uint h = 0;
uint numUsed = 0;
LILV_FOREACH(nodes, it, lilvExtensionDataNodes)
{
CARLA_SAFE_ASSERT_BREAK(h < numExtensions);
CARLA_SAFE_ASSERT_BREAK(numUsed < numExtensions);

Lilv::Node lilvExtensionDataNode(lilvExtensionDataNodes.get(it));
LV2_URI* const rdfExtension(&rdfDescriptor->Extensions[h++]);
LV2_URI* const rdfExtension(&rdfDescriptor->Extensions[numUsed++]);

if (lilvExtensionDataNode.is_uri())
{
@@ -2459,8 +2612,10 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
*rdfExtension = nullptr;
}

for (uint32_t x=h; x < rdfDescriptor->ExtensionCount; ++x)
for (uint32_t x=numUsed; x < rdfDescriptor->ExtensionCount; ++x)
rdfDescriptor->Extensions[x] = nullptr;

rdfDescriptor->ExtensionCount = numUsed;
}

lilv_nodes_free(const_cast<LilvNodes*>(lilvExtensionDataNodes.me));
@@ -2473,16 +2628,15 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)

if (const uint numUIs = lilvUIs.size())
{
rdfDescriptor->UICount = numUIs;
rdfDescriptor->UIs = new LV2_RDF_UI[numUIs];

uint h = 0;
uint numUsed = 0;
LILV_FOREACH(uis, it, lilvUIs)
{
CARLA_SAFE_ASSERT_BREAK(h < numUIs);
CARLA_SAFE_ASSERT_BREAK(numUsed < numUIs);

Lilv::UI lilvUI(lilvUIs.get(it));
LV2_RDF_UI* const rdfUI(&rdfDescriptor->UIs[h++]);
LV2_RDF_UI* const rdfUI(&rdfDescriptor->UIs[numUsed++]);

lv2World.load_resource(lilvUI.get_uri());

@@ -2507,8 +2661,8 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
rdfUI->Type = LV2_UI_EXTERNAL;
else if (lilvUI.is_a(lv2World.ui_externalOld))
rdfUI->Type = LV2_UI_OLD_EXTERNAL;
else if (lilvUI.is_a(lv2World.ui_externalOld2))
pass();
else if (lilvUI.is_a(lv2World.ui))
rdfUI->Type = LV2_UI_NONE;
else
carla_stderr("lv2_rdf_new(\"%s\") - UI '%s' is of unknown type", uri, lilvUI.get_uri().as_uri());

@@ -2534,16 +2688,15 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
{
Lilv::Nodes lilvFeatureNodesR(lilvUI.get_required_features());

rdfUI->FeatureCount = numFeatures;
rdfUI->Features = new LV2_RDF_Feature[numFeatures];

uint h2 = 0;
uint numUsed2 = 0;
LILV_FOREACH(nodes, it2, lilvFeatureNodes)
{
CARLA_SAFE_ASSERT_BREAK(h2 < numFeatures);
CARLA_SAFE_ASSERT_UINT2_BREAK(numUsed2 < numFeatures, numUsed2, numFeatures);

Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it2));
LV2_RDF_Feature* const rdfFeature(&rdfUI->Features[h2++]);
LV2_RDF_Feature* const rdfFeature(&rdfUI->Features[numUsed2++]);

rdfFeature->Required = lilvFeatureNodesR.contains(lilvFeatureNode);

@@ -2553,6 +2706,7 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
rdfFeature->URI = nullptr;
}

rdfUI->FeatureCount = numUsed2;
lilv_nodes_free(const_cast<LilvNodes*>(lilvFeatureNodesR.me));
}

@@ -2564,18 +2718,17 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
{
Lilv::Nodes lilvExtensionDataNodes(lilvUI.get_extension_data());

if (const uint numExtensions = lilvExtensionDataNodes.size() > 0)
if (const uint numExtensions = lilvExtensionDataNodes.size())
{
rdfUI->ExtensionCount = numExtensions;
rdfUI->Extensions = new LV2_URI[numExtensions];

uint h2 = 0;
uint numUsed2 = 0;
LILV_FOREACH(nodes, it2, lilvExtensionDataNodes)
{
CARLA_SAFE_ASSERT_BREAK(h2 < numExtensions);
CARLA_SAFE_ASSERT_UINT2_BREAK(numUsed2 < numExtensions, numUsed2, numExtensions);

Lilv::Node lilvExtensionDataNode(lilvExtensionDataNodes.get(it2));
LV2_URI* const rdfExtension(&rdfUI->Extensions[h2++]);
LV2_URI* const rdfExtension(&rdfUI->Extensions[numUsed2++]);

if (lilvExtensionDataNode.is_uri())
{
@@ -2588,8 +2741,10 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
*rdfExtension = nullptr;
}

for (uint x2=h2; x2 < rdfUI->ExtensionCount; ++x2)
for (uint x2=numUsed2; x2 < rdfUI->ExtensionCount; ++x2)
rdfUI->Extensions[x2] = nullptr;

rdfUI->ExtensionCount = numUsed2;
}

lilv_nodes_free(const_cast<LilvNodes*>(lilvExtensionDataNodes.me));
@@ -2605,13 +2760,13 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
rdfUI->PortNotificationCount = portNotifCount;
rdfUI->PortNotifications = new LV2_RDF_UI_PortNotification[portNotifCount];

uint h2 = 0;
uint numUsed2 = 0;
LILV_FOREACH(nodes, it2, portNotifNodes)
{
CARLA_SAFE_ASSERT_BREAK(h2 < portNotifCount);
CARLA_SAFE_ASSERT_UINT2_BREAK(numUsed2 < portNotifCount, numUsed2, portNotifCount);

Lilv::Node portNotifNode(portNotifNodes.get(it2));
LV2_RDF_UI_PortNotification* const rdfPortNotif(&rdfUI->PortNotifications[h2++]);
LV2_RDF_UI_PortNotification* const rdfPortNotif(&rdfUI->PortNotifications[numUsed2++]);

LilvNode* const protocolNode = lilv_world_get(lv2World.me, portNotifNode,
lv2World.ui_protocol.me, nullptr);
@@ -2665,6 +2820,8 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
lilv_nodes_free(const_cast<LilvNodes*>(portNotifNodes.me));
}
}

rdfDescriptor->UICount = numUsed;
}

lilv_nodes_free(const_cast<LilvNodes*>(lilvUIs.me));


Loading…
Cancel
Save