Browse Source

Rework ringbuffer class to allow stack vs heap, update lv2 for it

tags/1.9.4
falkTX 10 years ago
parent
commit
f0dcea3da9
5 changed files with 177 additions and 90 deletions
  1. +2
    -2
      source/backend/plugin/BridgePlugin.cpp
  2. +24
    -31
      source/backend/plugin/Lv2Plugin.cpp
  3. +1
    -1
      source/utils/CarlaBridgeUtils.hpp
  4. +46
    -24
      source/utils/CarlaRingBuffer.hpp
  5. +104
    -32
      source/utils/Lv2AtomQueue.hpp

+ 2
- 2
source/backend/plugin/BridgePlugin.cpp View File

@@ -151,13 +151,13 @@ struct BridgeAudioPool {
}
};

struct BridgeControl : public RingBufferControl {
struct BridgeControl : public RingBufferControlTemplate<StackRingBuffer> {
CarlaString filename;
BridgeShmControl* data;
shm_t shm;

BridgeControl()
: RingBufferControl(nullptr),
: RingBufferControlTemplate(nullptr),
data(nullptr)
{
carla_shm_init(shm);


+ 24
- 31
source/backend/plugin/Lv2Plugin.cpp View File

@@ -1204,36 +1204,39 @@ public:

void idle() override
{
#if 0
if (fUi.type == UI::TYPE_NULL)
return CarlaPlugin::idle();

if (! fAtomQueueOut.isEmpty())
{
char dumpBuf[fAtomQueueOut.getSize()];

Lv2AtomQueue tmpQueue;
tmpQueue.copyDataFrom(&fAtomQueueOut);
tmpQueue.copyAndDumpDataFromQueue(fAtomQueueOut, dumpBuf);

uint32_t portIndex;
const LV2_Atom* atom;
const bool hasPortEvent(fUi.handle != nullptr && fUi.descriptor != nullptr && fUi.descriptor->port_event != nullptr);

while (tmpQueue.get(&portIndex, &atom))
for (; tmpQueue.get(&atom, &portIndex);)
{
//carla_stdout("OUTPUT message IN GUI REMOVED FROM BUFFER");
carla_stdout("OUTPUT message IN GUI REMOVED FROM BUFFER");

if (fUi.type == PLUGIN_UI_OSC)
if (fUi.type == UI::TYPE_OSC)
{
if (pData->osc.data.target != nullptr)
{
QByteArray chunk((const char*)atom, lv2_atom_total_size(atom));
osc_send_lv2_atom_transfer(&pData->osc.data, portIndex, chunk.toBase64().constData());
QByteArray chunk((const char*)atom, static_cast<int>(lv2_atom_total_size(atom)));
osc_send_lv2_atom_transfer(pData->osc.data, portIndex, chunk.toBase64().constData());
}
}
else if (fUi.type != PLUGIN_UI_NULL)
else
{
if (hasPortEvent)
fUi.descriptor->port_event(fUi.handle, portIndex, lv2_atom_total_size(atom), CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom);
}
}
}
#endif

if (fUi.handle != nullptr && fUi.descriptor != nullptr)
{
@@ -2507,26 +2510,24 @@ public:
// ----------------------------------------------------------------------------------------------------
// Message Input

#if 0
if (fAtomQueueIn.tryLock())
{
if (! fAtomQueueIn.isEmpty())
{
uint32_t portIndex;
const LV2_Atom* atom;
uint32_t portIndex;

k = fEventsIn.ctrlIndex;
const uint32_t j = fEventsIn.ctrlIndex;

while (fAtomQueueIn.get(&portIndex, &atom))
for (; fAtomQueueIn.get(&atom, &portIndex);)
{
carla_debug("Event input message sent to plugin DSP, type %i:\"%s\", size:%i/%i",
atom->type, carla_lv2_urid_unmap(this, atom->type),
atom->size, lv2_atom_total_size(atom)
);
atom->size, lv2_atom_total_size(atom));

if (! lv2_atom_buffer_write(&evInAtomIters[k], 0, 0, atom->type, atom->size, LV2NV_ATOM_BODY_CONST(atom)))
if (! lv2_atom_buffer_write(&evInAtomIters[j], 0, 0, atom->type, atom->size, LV2_ATOM_BODY_CONST(atom)))
{
carla_stdout("Event input buffer full, 1 message lost");
carla_stdout("Event input buffer full, at least 1 message lost");
break;
}
}
@@ -2534,7 +2535,6 @@ public:

fAtomQueueIn.unlock();
}
#endif

// ----------------------------------------------------------------------------------------------------
// MIDI Input (External)
@@ -2912,7 +2912,6 @@ public:
{
if (fEventsOut.ctrl->type & CARLA_EVENT_DATA_ATOM)
{
//const uint32_t rindex(fEventsOut.ctrl->rindex);
const LV2_Atom_Event* ev;
LV2_Atom_Buffer_Iterator iter;

@@ -2932,12 +2931,11 @@ public:
if (fEventsOut.ctrl->port != nullptr && ev->time.frames >= 0 && ev->body.size <= 0xFF)
fEventsOut.ctrl->port->writeMidiEvent(static_cast<uint32_t>(ev->time.frames), static_cast<uint8_t>(ev->body.size), data);
}
#if 0
else if (ev->body.type == CARLA_URI_MAP_ID_ATOM_BLANK)
{
fAtomQueueOut.put(rindex, &ev->body);
fAtomQueueOut.put(&ev->body, fEventsOut.ctrl->rindex);
}
#endif
lv2_atom_buffer_increment(&iter);
}
}
@@ -3938,9 +3936,9 @@ public:

case CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM:
case CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT:
#if 0
fAtomQueueIn.put(rindex, (const LV2_Atom*)buffer);
#endif
CARLA_SAFE_ASSERT_RETURN(((const LV2_Atom*)buffer)->size == bufferSize,);
fAtomQueueIn.put((const LV2_Atom*)buffer, rindex);
break;

default:
@@ -4633,10 +4631,7 @@ public:
CARLA_SAFE_ASSERT_RETURN(atom != nullptr,);
carla_debug("Lv2Plugin::handleTransferAtom(%i, %p)", portIndex, atom);

#if 0
fAtomQueueIn.put(portIndex, atom);
#endif
return; (void)portIndex;
fAtomQueueIn.put(atom, portIndex);
}

void handleUridMap(const LV2_URID urid, const char* const uri)
@@ -4662,10 +4657,8 @@ private:
float** fAudioOutBuffers;
float* fParamBuffers;

#if 0
Lv2AtomQueue fAtomQueueIn;
Lv2AtomQueue fAtomQueueOut;
#endif
LV2_Atom_Forge fAtomForge;

Lv2PluginEventData fEventsIn;


+ 1
- 1
source/utils/CarlaBridgeUtils.hpp View File

@@ -79,7 +79,7 @@ struct BridgeShmControl {
void* runClient;
char _padClient[32];
};
RingBuffer ringBuffer;
StackRingBuffer ringBuffer;
} POST_PACKED_STRUCTURE;

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


+ 46
- 24
source/utils/CarlaRingBuffer.hpp View File

@@ -1,6 +1,5 @@
/*
* Carla Ring Buffer based on dssi-vst code
* Copyright (C) 2004-2010 Chris Cannam <cannam@all-day-breakfast.com>
* Carla Ring Buffer
* Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
@@ -21,26 +20,45 @@

#include "CarlaUtils.hpp"

//#ifndef RING_BUFFER_SIZE
#define RING_BUFFER_SIZE 2048
//#endif

// -----------------------------------------------------------------------
// RingBuffer struct
// RingBuffer structs

struct HeapRingBuffer {
uint32_t size;
int32_t head, tail, written;
bool invalidateCommit;
char* buf;

HeapRingBuffer& operator=(const HeapRingBuffer& rb)
{
CARLA_SAFE_ASSERT_RETURN(size == rb.size, *this);

size = rb.size;
head = rb.head;
tail = rb.tail;
written = rb.written;
invalidateCommit = rb.invalidateCommit;
std::memcpy(buf, rb.buf, size);

struct RingBuffer {
return *this;
}
};

struct StackRingBuffer {
static const uint32_t size = 2048;
int32_t head, tail, written;
bool invalidateCommit;
char buf[RING_BUFFER_SIZE];
char buf[size];
};

// -----------------------------------------------------------------------
// RingBufferControl class
// RingBufferControl templated class

class RingBufferControl
template <class RingBufferStruct>
class RingBufferControlTemplate
{
public:
RingBufferControl(RingBuffer* const ringBuf) noexcept
RingBufferControlTemplate(RingBufferStruct* const ringBuf) noexcept
: fRingBuf(ringBuf)
{
if (ringBuf != nullptr)
@@ -55,10 +73,12 @@ public:
fRingBuf->tail = 0;
fRingBuf->written = 0;
fRingBuf->invalidateCommit = false;
carla_zeroChar(fRingBuf->buf, RING_BUFFER_SIZE);

if (fRingBuf->size > 0)
carla_zeroChar(fRingBuf->buf, fRingBuf->size);
}

void setRingBuffer(RingBuffer* const ringBuf, const bool reset) noexcept
void setRingBuffer(RingBufferStruct* const ringBuf, const bool reset) noexcept
{
CARLA_SAFE_ASSERT_RETURN(ringBuf != nullptr,);
CARLA_SAFE_ASSERT_RETURN(ringBuf != fRingBuf,);
@@ -155,6 +175,7 @@ protected:
CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,);
CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
CARLA_SAFE_ASSERT_RETURN(size != 0,);
CARLA_SAFE_ASSERT_RETURN(size < fRingBuf->size,);

// this should not happen
CARLA_ASSERT(fRingBuf->head >= 0);
@@ -169,7 +190,7 @@ protected:

const size_t head(static_cast<size_t>(fRingBuf->head));
const size_t tail(static_cast<size_t>(fRingBuf->tail));
const size_t wrap((head < tail) ? RING_BUFFER_SIZE : 0);
const size_t wrap((head < tail) ? fRingBuf->size : 0);

if (head - tail + wrap < size)
{
@@ -179,10 +200,10 @@ protected:

size_t readto = tail + size;

if (readto >= RING_BUFFER_SIZE)
if (readto >= fRingBuf->size)
{
readto -= RING_BUFFER_SIZE;
const size_t firstpart(RING_BUFFER_SIZE - tail);
readto -= fRingBuf->size;
const size_t firstpart(fRingBuf->size - tail);
std::memcpy(charbuf, fRingBuf->buf + tail, firstpart);
std::memcpy(charbuf + firstpart, fRingBuf->buf, readto);
}
@@ -199,6 +220,7 @@ protected:
CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,);
CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
CARLA_SAFE_ASSERT_RETURN(size != 0,);
CARLA_SAFE_ASSERT_RETURN(size < fRingBuf->size,);

// this should not happen
CARLA_ASSERT(fRingBuf->head >= 0);
@@ -209,7 +231,7 @@ protected:

const size_t tail(static_cast<size_t>(fRingBuf->tail));
const size_t wrtn(static_cast<size_t>(fRingBuf->written));
const size_t wrap((tail <= wrtn) ? RING_BUFFER_SIZE : 0);
const size_t wrap((tail <= wrtn) ? fRingBuf->size : 0);

if (tail - wrtn + wrap <= size)
{
@@ -220,10 +242,10 @@ protected:

size_t writeto = wrtn + size;

if (writeto >= RING_BUFFER_SIZE)
if (writeto >= fRingBuf->size)
{
writeto -= RING_BUFFER_SIZE;
const size_t firstpart(RING_BUFFER_SIZE - wrtn);
writeto -= fRingBuf->size;
const size_t firstpart(fRingBuf->size - wrtn);
std::memcpy(fRingBuf->buf + wrtn, charbuf, firstpart);
std::memcpy(fRingBuf->buf, charbuf + firstpart, writeto);
}
@@ -236,10 +258,10 @@ protected:
}

private:
RingBuffer* fRingBuf;
RingBufferStruct* fRingBuf;

CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(RingBufferControl)
CARLA_DECLARE_NON_COPY_CLASS(RingBufferControlTemplate)
};

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


+ 104
- 32
source/utils/Lv2AtomQueue.hpp View File

@@ -1,6 +1,6 @@
/*
* Simple Queue, specially developed for Atom types
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2014 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
@@ -25,17 +25,47 @@

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

class Lv2AtomRingBufferControl : public RingBufferControl
class Lv2AtomRingBufferControl : public RingBufferControlTemplate<HeapRingBuffer>
{
public:
Lv2AtomRingBufferControl()
: RingBufferControl(&fBuffer)
: RingBufferControlTemplate(nullptr)
{
fBuffer.size = 0;
fBuffer.buf = nullptr;
}

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

const LV2_Atom* readAtom(uint32_t* const portIndex)
void createBuffer(const uint32_t size)
{
if (fBuffer.buf != nullptr)
delete[] fBuffer.buf;

fBuffer.size = size;
fBuffer.buf = new char[size];
setRingBuffer(&fBuffer, true);
}

// used for tmp buffers only
void copyDump(HeapRingBuffer& rb, char dumpBuf[])
{
CARLA_SAFE_ASSERT_RETURN(fBuffer.size == 0,);
CARLA_SAFE_ASSERT_RETURN(fBuffer.buf == nullptr,);

fBuffer.buf = dumpBuf;
fBuffer.size = rb.size;
fBuffer.head = rb.head;
fBuffer.tail = rb.tail;
fBuffer.written = rb.written;
fBuffer.invalidateCommit = rb.invalidateCommit;

std::memcpy(dumpBuf, rb.buf, rb.size);
}

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

const LV2_Atom* readAtom(uint32_t* const portIndex) noexcept
{
fRetAtom.atom.size = 0;
fRetAtom.atom.type = 0;
@@ -44,12 +74,12 @@ public:
if (fRetAtom.atom.size == 0 || fRetAtom.atom.type == 0)
return nullptr;

CARLA_SAFE_ASSERT_RETURN(fRetAtom.atom.size < RING_BUFFER_SIZE, nullptr);
CARLA_SAFE_ASSERT_RETURN(fRetAtom.atom.size < kMaxDataSize, nullptr);

int32_t index = -1;
tryRead(&index, sizeof(int32_t));

if (index == -1)
if (index < 0)
return nullptr;

if (portIndex != nullptr)
@@ -63,7 +93,7 @@ public:

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

bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex)
bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept
{
tryWrite(atom, sizeof(LV2_Atom));
tryWrite(&portIndex, sizeof(int32_t));
@@ -74,11 +104,13 @@ public:
// -------------------------------------------------------------------

private:
RingBuffer fBuffer;
HeapRingBuffer fBuffer;

static const size_t kMaxDataSize = 2048;

struct RetAtom {
LV2_Atom atom;
char data[RING_BUFFER_SIZE];
char data[kMaxDataSize];
} fRetAtom;

friend class Lv2AtomQueue;
@@ -96,21 +128,54 @@ public:
{
}

void copyDataFromQueue(Lv2AtomQueue& queue)
// -------------------------------------------------------------------

void createBuffer(const uint32_t size)
{
// lock queue
const CarlaMutex::ScopedLocker qsl(queue.fMutex);
fRingBufferCtrl.createBuffer(size);
}

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

uint32_t getSize() const noexcept
{
return fRingBufferCtrl.fBuffer.size;
}

bool isEmpty() const noexcept
{
return !fRingBufferCtrl.isDataAvailable();
}

// must have been locked before
bool get(const LV2_Atom** const atom, uint32_t* const portIndex)
{
CARLA_SAFE_ASSERT_RETURN(atom != nullptr && portIndex != nullptr, false);

if (! fRingBufferCtrl.isDataAvailable())
return false;

if (const LV2_Atom* retAtom = fRingBufferCtrl.readAtom(portIndex))
{
// copy data from queue
const CarlaMutex::ScopedLocker sl(fMutex);
carla_copyStruct<RingBuffer>(fRingBufferCtrl.fBuffer, queue.fRingBufferCtrl.fBuffer);
*atom = retAtom;
return true;
}

// reset queque - FIXME? no queue.?
queue.fRingBufferCtrl.clear();
return false;
}

// must NOT been locked, we do that here
bool put(const LV2_Atom* const atom, const uint32_t portIndex)
{
CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);

const CarlaMutex::ScopedLocker sl(fMutex);

return fRingBufferCtrl.writeAtom(atom, static_cast<int32_t>(portIndex));
}

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

void lock() const noexcept
{
fMutex.lock();
@@ -126,33 +191,40 @@ public:
fMutex.unlock();
}

bool put(const LV2_Atom* const atom, const uint32_t portIndex)
// -------------------------------------------------------------------

void copyDataFromQueue(Lv2AtomQueue& queue)
{
CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false);
// lock source
const CarlaMutex::ScopedLocker qsl(queue.fMutex);

const CarlaMutex::ScopedLocker sl(fMutex);
{
// copy data from source
const CarlaMutex::ScopedLocker sl(fMutex);
fRingBufferCtrl.fBuffer = queue.fRingBufferCtrl.fBuffer;
}

return fRingBufferCtrl.writeAtom(atom, static_cast<int32_t>(portIndex));
// clear source
queue.fRingBufferCtrl.clear();
}

bool get(const LV2_Atom** const atom, uint32_t* const portIndex)
void copyAndDumpDataFromQueue(Lv2AtomQueue& queue, char dumpBuf[])
{
CARLA_SAFE_ASSERT_RETURN(atom != nullptr && portIndex != nullptr, false);

const CarlaMutex::ScopedLocker sl(fMutex);

if (! fRingBufferCtrl.isDataAvailable())
return false;
// lock source
const CarlaMutex::ScopedLocker qsl(queue.fMutex);

if (const LV2_Atom* retAtom = fRingBufferCtrl.readAtom(portIndex))
{
*atom = retAtom;
return true;
// copy data from source
const CarlaMutex::ScopedLocker sl(fMutex);
fRingBufferCtrl.copyDump(queue.fRingBufferCtrl.fBuffer, dumpBuf);
}

return false;
// clear source
queue.fRingBufferCtrl.clear();
}

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

private:
CarlaMutex fMutex;
Lv2AtomRingBufferControl fRingBufferCtrl;


Loading…
Cancel
Save