@@ -34,6 +34,7 @@ | |||
#endif | |||
#include <map> | |||
#include <string> | |||
#ifndef DISTRHO_PLUGIN_URI | |||
# error DISTRHO_PLUGIN_URI undefined! | |||
@@ -110,6 +111,20 @@ public: | |||
#if DISTRHO_PLUGIN_WANT_LATENCY | |||
fPortLatency = nullptr; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
if (const uint32_t count = fPlugin.getStateCount()) | |||
{ | |||
fNeededUiSends = new bool[count]; | |||
for (uint32_t i=0; i < count; ++i) | |||
fNeededUiSends[i] = false; | |||
} | |||
else | |||
{ | |||
fNeededUiSends = nullptr; | |||
} | |||
#endif | |||
} | |||
~PluginLv2() | |||
@@ -127,6 +142,12 @@ public: | |||
} | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
if (fNeededUiSends != nullptr) | |||
{ | |||
delete[] fNeededUiSends; | |||
fNeededUiSends = nullptr; | |||
} | |||
fStateMap.clear(); | |||
#endif | |||
} | |||
@@ -384,7 +405,18 @@ public: | |||
if (event->body.type == fURIDs.distrhoState && fWorker != nullptr) | |||
{ | |||
const void* const data((const void*)(event + 1)); | |||
fWorker->schedule_work(fWorker->handle, event->body.size, data); | |||
// check if this is our special message | |||
if (std::strcmp((const char*)data, "__dpf_ui_data__") == 0) | |||
{ | |||
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | |||
fNeededUiSends[i] = true; | |||
} | |||
else | |||
// no, send to DSP as usual | |||
{ | |||
fWorker->schedule_work(fWorker->handle, event->body.size, data); | |||
} | |||
continue; | |||
} | |||
@@ -404,10 +436,76 @@ public: | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); | |||
#endif | |||
updateParameterOutputs(); | |||
#if DISTRHO_LV2_USE_EVENTS_OUT | |||
#endif | |||
const uint32_t capacity = fPortEventsOut->atom.size; | |||
updateParameterOutputs(); | |||
bool needsInit = true; | |||
uint32_t size, offset = 0; | |||
LV2_Atom_Event* aev; | |||
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i) | |||
{ | |||
if (! fNeededUiSends[i]) | |||
continue; | |||
const d_string& key = fPlugin.getStateKey(i); | |||
for (auto it = fStateMap.begin(), end = fStateMap.end(); it != end; ++it) | |||
{ | |||
const d_string& curKey = it->first; | |||
if (curKey != key) | |||
continue; | |||
const d_string& value = it->second; | |||
// TODO - RT safe | |||
d_stdout("Got msg (from DSP to UI via host):\n%s\n%s", (const char*)key, (const char*)value); | |||
// join key and value | |||
std::string tmpStr; | |||
tmpStr += std::string(key); | |||
tmpStr += std::string("\0", 1); | |||
tmpStr += std::string(value); | |||
// get msg size | |||
const size_t msgSize(tmpStr.size()+1); | |||
if (sizeof(LV2_Atom_Event) + msgSize > capacity - offset) | |||
return; | |||
if (needsInit) | |||
{ | |||
fPortEventsOut->atom.size = 0; | |||
fPortEventsOut->atom.type = fURIDs.atomSequence; | |||
fPortEventsOut->body.unit = 0; | |||
fPortEventsOut->body.pad = 0; | |||
needsInit = false; | |||
} | |||
// reserve atom space | |||
const size_t atomSize(lv2_atom_pad_size(sizeof(LV2_Atom) + msgSize)); | |||
char atomBuf[atomSize]; | |||
std::memset(atomBuf, 0, atomSize); | |||
// put data | |||
aev = (LV2_Atom_Event*)((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, fPortEventsOut) + offset); | |||
aev->time.frames = 0; | |||
aev->body.type = fURIDs.distrhoState; | |||
aev->body.size = msgSize; | |||
std::memcpy(LV2_ATOM_BODY(&aev->body), tmpStr.data(), msgSize-1); | |||
size = lv2_atom_pad_size(sizeof(LV2_Atom_Event) + msgSize); | |||
offset += size; | |||
fPortEventsOut->atom.size += size; | |||
fNeededUiSends[i] = false; | |||
break; | |||
} | |||
} | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -538,6 +636,13 @@ public: | |||
continue; | |||
setState(key, value); | |||
d_stdout("Got state msg:\n%s\n%s", (const char*)key, value); | |||
#if DISTRHO_LV2_USE_EVENTS_OUT | |||
// signal msg needed for UI | |||
fNeededUiSends[i] = true; | |||
#endif | |||
} | |||
return LV2_STATE_SUCCESS; | |||
@@ -610,6 +715,7 @@ private: | |||
LV2_URID atomFloat; | |||
LV2_URID atomInt; | |||
LV2_URID atomLong; | |||
LV2_URID atomSequence; | |||
LV2_URID atomString; | |||
LV2_URID distrhoState; | |||
LV2_URID midiEvent; | |||
@@ -629,6 +735,7 @@ private: | |||
atomFloat(uridMap->map(uridMap->handle, LV2_ATOM__Float)), | |||
atomInt(uridMap->map(uridMap->handle, LV2_ATOM__Int)), | |||
atomLong(uridMap->map(uridMap->handle, LV2_ATOM__Long)), | |||
atomSequence(uridMap->map(uridMap->handle, LV2_ATOM__Sequence)), | |||
atomString(uridMap->map(uridMap->handle, LV2_ATOM__String)), | |||
distrhoState(uridMap->map(uridMap->handle, "urn:distrho:keyValueState")), | |||
midiEvent(uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent)), | |||
@@ -650,6 +757,7 @@ private: | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
StringMap fStateMap; | |||
bool* fNeededUiSends; | |||
void setState(const char* const key, const char* const newValue) | |||
{ | |||
@@ -22,6 +22,7 @@ | |||
#include "lv2/instance-access.h" | |||
#include "lv2/midi.h" | |||
#include "lv2/options.h" | |||
#include "lv2/resize-port.h" | |||
#include "lv2/state.h" | |||
#include "lv2/time.h" | |||
#include "lv2/ui.h" | |||
@@ -37,6 +38,10 @@ | |||
# error DISTRHO_PLUGIN_URI undefined! | |||
#endif | |||
#ifndef DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE | |||
# define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048 | |||
#endif | |||
#define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)) | |||
#define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
@@ -130,6 +135,7 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | |||
pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"; | |||
pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||
pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n"; | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | |||
#endif | |||
@@ -226,6 +232,7 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:name \"Events Input\" ;\n"; | |||
pluginString += " lv2:symbol \"lv2_events_in\" ;\n"; | |||
pluginString += " rsz:minimumSize " + d_string(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | |||
pluginString += " atom:bufferType atom:Sequence ;\n"; | |||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||
@@ -247,6 +254,7 @@ void lv2_generate_ttl(const char* const basename) | |||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | |||
pluginString += " lv2:name \"Events Output\" ;\n"; | |||
pluginString += " lv2:symbol \"lv2_events_out\" ;\n"; | |||
pluginString += " rsz:minimumSize " + d_string(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | |||
pluginString += " atom:bufferType atom:Sequence ;\n"; | |||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||
pluginString += " ] ;\n\n"; | |||
@@ -40,9 +40,16 @@ public: | |||
fUiResize(uiResz), | |||
fUiTouch(uiTouch), | |||
fController(controller), | |||
fWriteFunction(writeFunc) | |||
fWriteFunction(writeFunc), | |||
fEventTransferURID(uridMap->map(uridMap->handle, LV2_ATOM__eventTransfer)), | |||
fKeyValueURID(uridMap->map(uridMap->handle, "urn:distrho:keyValueState")) | |||
{ | |||
fUiResize->ui_resize(fUiResize->handle, fUI.getWidth(), fUI.getHeight()); | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
// tell the DSP we're ready to receive msgs | |||
setState("__dpf_ui_data__", ""); | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -61,10 +68,17 @@ public: | |||
const float value(*(const float*)buffer); | |||
fUI.parameterChanged(rindex-parameterOffset, value); | |||
} | |||
else | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
else if (format == fEventTransferURID) | |||
{ | |||
//fUI.stateChanged(key, value); | |||
const LV2_Atom* const atom((const LV2_Atom*)buffer); | |||
const char* const stateKey((const char*)LV2_ATOM_BODY_CONST(atom)); | |||
const char* const stateValue(stateKey+std::strlen(stateKey)+1); | |||
d_stdout("Got MSG in UI from DSP ==> %s | %s", stateKey, stateValue); | |||
fUI.stateChanged(stateKey, stateValue); | |||
} | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -125,13 +139,13 @@ protected: | |||
// set atom info | |||
LV2_Atom* const atom((LV2_Atom*)atomBuf); | |||
atom->size = msgSize; | |||
atom->type = fUridMap->map(fUridMap->handle, "urn:distrho:keyValueState"); | |||
atom->type = fKeyValueURID; | |||
// set atom data | |||
std::memcpy(atomBuf + sizeof(LV2_Atom), tmpStr.data(), msgSize-1); | |||
// send to DSP side | |||
fWriteFunction(fController, eventInPortIndex, atomSize, fUridMap->map(fUridMap->handle, LV2_ATOM__eventTransfer), atom); | |||
fWriteFunction(fController, eventInPortIndex, atomSize, fEventTransferURID, atom); | |||
} | |||
void sendNote(const uint8_t /*channel*/, const uint8_t /*note*/, const uint8_t /*velocity*/) | |||
@@ -156,6 +170,10 @@ private: | |||
const LV2UI_Controller fController; | |||
const LV2UI_Write_Function fWriteFunction; | |||
// Need to save this | |||
const LV2_URID fEventTransferURID; | |||
const LV2_URID fKeyValueURID; | |||
// ------------------------------------------------------------------- | |||
// Callbacks | |||