| @@ -151,13 +151,13 @@ struct BridgeAudioPool { | |||
| } | |||
| }; | |||
| struct BridgeControl : public RingBufferControl { | |||
| struct BridgeControl : public RingBufferControlTemplate<StackRingBuffer> { | |||
| CarlaString filename; | |||
| BridgeShmControl* data; | |||
| shm_t shm; | |||
| BridgeControl() | |||
| : RingBufferControl(nullptr), | |||
| : RingBufferControlTemplate(nullptr), | |||
| data(nullptr) | |||
| { | |||
| carla_shm_init(shm); | |||
| @@ -1204,36 +1204,39 @@ public: | |||
| void idle() override | |||
| { | |||
| #if 0 | |||
| if (fUi.type == UI::TYPE_NULL) | |||
| return CarlaPlugin::idle(); | |||
| if (! fAtomQueueOut.isEmpty()) | |||
| { | |||
| char dumpBuf[fAtomQueueOut.getSize()]; | |||
| Lv2AtomQueue tmpQueue; | |||
| tmpQueue.copyDataFrom(&fAtomQueueOut); | |||
| tmpQueue.copyAndDumpDataFromQueue(fAtomQueueOut, dumpBuf); | |||
| uint32_t portIndex; | |||
| const LV2_Atom* atom; | |||
| const bool hasPortEvent(fUi.handle != nullptr && fUi.descriptor != nullptr && fUi.descriptor->port_event != nullptr); | |||
| while (tmpQueue.get(&portIndex, &atom)) | |||
| for (; tmpQueue.get(&atom, &portIndex);) | |||
| { | |||
| //carla_stdout("OUTPUT message IN GUI REMOVED FROM BUFFER"); | |||
| carla_stdout("OUTPUT message IN GUI REMOVED FROM BUFFER"); | |||
| if (fUi.type == PLUGIN_UI_OSC) | |||
| if (fUi.type == UI::TYPE_OSC) | |||
| { | |||
| if (pData->osc.data.target != nullptr) | |||
| { | |||
| QByteArray chunk((const char*)atom, lv2_atom_total_size(atom)); | |||
| osc_send_lv2_atom_transfer(&pData->osc.data, portIndex, chunk.toBase64().constData()); | |||
| QByteArray chunk((const char*)atom, static_cast<int>(lv2_atom_total_size(atom))); | |||
| osc_send_lv2_atom_transfer(pData->osc.data, portIndex, chunk.toBase64().constData()); | |||
| } | |||
| } | |||
| else if (fUi.type != PLUGIN_UI_NULL) | |||
| else | |||
| { | |||
| if (hasPortEvent) | |||
| fUi.descriptor->port_event(fUi.handle, portIndex, lv2_atom_total_size(atom), CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT, atom); | |||
| } | |||
| } | |||
| } | |||
| #endif | |||
| if (fUi.handle != nullptr && fUi.descriptor != nullptr) | |||
| { | |||
| @@ -2507,26 +2510,24 @@ public: | |||
| // ---------------------------------------------------------------------------------------------------- | |||
| // Message Input | |||
| #if 0 | |||
| if (fAtomQueueIn.tryLock()) | |||
| { | |||
| if (! fAtomQueueIn.isEmpty()) | |||
| { | |||
| uint32_t portIndex; | |||
| const LV2_Atom* atom; | |||
| uint32_t portIndex; | |||
| k = fEventsIn.ctrlIndex; | |||
| const uint32_t j = fEventsIn.ctrlIndex; | |||
| while (fAtomQueueIn.get(&portIndex, &atom)) | |||
| for (; fAtomQueueIn.get(&atom, &portIndex);) | |||
| { | |||
| carla_debug("Event input message sent to plugin DSP, type %i:\"%s\", size:%i/%i", | |||
| atom->type, carla_lv2_urid_unmap(this, atom->type), | |||
| atom->size, lv2_atom_total_size(atom) | |||
| ); | |||
| atom->size, lv2_atom_total_size(atom)); | |||
| if (! lv2_atom_buffer_write(&evInAtomIters[k], 0, 0, atom->type, atom->size, LV2NV_ATOM_BODY_CONST(atom))) | |||
| if (! lv2_atom_buffer_write(&evInAtomIters[j], 0, 0, atom->type, atom->size, LV2_ATOM_BODY_CONST(atom))) | |||
| { | |||
| carla_stdout("Event input buffer full, 1 message lost"); | |||
| carla_stdout("Event input buffer full, at least 1 message lost"); | |||
| break; | |||
| } | |||
| } | |||
| @@ -2534,7 +2535,6 @@ public: | |||
| fAtomQueueIn.unlock(); | |||
| } | |||
| #endif | |||
| // ---------------------------------------------------------------------------------------------------- | |||
| // MIDI Input (External) | |||
| @@ -2912,7 +2912,6 @@ public: | |||
| { | |||
| if (fEventsOut.ctrl->type & CARLA_EVENT_DATA_ATOM) | |||
| { | |||
| //const uint32_t rindex(fEventsOut.ctrl->rindex); | |||
| const LV2_Atom_Event* ev; | |||
| LV2_Atom_Buffer_Iterator iter; | |||
| @@ -2932,12 +2931,11 @@ public: | |||
| if (fEventsOut.ctrl->port != nullptr && ev->time.frames >= 0 && ev->body.size <= 0xFF) | |||
| fEventsOut.ctrl->port->writeMidiEvent(static_cast<uint32_t>(ev->time.frames), static_cast<uint8_t>(ev->body.size), data); | |||
| } | |||
| #if 0 | |||
| else if (ev->body.type == CARLA_URI_MAP_ID_ATOM_BLANK) | |||
| { | |||
| fAtomQueueOut.put(rindex, &ev->body); | |||
| fAtomQueueOut.put(&ev->body, fEventsOut.ctrl->rindex); | |||
| } | |||
| #endif | |||
| lv2_atom_buffer_increment(&iter); | |||
| } | |||
| } | |||
| @@ -3938,9 +3936,9 @@ public: | |||
| case CARLA_URI_MAP_ID_ATOM_TRANSFER_ATOM: | |||
| case CARLA_URI_MAP_ID_ATOM_TRANSFER_EVENT: | |||
| #if 0 | |||
| fAtomQueueIn.put(rindex, (const LV2_Atom*)buffer); | |||
| #endif | |||
| CARLA_SAFE_ASSERT_RETURN(((const LV2_Atom*)buffer)->size == bufferSize,); | |||
| fAtomQueueIn.put((const LV2_Atom*)buffer, rindex); | |||
| break; | |||
| default: | |||
| @@ -4633,10 +4631,7 @@ public: | |||
| CARLA_SAFE_ASSERT_RETURN(atom != nullptr,); | |||
| carla_debug("Lv2Plugin::handleTransferAtom(%i, %p)", portIndex, atom); | |||
| #if 0 | |||
| fAtomQueueIn.put(portIndex, atom); | |||
| #endif | |||
| return; (void)portIndex; | |||
| fAtomQueueIn.put(atom, portIndex); | |||
| } | |||
| void handleUridMap(const LV2_URID urid, const char* const uri) | |||
| @@ -4662,10 +4657,8 @@ private: | |||
| float** fAudioOutBuffers; | |||
| float* fParamBuffers; | |||
| #if 0 | |||
| Lv2AtomQueue fAtomQueueIn; | |||
| Lv2AtomQueue fAtomQueueOut; | |||
| #endif | |||
| LV2_Atom_Forge fAtomForge; | |||
| Lv2PluginEventData fEventsIn; | |||
| @@ -79,7 +79,7 @@ struct BridgeShmControl { | |||
| void* runClient; | |||
| char _padClient[32]; | |||
| }; | |||
| RingBuffer ringBuffer; | |||
| StackRingBuffer ringBuffer; | |||
| } POST_PACKED_STRUCTURE; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -1,6 +1,5 @@ | |||
| /* | |||
| * Carla Ring Buffer based on dssi-vst code | |||
| * Copyright (C) 2004-2010 Chris Cannam <cannam@all-day-breakfast.com> | |||
| * Carla Ring Buffer | |||
| * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| @@ -21,26 +20,45 @@ | |||
| #include "CarlaUtils.hpp" | |||
| //#ifndef RING_BUFFER_SIZE | |||
| #define RING_BUFFER_SIZE 2048 | |||
| //#endif | |||
| // ----------------------------------------------------------------------- | |||
| // RingBuffer struct | |||
| // RingBuffer structs | |||
| struct HeapRingBuffer { | |||
| uint32_t size; | |||
| int32_t head, tail, written; | |||
| bool invalidateCommit; | |||
| char* buf; | |||
| HeapRingBuffer& operator=(const HeapRingBuffer& rb) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(size == rb.size, *this); | |||
| size = rb.size; | |||
| head = rb.head; | |||
| tail = rb.tail; | |||
| written = rb.written; | |||
| invalidateCommit = rb.invalidateCommit; | |||
| std::memcpy(buf, rb.buf, size); | |||
| struct RingBuffer { | |||
| return *this; | |||
| } | |||
| }; | |||
| struct StackRingBuffer { | |||
| static const uint32_t size = 2048; | |||
| int32_t head, tail, written; | |||
| bool invalidateCommit; | |||
| char buf[RING_BUFFER_SIZE]; | |||
| char buf[size]; | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // RingBufferControl class | |||
| // RingBufferControl templated class | |||
| class RingBufferControl | |||
| template <class RingBufferStruct> | |||
| class RingBufferControlTemplate | |||
| { | |||
| public: | |||
| RingBufferControl(RingBuffer* const ringBuf) noexcept | |||
| RingBufferControlTemplate(RingBufferStruct* const ringBuf) noexcept | |||
| : fRingBuf(ringBuf) | |||
| { | |||
| if (ringBuf != nullptr) | |||
| @@ -55,10 +73,12 @@ public: | |||
| fRingBuf->tail = 0; | |||
| fRingBuf->written = 0; | |||
| fRingBuf->invalidateCommit = false; | |||
| carla_zeroChar(fRingBuf->buf, RING_BUFFER_SIZE); | |||
| if (fRingBuf->size > 0) | |||
| carla_zeroChar(fRingBuf->buf, fRingBuf->size); | |||
| } | |||
| void setRingBuffer(RingBuffer* const ringBuf, const bool reset) noexcept | |||
| void setRingBuffer(RingBufferStruct* const ringBuf, const bool reset) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(ringBuf != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(ringBuf != fRingBuf,); | |||
| @@ -155,6 +175,7 @@ protected: | |||
| CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(buf != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(size != 0,); | |||
| CARLA_SAFE_ASSERT_RETURN(size < fRingBuf->size,); | |||
| // this should not happen | |||
| CARLA_ASSERT(fRingBuf->head >= 0); | |||
| @@ -169,7 +190,7 @@ protected: | |||
| const size_t head(static_cast<size_t>(fRingBuf->head)); | |||
| const size_t tail(static_cast<size_t>(fRingBuf->tail)); | |||
| const size_t wrap((head < tail) ? RING_BUFFER_SIZE : 0); | |||
| const size_t wrap((head < tail) ? fRingBuf->size : 0); | |||
| if (head - tail + wrap < size) | |||
| { | |||
| @@ -179,10 +200,10 @@ protected: | |||
| size_t readto = tail + size; | |||
| if (readto >= RING_BUFFER_SIZE) | |||
| if (readto >= fRingBuf->size) | |||
| { | |||
| readto -= RING_BUFFER_SIZE; | |||
| const size_t firstpart(RING_BUFFER_SIZE - tail); | |||
| readto -= fRingBuf->size; | |||
| const size_t firstpart(fRingBuf->size - tail); | |||
| std::memcpy(charbuf, fRingBuf->buf + tail, firstpart); | |||
| std::memcpy(charbuf + firstpart, fRingBuf->buf, readto); | |||
| } | |||
| @@ -199,6 +220,7 @@ protected: | |||
| CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(buf != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(size != 0,); | |||
| CARLA_SAFE_ASSERT_RETURN(size < fRingBuf->size,); | |||
| // this should not happen | |||
| CARLA_ASSERT(fRingBuf->head >= 0); | |||
| @@ -209,7 +231,7 @@ protected: | |||
| const size_t tail(static_cast<size_t>(fRingBuf->tail)); | |||
| const size_t wrtn(static_cast<size_t>(fRingBuf->written)); | |||
| const size_t wrap((tail <= wrtn) ? RING_BUFFER_SIZE : 0); | |||
| const size_t wrap((tail <= wrtn) ? fRingBuf->size : 0); | |||
| if (tail - wrtn + wrap <= size) | |||
| { | |||
| @@ -220,10 +242,10 @@ protected: | |||
| size_t writeto = wrtn + size; | |||
| if (writeto >= RING_BUFFER_SIZE) | |||
| if (writeto >= fRingBuf->size) | |||
| { | |||
| writeto -= RING_BUFFER_SIZE; | |||
| const size_t firstpart(RING_BUFFER_SIZE - wrtn); | |||
| writeto -= fRingBuf->size; | |||
| const size_t firstpart(fRingBuf->size - wrtn); | |||
| std::memcpy(fRingBuf->buf + wrtn, charbuf, firstpart); | |||
| std::memcpy(fRingBuf->buf, charbuf + firstpart, writeto); | |||
| } | |||
| @@ -236,10 +258,10 @@ protected: | |||
| } | |||
| private: | |||
| RingBuffer* fRingBuf; | |||
| RingBufferStruct* fRingBuf; | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| CARLA_DECLARE_NON_COPY_CLASS(RingBufferControl) | |||
| CARLA_DECLARE_NON_COPY_CLASS(RingBufferControlTemplate) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * Simple Queue, specially developed for Atom types | |||
| * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
| * 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 | |||
| @@ -25,17 +25,47 @@ | |||
| // ----------------------------------------------------------------------- | |||
| class Lv2AtomRingBufferControl : public RingBufferControl | |||
| class Lv2AtomRingBufferControl : public RingBufferControlTemplate<HeapRingBuffer> | |||
| { | |||
| public: | |||
| Lv2AtomRingBufferControl() | |||
| : RingBufferControl(&fBuffer) | |||
| : RingBufferControlTemplate(nullptr) | |||
| { | |||
| fBuffer.size = 0; | |||
| fBuffer.buf = nullptr; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| const LV2_Atom* readAtom(uint32_t* const portIndex) | |||
| void createBuffer(const uint32_t size) | |||
| { | |||
| if (fBuffer.buf != nullptr) | |||
| delete[] fBuffer.buf; | |||
| fBuffer.size = size; | |||
| fBuffer.buf = new char[size]; | |||
| setRingBuffer(&fBuffer, true); | |||
| } | |||
| // used for tmp buffers only | |||
| void copyDump(HeapRingBuffer& rb, char dumpBuf[]) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer.size == 0,); | |||
| CARLA_SAFE_ASSERT_RETURN(fBuffer.buf == nullptr,); | |||
| fBuffer.buf = dumpBuf; | |||
| fBuffer.size = rb.size; | |||
| fBuffer.head = rb.head; | |||
| fBuffer.tail = rb.tail; | |||
| fBuffer.written = rb.written; | |||
| fBuffer.invalidateCommit = rb.invalidateCommit; | |||
| std::memcpy(dumpBuf, rb.buf, rb.size); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| const LV2_Atom* readAtom(uint32_t* const portIndex) noexcept | |||
| { | |||
| fRetAtom.atom.size = 0; | |||
| fRetAtom.atom.type = 0; | |||
| @@ -44,12 +74,12 @@ public: | |||
| if (fRetAtom.atom.size == 0 || fRetAtom.atom.type == 0) | |||
| return nullptr; | |||
| CARLA_SAFE_ASSERT_RETURN(fRetAtom.atom.size < RING_BUFFER_SIZE, nullptr); | |||
| CARLA_SAFE_ASSERT_RETURN(fRetAtom.atom.size < kMaxDataSize, nullptr); | |||
| int32_t index = -1; | |||
| tryRead(&index, sizeof(int32_t)); | |||
| if (index == -1) | |||
| if (index < 0) | |||
| return nullptr; | |||
| if (portIndex != nullptr) | |||
| @@ -63,7 +93,7 @@ public: | |||
| // ------------------------------------------------------------------- | |||
| bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) | |||
| bool writeAtom(const LV2_Atom* const atom, const int32_t portIndex) noexcept | |||
| { | |||
| tryWrite(atom, sizeof(LV2_Atom)); | |||
| tryWrite(&portIndex, sizeof(int32_t)); | |||
| @@ -74,11 +104,13 @@ public: | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| RingBuffer fBuffer; | |||
| HeapRingBuffer fBuffer; | |||
| static const size_t kMaxDataSize = 2048; | |||
| struct RetAtom { | |||
| LV2_Atom atom; | |||
| char data[RING_BUFFER_SIZE]; | |||
| char data[kMaxDataSize]; | |||
| } fRetAtom; | |||
| friend class Lv2AtomQueue; | |||
| @@ -96,21 +128,54 @@ public: | |||
| { | |||
| } | |||
| void copyDataFromQueue(Lv2AtomQueue& queue) | |||
| // ------------------------------------------------------------------- | |||
| void createBuffer(const uint32_t size) | |||
| { | |||
| // lock queue | |||
| const CarlaMutex::ScopedLocker qsl(queue.fMutex); | |||
| fRingBufferCtrl.createBuffer(size); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| uint32_t getSize() const noexcept | |||
| { | |||
| return fRingBufferCtrl.fBuffer.size; | |||
| } | |||
| bool isEmpty() const noexcept | |||
| { | |||
| return !fRingBufferCtrl.isDataAvailable(); | |||
| } | |||
| // must have been locked before | |||
| bool get(const LV2_Atom** const atom, uint32_t* const portIndex) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(atom != nullptr && portIndex != nullptr, false); | |||
| if (! fRingBufferCtrl.isDataAvailable()) | |||
| return false; | |||
| if (const LV2_Atom* retAtom = fRingBufferCtrl.readAtom(portIndex)) | |||
| { | |||
| // copy data from queue | |||
| const CarlaMutex::ScopedLocker sl(fMutex); | |||
| carla_copyStruct<RingBuffer>(fRingBufferCtrl.fBuffer, queue.fRingBufferCtrl.fBuffer); | |||
| *atom = retAtom; | |||
| return true; | |||
| } | |||
| // reset queque - FIXME? no queue.? | |||
| queue.fRingBufferCtrl.clear(); | |||
| return false; | |||
| } | |||
| // must NOT been locked, we do that here | |||
| bool put(const LV2_Atom* const atom, const uint32_t portIndex) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false); | |||
| const CarlaMutex::ScopedLocker sl(fMutex); | |||
| return fRingBufferCtrl.writeAtom(atom, static_cast<int32_t>(portIndex)); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| void lock() const noexcept | |||
| { | |||
| fMutex.lock(); | |||
| @@ -126,33 +191,40 @@ public: | |||
| fMutex.unlock(); | |||
| } | |||
| bool put(const LV2_Atom* const atom, const uint32_t portIndex) | |||
| // ------------------------------------------------------------------- | |||
| void copyDataFromQueue(Lv2AtomQueue& queue) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false); | |||
| // lock source | |||
| const CarlaMutex::ScopedLocker qsl(queue.fMutex); | |||
| const CarlaMutex::ScopedLocker sl(fMutex); | |||
| { | |||
| // copy data from source | |||
| const CarlaMutex::ScopedLocker sl(fMutex); | |||
| fRingBufferCtrl.fBuffer = queue.fRingBufferCtrl.fBuffer; | |||
| } | |||
| return fRingBufferCtrl.writeAtom(atom, static_cast<int32_t>(portIndex)); | |||
| // clear source | |||
| queue.fRingBufferCtrl.clear(); | |||
| } | |||
| bool get(const LV2_Atom** const atom, uint32_t* const portIndex) | |||
| void copyAndDumpDataFromQueue(Lv2AtomQueue& queue, char dumpBuf[]) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(atom != nullptr && portIndex != nullptr, false); | |||
| const CarlaMutex::ScopedLocker sl(fMutex); | |||
| if (! fRingBufferCtrl.isDataAvailable()) | |||
| return false; | |||
| // lock source | |||
| const CarlaMutex::ScopedLocker qsl(queue.fMutex); | |||
| if (const LV2_Atom* retAtom = fRingBufferCtrl.readAtom(portIndex)) | |||
| { | |||
| *atom = retAtom; | |||
| return true; | |||
| // copy data from source | |||
| const CarlaMutex::ScopedLocker sl(fMutex); | |||
| fRingBufferCtrl.copyDump(queue.fRingBufferCtrl.fBuffer, dumpBuf); | |||
| } | |||
| return false; | |||
| // clear source | |||
| queue.fRingBufferCtrl.clear(); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| private: | |||
| CarlaMutex fMutex; | |||
| Lv2AtomRingBufferControl fRingBufferCtrl; | |||