| @@ -93,6 +93,7 @@ public: | |||
| CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(fPlugin->isEnabled(),); | |||
| fPorts.hasUI = false; | |||
| fPorts.usesTime = true; | |||
| fPorts.numAudioIns = fPlugin->getAudioInCount(); | |||
| fPorts.numAudioOuts = fPlugin->getAudioOutCount(); | |||
| @@ -479,10 +480,10 @@ private: | |||
| CARLA_SAFE_ASSERT_RETURN(midiData != nullptr, 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); | |||
| Ports::MidiOutData& mData(fPorts.midiOutData[port]); | |||
| Ports::EventsOutData& mData(fPorts.eventsOutData[port]); | |||
| if (sizeof(LV2_Atom_Event) + midiSize > mData.capacity - mData.offset) | |||
| return false; | |||
| @@ -97,7 +97,7 @@ LIBS_ui = $(MODULEDIR)/water.a | |||
| TARGETS = \ | |||
| $(BINDIR)/carla.lv2/carla$(LIB_EXT) \ | |||
| $(BINDIR)/carla.lv2/carla_ui$(LIB_EXT) | |||
| $(BINDIR)/carla.lv2/carla-ui$(LIB_EXT) | |||
| ifneq ($(CROSS_COMPILING),true) | |||
| TARGETS += \ | |||
| @@ -139,7 +139,7 @@ $(BINDIR)/carla.lv2/carla$(LIB_EXT): $(OBJDIR)/carla-lv2.cpp.o $(LIBS) | |||
| @echo "Linking carla.lv2/carla$(LIB_EXT)" | |||
| @$(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 | |||
| @echo "Linking carla.lv2/carla-ui$(LIB_EXT)" | |||
| @$(CXX) $< $(LIBS_START) $(LIBS_ui) $(LIBS_END) $(SHARED) $(LINK_FLAGS) -o $@ | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * 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 | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -30,6 +30,7 @@ | |||
| #include "lv2/ui.h" | |||
| #include "lv2/units.h" | |||
| #include "lv2/urid.h" | |||
| #include "lv2/worker.h" | |||
| #include "lv2/lv2_external_ui.h" | |||
| #include "lv2/lv2_programs.h" | |||
| @@ -156,6 +157,14 @@ static void writeManifestFile(PluginListManager& plm) | |||
| text += " <" LV2_PROGRAMS__UIInterface "> ;\n"; | |||
| text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> ;\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 | |||
| @@ -292,6 +301,9 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||
| if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) | |||
| text += " lv2:extensionData <" LV2_PROGRAMS__Interface "> ;\n"; | |||
| if (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) | |||
| text += " lv2:extensionData <" LV2_WORKER__interface "> ;\n"; | |||
| text += "\n"; | |||
| // ------------------------------------------------------------------- | |||
| @@ -311,40 +323,48 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||
| if (std::strncmp(pluginDesc->label, "carla", 5) == 0) | |||
| { | |||
| 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 | |||
| #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"; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| // 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 += " a lv2:InputPort, atom:AtomPort ;\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 += " <" LV2_TIME__Position "> ;\n"; | |||
| } | |||
| else if (pluginDesc->midiIns > 0) | |||
| { | |||
| text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||
| } | |||
| else | |||
| { | |||
| text += " atom:supports <" LV2_TIME__Position "> ;\n"; | |||
| } | |||
| text += " lv2:designation lv2:control ;\n"; | |||
| text += " lv2:index " + String(portIndex++) + " ;\n"; | |||
| if (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) | |||
| if (hasEventInPort) | |||
| { | |||
| if (pluginDesc->midiIns > 1) | |||
| { | |||
| @@ -395,6 +415,52 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||
| 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 | |||
| @@ -24,7 +24,7 @@ class NativePluginUI : public LV2_External_UI_Widget_Compat | |||
| { | |||
| public: | |||
| 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), | |||
| fUridUnmap(nullptr), | |||
| fUridTranser(0), | |||
| @@ -37,7 +37,6 @@ public: | |||
| fUI.writeFunction = writeFunction; | |||
| fUI.controller = controller; | |||
| fUI.isEmbed = isEmbed; | |||
| const LV2_URID_Map* uridMap = nullptr; | |||
| const LV2_URID_Unmap* uridUnmap = nullptr; | |||
| @@ -50,7 +49,7 @@ public: | |||
| 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"); | |||
| return; | |||
| @@ -61,52 +60,6 @@ public: | |||
| fUridTranser = uridMap->map(uridMap->handle, LV2_ATOM__eventTransfer); | |||
| 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 | |||
| @@ -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_Controller controller; | |||
| const char* name; | |||
| bool isEmbed; | |||
| bool isVisible; | |||
| UI() | |||
| @@ -341,7 +297,6 @@ private: | |||
| writeFunction(nullptr), | |||
| controller(nullptr), | |||
| name(nullptr), | |||
| isEmbed(false), | |||
| isVisible(false) {} | |||
| ~UI() | |||
| @@ -385,38 +340,19 @@ private: | |||
| // ----------------------------------------------------------------------- | |||
| // 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); | |||
| #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 | |||
| 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) | |||
| 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); | |||
| #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 = { | |||
| /* URI */ "http://kxstudio.sf.net/carla/ui-bridge-ext", | |||
| /* instantiate */ lv2ui_instantiate_external, | |||
| /* instantiate */ lv2ui_instantiate, | |||
| /* cleanup */ lv2ui_cleanup, | |||
| /* port_event */ lv2ui_port_event, | |||
| /* extension_data */ lv2ui_extension_data | |||
| @@ -105,11 +105,12 @@ public: | |||
| fHandle = fDescriptor->instantiate(&fHost); | |||
| CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false); | |||
| fPorts.hasUI = fDescriptor->hints & NATIVE_PLUGIN_HAS_UI; | |||
| fPorts.usesTime = fDescriptor->hints & NATIVE_PLUGIN_USES_TIME; | |||
| fPorts.numAudioIns = fDescriptor->audioIns; | |||
| 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 && | |||
| fDescriptor->get_parameter_info != nullptr && | |||
| @@ -202,11 +203,19 @@ public: | |||
| 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; | |||
| } | |||
| @@ -242,13 +251,13 @@ public: | |||
| const_cast<float**>(fPorts.audioIns), fPorts.audioOuts, frames, | |||
| fMidiEvents, fMidiEventCount); | |||
| if (fWorkerUISignal == -1 && fPorts.numMidiOuts > 0) | |||
| if (fWorkerUISignal == -1 && fPorts.hasUI) | |||
| { | |||
| const char* const msg = "quit"; | |||
| 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) | |||
| { | |||
| @@ -596,10 +605,10 @@ protected: | |||
| const uint8_t port(event->port); | |||
| 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); | |||
| Ports::MidiOutData& mData(fPorts.midiOutData[port]); | |||
| Ports::EventsOutData& mData(fPorts.eventsOutData[port]); | |||
| if (sizeof(LV2_Atom_Event) + event->size > mData.capacity - mData.offset) | |||
| return false; | |||
| @@ -587,9 +587,9 @@ public: | |||
| 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; | |||
| } | |||
| @@ -935,15 +935,15 @@ public: | |||
| return false; | |||
| // init midi out data | |||
| if (fPorts.numMidiOuts > 0) | |||
| if (fPorts.numMidiOuts > 0 || fPorts.hasUI) | |||
| { | |||
| 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); | |||
| 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.type = fURIs.atomSequence; | |||
| @@ -1191,11 +1191,11 @@ protected: | |||
| // Port stuff | |||
| struct Ports { | |||
| // need to save current state | |||
| struct MidiOutData { | |||
| struct EventsOutData { | |||
| uint32_t capacity; | |||
| uint32_t offset; | |||
| MidiOutData() | |||
| EventsOutData() | |||
| : capacity(0), | |||
| offset(0) {} | |||
| }; | |||
| @@ -1207,12 +1207,13 @@ protected: | |||
| uint32_t numMidiIns; | |||
| uint32_t numMidiOuts; | |||
| uint32_t numParams; | |||
| bool hasUI; | |||
| bool usesTime; | |||
| // port buffers | |||
| const LV2_Atom_Sequence** eventsIn; | |||
| /* */ LV2_Atom_Sequence** midiOuts; | |||
| /* */ MidiOutData* midiOutData; | |||
| /* */ LV2_Atom_Sequence** eventsOut; | |||
| /* */ EventsOutData* eventsOutData; | |||
| const float** audioIns; | |||
| /* */ float** audioOuts; | |||
| /* */ float* freewheel; | |||
| @@ -1229,10 +1230,11 @@ protected: | |||
| numMidiIns(0), | |||
| numMidiOuts(0), | |||
| numParams(0), | |||
| hasUI(false), | |||
| usesTime(false), | |||
| eventsIn(nullptr), | |||
| midiOuts(nullptr), | |||
| midiOutData(nullptr), | |||
| eventsOut(nullptr), | |||
| eventsOutData(nullptr), | |||
| audioIns(nullptr), | |||
| audioOuts(nullptr), | |||
| freewheel(nullptr), | |||
| @@ -1248,16 +1250,16 @@ protected: | |||
| 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) | |||
| @@ -1301,7 +1303,7 @@ protected: | |||
| for (uint32_t i=0; i < numMidiIns; ++i) | |||
| eventsIn[i] = nullptr; | |||
| } | |||
| else if (usesTime) | |||
| else if (usesTime || hasUI) | |||
| { | |||
| eventsIn = new const LV2_Atom_Sequence*[1]; | |||
| eventsIn[0] = nullptr; | |||
| @@ -1309,11 +1311,16 @@ protected: | |||
| 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) | |||
| midiOuts[i] = nullptr; | |||
| eventsOut[i] = nullptr; | |||
| } | |||
| else if (hasUI) | |||
| { | |||
| eventsOut = new LV2_Atom_Sequence*[1]; | |||
| eventsOut[0] = nullptr; | |||
| } | |||
| if (numAudioIns > 0) | |||
| @@ -1345,9 +1352,11 @@ protected: | |||
| // 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 | |||
| indexOffset += 1; | |||
| } | |||
| @@ -1356,7 +1365,7 @@ protected: | |||
| { | |||
| uint32_t index = 0; | |||
| if (numMidiIns > 0 || usesTime) | |||
| if (numMidiIns > 0 || usesTime || hasUI) | |||
| { | |||
| 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++) | |||
| { | |||
| midiOuts[i] = (LV2_Atom_Sequence*)dataLocation; | |||
| eventsOut[i] = (LV2_Atom_Sequence*)dataLocation; | |||
| return; | |||
| } | |||
| } | |||