| @@ -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 | |||||