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