Browse Source

Make carla-lv2 non-instance-access UI optional

tags/v1.9.11
falkTX 6 years ago
parent
commit
cdf6907943
6 changed files with 157 additions and 142 deletions
  1. +3
    -2
      source/bridges-plugin/CarlaBridgeSingleLV2.cpp
  2. +2
    -2
      source/plugin/Makefile
  3. +73
    -7
      source/plugin/carla-lv2-export.cpp
  4. +12
    -91
      source/plugin/carla-lv2-ui.cpp
  5. +21
    -12
      source/plugin/carla-lv2.cpp
  6. +46
    -28
      source/utils/CarlaLv2Utils.hpp

+ 3
- 2
source/bridges-plugin/CarlaBridgeSingleLV2.cpp View File

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


+ 2
- 2
source/plugin/Makefile View File

@@ -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 $@


+ 73
- 7
source/plugin/carla-lv2-export.cpp View File

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



+ 12
- 91
source/plugin/carla-lv2-ui.cpp View File

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


+ 21
- 12
source/plugin/carla-lv2.cpp View File

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


+ 46
- 28
source/utils/CarlaLv2Utils.hpp View File

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


Loading…
Cancel
Save