Browse Source

More ringbuffer work

tags/1.9.4
falkTX 10 years ago
parent
commit
791da3670e
6 changed files with 290 additions and 359 deletions
  1. +21
    -24
      source/backend/plugin/Lv2Plugin.cpp
  2. +10
    -10
      source/tests/CarlaRingBuffer.cpp
  3. +4
    -5
      source/tests/CarlaUtils.cpp
  4. +41
    -34
      source/utils/CarlaRingBuffer.hpp
  5. +0
    -286
      source/utils/Lv2AtomQueue.hpp
  6. +214
    -0
      source/utils/Lv2AtomRingBuffer.hpp

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

@@ -1288,21 +1288,18 @@ public:

void idle() override
{
if (! fAtomQueueOut.isEmpty())
if (fAtomBufferOut.isDataAvailableForReading())
{
fAtomQueueOut.lock();
char dumpBuf[fAtomQueueOut.getSize()];
char dumpBuf[fAtomBufferOut.getSize()];

Lv2AtomQueue tmpQueue;
tmpQueue.copyAndDumpDataFromQueue(fAtomQueueOut, dumpBuf);
CARLA_SAFE_ASSERT(! tmpQueue.isEmpty());
fAtomQueueOut.unlock();
Lv2AtomRingBuffer tmpRingBuffer(fAtomBufferOut, dumpBuf);
CARLA_SAFE_ASSERT(tmpRingBuffer.isDataAvailableForReading());

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

for (; tmpQueue.get(&atom, &portIndex);)
for (; tmpRingBuffer.get(atom, portIndex);)
{
if (atom->type == CARLA_URI_MAP_ID_CARLA_ATOM_WORKER)
{
@@ -1313,14 +1310,14 @@ public:
{
if (pData->osc.data.target != nullptr)
{
QByteArray chunk((const char*)atom, static_cast<int>(lv2_atom_total_size(atom)));
QByteArray chunk((const char*)atom, atom->size);
osc_send_lv2_atom_transfer(pData->osc.data, portIndex, chunk.toBase64().constData());
}
}
else
{
if (hasPortEvent)
fUi.descriptor->port_event(fUi.handle, portIndex, lv2_atom_total_size(atom), CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom);
fUi.descriptor->port_event(fUi.handle, portIndex, atom->size, CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom);
}
}
}
@@ -2129,10 +2126,10 @@ public:
}

if (fExt.worker != nullptr || (fUi.type != UI::TYPE_NULL && fEventsIn.count > 0 && (fEventsIn.data[0].type & CARLA_EVENT_DATA_ATOM) != 0))
fAtomQueueIn.createBuffer(eventBufferSize);
fAtomBufferIn.createBuffer(eventBufferSize);

if (fExt.worker != nullptr || (fUi.type != UI::TYPE_NULL && fEventsOut.count > 0 && (fEventsOut.data[0].type & CARLA_EVENT_DATA_ATOM) != 0))
fAtomQueueOut.createBuffer(eventBufferSize);
fAtomBufferOut.createBuffer(eventBufferSize);

if (fEventsIn.ctrl != nullptr && fEventsIn.ctrl->port == nullptr)
fEventsIn.ctrl->port = pData->event.portIn;
@@ -2738,14 +2735,14 @@ public:
// ----------------------------------------------------------------------------------------------------
// Message Input

if (fAtomQueueIn.tryLock())
if (fAtomBufferIn.tryLock())
{
if (! fAtomQueueIn.isEmpty())
if (fAtomBufferIn.isDataAvailableForReading())
{
const LV2_Atom* atom;
uint32_t j, portIndex;

for (; fAtomQueueIn.get(&atom, &portIndex);)
for (; fAtomBufferIn.get(atom, portIndex);)
{
j = (portIndex < fEventsIn.count) ? portIndex : fEventsIn.ctrlIndex;

@@ -2762,7 +2759,7 @@ public:
}
}

fAtomQueueIn.unlock();
fAtomBufferIn.unlock();
}

// ----------------------------------------------------------------------------------------------------
@@ -3187,7 +3184,7 @@ public:
else //if (ev->body.type == CARLA_URI_MAP_ID_ATOM_BLANK)
{
//carla_stdout("Got out event, %s", carla_lv2_urid_unmap(this, ev->body.type));
fAtomQueueOut.put(&ev->body, fEventsOut.ctrl->rindex);
fAtomBufferOut.put(&ev->body, fEventsOut.ctrl->rindex);
}

lv2_atom_buffer_increment(&iter);
@@ -4214,7 +4211,7 @@ public:
atom.size = size;
atom.type = CARLA_URI_MAP_ID_CARLA_ATOM_WORKER;

return fAtomQueueOut.putChunk(&atom, data, fEventsOut.ctrlIndex) ? LV2_WORKER_SUCCESS : LV2_WORKER_ERR_NO_SPACE;
return fAtomBufferOut.putChunk(&atom, data, fEventsOut.ctrlIndex) ? LV2_WORKER_SUCCESS : LV2_WORKER_ERR_NO_SPACE;
}

LV2_Worker_Status handleWorkerRespond(const uint32_t size, const void* const data)
@@ -4225,7 +4222,7 @@ public:
atom.size = size;
atom.type = CARLA_URI_MAP_ID_CARLA_ATOM_WORKER;

return fAtomQueueIn.putChunk(&atom, data, fEventsIn.ctrlIndex) ? LV2_WORKER_SUCCESS : LV2_WORKER_ERR_NO_SPACE;
return fAtomBufferIn.putChunk(&atom, data, fEventsIn.ctrlIndex) ? LV2_WORKER_SUCCESS : LV2_WORKER_ERR_NO_SPACE;
}

// -------------------------------------------------------------------
@@ -4341,7 +4338,7 @@ public:
index = fEventsIn.ctrlIndex;
}

fAtomQueueIn.put(atom, index);
fAtomBufferIn.put(atom, index);
} break;

default:
@@ -5187,7 +5184,7 @@ public:
CARLA_SAFE_ASSERT_RETURN(atom != nullptr,);
carla_stdout("Lv2Plugin::handleTransferAtom(%i, %p)", portIndex, atom);

fAtomQueueIn.put(atom, portIndex);
fAtomBufferIn.put(atom, portIndex);
}

void handleUridMap(const LV2_URID urid, const char* const uri)
@@ -5231,9 +5228,9 @@ private:
bool fLatencyChanged;
int32_t fLatencyIndex; // -1 if invalid

Lv2AtomQueue fAtomQueueIn;
Lv2AtomQueue fAtomQueueOut;
LV2_Atom_Forge fAtomForge;
Lv2AtomRingBuffer fAtomBufferIn;
Lv2AtomRingBuffer fAtomBufferOut;
LV2_Atom_Forge fAtomForge;

PluginCVData fCvIn;
PluginCVData fCvOut;


+ 10
- 10
source/tests/CarlaRingBuffer.cpp View File

@@ -27,13 +27,13 @@ static void test_CarlaRingBuffer1(CarlaRingBuffer<BufferStruct>& b) noexcept
assert(b.isEmpty());

// write all types
assert(b.writeBool(true));
assert(b.writeByte(123));
assert(b.writeShort(1234));
assert(b.writeInt(99999123));
assert(b.writeLong(0xffffffff));
assert(b.writeFloat(0.0123f));
assert(b.writeDouble(0.0123));
b.writeBool(true);
b.writeByte(123);
b.writeShort(1234);
b.writeInt(99999123);
b.writeLong(0xffffffff);
b.writeFloat(0.0123f);
b.writeDouble(0.0123);

// should be considered empty until a commitWrite
assert(b.isEmpty());
@@ -88,7 +88,7 @@ static void test_CarlaRingBuffer2(CarlaRingBuffer<BufferStruct>& b) noexcept
// write unmodified
BufferTestStruct t1, t2;
assert(t1 == t2);
assert(b.writeCustomType(t1));
b.writeCustomType(t1);
assert(b.commitWrite());

// test read
@@ -96,7 +96,7 @@ static void test_CarlaRingBuffer2(CarlaRingBuffer<BufferStruct>& b) noexcept
assert(t1 == t2);

// modify t1
assert(b.writeCustomType(t1));
b.writeCustomType(t1);
assert(b.commitWrite());
carla_zeroStruct(t1);

@@ -134,7 +134,7 @@ static void test_CarlaRingBuffer3(CarlaRingBuffer<BufferStruct>& b) noexcept
assert(b.isEmpty());

// write big chunk
assert(b.writeCustomData(kLicense, kLicenseSize));
b.writeCustomData(kLicense, kLicenseSize);

// still empty
assert(b.isEmpty());


+ 4
- 5
source/tests/CarlaUtils.cpp View File

@@ -39,7 +39,10 @@
#include "CarlaBridgeUtils.hpp"
#include "CarlaJuceUtils.hpp"
#include "CarlaLibCounter.hpp"
#include "CarlaOscUtils.hpp"
#include "CarlaOscUtils.hpp" // TODO
#include "CarlaPatchbayUtils.hpp" // TODO
// #include "CarlaPipeUtils.hpp"
// #include "CarlaStateUtils.hpp"
#include "CarlaShmUtils.hpp"

// used in dssi utils
@@ -48,10 +51,6 @@
#include <QtCore/QFileInfo>
#include <QtCore/QStringList>

// #include "CarlaPatchbayUtils.hpp"
// #include "CarlaPipeUtils.hpp"
// #include "CarlaStateUtils.hpp"

#if 0
// -----------------------------------------------------------------------



+ 41
- 34
source/utils/CarlaRingBuffer.hpp View File

@@ -123,14 +123,14 @@ public:
{
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);

return (fBuffer->head != fBuffer->tail);
return (fBuffer->buf != nullptr && fBuffer->head != fBuffer->tail);
}

bool isEmpty() const noexcept
{
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);

return (fBuffer->head == fBuffer->tail);
return (fBuffer->buf == nullptr || fBuffer->head == fBuffer->tail);
}

// -------------------------------------------------------------------
@@ -216,50 +216,50 @@ public:

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

bool writeBool(const bool value) noexcept
void writeBool(const bool value) noexcept
{
return tryWrite(&value, sizeof(bool));
tryWrite(&value, sizeof(bool));
}

bool writeByte(const int8_t value) noexcept
void writeByte(const int8_t value) noexcept
{
return tryWrite(&value, sizeof(int8_t));
tryWrite(&value, sizeof(int8_t));
}

bool writeShort(const int16_t value) noexcept
void writeShort(const int16_t value) noexcept
{
return tryWrite(&value, sizeof(int16_t));
tryWrite(&value, sizeof(int16_t));
}

bool writeInt(const int32_t value) noexcept
void writeInt(const int32_t value) noexcept
{
return tryWrite(&value, sizeof(int32_t));
tryWrite(&value, sizeof(int32_t));
}

bool writeLong(const int64_t value) noexcept
void writeLong(const int64_t value) noexcept
{
return tryWrite(&value, sizeof(int64_t));
tryWrite(&value, sizeof(int64_t));
}

bool writeFloat(const float value) noexcept
void writeFloat(const float value) noexcept
{
return tryWrite(&value, sizeof(float));
tryWrite(&value, sizeof(float));
}

bool writeDouble(const double value) noexcept
void writeDouble(const double value) noexcept
{
return tryWrite(&value, sizeof(double));
tryWrite(&value, sizeof(double));
}

bool writeCustomData(const void* const value, const std::size_t size) noexcept
void writeCustomData(const void* const value, const std::size_t size) noexcept
{
return tryWrite(value, size);
tryWrite(value, size);
}

template <typename T>
bool writeCustomType(const T& value) noexcept
void writeCustomType(const T& value) noexcept
{
return tryWrite(&value, sizeof(T));
tryWrite(&value, sizeof(T));
}

// -------------------------------------------------------------------
@@ -277,9 +277,6 @@ protected:

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

private:
BufferStruct* fBuffer;

bool tryRead(void* const buf, const std::size_t size) noexcept
{
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);
@@ -324,12 +321,12 @@ private:
return true;
}

bool tryWrite(const void* const buf, const std::size_t size) noexcept
void tryWrite(const void* const buf, const std::size_t size) noexcept
{
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(buf != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(size > 0, false);
CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size, false);
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr,);
CARLA_SAFE_ASSERT_RETURN(buf != nullptr,);
CARLA_SAFE_ASSERT_RETURN(size > 0,);
CARLA_SAFE_ASSERT_RETURN(size < fBuffer->size,);

const uint8_t* const bytebuf(static_cast<const uint8_t*>(buf));

@@ -341,7 +338,7 @@ private:
{
carla_stderr2("CarlaRingBuffer::tryWrite(%p, " P_SIZE "): failed, not enough space", buf, size);
fBuffer->invalidateCommit = true;
return false;
return;
}

std::size_t writeto(wrtn + size);
@@ -362,9 +359,11 @@ private:
}

fBuffer->wrtn = writeto;
return true;
}

private:
BufferStruct* fBuffer;

CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(CarlaRingBuffer)
};
@@ -376,7 +375,10 @@ class CarlaHeapRingBuffer : public CarlaRingBuffer<HeapBuffer>
{
public:
CarlaHeapRingBuffer() noexcept
: CarlaRingBuffer<HeapBuffer>() {}
: CarlaRingBuffer<HeapBuffer>()
{
carla_zeroStruct(fHeapBuffer);
}

~CarlaHeapRingBuffer() noexcept
{
@@ -387,13 +389,18 @@ public:
fHeapBuffer.buf = nullptr;
}

void createBuffer(const uint32_t size)
void createBuffer(const uint32_t size) noexcept
{
CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf == nullptr,);
CARLA_SAFE_ASSERT_RETURN(size > 0,);

fHeapBuffer.size = carla_nextPowerOf2(size);
fHeapBuffer.buf = new uint8_t[fHeapBuffer.size];
const uint32_t p2size(carla_nextPowerOf2(size));

try {
fHeapBuffer.buf = new uint8_t[p2size];
} CARLA_SAFE_EXCEPTION_RETURN("CarlaHeapRingBuffer::createBuffer",);

fHeapBuffer.size = p2size;
setRingBuffer(&fHeapBuffer, true);
}



+ 0
- 286
source/utils/Lv2AtomQueue.hpp View File

@@ -1,286 +0,0 @@
/*
* Simple Queue, specially developed for Atom types
* 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
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/

#ifndef LV2_ATOM_QUEUE_HPP_INCLUDED
#define LV2_ATOM_QUEUE_HPP_INCLUDED

#include "CarlaMathUtils.hpp"
#include "CarlaMutex.hpp"
#include "CarlaRingBuffer.hpp"

#include "lv2/atom.h"

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

class Lv2AtomRingBufferControl : public RingBufferControl<HeapBuffer>
{
public:
Lv2AtomRingBufferControl() noexcept
: RingBufferControl<HeapBuffer>(nullptr),
fIsDummy(false)
{
fLv2Buffer.size = 0;
fLv2Buffer.buf = nullptr;
}

~Lv2AtomRingBufferControl() noexcept
{
if (fLv2Buffer.buf != nullptr && ! fIsDummy)
{
delete[] fLv2Buffer.buf;
fLv2Buffer.buf = nullptr;
}
}

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

void createBuffer(const uint32_t size) noexcept
{
if (fLv2Buffer.size == size && ! fIsDummy)
return;

if (fLv2Buffer.buf != nullptr)
{
if (! fIsDummy)
delete[] fLv2Buffer.buf;
fLv2Buffer.buf = nullptr;
}

// shouldn't really happen please...
CARLA_SAFE_ASSERT_RETURN(size > 0,);

const uint32_t p2size(carla_nextPowerOf2(size));

try {
fLv2Buffer.buf = new char[p2size];
} CARLA_SAFE_EXCEPTION_RETURN("Lv2AtomRingBufferControl::createBuffer",);

fLv2Buffer.size = p2size;
setRingBuffer(&fLv2Buffer, true);
//lockMemory();
}

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

fLv2Buffer.buf = dumpBuf;
fLv2Buffer.size = rb.size;
fLv2Buffer.head = rb.head;
fLv2Buffer.tail = rb.tail;
fLv2Buffer.written = rb.written;
fLv2Buffer.invalidateCommit = rb.invalidateCommit;
fIsDummy = true;

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

setRingBuffer(&fLv2Buffer, false);
}

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

const LV2_Atom* readAtom(uint32_t* const portIndex) noexcept
{
fRetAtom.atom.size = 0;
fRetAtom.atom.type = 0;
tryRead(&fRetAtom.atom, sizeof(LV2_Atom));

if (fRetAtom.atom.size == 0 || fRetAtom.atom.type == 0)
return nullptr;

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

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

if (index < 0)
return nullptr;

if (portIndex != nullptr)
*portIndex = static_cast<uint32_t>(index);

carla_zeroChar(fRetAtom.data, fRetAtom.atom.size);
tryRead(fRetAtom.data, fRetAtom.atom.size);

return &fRetAtom.atom;
}

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

bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept
{
tryWrite(atom, sizeof(LV2_Atom));
tryWrite(&portIndex, sizeof(int32_t));
tryWrite(LV2_ATOM_BODY_CONST(atom), atom->size);
return commitWrite();
}

bool writeAtomChunk(const LV2_Atom* const atom, const void* const data, const int32_t portIndex) noexcept
{
tryWrite(atom, sizeof(LV2_Atom));
tryWrite(&portIndex, sizeof(int32_t));
tryWrite(data, atom->size);
return commitWrite();
}

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

private:
HeapBuffer fLv2Buffer;
bool fIsDummy;

static const size_t kMaxDataSize = 8192;

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

friend class Lv2AtomQueue;

CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(Lv2AtomRingBufferControl)
};

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

class Lv2AtomQueue
{
public:
Lv2AtomQueue() noexcept {}

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

void createBuffer(const uint32_t size) noexcept
{
fRingBufferCtrl.createBuffer(size);
}

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

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

bool isEmpty() const noexcept
{
return (fRingBufferCtrl.fLv2Buffer.buf == nullptr || !fRingBufferCtrl.isDataAvailable());
}

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

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

if (const LV2_Atom* const retAtom = fRingBufferCtrl.readAtom(portIndex))
{
*atom = retAtom;
return true;
}

return false;
}

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

const CarlaMutexLocker cml(fMutex);

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

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

const CarlaMutexLocker cml(fMutex);

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

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

void lock() const noexcept
{
fMutex.lock();
}

bool tryLock() const noexcept
{
return fMutex.tryLock();
}

void unlock() const noexcept
{
fMutex.unlock();
}

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

void copyDataFromQueue(Lv2AtomQueue& queue) noexcept
{
// lock source
const CarlaMutexLocker cml1(queue.fMutex);

{
// copy data from source
const CarlaMutexLocker cml2(fMutex);
fRingBufferCtrl.fLv2Buffer = queue.fRingBufferCtrl.fLv2Buffer;
}

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

// used for tmp buffers only
void copyAndDumpDataFromQueue(Lv2AtomQueue& queue, char dumpBuf[]) noexcept
{
// source is locked

{
// copy data from source
const CarlaMutexLocker cml2(fMutex);
fRingBufferCtrl.copyDump(queue.fRingBufferCtrl.fLv2Buffer, dumpBuf);
}

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

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

private:
CarlaMutex fMutex;
Lv2AtomRingBufferControl fRingBufferCtrl;

CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(Lv2AtomQueue)
};

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

#endif // LV2_ATOM_QUEUE_HPP_INCLUDED

+ 214
- 0
source/utils/Lv2AtomRingBuffer.hpp View File

@@ -0,0 +1,214 @@
/*
* LV2 Atom Ring Buffer
* 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
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/

#ifndef LV2_ATOM_RING_BUFFER_HPP_INCLUDED
#define LV2_ATOM_RING_BUFFER_HPP_INCLUDED

#include "CarlaMutex.hpp"
#include "CarlaRingBuffer.hpp"

#include "lv2/atom.h"

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

class Lv2AtomRingBuffer : public CarlaRingBuffer<HeapBuffer>
{
public:
Lv2AtomRingBuffer() noexcept
: CarlaRingBuffer<HeapBuffer>(),
fNeedsDataDelete(true)
{
carla_zeroStruct(fHeapBuffer);
}

Lv2AtomRingBuffer(Lv2AtomRingBuffer& ringBuf, uint8_t buf[]) noexcept
: CarlaRingBuffer<HeapBuffer>(),
fNeedsDataDelete(false)
{
fHeapBuffer.buf = buf;

{
const CarlaMutexLocker cml(ringBuf.fMutex);
fHeapBuffer.copyDataFrom(ringBuf.fHeapBuffer);
ringBuf.clear();
}

setRingBuffer(&fHeapBuffer, false);
}

~Lv2AtomRingBuffer() noexcept
{
if (fHeapBuffer.buf == nullptr || ! fNeedsDataDelete)
return;

delete[] fHeapBuffer.buf;
fHeapBuffer.buf = nullptr;
}

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

void createBuffer(const uint32_t size) noexcept
{
CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf == nullptr,);
CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);
CARLA_SAFE_ASSERT_RETURN(size > 0,);

const uint32_t p2size(carla_nextPowerOf2(size));

try {
fHeapBuffer.buf = new uint8_t[p2size];
} CARLA_SAFE_EXCEPTION_RETURN("Lv2AtomRingBuffer::createBuffer",);

fHeapBuffer.size = p2size;
setRingBuffer(&fHeapBuffer, true);
}

void deleteBuffer() noexcept
{
CARLA_SAFE_ASSERT_RETURN(fHeapBuffer.buf != nullptr,);
CARLA_SAFE_ASSERT_RETURN(fNeedsDataDelete,);

setRingBuffer(nullptr, false);

delete[] fHeapBuffer.buf;
fHeapBuffer.buf = nullptr;
fHeapBuffer.size = 0;
}

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

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

bool tryLock() const noexcept
{
return fMutex.tryLock();
}

void unlock() const noexcept
{
fMutex.unlock();
}

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

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

if (const LV2_Atom* const retAtom = readAtom(portIndex))
{
atom = retAtom;
return true;
}

return false;
}

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

const CarlaMutexLocker cml(fMutex);

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

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

const CarlaMutexLocker cml(fMutex);

return writeAtomChunk(atom, data, static_cast<int32_t>(portIndex));
}

protected:
// -------------------------------------------------------------------

const LV2_Atom* readAtom(uint32_t& portIndex) noexcept
{
fRetAtom.atom.size = 0;
fRetAtom.atom.type = 0;

if (! tryRead(&fRetAtom.atom, sizeof(LV2_Atom)))
return nullptr;
if (fRetAtom.atom.size == 0 || fRetAtom.atom.type == 0)
return nullptr;

CARLA_SAFE_ASSERT_RETURN(fRetAtom.atom.size < kMaxAtomDataSize, nullptr);

int32_t index = -1;
if (! tryRead(&index, sizeof(int32_t)))
return nullptr;
if (index < 0)
return nullptr;

if (! tryRead(fRetAtom.data, fRetAtom.atom.size))
return nullptr;

portIndex = static_cast<uint32_t>(index);
return &fRetAtom.atom;
}

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

bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept
{
tryWrite(atom, sizeof(LV2_Atom));
tryWrite(&portIndex, sizeof(int32_t));
tryWrite(LV2_ATOM_BODY_CONST(atom), atom->size);
return commitWrite();
}

bool writeAtomChunk(const LV2_Atom* const atom, const void* const data, const int32_t portIndex) noexcept
{
tryWrite(atom, sizeof(LV2_Atom));
tryWrite(&portIndex, sizeof(int32_t));
tryWrite(data, atom->size);
return commitWrite();
}

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

private:
CarlaMutex fMutex;
HeapBuffer fHeapBuffer;
const bool fNeedsDataDelete;

static const size_t kMaxAtomDataSize = 8192;

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

friend class Lv2AtomQueue;

CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(Lv2AtomRingBuffer)
};

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

#endif // LV2_ATOM_RING_BUFFER_HPP_INCLUDED

Loading…
Cancel
Save