@@ -93,6 +93,7 @@ public: | |||||
CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | ||||
CARLA_SAFE_ASSERT_RETURN(fPlugin->isEnabled(),); | CARLA_SAFE_ASSERT_RETURN(fPlugin->isEnabled(),); | ||||
fPorts.hasUI = false; | |||||
fPorts.usesTime = true; | fPorts.usesTime = true; | ||||
fPorts.numAudioIns = fPlugin->getAudioInCount(); | fPorts.numAudioIns = fPlugin->getAudioInCount(); | ||||
fPorts.numAudioOuts = fPlugin->getAudioOutCount(); | fPorts.numAudioOuts = fPlugin->getAudioOutCount(); | ||||
@@ -479,10 +480,10 @@ private: | |||||
CARLA_SAFE_ASSERT_RETURN(midiData != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(midiData != nullptr, false); | ||||
CARLA_SAFE_ASSERT_RETURN(midiSize > 0, false); | CARLA_SAFE_ASSERT_RETURN(midiSize > 0, false); | ||||
LV2_Atom_Sequence* const seq(fPorts.midiOuts[port]); | |||||
LV2_Atom_Sequence* const seq(fPorts.eventsOut[port]); | |||||
CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false); | ||||
Ports::MidiOutData& mData(fPorts.midiOutData[port]); | |||||
Ports::EventsOutData& mData(fPorts.eventsOutData[port]); | |||||
if (sizeof(LV2_Atom_Event) + midiSize > mData.capacity - mData.offset) | if (sizeof(LV2_Atom_Event) + midiSize > mData.capacity - mData.offset) | ||||
return false; | return false; | ||||
@@ -97,7 +97,7 @@ LIBS_ui = $(MODULEDIR)/water.a | |||||
TARGETS = \ | TARGETS = \ | ||||
$(BINDIR)/carla.lv2/carla$(LIB_EXT) \ | $(BINDIR)/carla.lv2/carla$(LIB_EXT) \ | ||||
$(BINDIR)/carla.lv2/carla_ui$(LIB_EXT) | |||||
$(BINDIR)/carla.lv2/carla-ui$(LIB_EXT) | |||||
ifneq ($(CROSS_COMPILING),true) | ifneq ($(CROSS_COMPILING),true) | ||||
TARGETS += \ | TARGETS += \ | ||||
@@ -139,7 +139,7 @@ $(BINDIR)/carla.lv2/carla$(LIB_EXT): $(OBJDIR)/carla-lv2.cpp.o $(LIBS) | |||||
@echo "Linking carla.lv2/carla$(LIB_EXT)" | @echo "Linking carla.lv2/carla$(LIB_EXT)" | ||||
@$(CXX) $< $(LIBS_START) $(LIBS) $(LIBS_END) $(SHARED) $(LINK_FLAGS) -o $@ | @$(CXX) $< $(LIBS_START) $(LIBS) $(LIBS_END) $(SHARED) $(LINK_FLAGS) -o $@ | ||||
$(BINDIR)/carla.lv2/carla_ui$(LIB_EXT): $(OBJDIR)/carla-lv2-ui.cpp.o $(LIBS_ui) | |||||
$(BINDIR)/carla.lv2/carla-ui$(LIB_EXT): $(OBJDIR)/carla-lv2-ui.cpp.o $(LIBS_ui) | |||||
-@mkdir -p $(BINDIR)/carla.lv2 | -@mkdir -p $(BINDIR)/carla.lv2 | ||||
@echo "Linking carla.lv2/carla-ui$(LIB_EXT)" | @echo "Linking carla.lv2/carla-ui$(LIB_EXT)" | ||||
@$(CXX) $< $(LIBS_START) $(LIBS_ui) $(LIBS_END) $(SHARED) $(LINK_FLAGS) -o $@ | @$(CXX) $< $(LIBS_START) $(LIBS_ui) $(LIBS_END) $(SHARED) $(LINK_FLAGS) -o $@ | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* Carla Native Plugins | * Carla Native Plugins | ||||
* Copyright (C) 2013-2017 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2013-2018 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -30,6 +30,7 @@ | |||||
#include "lv2/ui.h" | #include "lv2/ui.h" | ||||
#include "lv2/units.h" | #include "lv2/units.h" | ||||
#include "lv2/urid.h" | #include "lv2/urid.h" | ||||
#include "lv2/worker.h" | |||||
#include "lv2/lv2_external_ui.h" | #include "lv2/lv2_external_ui.h" | ||||
#include "lv2/lv2_programs.h" | #include "lv2/lv2_programs.h" | ||||
@@ -156,6 +157,14 @@ static void writeManifestFile(PluginListManager& plm) | |||||
text += " <" LV2_PROGRAMS__UIInterface "> ;\n"; | text += " <" LV2_PROGRAMS__UIInterface "> ;\n"; | ||||
text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> ;\n"; | text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> ;\n"; | ||||
text += " opts:supportedOption <" LV2_PARAMETERS__sampleRate "> .\n"; | text += " opts:supportedOption <" LV2_PARAMETERS__sampleRate "> .\n"; | ||||
text += "\n"; | |||||
text += "<http://kxstudio.sf.net/carla/ui-bridge-ext>\n"; | |||||
text += " a <" LV2_EXTERNAL_UI__Widget "> ;\n"; | |||||
text += " ui:binary <carla-ui" PLUGIN_EXT "> ;\n"; | |||||
text += " lv2:extensionData <" LV2_UI__idleInterface "> ,\n"; | |||||
text += " <" LV2_UI__showInterface "> ,\n"; | |||||
text += " <" LV2_PROGRAMS__UIInterface "> .\n"; | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Write file now | // Write file now | ||||
@@ -292,6 +301,9 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) | if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) | ||||
text += " lv2:extensionData <" LV2_PROGRAMS__Interface "> ;\n"; | text += " lv2:extensionData <" LV2_PROGRAMS__Interface "> ;\n"; | ||||
if (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) | |||||
text += " lv2:extensionData <" LV2_WORKER__interface "> ;\n"; | |||||
text += "\n"; | text += "\n"; | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -311,40 +323,48 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
if (std::strncmp(pluginDesc->label, "carla", 5) == 0) | if (std::strncmp(pluginDesc->label, "carla", 5) == 0) | ||||
{ | { | ||||
text += " ui:ui <http://kxstudio.sf.net/carla/ui-embed> ,\n"; | text += " ui:ui <http://kxstudio.sf.net/carla/ui-embed> ,\n"; | ||||
text += " <http://kxstudio.sf.net/carla/ui-ext> ;\n"; | |||||
text += " <http://kxstudio.sf.net/carla/ui-ext> ,\n"; | |||||
text += " <http://kxstudio.sf.net/carla/ui-bridge-ext> ;\n"; | |||||
} | } | ||||
else | else | ||||
#endif | #endif | ||||
{ | { | ||||
text += " ui:ui <http://kxstudio.sf.net/carla/ui-ext> ;\n"; | |||||
text += " ui:ui <http://kxstudio.sf.net/carla/ui-ext> ,\n"; | |||||
text += " <http://kxstudio.sf.net/carla/ui-bridge-ext> ;\n"; | |||||
} | } | ||||
text += "\n"; | text += "\n"; | ||||
} | } | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// First MIDI/Time port | |||||
// First input MIDI/Time/UI port | |||||
const bool hasEventInPort = (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0 || (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0; | |||||
if (pluginDesc->midiIns > 0 || (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0) | |||||
if (pluginDesc->midiIns > 0 || hasEventInPort) | |||||
{ | { | ||||
text += " lv2:port [\n"; | text += " lv2:port [\n"; | ||||
text += " a lv2:InputPort, atom:AtomPort ;\n"; | text += " a lv2:InputPort, atom:AtomPort ;\n"; | ||||
text += " atom:bufferType atom:Sequence ;\n"; | text += " atom:bufferType atom:Sequence ;\n"; | ||||
if (pluginDesc->midiIns > 0 && (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0) | |||||
if (pluginDesc->midiIns > 0 && hasEventInPort) | |||||
{ | { | ||||
text += " atom:supports <" LV2_MIDI__MidiEvent "> ,\n"; | text += " atom:supports <" LV2_MIDI__MidiEvent "> ,\n"; | ||||
text += " <" LV2_TIME__Position "> ;\n"; | text += " <" LV2_TIME__Position "> ;\n"; | ||||
} | } | ||||
else if (pluginDesc->midiIns > 0) | else if (pluginDesc->midiIns > 0) | ||||
{ | |||||
text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | ||||
} | |||||
else | else | ||||
{ | |||||
text += " atom:supports <" LV2_TIME__Position "> ;\n"; | text += " atom:supports <" LV2_TIME__Position "> ;\n"; | ||||
} | |||||
text += " lv2:designation lv2:control ;\n"; | text += " lv2:designation lv2:control ;\n"; | ||||
text += " lv2:index " + String(portIndex++) + " ;\n"; | text += " lv2:index " + String(portIndex++) + " ;\n"; | ||||
if (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) | |||||
if (hasEventInPort) | |||||
{ | { | ||||
if (pluginDesc->midiIns > 1) | if (pluginDesc->midiIns > 1) | ||||
{ | { | ||||
@@ -395,6 +415,52 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
text += " ] , [\n"; | text += " ] , [\n"; | ||||
} | } | ||||
// ------------------------------------------------------------------- | |||||
// First output MIDI/UI port | |||||
const bool hasEventOutPort = (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0; | |||||
if (pluginDesc->midiIns > 0 || hasEventOutPort) | |||||
{ | |||||
text += " lv2:port [\n"; | |||||
text += " a lv2:OutputPort, atom:AtomPort ;\n"; | |||||
text += " atom:bufferType atom:Sequence ;\n"; | |||||
if (pluginDesc->midiOuts > 0) | |||||
text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||||
text += " lv2:index " + String(portIndex++) + " ;\n"; | |||||
if (hasEventOutPort) | |||||
{ | |||||
if (pluginDesc->midiOuts > 1) | |||||
{ | |||||
text += " lv2:symbol \"lv2_events_out_1\" ;\n"; | |||||
text += " lv2:name \"Events Input #1\" ;\n"; | |||||
} | |||||
else | |||||
{ | |||||
text += " lv2:symbol \"lv2_events_out\" ;\n"; | |||||
text += " lv2:name \"Events Output\" ;\n"; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
if (pluginDesc->midiOuts > 1) | |||||
{ | |||||
text += " lv2:symbol \"lv2_midi_out_" + String(portIndex+1) + "\" ;\n"; | |||||
text += " lv2:name \"MIDI Output #" + String(portIndex+1) + "\" ;\n"; | |||||
} | |||||
else | |||||
{ | |||||
text += " lv2:symbol \"lv2_midi_out\" ;\n"; | |||||
text += " lv2:name \"MIDI Output\" ;\n"; | |||||
} | |||||
} | |||||
text += " ] ;\n\n"; | |||||
} | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// MIDI outputs | // MIDI outputs | ||||
@@ -24,7 +24,7 @@ class NativePluginUI : public LV2_External_UI_Widget_Compat | |||||
{ | { | ||||
public: | public: | ||||
NativePluginUI(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | NativePluginUI(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | ||||
LV2UI_Widget* widget, const LV2_Feature* const* features, const bool isEmbed) | |||||
LV2UI_Widget* widget, const LV2_Feature* const* features) | |||||
: fUridMap(nullptr), | : fUridMap(nullptr), | ||||
fUridUnmap(nullptr), | fUridUnmap(nullptr), | ||||
fUridTranser(0), | fUridTranser(0), | ||||
@@ -37,7 +37,6 @@ public: | |||||
fUI.writeFunction = writeFunction; | fUI.writeFunction = writeFunction; | ||||
fUI.controller = controller; | fUI.controller = controller; | ||||
fUI.isEmbed = isEmbed; | |||||
const LV2_URID_Map* uridMap = nullptr; | const LV2_URID_Map* uridMap = nullptr; | ||||
const LV2_URID_Unmap* uridUnmap = nullptr; | const LV2_URID_Unmap* uridUnmap = nullptr; | ||||
@@ -50,7 +49,7 @@ public: | |||||
uridUnmap = (const LV2_URID_Unmap*)features[i]->data; | uridUnmap = (const LV2_URID_Unmap*)features[i]->data; | ||||
} | } | ||||
if (uridMap == nullptr || uridUnmap == nullptr) | |||||
if (uridMap == nullptr) | |||||
{ | { | ||||
carla_stderr("Host doesn't provide urid-map feature"); | carla_stderr("Host doesn't provide urid-map feature"); | ||||
return; | return; | ||||
@@ -61,52 +60,6 @@ public: | |||||
fUridTranser = uridMap->map(uridMap->handle, LV2_ATOM__eventTransfer); | fUridTranser = uridMap->map(uridMap->handle, LV2_ATOM__eventTransfer); | ||||
fUridTranser2 = uridMap->map(uridMap->handle, "urn:carla:transmitEv"); | fUridTranser2 = uridMap->map(uridMap->handle, "urn:carla:transmitEv"); | ||||
#ifdef CARLA_OS_LINUX | |||||
// --------------------------------------------------------------- | |||||
// show embed UI if needed | |||||
if (isEmbed) | |||||
{ | |||||
intptr_t parentId = 0; | |||||
const LV2UI_Resize* uiResize = nullptr; | |||||
for (int i=0; features[i] != nullptr; ++i) | |||||
{ | |||||
if (std::strcmp(features[i]->URI, LV2_UI__parent) == 0) | |||||
{ | |||||
parentId = (intptr_t)features[i]->data; | |||||
} | |||||
else if (std::strcmp(features[i]->URI, LV2_UI__resize) == 0) | |||||
{ | |||||
uiResize = (const LV2UI_Resize*)features[i]->data; | |||||
} | |||||
} | |||||
// ----------------------------------------------------------- | |||||
// see if the host can really embed the UI | |||||
if (parentId != 0) | |||||
{ | |||||
if (uiResize && uiResize->ui_resize != nullptr) | |||||
uiResize->ui_resize(uiResize->handle, 740, 512); | |||||
fUI.name = carla_strdup("Carla"); | |||||
fUI.isVisible = true; | |||||
char strBuf[0xff+1]; | |||||
strBuf[0xff] = '\0'; | |||||
std::snprintf(strBuf, 0xff, P_INTPTR, parentId); | |||||
carla_setenv("CARLA_PLUGIN_EMBED_WINID", strBuf); | |||||
writeAtomMessage("show"); | |||||
// FIXME | |||||
*widget = nullptr; | |||||
return; | |||||
} | |||||
} | |||||
#endif | |||||
// --------------------------------------------------------------- | // --------------------------------------------------------------- | ||||
// see if the host supports external-ui | // see if the host supports external-ui | ||||
@@ -209,7 +162,11 @@ public: | |||||
} | } | ||||
} | } | ||||
carla_stdout("lv2ui_port_event %u %u %u:%s %p", portIndex, bufferSize, format, fUridUnmap->unmap(fUridUnmap->handle, format), buffer); | |||||
if (fUridUnmap != nullptr) | |||||
{ | |||||
carla_stdout("lv2ui_port_event %u %u %u:%s %p", | |||||
portIndex, bufferSize, format, fUridUnmap->unmap(fUridUnmap->handle, format), buffer); | |||||
} | |||||
} | } | ||||
// ---------------------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------------------- | ||||
@@ -333,7 +290,6 @@ private: | |||||
LV2UI_Write_Function writeFunction; | LV2UI_Write_Function writeFunction; | ||||
LV2UI_Controller controller; | LV2UI_Controller controller; | ||||
const char* name; | const char* name; | ||||
bool isEmbed; | |||||
bool isVisible; | bool isVisible; | ||||
UI() | UI() | ||||
@@ -341,7 +297,6 @@ private: | |||||
writeFunction(nullptr), | writeFunction(nullptr), | ||||
controller(nullptr), | controller(nullptr), | ||||
name(nullptr), | name(nullptr), | ||||
isEmbed(false), | |||||
isVisible(false) {} | isVisible(false) {} | ||||
~UI() | ~UI() | ||||
@@ -385,38 +340,19 @@ private: | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// LV2 UI descriptor functions | // LV2 UI descriptor functions | ||||
static LV2UI_Handle lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | |||||
LV2UI_Widget* widget, const LV2_Feature* const* features, const bool isEmbed) | |||||
static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char*, const char*, | |||||
LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | |||||
LV2UI_Widget* widget, const LV2_Feature* const* features) | |||||
{ | { | ||||
carla_debug("lv2ui_instantiate(..., %p, %p, %p)", writeFunction, controller, widget, features); | carla_debug("lv2ui_instantiate(..., %p, %p, %p)", writeFunction, controller, widget, features); | ||||
#ifndef CARLA_OS_LINUX | |||||
CARLA_SAFE_ASSERT_RETURN(! isEmbed, nullptr); | |||||
#endif | |||||
carla_debug("writeAtomMessage=========================================================================="); | |||||
NativePluginUI* const ui = new NativePluginUI(writeFunction, controller, widget, features, isEmbed); | |||||
NativePluginUI* const ui = new NativePluginUI(writeFunction, controller, widget, features); | |||||
// TODO: check ok | // TODO: check ok | ||||
return (LV2UI_Handle)ui; | return (LV2UI_Handle)ui; | ||||
} | } | ||||
#ifdef CARLA_OS_LINUX | |||||
static LV2UI_Handle lv2ui_instantiate_embed(const LV2UI_Descriptor*, const char*, const char*, | |||||
LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | |||||
LV2UI_Widget* widget, const LV2_Feature* const* features) | |||||
{ | |||||
return lv2ui_instantiate(writeFunction, controller, widget, features, true); | |||||
} | |||||
#endif | |||||
static LV2UI_Handle lv2ui_instantiate_external(const LV2UI_Descriptor*, const char*, const char*, | |||||
LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | |||||
LV2UI_Widget* widget, const LV2_Feature* const* features) | |||||
{ | |||||
return lv2ui_instantiate(writeFunction, controller, widget, features, false); | |||||
} | |||||
#define uiPtr ((NativePluginUI*)ui) | #define uiPtr ((NativePluginUI*)ui) | ||||
static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) | static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) | ||||
@@ -482,24 +418,9 @@ const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) | |||||
{ | { | ||||
carla_debug("lv2ui_descriptor(%i)", index); | carla_debug("lv2ui_descriptor(%i)", index); | ||||
#ifdef CARLA_OS_LINUX | |||||
static const LV2UI_Descriptor lv2UiEmbedDesc = { | |||||
/* URI */ "http://kxstudio.sf.net/carla/ui-bridge-embed", | |||||
/* instantiate */ lv2ui_instantiate_embed, | |||||
/* cleanup */ lv2ui_cleanup, | |||||
/* port_event */ lv2ui_port_event, | |||||
/* extension_data */ lv2ui_extension_data | |||||
}; | |||||
if (index == 0) | |||||
return &lv2UiEmbedDesc; | |||||
else | |||||
--index; | |||||
#endif | |||||
static const LV2UI_Descriptor lv2UiExtDesc = { | static const LV2UI_Descriptor lv2UiExtDesc = { | ||||
/* URI */ "http://kxstudio.sf.net/carla/ui-bridge-ext", | /* URI */ "http://kxstudio.sf.net/carla/ui-bridge-ext", | ||||
/* instantiate */ lv2ui_instantiate_external, | |||||
/* instantiate */ lv2ui_instantiate, | |||||
/* cleanup */ lv2ui_cleanup, | /* cleanup */ lv2ui_cleanup, | ||||
/* port_event */ lv2ui_port_event, | /* port_event */ lv2ui_port_event, | ||||
/* extension_data */ lv2ui_extension_data | /* extension_data */ lv2ui_extension_data | ||||
@@ -105,11 +105,12 @@ public: | |||||
fHandle = fDescriptor->instantiate(&fHost); | fHandle = fDescriptor->instantiate(&fHost); | ||||
CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false); | ||||
fPorts.hasUI = fDescriptor->hints & NATIVE_PLUGIN_HAS_UI; | |||||
fPorts.usesTime = fDescriptor->hints & NATIVE_PLUGIN_USES_TIME; | fPorts.usesTime = fDescriptor->hints & NATIVE_PLUGIN_USES_TIME; | ||||
fPorts.numAudioIns = fDescriptor->audioIns; | fPorts.numAudioIns = fDescriptor->audioIns; | ||||
fPorts.numAudioOuts = fDescriptor->audioOuts; | fPorts.numAudioOuts = fDescriptor->audioOuts; | ||||
fPorts.numMidiIns = std::max(fDescriptor->midiIns, 1U); | |||||
fPorts.numMidiOuts = std::max(fDescriptor->midiOuts, 1U); | |||||
fPorts.numMidiIns = fDescriptor->midiIns; | |||||
fPorts.numMidiOuts = fDescriptor->midiOuts; | |||||
if (fDescriptor->get_parameter_count != nullptr && | if (fDescriptor->get_parameter_count != nullptr && | ||||
fDescriptor->get_parameter_info != nullptr && | fDescriptor->get_parameter_info != nullptr && | ||||
@@ -202,11 +203,19 @@ public: | |||||
if (event->body.type == fURIs.uiEvents && fWorkerUISignal != -1) | if (event->body.type == fURIs.uiEvents && fWorkerUISignal != -1) | ||||
{ | { | ||||
fWorkerUISignal = 1; | |||||
const char* const msg((const char*)(event + 1)); | |||||
const size_t msgSize = std::strlen(msg); | |||||
//std::puts(msg); | |||||
fWorker->schedule_work(fWorker->handle, msgSize+1, msg); | |||||
if (fWorker != nullptr) | |||||
{ | |||||
// worker is supported by the host, we can continue | |||||
fWorkerUISignal = 1; | |||||
const char* const msg((const char*)(event + 1)); | |||||
const size_t msgSize = std::strlen(msg); | |||||
fWorker->schedule_work(fWorker->handle, msgSize+1, msg); | |||||
} | |||||
else | |||||
{ | |||||
// worker is not supported, cancel | |||||
fWorkerUISignal = -1; | |||||
} | |||||
continue; | continue; | ||||
} | } | ||||
@@ -242,13 +251,13 @@ public: | |||||
const_cast<float**>(fPorts.audioIns), fPorts.audioOuts, frames, | const_cast<float**>(fPorts.audioIns), fPorts.audioOuts, frames, | ||||
fMidiEvents, fMidiEventCount); | fMidiEvents, fMidiEventCount); | ||||
if (fWorkerUISignal == -1 && fPorts.numMidiOuts > 0) | |||||
if (fWorkerUISignal == -1 && fPorts.hasUI) | |||||
{ | { | ||||
const char* const msg = "quit"; | const char* const msg = "quit"; | ||||
const size_t msgSize = 5; | const size_t msgSize = 5; | ||||
LV2_Atom_Sequence* const seq(fPorts.midiOuts[0]); | |||||
Ports::MidiOutData& mData(fPorts.midiOutData[0]); | |||||
LV2_Atom_Sequence* const seq(fPorts.eventsOut[0]); | |||||
Ports::EventsOutData& mData(fPorts.eventsOutData[0]); | |||||
if (sizeof(LV2_Atom_Event) + msgSize <= mData.capacity - mData.offset) | if (sizeof(LV2_Atom_Event) + msgSize <= mData.capacity - mData.offset) | ||||
{ | { | ||||
@@ -596,10 +605,10 @@ protected: | |||||
const uint8_t port(event->port); | const uint8_t port(event->port); | ||||
CARLA_SAFE_ASSERT_RETURN(port < fPorts.numMidiOuts, false); | CARLA_SAFE_ASSERT_RETURN(port < fPorts.numMidiOuts, false); | ||||
LV2_Atom_Sequence* const seq(fPorts.midiOuts[port]); | |||||
LV2_Atom_Sequence* const seq(fPorts.eventsOut[port]); | |||||
CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false); | ||||
Ports::MidiOutData& mData(fPorts.midiOutData[port]); | |||||
Ports::EventsOutData& mData(fPorts.eventsOutData[port]); | |||||
if (sizeof(LV2_Atom_Event) + event->size > mData.capacity - mData.offset) | if (sizeof(LV2_Atom_Event) + event->size > mData.capacity - mData.offset) | ||||
return false; | return false; | ||||
@@ -587,9 +587,9 @@ public: | |||||
worker = (const LV2_Worker_Schedule*)features[i]->data; | worker = (const LV2_Worker_Schedule*)features[i]->data; | ||||
} | } | ||||
if (options == nullptr || uridMap == nullptr || worker == nullptr) | |||||
if (options == nullptr || uridMap == nullptr) | |||||
{ | { | ||||
carla_stderr("Host doesn't provide option, urid-map and worker features"); | |||||
carla_stderr("Host doesn't provide option and urid-map features"); | |||||
return; | return; | ||||
} | } | ||||
@@ -935,15 +935,15 @@ public: | |||||
return false; | return false; | ||||
// init midi out data | // init midi out data | ||||
if (fPorts.numMidiOuts > 0) | |||||
if (fPorts.numMidiOuts > 0 || fPorts.hasUI) | |||||
{ | { | ||||
for (uint32_t i=0; i<fPorts.numMidiOuts; ++i) | for (uint32_t i=0; i<fPorts.numMidiOuts; ++i) | ||||
{ | { | ||||
LV2_Atom_Sequence* const seq(fPorts.midiOuts[i]); | |||||
LV2_Atom_Sequence* const seq(fPorts.eventsOut[i]); | |||||
CARLA_SAFE_ASSERT_CONTINUE(seq != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(seq != nullptr); | ||||
fPorts.midiOutData[i].capacity = seq->atom.size; | |||||
fPorts.midiOutData[i].offset = 0; | |||||
fPorts.eventsOutData[i].capacity = seq->atom.size; | |||||
fPorts.eventsOutData[i].offset = 0; | |||||
seq->atom.size = sizeof(LV2_Atom_Sequence_Body); | seq->atom.size = sizeof(LV2_Atom_Sequence_Body); | ||||
seq->atom.type = fURIs.atomSequence; | seq->atom.type = fURIs.atomSequence; | ||||
@@ -1191,11 +1191,11 @@ protected: | |||||
// Port stuff | // Port stuff | ||||
struct Ports { | struct Ports { | ||||
// need to save current state | // need to save current state | ||||
struct MidiOutData { | |||||
struct EventsOutData { | |||||
uint32_t capacity; | uint32_t capacity; | ||||
uint32_t offset; | uint32_t offset; | ||||
MidiOutData() | |||||
EventsOutData() | |||||
: capacity(0), | : capacity(0), | ||||
offset(0) {} | offset(0) {} | ||||
}; | }; | ||||
@@ -1207,12 +1207,13 @@ protected: | |||||
uint32_t numMidiIns; | uint32_t numMidiIns; | ||||
uint32_t numMidiOuts; | uint32_t numMidiOuts; | ||||
uint32_t numParams; | uint32_t numParams; | ||||
bool hasUI; | |||||
bool usesTime; | bool usesTime; | ||||
// port buffers | // port buffers | ||||
const LV2_Atom_Sequence** eventsIn; | const LV2_Atom_Sequence** eventsIn; | ||||
/* */ LV2_Atom_Sequence** midiOuts; | |||||
/* */ MidiOutData* midiOutData; | |||||
/* */ LV2_Atom_Sequence** eventsOut; | |||||
/* */ EventsOutData* eventsOutData; | |||||
const float** audioIns; | const float** audioIns; | ||||
/* */ float** audioOuts; | /* */ float** audioOuts; | ||||
/* */ float* freewheel; | /* */ float* freewheel; | ||||
@@ -1229,10 +1230,11 @@ protected: | |||||
numMidiIns(0), | numMidiIns(0), | ||||
numMidiOuts(0), | numMidiOuts(0), | ||||
numParams(0), | numParams(0), | ||||
hasUI(false), | |||||
usesTime(false), | usesTime(false), | ||||
eventsIn(nullptr), | eventsIn(nullptr), | ||||
midiOuts(nullptr), | |||||
midiOutData(nullptr), | |||||
eventsOut(nullptr), | |||||
eventsOutData(nullptr), | |||||
audioIns(nullptr), | audioIns(nullptr), | ||||
audioOuts(nullptr), | audioOuts(nullptr), | ||||
freewheel(nullptr), | freewheel(nullptr), | ||||
@@ -1248,16 +1250,16 @@ protected: | |||||
eventsIn = nullptr; | eventsIn = nullptr; | ||||
} | } | ||||
if (midiOuts != nullptr) | |||||
if (eventsOut != nullptr) | |||||
{ | { | ||||
delete[] midiOuts; | |||||
midiOuts = nullptr; | |||||
delete[] eventsOut; | |||||
eventsOut = nullptr; | |||||
} | } | ||||
if (midiOutData != nullptr) | |||||
if (eventsOutData != nullptr) | |||||
{ | { | ||||
delete[] midiOutData; | |||||
midiOutData = nullptr; | |||||
delete[] eventsOutData; | |||||
eventsOutData = nullptr; | |||||
} | } | ||||
if (audioIns != nullptr) | if (audioIns != nullptr) | ||||
@@ -1301,7 +1303,7 @@ protected: | |||||
for (uint32_t i=0; i < numMidiIns; ++i) | for (uint32_t i=0; i < numMidiIns; ++i) | ||||
eventsIn[i] = nullptr; | eventsIn[i] = nullptr; | ||||
} | } | ||||
else if (usesTime) | |||||
else if (usesTime || hasUI) | |||||
{ | { | ||||
eventsIn = new const LV2_Atom_Sequence*[1]; | eventsIn = new const LV2_Atom_Sequence*[1]; | ||||
eventsIn[0] = nullptr; | eventsIn[0] = nullptr; | ||||
@@ -1309,11 +1311,16 @@ protected: | |||||
if (numMidiOuts > 0) | if (numMidiOuts > 0) | ||||
{ | { | ||||
midiOuts = new LV2_Atom_Sequence*[numMidiOuts]; | |||||
midiOutData = new MidiOutData[numMidiOuts]; | |||||
eventsOut = new LV2_Atom_Sequence*[numMidiOuts]; | |||||
eventsOutData = new EventsOutData[numMidiOuts]; | |||||
for (uint32_t i=0; i < numMidiOuts; ++i) | for (uint32_t i=0; i < numMidiOuts; ++i) | ||||
midiOuts[i] = nullptr; | |||||
eventsOut[i] = nullptr; | |||||
} | |||||
else if (hasUI) | |||||
{ | |||||
eventsOut = new LV2_Atom_Sequence*[1]; | |||||
eventsOut[0] = nullptr; | |||||
} | } | ||||
if (numAudioIns > 0) | if (numAudioIns > 0) | ||||
@@ -1345,9 +1352,11 @@ protected: | |||||
// NOTE: need to be filled in by the parent class | // NOTE: need to be filled in by the parent class | ||||
} | } | ||||
indexOffset = numAudioIns + numAudioOuts + numMidiOuts; | |||||
// 1 event port for time if no midi input is used | |||||
indexOffset += numMidiIns > 0 ? numMidiIns : (usesTime ? 1 : 0); | |||||
indexOffset = numAudioIns + numAudioOuts; | |||||
// 1 event port for time or ui if no midi input is used | |||||
indexOffset += numMidiIns > 0 ? numMidiIns : ((usesTime || hasUI) ? 1 : 0); | |||||
// 1 event port for ui if no midi output is used | |||||
indexOffset += numMidiOuts > 0 ? numMidiOuts : (hasUI ? 1 : 0); | |||||
// 1 extra for freewheel port | // 1 extra for freewheel port | ||||
indexOffset += 1; | indexOffset += 1; | ||||
} | } | ||||
@@ -1356,7 +1365,7 @@ protected: | |||||
{ | { | ||||
uint32_t index = 0; | uint32_t index = 0; | ||||
if (numMidiIns > 0 || usesTime) | |||||
if (numMidiIns > 0 || usesTime || hasUI) | |||||
{ | { | ||||
if (port == index++) | if (port == index++) | ||||
{ | { | ||||
@@ -1374,11 +1383,20 @@ protected: | |||||
} | } | ||||
} | } | ||||
for (uint32_t i=0; i < numMidiOuts; ++i) | |||||
if (numMidiOuts > 0 || hasUI) | |||||
{ | |||||
if (port == index++) | |||||
{ | |||||
eventsOut[0] = (LV2_Atom_Sequence*)dataLocation; | |||||
return; | |||||
} | |||||
} | |||||
for (uint32_t i=1; i < numMidiOuts; ++i) | |||||
{ | { | ||||
if (port == index++) | if (port == index++) | ||||
{ | { | ||||
midiOuts[i] = (LV2_Atom_Sequence*)dataLocation; | |||||
eventsOut[i] = (LV2_Atom_Sequence*)dataLocation; | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||