/* * Carla Ring Buffer imported from dssi-vst code * Copyright (C) 2004-2010 Chris Cannam * Copyright (C) 2013 Filipe Coelho * * 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 GPL.txt file */ #ifndef __CARLA_RING_BUFFER_HPP__ #define __CARLA_RING_BUFFER_HPP__ #include "CarlaJuceUtils.hpp" #define RING_BUFFER_SIZE 2048 // ------------------------------------------------- // RingBuffer struct struct RingBuffer { int head, tail, written; bool invalidateCommit; char buf[RING_BUFFER_SIZE]; CARLA_DECLARE_NON_COPY_STRUCT(RingBuffer) }; // ------------------------------------------------- // RingBufferControl class class RingBufferControl { public: RingBufferControl(RingBuffer* const ringBuf) : fRingBuf(nullptr) { if (ringBuf != nullptr) setRingBuffer(ringBuf, true); } void setRingBuffer(RingBuffer* const ringBuf, const bool reset) { CARLA_ASSERT(ringBuf != nullptr); CARLA_ASSERT(ringBuf != fRingBuf); fRingBuf = ringBuf; if (! reset) return; fRingBuf->head = 0; fRingBuf->tail = 0; fRingBuf->written = 0; fRingBuf->invalidateCommit = false; carla_fill(fRingBuf->buf, RING_BUFFER_SIZE, 0); } // --------------------------------------------- void commitWrite() { CARLA_ASSERT(fRingBuf != nullptr); if (fRingBuf == nullptr) return; if (fRingBuf->invalidateCommit) { fRingBuf->written = fRingBuf->head; fRingBuf->invalidateCommit = false; } else { fRingBuf->head = fRingBuf->written; } } bool dataAvailable() const { CARLA_ASSERT(fRingBuf != nullptr); if (fRingBuf == nullptr) return false; return (fRingBuf->tail != fRingBuf->head); } // --------------------------------------------- template T read() { T t = 0; tryRead(&t, sizeof(T)); return t; } char readChar() { char c = 0; tryRead(&c, sizeof(char)); return c; } int readInt() { int i = 0; tryRead(&i, sizeof(int)); return i; } long readLong() { long l = 0; tryRead(&l, sizeof(long)); return l; } float readFloat() { float f = 0.0f; tryRead(&f, sizeof(float)); return f; } // --------------------------------------------- template void write(const T value) { tryWrite(&value, sizeof(T)); } void writeChar(const char value) { tryWrite(&value, sizeof(char)); } void writeInt(const int value) { tryWrite(&value, sizeof(int)); } void writeLong(const long value) { tryWrite(&value, sizeof(long)); } void writeFloat(const float value) { tryWrite(&value, sizeof(float)); } // --------------------------------------------- private: RingBuffer* fRingBuf; void tryRead(void* const buf, const size_t size) { CARLA_ASSERT(fRingBuf != nullptr); CARLA_ASSERT(buf != nullptr); CARLA_ASSERT(size != 0); if (fRingBuf == nullptr) return; if (buf == nullptr) return; if (size == 0) return; // this should not happen CARLA_ASSERT(fRingBuf->head >= 0); CARLA_ASSERT(fRingBuf->tail >= 0); CARLA_ASSERT(fRingBuf->written >= 0); char* const charbuf(static_cast(buf)); const size_t head(fRingBuf->head); const size_t tail(fRingBuf->tail); const size_t wrap((head <= tail) ? RING_BUFFER_SIZE : 0); if (head - tail + wrap < size) return; size_t readto = tail + size; if (readto >= RING_BUFFER_SIZE) { readto -= RING_BUFFER_SIZE; const size_t firstpart(RING_BUFFER_SIZE - tail); std::memcpy(charbuf, fRingBuf->buf + tail, firstpart); std::memcpy(charbuf + firstpart, fRingBuf->buf, readto); } else { std::memcpy(charbuf, fRingBuf->buf + tail, size); } fRingBuf->tail = readto; } void tryWrite(const void* const buf, const size_t size) { CARLA_ASSERT(fRingBuf != nullptr); CARLA_ASSERT(buf != nullptr); CARLA_ASSERT(size != 0); if (fRingBuf == nullptr) return; if (buf == nullptr) return; if (size == 0) return; const char* const charbuf(static_cast(buf)); const size_t tail(fRingBuf->tail); const size_t written(fRingBuf->written); const size_t wrap((tail <= written) ? RING_BUFFER_SIZE : 0); if (tail - written + wrap < size) { carla_stderr2("RingBufferControl::tryWrite() - buffer full!"); fRingBuf->invalidateCommit = true; return; } size_t writeto = written + size; if (writeto >= RING_BUFFER_SIZE) { writeto -= RING_BUFFER_SIZE; const size_t firstpart(RING_BUFFER_SIZE - written); std::memcpy(fRingBuf->buf + written, charbuf, firstpart); std::memcpy(fRingBuf->buf, charbuf + firstpart, writeto); } else { std::memcpy(fRingBuf->buf + written, charbuf, size); } fRingBuf->written = writeto; } }; // ------------------------------------------------- #endif // __CARLA_RING_BUFFER_HPP__