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