@@ -1288,21 +1288,18 @@ public: | |||||
void idle() override | 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; | uint32_t portIndex; | ||||
const LV2_Atom* atom; | const LV2_Atom* atom; | ||||
const bool hasPortEvent(fUi.handle != nullptr && fUi.descriptor != nullptr && fUi.descriptor->port_event != nullptr); | 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) | if (atom->type == CARLA_URI_MAP_ID_CARLA_ATOM_WORKER) | ||||
{ | { | ||||
@@ -1313,14 +1310,14 @@ public: | |||||
{ | { | ||||
if (pData->osc.data.target != nullptr) | 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()); | osc_send_lv2_atom_transfer(pData->osc.data, portIndex, chunk.toBase64().constData()); | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
if (hasPortEvent) | 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)) | 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)) | 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) | if (fEventsIn.ctrl != nullptr && fEventsIn.ctrl->port == nullptr) | ||||
fEventsIn.ctrl->port = pData->event.portIn; | fEventsIn.ctrl->port = pData->event.portIn; | ||||
@@ -2738,14 +2735,14 @@ public: | |||||
// ---------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------- | ||||
// Message Input | // Message Input | ||||
if (fAtomQueueIn.tryLock()) | |||||
if (fAtomBufferIn.tryLock()) | |||||
{ | { | ||||
if (! fAtomQueueIn.isEmpty()) | |||||
if (fAtomBufferIn.isDataAvailableForReading()) | |||||
{ | { | ||||
const LV2_Atom* atom; | const LV2_Atom* atom; | ||||
uint32_t j, portIndex; | uint32_t j, portIndex; | ||||
for (; fAtomQueueIn.get(&atom, &portIndex);) | |||||
for (; fAtomBufferIn.get(atom, portIndex);) | |||||
{ | { | ||||
j = (portIndex < fEventsIn.count) ? portIndex : fEventsIn.ctrlIndex; | 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) | 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)); | //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); | lv2_atom_buffer_increment(&iter); | ||||
@@ -4214,7 +4211,7 @@ public: | |||||
atom.size = size; | atom.size = size; | ||||
atom.type = CARLA_URI_MAP_ID_CARLA_ATOM_WORKER; | 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) | LV2_Worker_Status handleWorkerRespond(const uint32_t size, const void* const data) | ||||
@@ -4225,7 +4222,7 @@ public: | |||||
atom.size = size; | atom.size = size; | ||||
atom.type = CARLA_URI_MAP_ID_CARLA_ATOM_WORKER; | 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; | index = fEventsIn.ctrlIndex; | ||||
} | } | ||||
fAtomQueueIn.put(atom, index); | |||||
fAtomBufferIn.put(atom, index); | |||||
} break; | } break; | ||||
default: | default: | ||||
@@ -5187,7 +5184,7 @@ public: | |||||
CARLA_SAFE_ASSERT_RETURN(atom != nullptr,); | CARLA_SAFE_ASSERT_RETURN(atom != nullptr,); | ||||
carla_stdout("Lv2Plugin::handleTransferAtom(%i, %p)", portIndex, atom); | 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) | void handleUridMap(const LV2_URID urid, const char* const uri) | ||||
@@ -5231,9 +5228,9 @@ private: | |||||
bool fLatencyChanged; | bool fLatencyChanged; | ||||
int32_t fLatencyIndex; // -1 if invalid | 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 fCvIn; | ||||
PluginCVData fCvOut; | PluginCVData fCvOut; | ||||
@@ -27,13 +27,13 @@ static void test_CarlaRingBuffer1(CarlaRingBuffer<BufferStruct>& b) noexcept | |||||
assert(b.isEmpty()); | assert(b.isEmpty()); | ||||
// write all types | // 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 | // should be considered empty until a commitWrite | ||||
assert(b.isEmpty()); | assert(b.isEmpty()); | ||||
@@ -88,7 +88,7 @@ static void test_CarlaRingBuffer2(CarlaRingBuffer<BufferStruct>& b) noexcept | |||||
// write unmodified | // write unmodified | ||||
BufferTestStruct t1, t2; | BufferTestStruct t1, t2; | ||||
assert(t1 == t2); | assert(t1 == t2); | ||||
assert(b.writeCustomType(t1)); | |||||
b.writeCustomType(t1); | |||||
assert(b.commitWrite()); | assert(b.commitWrite()); | ||||
// test read | // test read | ||||
@@ -96,7 +96,7 @@ static void test_CarlaRingBuffer2(CarlaRingBuffer<BufferStruct>& b) noexcept | |||||
assert(t1 == t2); | assert(t1 == t2); | ||||
// modify t1 | // modify t1 | ||||
assert(b.writeCustomType(t1)); | |||||
b.writeCustomType(t1); | |||||
assert(b.commitWrite()); | assert(b.commitWrite()); | ||||
carla_zeroStruct(t1); | carla_zeroStruct(t1); | ||||
@@ -134,7 +134,7 @@ static void test_CarlaRingBuffer3(CarlaRingBuffer<BufferStruct>& b) noexcept | |||||
assert(b.isEmpty()); | assert(b.isEmpty()); | ||||
// write big chunk | // write big chunk | ||||
assert(b.writeCustomData(kLicense, kLicenseSize)); | |||||
b.writeCustomData(kLicense, kLicenseSize); | |||||
// still empty | // still empty | ||||
assert(b.isEmpty()); | assert(b.isEmpty()); | ||||
@@ -39,7 +39,10 @@ | |||||
#include "CarlaBridgeUtils.hpp" | #include "CarlaBridgeUtils.hpp" | ||||
#include "CarlaJuceUtils.hpp" | #include "CarlaJuceUtils.hpp" | ||||
#include "CarlaLibCounter.hpp" | #include "CarlaLibCounter.hpp" | ||||
#include "CarlaOscUtils.hpp" | |||||
#include "CarlaOscUtils.hpp" // TODO | |||||
#include "CarlaPatchbayUtils.hpp" // TODO | |||||
// #include "CarlaPipeUtils.hpp" | |||||
// #include "CarlaStateUtils.hpp" | |||||
#include "CarlaShmUtils.hpp" | #include "CarlaShmUtils.hpp" | ||||
// used in dssi utils | // used in dssi utils | ||||
@@ -48,10 +51,6 @@ | |||||
#include <QtCore/QFileInfo> | #include <QtCore/QFileInfo> | ||||
#include <QtCore/QStringList> | #include <QtCore/QStringList> | ||||
// #include "CarlaPatchbayUtils.hpp" | |||||
// #include "CarlaPipeUtils.hpp" | |||||
// #include "CarlaStateUtils.hpp" | |||||
#if 0 | #if 0 | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -123,14 +123,14 @@ public: | |||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false); | ||||
return (fBuffer->head != fBuffer->tail); | |||||
return (fBuffer->buf != nullptr && fBuffer->head != fBuffer->tail); | |||||
} | } | ||||
bool isEmpty() const noexcept | bool isEmpty() const noexcept | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false); | 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> | 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 | bool tryRead(void* const buf, const std::size_t size) noexcept | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(fBuffer != nullptr, false); | ||||
@@ -324,12 +321,12 @@ private: | |||||
return true; | 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)); | 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); | carla_stderr2("CarlaRingBuffer::tryWrite(%p, " P_SIZE "): failed, not enough space", buf, size); | ||||
fBuffer->invalidateCommit = true; | fBuffer->invalidateCommit = true; | ||||
return false; | |||||
return; | |||||
} | } | ||||
std::size_t writeto(wrtn + size); | std::size_t writeto(wrtn + size); | ||||
@@ -362,9 +359,11 @@ private: | |||||
} | } | ||||
fBuffer->wrtn = writeto; | fBuffer->wrtn = writeto; | ||||
return true; | |||||
} | } | ||||
private: | |||||
BufferStruct* fBuffer; | |||||
CARLA_PREVENT_HEAP_ALLOCATION | CARLA_PREVENT_HEAP_ALLOCATION | ||||
CARLA_DECLARE_NON_COPY_CLASS(CarlaRingBuffer) | CARLA_DECLARE_NON_COPY_CLASS(CarlaRingBuffer) | ||||
}; | }; | ||||
@@ -376,7 +375,10 @@ class CarlaHeapRingBuffer : public CarlaRingBuffer<HeapBuffer> | |||||
{ | { | ||||
public: | public: | ||||
CarlaHeapRingBuffer() noexcept | CarlaHeapRingBuffer() noexcept | ||||
: CarlaRingBuffer<HeapBuffer>() {} | |||||
: CarlaRingBuffer<HeapBuffer>() | |||||
{ | |||||
carla_zeroStruct(fHeapBuffer); | |||||
} | |||||
~CarlaHeapRingBuffer() noexcept | ~CarlaHeapRingBuffer() noexcept | ||||
{ | { | ||||
@@ -387,13 +389,18 @@ public: | |||||
fHeapBuffer.buf = nullptr; | 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,); | 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); | 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 |