@@ -34,6 +34,7 @@ | |||||
#endif | #endif | ||||
#include <map> | #include <map> | ||||
#include <string> | |||||
#ifndef DISTRHO_PLUGIN_URI | #ifndef DISTRHO_PLUGIN_URI | ||||
# error DISTRHO_PLUGIN_URI undefined! | # error DISTRHO_PLUGIN_URI undefined! | ||||
@@ -110,6 +111,20 @@ public: | |||||
#if DISTRHO_PLUGIN_WANT_LATENCY | #if DISTRHO_PLUGIN_WANT_LATENCY | ||||
fPortLatency = nullptr; | fPortLatency = nullptr; | ||||
#endif | #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() | ~PluginLv2() | ||||
@@ -127,6 +142,12 @@ public: | |||||
} | } | ||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
if (fNeededUiSends != nullptr) | |||||
{ | |||||
delete[] fNeededUiSends; | |||||
fNeededUiSends = nullptr; | |||||
} | |||||
fStateMap.clear(); | fStateMap.clear(); | ||||
#endif | #endif | ||||
} | } | ||||
@@ -384,7 +405,18 @@ public: | |||||
if (event->body.type == fURIDs.distrhoState && fWorker != nullptr) | if (event->body.type == fURIDs.distrhoState && fWorker != nullptr) | ||||
{ | { | ||||
const void* const data((const void*)(event + 1)); | 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; | continue; | ||||
} | } | ||||
@@ -404,10 +436,76 @@ public: | |||||
fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); | fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount); | ||||
#endif | #endif | ||||
updateParameterOutputs(); | |||||
#if DISTRHO_LV2_USE_EVENTS_OUT | #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; | continue; | ||||
setState(key, value); | 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; | return LV2_STATE_SUCCESS; | ||||
@@ -610,6 +715,7 @@ private: | |||||
LV2_URID atomFloat; | LV2_URID atomFloat; | ||||
LV2_URID atomInt; | LV2_URID atomInt; | ||||
LV2_URID atomLong; | LV2_URID atomLong; | ||||
LV2_URID atomSequence; | |||||
LV2_URID atomString; | LV2_URID atomString; | ||||
LV2_URID distrhoState; | LV2_URID distrhoState; | ||||
LV2_URID midiEvent; | LV2_URID midiEvent; | ||||
@@ -629,6 +735,7 @@ private: | |||||
atomFloat(uridMap->map(uridMap->handle, LV2_ATOM__Float)), | atomFloat(uridMap->map(uridMap->handle, LV2_ATOM__Float)), | ||||
atomInt(uridMap->map(uridMap->handle, LV2_ATOM__Int)), | atomInt(uridMap->map(uridMap->handle, LV2_ATOM__Int)), | ||||
atomLong(uridMap->map(uridMap->handle, LV2_ATOM__Long)), | atomLong(uridMap->map(uridMap->handle, LV2_ATOM__Long)), | ||||
atomSequence(uridMap->map(uridMap->handle, LV2_ATOM__Sequence)), | |||||
atomString(uridMap->map(uridMap->handle, LV2_ATOM__String)), | atomString(uridMap->map(uridMap->handle, LV2_ATOM__String)), | ||||
distrhoState(uridMap->map(uridMap->handle, "urn:distrho:keyValueState")), | distrhoState(uridMap->map(uridMap->handle, "urn:distrho:keyValueState")), | ||||
midiEvent(uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent)), | midiEvent(uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent)), | ||||
@@ -650,6 +757,7 @@ private: | |||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
StringMap fStateMap; | StringMap fStateMap; | ||||
bool* fNeededUiSends; | |||||
void setState(const char* const key, const char* const newValue) | void setState(const char* const key, const char* const newValue) | ||||
{ | { | ||||
@@ -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/resize-port.h" | |||||
#include "lv2/state.h" | #include "lv2/state.h" | ||||
#include "lv2/time.h" | #include "lv2/time.h" | ||||
#include "lv2/ui.h" | #include "lv2/ui.h" | ||||
@@ -37,6 +38,10 @@ | |||||
# error DISTRHO_PLUGIN_URI undefined! | # error DISTRHO_PLUGIN_URI undefined! | ||||
#endif | #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_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) | #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 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"; | ||||
pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n"; | |||||
#if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | ||||
#endif | #endif | ||||
@@ -226,6 +232,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | pluginString += " lv2:index " + d_string(portIndex) + " ;\n"; | ||||
pluginString += " lv2:name \"Events Input\" ;\n"; | pluginString += " lv2:name \"Events Input\" ;\n"; | ||||
pluginString += " lv2:symbol \"lv2_events_in\" ;\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"; | pluginString += " atom:bufferType atom:Sequence ;\n"; | ||||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | # if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | ||||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | 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:index " + d_string(portIndex) + " ;\n"; | ||||
pluginString += " lv2:name \"Events Output\" ;\n"; | pluginString += " lv2:name \"Events Output\" ;\n"; | ||||
pluginString += " lv2:symbol \"lv2_events_out\" ;\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:bufferType atom:Sequence ;\n"; | ||||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | ||||
pluginString += " ] ;\n\n"; | pluginString += " ] ;\n\n"; | ||||
@@ -40,9 +40,16 @@ public: | |||||
fUiResize(uiResz), | fUiResize(uiResz), | ||||
fUiTouch(uiTouch), | fUiTouch(uiTouch), | ||||
fController(controller), | 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()); | 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); | const float value(*(const float*)buffer); | ||||
fUI.parameterChanged(rindex-parameterOffset, value); | 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 | // set atom info | ||||
LV2_Atom* const atom((LV2_Atom*)atomBuf); | LV2_Atom* const atom((LV2_Atom*)atomBuf); | ||||
atom->size = msgSize; | atom->size = msgSize; | ||||
atom->type = fUridMap->map(fUridMap->handle, "urn:distrho:keyValueState"); | |||||
atom->type = fKeyValueURID; | |||||
// set atom data | // set atom data | ||||
std::memcpy(atomBuf + sizeof(LV2_Atom), tmpStr.data(), msgSize-1); | std::memcpy(atomBuf + sizeof(LV2_Atom), tmpStr.data(), msgSize-1); | ||||
// send to DSP side | // 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*/) | 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_Controller fController; | ||||
const LV2UI_Write_Function fWriteFunction; | const LV2UI_Write_Function fWriteFunction; | ||||
// Need to save this | |||||
const LV2_URID fEventTransferURID; | |||||
const LV2_URID fKeyValueURID; | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Callbacks | // Callbacks | ||||