| @@ -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; | ||||
| } | } | ||||
| } | } | ||||