Rework state path support in carla lv2 plugins
This commit is contained in:
parent
523a6f0026
commit
b105847cf8
|
@ -11,6 +11,7 @@
|
|||
a lv2:UtilityPlugin, lv2:Plugin ;
|
||||
|
||||
lv2:optionalFeature <http://lv2plug.in/ns/lv2core#hardRTCapable> ;
|
||||
lv2:optionalFeature <http://lv2plug.in/ns/ext/state#threadSafeRestore> ;
|
||||
|
||||
lv2:requiredFeature <http://lv2plug.in/ns/ext/buf-size#boundedBlockLength> ,
|
||||
<http://lv2plug.in/ns/ext/worker#schedule> ,
|
||||
|
@ -30,6 +31,7 @@
|
|||
a lv2:InputPort, atom:AtomPort ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports <http://lv2plug.in/ns/ext/time#Position> ;
|
||||
atom:supports <http://lv2plug.in/ns/ext/patch#Message> ;
|
||||
lv2:designation lv2:control ;
|
||||
lv2:index 0 ;
|
||||
lv2:symbol "lv2_events_in" ;
|
||||
|
@ -41,6 +43,7 @@
|
|||
lv2:port [
|
||||
a lv2:OutputPort, atom:AtomPort ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports <http://lv2plug.in/ns/ext/patch#Message> ;
|
||||
lv2:index 1 ;
|
||||
lv2:symbol "lv2_events_out" ;
|
||||
lv2:name "Events Output" ;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
a lv2:UtilityPlugin, lv2:Plugin ;
|
||||
|
||||
lv2:optionalFeature <http://lv2plug.in/ns/lv2core#hardRTCapable> ;
|
||||
lv2:optionalFeature <http://lv2plug.in/ns/ext/state#threadSafeRestore> ;
|
||||
|
||||
lv2:requiredFeature <http://lv2plug.in/ns/ext/buf-size#boundedBlockLength> ,
|
||||
<http://lv2plug.in/ns/ext/options#options> ,
|
||||
|
@ -27,6 +28,7 @@
|
|||
a lv2:InputPort, atom:AtomPort ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports <http://lv2plug.in/ns/ext/time#Position> ;
|
||||
atom:supports <http://lv2plug.in/ns/ext/patch#Message> ;
|
||||
lv2:designation lv2:control ;
|
||||
lv2:index 0 ;
|
||||
lv2:symbol "lv2_events_in" ;
|
||||
|
@ -39,6 +41,7 @@
|
|||
a lv2:OutputPort, atom:AtomPort ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;
|
||||
atom:supports <http://lv2plug.in/ns/ext/patch#Message> ;
|
||||
lv2:index 1 ;
|
||||
lv2:symbol "lv2_events_out" ;
|
||||
lv2:name "Events Output" ;
|
||||
|
|
|
@ -7303,7 +7303,7 @@ public:
|
|||
lv2_atom_forge_urid(&atomForge, urid);
|
||||
|
||||
lv2_atom_forge_key(&atomForge, kUridPatchValue);
|
||||
lv2_atom_forge_path(&atomForge, path, static_cast<uint32_t>(std::strlen(path)));
|
||||
lv2_atom_forge_path(&atomForge, path, static_cast<uint32_t>(std::strlen(path))+1);
|
||||
|
||||
lv2_atom_forge_pop(&atomForge, &forgeFrame);
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size);
|
|||
not held.
|
||||
*/
|
||||
static inline void
|
||||
lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)
|
||||
lv2_atom_forge_init(LV2_Atom_Forge* forge, const LV2_URID_Map* map)
|
||||
{
|
||||
lv2_atom_forge_set_buffer(forge, NULL, 0);
|
||||
forge->Blank = map->map(map->handle, LV2_ATOM__Blank);
|
||||
|
|
|
@ -323,10 +323,12 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc,
|
|||
|
||||
// optional
|
||||
if (pluginDesc->hints & NATIVE_PLUGIN_IS_RTSAFE)
|
||||
text += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ;\n\n";
|
||||
|
||||
text += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ;\n";
|
||||
if (pluginDesc->hints & NATIVE_PLUGIN_HAS_INLINE_DISPLAY)
|
||||
text += " lv2:optionalFeature <" LV2_INLINEDISPLAY__queue_draw "> ;\n";
|
||||
if ((pluginDesc->hints & NATIVE_PLUGIN_USES_STATE) || (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE))
|
||||
text += " lv2:optionalFeature <" LV2_STATE__threadSafeRestore "> ;\n";
|
||||
text += "\n";
|
||||
|
||||
// required
|
||||
text += " lv2:requiredFeature <" LV2_BUF_SIZE__boundedBlockLength "> ,\n";
|
||||
|
@ -404,6 +406,8 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc,
|
|||
{
|
||||
text += " atom:supports <" LV2_TIME__Position "> ;\n";
|
||||
}
|
||||
if (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
|
||||
text += " atom:supports <" LV2_PATCH__Message "> ;\n";
|
||||
|
||||
text += " lv2:designation lv2:control ;\n";
|
||||
text += " lv2:index " + String(portIndex++) + " ;\n";
|
||||
|
@ -482,6 +486,8 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc,
|
|||
|
||||
if (pluginDesc->midiOuts > 0)
|
||||
text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n";
|
||||
if (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
|
||||
text += " atom:supports <" LV2_PATCH__Message "> ;\n";
|
||||
|
||||
text += " lv2:index " + String(portIndex++) + " ;\n";
|
||||
|
||||
|
|
|
@ -54,9 +54,11 @@ public:
|
|||
fProgramDesc({0, 0, nullptr}),
|
||||
#endif
|
||||
kIgnoreParameters(std::strncmp(desc->label, "carla", 5) == 0),
|
||||
fAtomForge(),
|
||||
fMidiEventCount(0),
|
||||
fLastProjectPath(),
|
||||
fLoadedFile(),
|
||||
fNeedsNotifyFileChanged(false),
|
||||
fPluginNeedsIdle(false),
|
||||
fWorkerUISignal(0)
|
||||
{
|
||||
|
@ -89,6 +91,9 @@ public:
|
|||
fHost.ui_open_file = host_ui_open_file;
|
||||
fHost.ui_save_file = host_ui_save_file;
|
||||
fHost.dispatcher = host_dispatcher;
|
||||
|
||||
carla_zeroStruct(fAtomForge);
|
||||
lv2_atom_forge_init(&fAtomForge, fUridMap);
|
||||
}
|
||||
|
||||
~NativePlugin()
|
||||
|
@ -259,7 +264,8 @@ public:
|
|||
{
|
||||
const LV2_Atom_Object* const obj = (const LV2_Atom_Object*)(&event->body);
|
||||
|
||||
if (obj->body.otype == fURIs.patchSet) {
|
||||
if (obj->body.otype == fURIs.patchSet)
|
||||
{
|
||||
// Get property URI.
|
||||
const LV2_Atom* property = nullptr;
|
||||
lv2_atom_object_get(obj, fURIs.patchProperty, &property, 0);
|
||||
|
@ -288,6 +294,11 @@ public:
|
|||
static_cast<uint32_t>(std::strlen(filepath) + 1U),
|
||||
filepath);
|
||||
}
|
||||
else if (obj->body.otype == fURIs.patchGet)
|
||||
{
|
||||
if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
|
||||
fNeedsNotifyFileChanged = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -317,6 +328,54 @@ public:
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fNeedsNotifyFileChanged)
|
||||
{
|
||||
fNeedsNotifyFileChanged = false;
|
||||
|
||||
uint8_t atomBuf[4096];
|
||||
LV2_Atom_Forge atomForge = fAtomForge;
|
||||
lv2_atom_forge_set_buffer(&atomForge, atomBuf, sizeof(atomBuf));
|
||||
|
||||
LV2_Atom_Forge_Frame forgeFrame;
|
||||
lv2_atom_forge_object(&atomForge, &forgeFrame, 0, fURIs.patchSet);
|
||||
|
||||
lv2_atom_forge_key(&atomForge, fURIs.patchProperty);
|
||||
|
||||
/* */ if (std::strcmp(fDescriptor->label, "audiofile") == 0) {
|
||||
lv2_atom_forge_urid(&atomForge, fURIs.carlaFileAudio);
|
||||
} else if (std::strcmp(fDescriptor->label, "midifile") == 0) {
|
||||
lv2_atom_forge_urid(&atomForge, fURIs.carlaFileMIDI);
|
||||
} else {
|
||||
lv2_atom_forge_urid(&atomForge, fURIs.carlaFile);
|
||||
}
|
||||
|
||||
lv2_atom_forge_key(&atomForge, fURIs.patchValue);
|
||||
lv2_atom_forge_path(&atomForge,
|
||||
fLoadedFile.buffer(),
|
||||
static_cast<uint32_t>(fLoadedFile.length()+1));
|
||||
|
||||
lv2_atom_forge_pop(&atomForge, &forgeFrame);
|
||||
|
||||
LV2_Atom* const atom = (LV2_Atom*)atomBuf;
|
||||
|
||||
LV2_Atom_Sequence* const seq = fPorts.eventsOut[0];
|
||||
Ports::EventsOutData& mData(fPorts.eventsOutData[0]);
|
||||
|
||||
if (sizeof(LV2_Atom_Event) + atom->size <= mData.capacity - mData.offset)
|
||||
{
|
||||
LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + mData.offset);
|
||||
|
||||
aev->time.frames = 0;
|
||||
aev->body.size = atom->size;
|
||||
aev->body.type = atom->type;
|
||||
std::memcpy(LV2_ATOM_BODY(&aev->body), atom + 1, atom->size);
|
||||
|
||||
const uint32_t size = lv2_atom_pad_size(static_cast<uint32_t>(sizeof(LV2_Atom_Event) + atom->size));
|
||||
mData.offset += size;
|
||||
seq->atom.size += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fDescriptor->process(fHandle, fPorts.audioCVIns, fPorts.audioCVOuts, frames, fMidiEvents, fMidiEventCount);
|
||||
|
@ -324,7 +383,7 @@ public:
|
|||
if (fPluginNeedsIdle)
|
||||
{
|
||||
fPluginNeedsIdle = false;
|
||||
const char* const msg = "idle";
|
||||
const char* const msg = "_idle_";
|
||||
const size_t msgSize = std::strlen(msg);
|
||||
fWorker->schedule_work(fWorker->handle, static_cast<uint32_t>(msgSize + 1U), msg);
|
||||
}
|
||||
|
@ -453,22 +512,57 @@ public:
|
|||
|
||||
if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
|
||||
{
|
||||
if (fLoadedFile.isEmpty())
|
||||
return LV2_STATE_SUCCESS;
|
||||
|
||||
const LV2_State_Free_Path* freePath = nullptr;
|
||||
const LV2_State_Map_Path* mapPath = nullptr;
|
||||
|
||||
if (features != nullptr)
|
||||
{
|
||||
for (int i=0; features[i] != nullptr; ++i)
|
||||
{
|
||||
/**/ if (freePath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
|
||||
freePath = (const LV2_State_Free_Path*)features[i]->data;
|
||||
else if (mapPath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
|
||||
mapPath = (const LV2_State_Map_Path*)features[i]->data;
|
||||
}
|
||||
}
|
||||
|
||||
if (mapPath == nullptr || mapPath->abstract_path == nullptr)
|
||||
return LV2_STATE_ERR_NO_FEATURE;
|
||||
|
||||
char* path = mapPath->abstract_path(mapPath->handle, fLoadedFile.buffer());
|
||||
|
||||
store(handle,
|
||||
fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/file"),
|
||||
fLoadedFile.buffer(),
|
||||
fLoadedFile.length()+1,
|
||||
path,
|
||||
std::strlen(path)+1,
|
||||
fURIs.atomPath,
|
||||
LV2_STATE_IS_POD);
|
||||
LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
|
||||
|
||||
if (freePath != nullptr && freePath->free_path != nullptr)
|
||||
freePath->free_path(freePath->handle, path);
|
||||
#ifndef CARLA_OS_WIN
|
||||
// this is not safe to call under windows
|
||||
else
|
||||
std::free(path);
|
||||
#endif
|
||||
|
||||
return LV2_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->get_state == nullptr)
|
||||
return LV2_STATE_ERR_NO_FEATURE;
|
||||
return LV2_STATE_ERR_UNKNOWN;
|
||||
|
||||
if (char* const state = fDescriptor->get_state(fHandle))
|
||||
{
|
||||
store(handle, fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"),
|
||||
state, std::strlen(state)+1, fURIs.atomString, LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
|
||||
store(handle,
|
||||
fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"),
|
||||
state,
|
||||
std::strlen(state)+1,
|
||||
fURIs.atomString,
|
||||
LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE);
|
||||
std::free(state);
|
||||
return LV2_STATE_SUCCESS;
|
||||
}
|
||||
|
@ -476,8 +570,10 @@ public:
|
|||
return LV2_STATE_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle,
|
||||
uint32_t flags, const LV2_Feature* const* const features)
|
||||
LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve,
|
||||
const LV2_State_Handle handle,
|
||||
uint32_t flags,
|
||||
const LV2_Feature* const* const features)
|
||||
{
|
||||
saveLastProjectPathIfPossible(features);
|
||||
|
||||
|
@ -490,21 +586,53 @@ public:
|
|||
const void* const data = retrieve(handle,
|
||||
fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/file"),
|
||||
&size, &type, &flags);
|
||||
if (size <= 1 || type == 0)
|
||||
return LV2_STATE_ERR_NO_PROPERTY;
|
||||
|
||||
CARLA_SAFE_ASSERT_RETURN(type == fURIs.atomPath, LV2_STATE_ERR_UNKNOWN);
|
||||
|
||||
const LV2_State_Free_Path* freePath = nullptr;
|
||||
const LV2_State_Map_Path* mapPath = nullptr;
|
||||
|
||||
if (features != nullptr)
|
||||
{
|
||||
for (int i=0; features[i] != nullptr; ++i)
|
||||
{
|
||||
/**/ if (freePath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
|
||||
freePath = (const LV2_State_Free_Path*)features[i]->data;
|
||||
else if (mapPath == nullptr && std::strcmp(features[i]->URI, LV2_STATE__mapPath) == 0)
|
||||
mapPath = (const LV2_State_Map_Path*)features[i]->data;
|
||||
}
|
||||
}
|
||||
|
||||
if (mapPath == nullptr || mapPath->absolute_path == nullptr)
|
||||
return LV2_STATE_ERR_NO_FEATURE;
|
||||
|
||||
const char* const filename = (const char*)data;
|
||||
|
||||
fLoadedFile = filename;
|
||||
fDescriptor->set_custom_data(fHandle, "file", filename);
|
||||
char* const absolute_filename = mapPath->absolute_path(mapPath->handle, filename);
|
||||
fLoadedFile = absolute_filename;
|
||||
|
||||
if (freePath != nullptr && freePath->free_path != nullptr)
|
||||
freePath->free_path(freePath->handle, absolute_filename);
|
||||
#ifndef CARLA_OS_WIN
|
||||
// this is not safe to call under windows
|
||||
else
|
||||
std::free(absolute_filename);
|
||||
#endif
|
||||
|
||||
fNeedsNotifyFileChanged = true;
|
||||
fDescriptor->set_custom_data(fHandle, "file", fLoadedFile);
|
||||
return LV2_STATE_SUCCESS;
|
||||
}
|
||||
|
||||
if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->set_state == nullptr)
|
||||
return LV2_STATE_ERR_NO_FEATURE;
|
||||
return LV2_STATE_ERR_UNKNOWN;
|
||||
|
||||
size = type = 0;
|
||||
const void* const data = retrieve(handle, fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"), &size, &type, &flags);
|
||||
const void* const data = retrieve(handle,
|
||||
fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"),
|
||||
&size, &type, &flags);
|
||||
|
||||
if (size == 0)
|
||||
return LV2_STATE_ERR_UNKNOWN;
|
||||
|
@ -526,13 +654,14 @@ public:
|
|||
{
|
||||
const char* const msg = (const char*)data;
|
||||
|
||||
if (fDescriptor->hints & NATIVE_PLUGIN_REQUESTS_IDLE)
|
||||
if (std::strcmp(msg, "_idle_") == 0)
|
||||
{
|
||||
if (std::strcmp(msg, "idle") == 0)
|
||||
if (fDescriptor->hints & NATIVE_PLUGIN_REQUESTS_IDLE)
|
||||
{
|
||||
fDescriptor->dispatcher(fHandle, NATIVE_PLUGIN_OPCODE_IDLE, 0, 0, nullptr, 0.0f);
|
||||
return LV2_WORKER_SUCCESS;
|
||||
}
|
||||
return LV2_WORKER_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)
|
||||
|
@ -949,11 +1078,13 @@ private:
|
|||
// carla as plugin does not implement lv2 parameter API yet, needed for feedback
|
||||
const bool kIgnoreParameters;
|
||||
|
||||
LV2_Atom_Forge fAtomForge;
|
||||
uint32_t fMidiEventCount;
|
||||
NativeMidiEvent fMidiEvents[kMaxMidiEvents];
|
||||
|
||||
CarlaString fLastProjectPath;
|
||||
CarlaString fLoadedFile;
|
||||
volatile bool fNeedsNotifyFileChanged;
|
||||
volatile bool fPluginNeedsIdle;
|
||||
|
||||
int fWorkerUISignal;
|
||||
|
|
|
@ -963,10 +963,12 @@ public:
|
|||
if (frames == 0)
|
||||
return false;
|
||||
|
||||
// init midi out data
|
||||
// init event out data
|
||||
if (fPorts.numMidiOuts > 0 || fPorts.hasUI)
|
||||
{
|
||||
for (uint32_t i=0; i<fPorts.numMidiOuts; ++i)
|
||||
const uint32_t count = fPorts.numMidiOuts > 0 ? fPorts.numMidiOuts : 1;
|
||||
|
||||
for (uint32_t i=0; i < count; ++i)
|
||||
{
|
||||
LV2_Atom_Sequence* const seq(fPorts.eventsOut[i]);
|
||||
CARLA_SAFE_ASSERT_CONTINUE(seq != nullptr);
|
||||
|
@ -1371,6 +1373,7 @@ protected:
|
|||
{
|
||||
eventsOut = new LV2_Atom_Sequence*[1];
|
||||
eventsOut[0] = nullptr;
|
||||
eventsOutData = new EventsOutData[1];
|
||||
}
|
||||
|
||||
if (const uint32_t numAudioCVIns = numAudioIns+numCVIns)
|
||||
|
@ -1519,6 +1522,7 @@ protected:
|
|||
LV2_URID carlaFileMIDI;
|
||||
LV2_URID midiEvent;
|
||||
LV2_URID patchProperty;
|
||||
LV2_URID patchGet;
|
||||
LV2_URID patchSet;
|
||||
LV2_URID patchValue;
|
||||
LV2_URID timePos;
|
||||
|
@ -1549,6 +1553,7 @@ protected:
|
|||
carlaFileMIDI(0),
|
||||
midiEvent(0),
|
||||
patchProperty(0),
|
||||
patchGet(0),
|
||||
patchSet(0),
|
||||
patchValue(0),
|
||||
timePos(0),
|
||||
|
@ -1580,6 +1585,7 @@ protected:
|
|||
carlaFileMIDI = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/file/midi");
|
||||
midiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent);
|
||||
patchProperty = uridMap->map(uridMap->handle, LV2_PATCH__property);
|
||||
patchGet = uridMap->map(uridMap->handle, LV2_PATCH__Get);
|
||||
patchSet = uridMap->map(uridMap->handle, LV2_PATCH__Set);
|
||||
patchValue = uridMap->map(uridMap->handle, LV2_PATCH__value);
|
||||
timePos = uridMap->map(uridMap->handle, LV2_TIME__Position);
|
||||
|
@ -2344,12 +2350,11 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
|
|||
// ----------------------------------------------------------------------------------------------------------------
|
||||
// Set Plugin Parameters
|
||||
{
|
||||
std::map<std::string, LV2_RDF_Parameter> parameters;
|
||||
Lilv::Nodes patchWritableNodes(lilvPlugin.get_value(lv2World.patch_writable));
|
||||
|
||||
if (const uint numParameters = patchWritableNodes.size())
|
||||
{
|
||||
rdfDescriptor->Parameters = new LV2_RDF_Parameter[numParameters];
|
||||
|
||||
uint numUsed = 0;
|
||||
LILV_FOREACH(nodes, it, patchWritableNodes)
|
||||
{
|
||||
|
@ -2371,10 +2376,10 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
|
|||
lilv_node_free(typeNode);
|
||||
}
|
||||
|
||||
LV2_RDF_Parameter& rdfParam(rdfDescriptor->Parameters[numUsed++]);
|
||||
|
||||
CARLA_SAFE_ASSERT_CONTINUE(patchWritableNode.is_uri());
|
||||
|
||||
++numUsed;
|
||||
LV2_RDF_Parameter rdfParam;
|
||||
rdfParam.URI = carla_strdup(patchWritableNode.as_uri());
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
@ -2557,9 +2562,20 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
|
|||
|
||||
lilv_node_free(unitUnitNode);
|
||||
}
|
||||
|
||||
parameters[rdfParam.URI] = rdfParam;
|
||||
}
|
||||
|
||||
CARLA_SAFE_ASSERT_UINT2(parameters.size() == numUsed, parameters.size(), numUsed);
|
||||
rdfDescriptor->Parameters = new LV2_RDF_Parameter[numUsed];
|
||||
rdfDescriptor->ParameterCount = numUsed;
|
||||
|
||||
numUsed = 0;
|
||||
for (std::map<std::string, LV2_RDF_Parameter>::iterator it = parameters.begin(), end = parameters.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
rdfDescriptor->Parameters[numUsed++] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
lilv_nodes_free(const_cast<LilvNodes*>(patchWritableNodes.me));
|
||||
|
|
Loading…
Reference in New Issue