Browse Source

Carla: LV2 work for event messages (experimental)

tags/v0.9.0
falkTX 13 years ago
parent
commit
ca28780f45
1 changed files with 272 additions and 49 deletions
  1. +272
    -49
      c++/carla-backend/lv2.cpp

+ 272
- 49
c++/carla-backend/lv2.cpp View File

@@ -139,6 +139,7 @@ const uint32_t CARLA_URI_MAP_ID_COUNT = 18;


struct Lv2EventData { struct Lv2EventData {
uint32_t type; uint32_t type;
uint32_t rindex;
CarlaEngineMidiPort* port; CarlaEngineMidiPort* port;
union { union {
LV2_Atom_Sequence* atom; LV2_Atom_Sequence* atom;
@@ -148,6 +149,7 @@ struct Lv2EventData {


Lv2EventData() Lv2EventData()
: type(0), : type(0),
rindex(0),
port(nullptr) {} port(nullptr) {}
}; };


@@ -206,6 +208,173 @@ LV2_Atom_Event* getLv2AtomEvent(LV2_Atom_Sequence* const atom, const uint32_t of
return (LV2_Atom_Event*)((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atom) + offset); return (LV2_Atom_Event*)((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atom) + offset);
} }


class Lv2AtomQueue
{
public:
Lv2AtomQueue()
{
index = indexPool = 0;
empty = true;
full = false;

memset(dataPool, 0, sizeof(unsigned char)*MAX_POOL_SIZE);
}

void copyDataFrom(Lv2AtomQueue* const queue)
{
// lock mutexes
queue->mutex.lock();
mutex.lock();

// copy data from queue
memcpy(data, queue->data, sizeof(datatype)*MAX_SIZE);
memcpy(dataPool, queue->dataPool, sizeof(unsigned char)*MAX_POOL_SIZE);
index = queue->index;
indexPool = queue->indexPool;
empty = queue->empty;
full = queue->full;

// unlock our mutex, no longer needed
mutex.unlock();

// reset queque
memset(queue->data, 0, sizeof(datatype)*MAX_SIZE);
memset(queue->dataPool, 0, sizeof(unsigned char)*MAX_POOL_SIZE);
queue->index = queue->indexPool = 0;
queue->empty = true;
queue->full = false;

// unlock queque mutex
queue->mutex.unlock();
}

bool isEmpty()
{
return empty;
}

bool isFull()
{
return full;
}

void lock()
{
mutex.lock();
}

void unlock()
{
mutex.unlock();
}

void put(const uint32_t portIndex, const LV2_Atom& atom, const bool lock = true)
{
qDebug("Lv2AtomQueue::put(%i, size:%i, %s)", portIndex, atom.size, bool2str(lock));
Q_ASSERT(atom.size > 0);
Q_ASSERT(indexPool + atom.size < MAX_POOL_SIZE); // overflow

if (full || atom.size == 0 || indexPool + atom.size >= MAX_POOL_SIZE)
return;

if (lock)
mutex.lock();

for (unsigned short i=0; i < MAX_SIZE; i++)
{
if (data[i].size == 0)
{
data[i].portIndex = portIndex;
data[i].size = atom.size;
data[i].poolOffset = indexPool;
memcpy(dataPool + indexPool, (const unsigned char*)LV2_ATOM_BODY_CONST(&atom), atom.size);
empty = false;
full = (i == MAX_SIZE-1);
indexPool += atom.size;
break;
}
}

if (lock)
mutex.unlock();
}

bool get(uint32_t* const portIndex, LV2_Atom** const atom, const bool lock = true)
{
qDebug("Lv2AtomQueue::get(%p, %p, %s)", portIndex, atom, bool2str(lock));
Q_ASSERT(portIndex && atom);

if (empty || ! (portIndex && atom))
return false;

if (lock)
mutex.lock();

full = false;

if (data[index].size == 0)
{
index = indexPool = 0;
empty = true;

if (lock)
mutex.lock();

return false;
}

static struct {
uint32_t size;
uint32_t type;
unsigned char* data;
} thisAtom;
thisAtom.size = data[index].size;
thisAtom.type = data[index].type;
thisAtom.data = dataPool + data[index].poolOffset;

*portIndex = data[index].portIndex;
*atom = (LV2_Atom*)&thisAtom;

data[index].portIndex = 0;
data[index].size = 0;
data[index].type = 0;
data[index].poolOffset = 0;
index++;
empty = false;

if (lock)
mutex.unlock();

return true;
}

private:
struct datatype {
size_t size;
LV2_URID type;
uint32_t portIndex;
uint32_t poolOffset;

datatype()
: size(0),
type(CARLA_URI_MAP_ID_NULL),
portIndex(0),
poolOffset(0) {}
};

static const unsigned short MAX_SIZE = 32;
static const unsigned short MAX_POOL_SIZE = 8192;

datatype data[MAX_SIZE];
unsigned char dataPool[MAX_POOL_SIZE];

unsigned short index;
uint32_t indexPool;
bool empty, full;

QMutex mutex;
};

class Lv2Plugin : public CarlaPlugin class Lv2Plugin : public CarlaPlugin
{ {
public: public:
@@ -1018,9 +1187,36 @@ public:


void idleGui() void idleGui()
{ {
// Update external UI
if (gui.type == GUI_EXTERNAL_LV2 && ui.handle && ui.descriptor && ui.widget)
LV2_EXTERNAL_UI_RUN((LV2_External_UI_Widget*)ui.widget);
const bool haveUI = (gui.type == GUI_EXTERNAL_OSC && osc.data.target) || (ui.handle && ui.descriptor);

if (haveUI)
{
// Update event ports
static Lv2AtomQueue queue;
queue.copyDataFrom(&atomQueueOut);

uint32_t portIndex;
LV2_Atom* atom;

while (atomQueueIn.get(&portIndex, &atom, false))
{
#ifndef BUILD_BRIDGE
if (gui.type == GUI_EXTERNAL_OSC)
{
osc_send_lv2_transfer_event(&osc.data, nullptr, nullptr);
}
else
#endif
{
if (ui.descriptor->port_event)
ui.descriptor->port_event(ui.handle, portIndex, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom);
}
}

// Update external UI
if (gui.type == GUI_EXTERNAL_LV2 && ui.widget)
LV2_EXTERNAL_UI_RUN((LV2_External_UI_Widget*)ui.widget);
}


CarlaPlugin::idleGui(); CarlaPlugin::idleGui();
} }
@@ -1283,6 +1479,8 @@ public:
descriptor->connect_port(handle, i, evIn.data[j].atom); descriptor->connect_port(handle, i, evIn.data[j].atom);
if (h2) descriptor->connect_port(h2, i, evIn.data[j].atom); if (h2) descriptor->connect_port(h2, i, evIn.data[j].atom);


evIn.data[j].rindex = i;

if (portType & LV2_PORT_SUPPORTS_MIDI_EVENT) if (portType & LV2_PORT_SUPPORTS_MIDI_EVENT)
{ {
evIn.data[j].type |= CARLA_EVENT_TYPE_MIDI; evIn.data[j].type |= CARLA_EVENT_TYPE_MIDI;
@@ -1299,6 +1497,8 @@ public:
descriptor->connect_port(handle, i, evOut.data[j].atom); descriptor->connect_port(handle, i, evOut.data[j].atom);
if (h2) descriptor->connect_port(h2, i, evOut.data[j].atom); if (h2) descriptor->connect_port(h2, i, evOut.data[j].atom);


evOut.data[j].rindex = i;

if (portType & LV2_PORT_SUPPORTS_MIDI_EVENT) if (portType & LV2_PORT_SUPPORTS_MIDI_EVENT)
{ {
evOut.data[j].type |= CARLA_EVENT_TYPE_MIDI; evOut.data[j].type |= CARLA_EVENT_TYPE_MIDI;
@@ -1320,6 +1520,8 @@ public:
descriptor->connect_port(handle, i, evIn.data[j].event); descriptor->connect_port(handle, i, evIn.data[j].event);
if (h2) descriptor->connect_port(h2, i, evIn.data[j].event); if (h2) descriptor->connect_port(h2, i, evIn.data[j].event);


evIn.data[j].rindex = i;

if (portType & LV2_PORT_SUPPORTS_MIDI_EVENT) if (portType & LV2_PORT_SUPPORTS_MIDI_EVENT)
{ {
evIn.data[j].type |= CARLA_EVENT_TYPE_MIDI; evIn.data[j].type |= CARLA_EVENT_TYPE_MIDI;
@@ -1332,6 +1534,8 @@ public:
descriptor->connect_port(handle, i, evOut.data[j].event); descriptor->connect_port(handle, i, evOut.data[j].event);
if (h2) descriptor->connect_port(h2, i, evOut.data[j].event); if (h2) descriptor->connect_port(h2, i, evOut.data[j].event);


evOut.data[j].rindex = i;

if (portType & LV2_PORT_SUPPORTS_MIDI_EVENT) if (portType & LV2_PORT_SUPPORTS_MIDI_EVENT)
{ {
evOut.data[j].type |= CARLA_EVENT_TYPE_MIDI; evOut.data[j].type |= CARLA_EVENT_TYPE_MIDI;
@@ -1349,8 +1553,9 @@ public:
descriptor->connect_port(handle, i, evIn.data[j].midi); descriptor->connect_port(handle, i, evIn.data[j].midi);
if (h2) descriptor->connect_port(h2, i, evIn.data[j].midi); if (h2) descriptor->connect_port(h2, i, evIn.data[j].midi);


evIn.data[j].type |= CARLA_EVENT_TYPE_MIDI;
evIn.data[j].port = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, true);
evIn.data[j].type |= CARLA_EVENT_TYPE_MIDI;
evIn.data[j].port = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, true);
evIn.data[j].rindex = i;
} }
else if (LV2_IS_PORT_OUTPUT(portType)) else if (LV2_IS_PORT_OUTPUT(portType))
{ {
@@ -1358,8 +1563,9 @@ public:
descriptor->connect_port(handle, i, evOut.data[j].midi); descriptor->connect_port(handle, i, evOut.data[j].midi);
if (h2) descriptor->connect_port(h2, i, evOut.data[j].midi); if (h2) descriptor->connect_port(h2, i, evOut.data[j].midi);


evOut.data[j].type |= CARLA_EVENT_TYPE_MIDI;
evOut.data[j].port = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, false);
evOut.data[j].type |= CARLA_EVENT_TYPE_MIDI;
evOut.data[j].port = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, false);
evOut.data[j].rindex = i;
} }
else else
qWarning("WARNING - Got a broken Port (Midi, but not input or output)"); qWarning("WARNING - Got a broken Port (Midi, but not input or output)");
@@ -2225,13 +2431,24 @@ public:
} }
#endif #endif


// TODO - get messages from ringbuffer
atomQueueIn.lock();

if (! atomQueueIn.isEmpty())
{
uint32_t portIndex;
LV2_Atom* atom;

while (atomQueueIn.get(&portIndex, &atom, false))
{
LV2_Atom_Event* const aev = getLv2AtomEvent(evIn.data[i].atom, evInAtomOffsets[i]);
aev->time.frames = framesOffset;
aev->body.type = CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT;
aev->body.size = atom->size;
memcpy(LV2_ATOM_BODY(&aev->body), LV2_ATOM_BODY(atom), atom->size);
}
}


//LV2_Atom_Event* const aev = getLv2AtomEvent(evIn.data[i].atom, evInAtomOffsets[i]);
//aev->time.frames = framesOffset;
//aev->body.type = CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT;
//aev->body.size = 0; // message size
//memcpy(LV2_ATOM_BODY(&aev->body), nullptr /* message data body */, 0 /* message size */);
atomQueueIn.unlock();
} }
} }


@@ -2525,12 +2742,12 @@ public:


if (evOut.count > 0 && m_active) if (evOut.count > 0 && m_active)
{ {
// ----------------------------------------------------------------------------------------------------
// MIDI Output
atomQueueOut.lock();


for (i=0; i < evOut.count; i++) for (i=0; i < evOut.count; i++)
{ {
if (! evOut.data[i].port)
// midi events need the midi port to send events to
if ((evOut.data[i].type & CARLA_EVENT_TYPE_MIDI) > 0 && ! evOut.data[i].port)
continue; continue;


if (evOut.data[i].type & CARLA_EVENT_DATA_ATOM) if (evOut.data[i].type & CARLA_EVENT_DATA_ATOM)
@@ -2550,6 +2767,11 @@ public:
const unsigned char* const data = (unsigned char*)LV2_ATOM_BODY(&aev->body); const unsigned char* const data = (unsigned char*)LV2_ATOM_BODY(&aev->body);
evOut.data[i].port->writeEvent(aev->time.frames, data, aev->body.size); evOut.data[i].port->writeEvent(aev->time.frames, data, aev->body.size);
} }
else if (aev->body.type == CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT)
{
if (! atomQueueOut.isFull())
atomQueueOut.put(evOut.data[i].rindex, aev->body);
}


offset += lv2_atom_pad_size(sizeof(LV2_Atom_Event) + aev->body.size); offset += lv2_atom_pad_size(sizeof(LV2_Atom_Event) + aev->body.size);
} }
@@ -2588,10 +2810,7 @@ public:
} }
} }


// ----------------------------------------------------------------------------------------------------
// Message Output

// TODO
atomQueueOut.unlock();


} // End of Event Output } // End of Event Output


@@ -2856,20 +3075,18 @@ public:


// ------------------------------------------------------------------- // -------------------------------------------------------------------


void handleTransferAtom(const LV2_Atom* const atom, const char* const stype)
void handleTransferAtom(const uint32_t portIndex, const LV2_Atom* const atom)
{ {
qDebug("Lv2Plugin::handleAtomTransfer(%p, \"%s\")", atom, stype);
qDebug("Lv2Plugin::handleAtomTransfer(%i, %p)", portIndex, atom);
Q_ASSERT(atom); Q_ASSERT(atom);
Q_ASSERT(stype);


// TODO // TODO
} }


void handleTransferEvent(const LV2_Atom* const atom, const char* const stype)
void handleTransferEvent(const uint32_t portIndex, const LV2_Atom* const atom)
{ {
qDebug("Lv2Plugin::handleEventTransfer(%p, \"%s\")", atom, stype);
qDebug("Lv2Plugin::handleEventTransfer(%i, %p)", portIndex, atom);
Q_ASSERT(atom); Q_ASSERT(atom);
Q_ASSERT(stype);


const LV2_URID uridAtomBlank = getCustomURID(LV2_ATOM__Blank); const LV2_URID uridAtomBlank = getCustomURID(LV2_ATOM__Blank);
const LV2_URID uridPatchBody = getCustomURID(LV2_PATCH__body); const LV2_URID uridPatchBody = getCustomURID(LV2_PATCH__body);
@@ -2877,7 +3094,7 @@ public:


if (atom->type != uridAtomBlank) if (atom->type != uridAtomBlank)
{ {
qWarning("Lv2Plugin::handleEventTransfer() - Not blank");
qWarning("Lv2Plugin::handleEventTransfer() - not blank");
return; return;
} }


@@ -2885,7 +3102,7 @@ public:


if (obj->body.otype != uridPatchSet) if (obj->body.otype != uridPatchSet)
{ {
qWarning("Lv2Plugin::handleEventTransfer() - Not Patch Set");
qWarning("Lv2Plugin::handleEventTransfer() - not Patch:Set");
return; return;
} }


@@ -2894,12 +3111,14 @@ public:


if (! body) if (! body)
{ {
qWarning("Lv2Plugin::handleEventTransfer() - Has no body");
qWarning("Lv2Plugin::handleEventTransfer() - has no body");
return; return;
} }


LV2_ATOM_OBJECT_FOREACH(body, iter) LV2_ATOM_OBJECT_FOREACH(body, iter)
{ {
atomQueueIn.put(portIndex, iter->value);
#if 0
CustomDataType dtype = CUSTOM_DATA_INVALID; CustomDataType dtype = CUSTOM_DATA_INVALID;
const char* const key = getCustomURIString(iter->key); const char* const key = getCustomURIString(iter->key);
const char* value = nullptr; const char* value = nullptr;
@@ -2921,6 +3140,7 @@ public:
setCustomData(dtype, key, value, false); setCustomData(dtype, key, value, false);


free((void*)value); free((void*)value);
#endif
} }
} }


@@ -3155,20 +3375,20 @@ public:
Q_ASSERT(buffer); Q_ASSERT(buffer);


const LV2_Atom* const atom = (const LV2_Atom*)buffer; const LV2_Atom* const atom = (const LV2_Atom*)buffer;
handleTransferAtom(atom, getCustomURIString(atom->type));
handleTransferAtom(rindex, atom);


if (ui.handle && ui.descriptor && ui.descriptor->port_event)
ui.descriptor->port_event(ui.handle, 0, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM, atom);
//if (ui.handle && ui.descriptor && ui.descriptor->port_event)
// ui.descriptor->port_event(ui.handle, 0, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM, atom);
} }
else if (format == CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT) else if (format == CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT)
{ {
Q_ASSERT(buffer); Q_ASSERT(buffer);


const LV2_Atom* const atom = (const LV2_Atom*)buffer; const LV2_Atom* const atom = (const LV2_Atom*)buffer;
handleTransferEvent(atom, getCustomURIString(atom->type));
handleTransferEvent(rindex, atom);


if (ui.handle && ui.descriptor && ui.descriptor->port_event)
ui.descriptor->port_event(ui.handle, 0, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom);
//if (ui.handle && ui.descriptor && ui.descriptor->port_event)
// ui.descriptor->port_event(ui.handle, 0, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom);
} }
} }


@@ -4343,6 +4563,8 @@ private:
} suil; } suil;
#endif #endif


Lv2AtomQueue atomQueueIn;
Lv2AtomQueue atomQueueOut;
Lv2PluginEventData evIn; Lv2PluginEventData evIn;
Lv2PluginEventData evOut; Lv2PluginEventData evOut;
float* paramBuffers; float* paramBuffers;
@@ -4404,16 +4626,17 @@ int CarlaOsc::handle_lv2_atom_transfer(CARLA_OSC_HANDLE_ARGS2)
qDebug("CarlaOsc::handle_lv2_atom_transfer()"); qDebug("CarlaOsc::handle_lv2_atom_transfer()");
CARLA_OSC_CHECK_OSC_TYPES(2, "ss"); CARLA_OSC_CHECK_OSC_TYPES(2, "ss");


const char* const type = (const char*)&argv[0]->s;
const char* const value = (const char*)&argv[1]->s;
//const char* const type = (const char*)&argv[0]->s;
//const char* const value = (const char*)&argv[1]->s;

//QByteArray chunk;
//chunk = QByteArray::fromBase64(value);


QByteArray chunk;
chunk = QByteArray::fromBase64(value);
//const LV2_Atom* const atom = (LV2_Atom*)chunk.constData();


const LV2_Atom* const atom = (LV2_Atom*)chunk.constData();
//CarlaBackend::Lv2Plugin* const lv2plugin = (CarlaBackend::Lv2Plugin*)plugin;
//lv2plugin->handleTransferAtom(atom, type);


CarlaBackend::Lv2Plugin* const lv2plugin = (CarlaBackend::Lv2Plugin*)plugin;
lv2plugin->handleTransferAtom(atom, type);


return 0; return 0;
} }
@@ -4423,16 +4646,16 @@ int CarlaOsc::handle_lv2_event_transfer(CARLA_OSC_HANDLE_ARGS2)
qDebug("CarlaOsc::handle_lv2_event_transfer()"); qDebug("CarlaOsc::handle_lv2_event_transfer()");
CARLA_OSC_CHECK_OSC_TYPES(2, "ss"); CARLA_OSC_CHECK_OSC_TYPES(2, "ss");


const char* const type = (const char*)&argv[0]->s;
const char* const value = (const char*)&argv[1]->s;
//const char* const type = (const char*)&argv[0]->s;
//const char* const value = (const char*)&argv[1]->s;


QByteArray chunk;
chunk = QByteArray::fromBase64(value);
//QByteArray chunk;
//chunk = QByteArray::fromBase64(value);


const LV2_Atom* const atom = (LV2_Atom*)chunk.constData();
//const LV2_Atom* const atom = (LV2_Atom*)chunk.constData();


CarlaBackend::Lv2Plugin* const lv2plugin = (CarlaBackend::Lv2Plugin*)plugin;
lv2plugin->handleTransferEvent(atom, type);
//CarlaBackend::Lv2Plugin* const lv2plugin = (CarlaBackend::Lv2Plugin*)plugin;
//lv2plugin->handleTransferEvent(atom, type);


return 0; return 0;
} }


Loading…
Cancel
Save