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