|
|
@@ -1,6 +1,6 @@ |
|
|
|
/* |
|
|
|
* DISTRHO Plugin Framework (DPF) |
|
|
|
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> |
|
|
|
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> |
|
|
|
* |
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any purpose with |
|
|
|
* or without fee is hereby granted, provided that the above copyright notice and this |
|
|
@@ -17,6 +17,7 @@ |
|
|
|
#include "DistrhoPluginInternal.hpp" |
|
|
|
|
|
|
|
#include "lv2/atom.h" |
|
|
|
#include "lv2/atom-forge.h" |
|
|
|
#include "lv2/atom-util.h" |
|
|
|
#include "lv2/buf-size.h" |
|
|
|
#include "lv2/data-access.h" |
|
|
@@ -47,8 +48,8 @@ |
|
|
|
# define DISTRHO_PLUGIN_LV2_STATE_PREFIX "urn:distrho:" |
|
|
|
#endif |
|
|
|
|
|
|
|
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) || DISTRHO_PLUGIN_WANT_STATEFILES) |
|
|
|
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) |
|
|
|
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) |
|
|
|
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) |
|
|
|
|
|
|
|
START_NAMESPACE_DISTRHO |
|
|
|
|
|
|
@@ -126,29 +127,29 @@ public: |
|
|
|
#endif |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE |
|
|
|
std::memset(&fAtomForge, 0, sizeof(fAtomForge)); |
|
|
|
lv2_atom_forge_init(&fAtomForge, uridMap); |
|
|
|
|
|
|
|
if (const uint32_t count = fPlugin.getStateCount()) |
|
|
|
{ |
|
|
|
fUrids = new LV2_URID[count]; |
|
|
|
fNeededUiSends = new bool[count]; |
|
|
|
|
|
|
|
for (uint32_t i=0; i < count; ++i) |
|
|
|
{ |
|
|
|
fNeededUiSends[i] = false; |
|
|
|
|
|
|
|
const String& dkey(fPlugin.getStateKey(i)); |
|
|
|
fStateMap[dkey] = fPlugin.getStateDefaultValue(i); |
|
|
|
const String& statekey(fPlugin.getStateKey(i)); |
|
|
|
fStateMap[statekey] = fPlugin.getStateDefaultValue(i); |
|
|
|
|
|
|
|
# if DISTRHO_PLUGIN_WANT_STATEFILES |
|
|
|
if (fPlugin.isStateFile(i)) |
|
|
|
{ |
|
|
|
const String dpf_lv2_key(DISTRHO_PLUGIN_URI "#" + dkey); |
|
|
|
const LV2_URID urid = uridMap->map(uridMap->handle, dpf_lv2_key.buffer()); |
|
|
|
fUridStateFileMap[urid] = dkey; |
|
|
|
} |
|
|
|
# endif |
|
|
|
const String lv2key(DISTRHO_PLUGIN_URI "#" + statekey); |
|
|
|
const LV2_URID urid = fUrids[i] = uridMap->map(uridMap->handle, lv2key.buffer()); |
|
|
|
fUridStateMap[urid] = statekey; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
fUrids = nullptr; |
|
|
|
fNeededUiSends = nullptr; |
|
|
|
} |
|
|
|
#else |
|
|
@@ -544,13 +545,14 @@ public: |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
// check for messages from UI or files |
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE && (DISTRHO_PLUGIN_HAS_UI || DISTRHO_PLUGIN_WANT_STATEFILES) |
|
|
|
// check for messages from UI or host |
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE |
|
|
|
LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) |
|
|
|
{ |
|
|
|
if (event == nullptr) |
|
|
|
break; |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_HAS_UI |
|
|
|
if (event->body.type == fURIDs.dpfKeyValue) |
|
|
|
{ |
|
|
|
const void* const data = (const void*)(event + 1); |
|
|
@@ -567,8 +569,9 @@ public: |
|
|
|
fWorker->schedule_work(fWorker->handle, sizeof(LV2_Atom)+event->body.size, &event->body); |
|
|
|
} |
|
|
|
} |
|
|
|
# if DISTRHO_PLUGIN_WANT_STATEFILES |
|
|
|
else if (event->body.type == fURIDs.atomObject && fWorker != nullptr) |
|
|
|
else |
|
|
|
#endif |
|
|
|
if (event->body.type == fURIDs.atomObject && fWorker != nullptr) |
|
|
|
{ |
|
|
|
const LV2_Atom_Object* const object = (const LV2_Atom_Object*)&event->body; |
|
|
|
|
|
|
@@ -576,13 +579,12 @@ public: |
|
|
|
const LV2_Atom* value = nullptr; |
|
|
|
lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr); |
|
|
|
|
|
|
|
if (property != nullptr && property->type == fURIDs.atomURID && |
|
|
|
value != nullptr && value->type == fURIDs.atomPath) |
|
|
|
if (property != nullptr && property->type == fURIDs.atomURID && value != nullptr && |
|
|
|
(value->type == fURIDs.atomPath || value->type == fURIDs.atomString)) |
|
|
|
{ |
|
|
|
fWorker->schedule_work(fWorker->handle, sizeof(LV2_Atom)+event->body.size, &event->body); |
|
|
|
} |
|
|
|
} |
|
|
|
# endif |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
@@ -681,7 +683,7 @@ public: |
|
|
|
|
|
|
|
updateParameterOutputsAndTriggers(); |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI |
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE |
|
|
|
fEventsOutData.initIfNeeded(fURIDs.atomSequence); |
|
|
|
|
|
|
|
LV2_Atom_Event* aev; |
|
|
@@ -692,6 +694,16 @@ public: |
|
|
|
if (! fNeededUiSends[i]) |
|
|
|
continue; |
|
|
|
|
|
|
|
const uint32_t hints = fPlugin.getStateHints(i); |
|
|
|
|
|
|
|
#if ! DISTRHO_PLUGIN_HAS_UI |
|
|
|
if ((hints & kStateIsHostVisible) == 0x0) |
|
|
|
{ |
|
|
|
fNeededUiSends[i] = false; |
|
|
|
continue; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
const String& curKey(fPlugin.getStateKey(i)); |
|
|
|
|
|
|
|
for (StringToStringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit) |
|
|
@@ -703,8 +715,19 @@ public: |
|
|
|
|
|
|
|
const String& value(cit->second); |
|
|
|
|
|
|
|
// set msg size (key + value + separator + 2x null terminator) |
|
|
|
const uint32_t msgSize = static_cast<uint32_t>(key.length()+value.length())+3U; |
|
|
|
// set msg size |
|
|
|
uint32_t msgSize; |
|
|
|
|
|
|
|
if (hints & kStateIsHostVisible) |
|
|
|
{ |
|
|
|
// object, prop key, prop urid, value key, value |
|
|
|
msgSize = sizeof(LV2_Atom_Object) + sizeof(LV2_URID) * 3 + value.length() + 1; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// key + value + 2x null terminator + separator |
|
|
|
msgSize = static_cast<uint32_t>(key.length()+value.length())+3U; |
|
|
|
} |
|
|
|
|
|
|
|
if (sizeof(LV2_Atom_Event) + msgSize > capacity - fEventsOutData.offset) |
|
|
|
{ |
|
|
@@ -715,18 +738,38 @@ public: |
|
|
|
// put data |
|
|
|
aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fEventsOutData.port) + fEventsOutData.offset); |
|
|
|
aev->time.frames = 0; |
|
|
|
aev->body.type = fURIDs.dpfKeyValue; |
|
|
|
aev->body.size = msgSize; |
|
|
|
|
|
|
|
uint8_t* const msgBuf = LV2_ATOM_BODY(&aev->body); |
|
|
|
std::memset(msgBuf, 0, msgSize); |
|
|
|
|
|
|
|
// write key and value in atom buffer |
|
|
|
std::memcpy(msgBuf, key.buffer(), key.length()+1); |
|
|
|
std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()+1); |
|
|
|
if (hints & kStateIsHostVisible) |
|
|
|
{ |
|
|
|
LV2_Atom_Forge atomForge = fAtomForge; |
|
|
|
lv2_atom_forge_set_buffer(&atomForge, msgBuf, msgSize); |
|
|
|
|
|
|
|
fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize)); |
|
|
|
LV2_Atom_Forge_Frame forgeFrame; |
|
|
|
lv2_atom_forge_object(&atomForge, &forgeFrame, 0, fURIDs.patchSet); |
|
|
|
|
|
|
|
lv2_atom_forge_key(&atomForge, fURIDs.patchProperty); |
|
|
|
lv2_atom_forge_urid(&atomForge, fUrids[i]); |
|
|
|
|
|
|
|
lv2_atom_forge_key(&atomForge, fURIDs.patchValue); |
|
|
|
lv2_atom_forge_path(&atomForge, value.buffer(), static_cast<uint32_t>(value.length()+1)); |
|
|
|
|
|
|
|
lv2_atom_forge_pop(&atomForge, &forgeFrame); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
aev->body.type = fURIDs.dpfKeyValue; |
|
|
|
aev->body.size = msgSize; |
|
|
|
|
|
|
|
std::memset(msgBuf, 0, msgSize); |
|
|
|
|
|
|
|
// write key and value in atom buffer |
|
|
|
std::memcpy(msgBuf, key.buffer(), key.length()+1); |
|
|
|
std::memcpy(msgBuf+(key.length()+1), value.buffer(), value.length()+1); |
|
|
|
} |
|
|
|
|
|
|
|
fEventsOutData.growBy(lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize)); |
|
|
|
fNeededUiSends[i] = false; |
|
|
|
break; |
|
|
|
} |
|
|
@@ -854,7 +897,7 @@ public: |
|
|
|
} |
|
|
|
# endif |
|
|
|
|
|
|
|
String dpf_lv2_key; |
|
|
|
String lv2key; |
|
|
|
LV2_URID urid; |
|
|
|
|
|
|
|
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) |
|
|
@@ -870,24 +913,24 @@ public: |
|
|
|
|
|
|
|
const String& value(cit->second); |
|
|
|
|
|
|
|
# if DISTRHO_PLUGIN_WANT_STATEFILES |
|
|
|
if (fPlugin.isStateFile(i)) |
|
|
|
if (const uint32_t hints = fPlugin.getStateHints(i)) |
|
|
|
{ |
|
|
|
dpf_lv2_key = DISTRHO_PLUGIN_URI "#"; |
|
|
|
urid = fURIDs.atomPath; |
|
|
|
lv2key = DISTRHO_PLUGIN_URI "#"; |
|
|
|
urid = (hints & kStateIsFilenamePath) == kStateIsFilenamePath |
|
|
|
? fURIDs.atomPath |
|
|
|
: fURIDs.atomString; |
|
|
|
} |
|
|
|
else |
|
|
|
# endif |
|
|
|
{ |
|
|
|
dpf_lv2_key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; |
|
|
|
lv2key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; |
|
|
|
urid = fURIDs.atomString; |
|
|
|
} |
|
|
|
|
|
|
|
dpf_lv2_key += key; |
|
|
|
lv2key += key; |
|
|
|
|
|
|
|
// some hosts need +1 for the null terminator, even though the type is string |
|
|
|
store(handle, |
|
|
|
fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()), |
|
|
|
fUridMap->map(fUridMap->handle, lv2key.buffer()), |
|
|
|
value.buffer(), |
|
|
|
value.length()+1, |
|
|
|
urid, |
|
|
@@ -903,33 +946,33 @@ public: |
|
|
|
size_t size; |
|
|
|
uint32_t type, flags; |
|
|
|
|
|
|
|
String dpf_lv2_key; |
|
|
|
String lv2key; |
|
|
|
LV2_URID urid; |
|
|
|
|
|
|
|
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) |
|
|
|
{ |
|
|
|
const String& key(fPlugin.getStateKey(i)); |
|
|
|
|
|
|
|
# if DISTRHO_PLUGIN_WANT_STATEFILES |
|
|
|
if (fPlugin.isStateFile(i)) |
|
|
|
if (const uint32_t hints = fPlugin.getStateHints(i)) |
|
|
|
{ |
|
|
|
dpf_lv2_key = DISTRHO_PLUGIN_URI "#"; |
|
|
|
urid = fURIDs.atomPath; |
|
|
|
lv2key = DISTRHO_PLUGIN_URI "#"; |
|
|
|
urid = (hints & kStateIsFilenamePath) == kStateIsFilenamePath |
|
|
|
? fURIDs.atomPath |
|
|
|
: fURIDs.atomString; |
|
|
|
} |
|
|
|
else |
|
|
|
# endif |
|
|
|
{ |
|
|
|
dpf_lv2_key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; |
|
|
|
lv2key = DISTRHO_PLUGIN_LV2_STATE_PREFIX; |
|
|
|
urid = fURIDs.atomString; |
|
|
|
} |
|
|
|
|
|
|
|
dpf_lv2_key += key; |
|
|
|
lv2key += key; |
|
|
|
|
|
|
|
size = 0; |
|
|
|
type = 0; |
|
|
|
flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE; |
|
|
|
const void* data = retrieve(handle, |
|
|
|
fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()), |
|
|
|
fUridMap->map(fUridMap->handle, lv2key.buffer()), |
|
|
|
&size, &type, &flags); |
|
|
|
|
|
|
|
if (data == nullptr || size == 0) |
|
|
@@ -967,7 +1010,6 @@ public: |
|
|
|
return LV2_WORKER_SUCCESS; |
|
|
|
} |
|
|
|
|
|
|
|
# if DISTRHO_PLUGIN_WANT_STATEFILES |
|
|
|
if (eventBody->type == fURIDs.atomObject) |
|
|
|
{ |
|
|
|
const LV2_Atom_Object* const object = (const LV2_Atom_Object*)eventBody; |
|
|
@@ -978,7 +1020,8 @@ public: |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(property != nullptr, LV2_WORKER_ERR_UNKNOWN); |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(property->type == fURIDs.atomURID, LV2_WORKER_ERR_UNKNOWN); |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, LV2_WORKER_ERR_UNKNOWN); |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(value->type == fURIDs.atomPath, LV2_WORKER_ERR_UNKNOWN); |
|
|
|
DISTRHO_SAFE_ASSERT_RETURN(value->type == fURIDs.atomPath || |
|
|
|
value->type == fURIDs.atomString, LV2_WORKER_ERR_UNKNOWN); |
|
|
|
|
|
|
|
const LV2_URID urid = ((const LV2_Atom_URID*)property)->body; |
|
|
|
const char* const filename = (const char*)(value + 1); |
|
|
@@ -986,8 +1029,8 @@ public: |
|
|
|
String key; |
|
|
|
|
|
|
|
try { |
|
|
|
key = fUridStateFileMap[urid]; |
|
|
|
} DISTRHO_SAFE_EXCEPTION_RETURN("lv2_work fUridStateFileMap[urid]", LV2_WORKER_ERR_UNKNOWN); |
|
|
|
key = fUridStateMap[urid]; |
|
|
|
} DISTRHO_SAFE_EXCEPTION_RETURN("lv2_work fUridStateMap[urid]", LV2_WORKER_ERR_UNKNOWN); |
|
|
|
|
|
|
|
setState(key, filename); |
|
|
|
|
|
|
@@ -1002,7 +1045,6 @@ public: |
|
|
|
|
|
|
|
return LV2_WORKER_SUCCESS; |
|
|
|
} |
|
|
|
# endif |
|
|
|
|
|
|
|
return LV2_WORKER_ERR_UNKNOWN; |
|
|
|
} |
|
|
@@ -1136,6 +1178,7 @@ private: |
|
|
|
LV2_URID atomURID; |
|
|
|
LV2_URID dpfKeyValue; |
|
|
|
LV2_URID midiEvent; |
|
|
|
LV2_URID patchSet; |
|
|
|
LV2_URID patchProperty; |
|
|
|
LV2_URID patchValue; |
|
|
|
LV2_URID timePosition; |
|
|
@@ -1162,6 +1205,7 @@ private: |
|
|
|
atomURID(map(LV2_ATOM__URID)), |
|
|
|
dpfKeyValue(map(DISTRHO_PLUGIN_LV2_STATE_PREFIX "KeyValueState")), |
|
|
|
midiEvent(map(LV2_MIDI__MidiEvent)), |
|
|
|
patchSet(map(LV2_PATCH__Set)), |
|
|
|
patchProperty(map(LV2_PATCH__property)), |
|
|
|
patchValue(map(LV2_PATCH__value)), |
|
|
|
timePosition(map(LV2_TIME__Position)), |
|
|
@@ -1188,7 +1232,10 @@ private: |
|
|
|
const LV2_Worker_Schedule* const fWorker; |
|
|
|
|
|
|
|
#if DISTRHO_PLUGIN_WANT_STATE |
|
|
|
LV2_Atom_Forge fAtomForge; |
|
|
|
StringToStringMap fStateMap; |
|
|
|
UridToStringMap fUridStateMap; |
|
|
|
LV2_URID* fUrids; |
|
|
|
bool* fNeededUiSends; |
|
|
|
|
|
|
|
void setState(const char* const key, const char* const newValue) |
|
|
@@ -1213,10 +1260,6 @@ private: |
|
|
|
|
|
|
|
d_stderr("Failed to find plugin state with key \"%s\"", key); |
|
|
|
} |
|
|
|
|
|
|
|
# if DISTRHO_PLUGIN_WANT_STATEFILES |
|
|
|
UridToStringMap fUridStateFileMap; |
|
|
|
# endif |
|
|
|
#endif |
|
|
|
|
|
|
|
void updateParameterOutputsAndTriggers() |
|
|
|