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 {
uint32_t type;
uint32_t rindex;
CarlaEngineMidiPort* port;
union {
LV2_Atom_Sequence* atom;
@@ -148,6 +149,7 @@ struct Lv2EventData {

Lv2EventData()
: type(0),
rindex(0),
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);
}

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
{
public:
@@ -1018,9 +1187,36 @@ public:

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();
}
@@ -1283,6 +1479,8 @@ public:
descriptor->connect_port(handle, 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)
{
evIn.data[j].type |= CARLA_EVENT_TYPE_MIDI;
@@ -1299,6 +1497,8 @@ public:
descriptor->connect_port(handle, 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)
{
evOut.data[j].type |= CARLA_EVENT_TYPE_MIDI;
@@ -1320,6 +1520,8 @@ public:
descriptor->connect_port(handle, 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)
{
evIn.data[j].type |= CARLA_EVENT_TYPE_MIDI;
@@ -1332,6 +1534,8 @@ public:
descriptor->connect_port(handle, 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)
{
evOut.data[j].type |= CARLA_EVENT_TYPE_MIDI;
@@ -1349,8 +1553,9 @@ public:
descriptor->connect_port(handle, 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))
{
@@ -1358,8 +1563,9 @@ public:
descriptor->connect_port(handle, 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
qWarning("WARNING - Got a broken Port (Midi, but not input or output)");
@@ -2225,13 +2431,24 @@ public:
}
#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)
{
// ----------------------------------------------------------------------------------------------------
// MIDI Output
atomQueueOut.lock();

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;

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);
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);
}
@@ -2588,10 +2810,7 @@ public:
}
}

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

// TODO
atomQueueOut.unlock();

} // 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(stype);

// 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(stype);

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

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

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

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

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

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

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

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

@@ -3155,20 +3375,20 @@ public:
Q_ASSERT(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)
{
Q_ASSERT(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;
#endif

Lv2AtomQueue atomQueueIn;
Lv2AtomQueue atomQueueOut;
Lv2PluginEventData evIn;
Lv2PluginEventData evOut;
float* paramBuffers;
@@ -4404,16 +4626,17 @@ int CarlaOsc::handle_lv2_atom_transfer(CARLA_OSC_HANDLE_ARGS2)
qDebug("CarlaOsc::handle_lv2_atom_transfer()");
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;
}
@@ -4423,16 +4646,16 @@ int CarlaOsc::handle_lv2_event_transfer(CARLA_OSC_HANDLE_ARGS2)
qDebug("CarlaOsc::handle_lv2_event_transfer()");
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;
}


Loading…
Cancel
Save