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