/* ============================================================================== CircularBuffer.h Created: 4 Nov 2025 6:20:15pm Author: mickl ============================================================================== */ #pragma once #include class CircularBuffer { public: CircularBuffer(int numChannels, int numSamples) : buffer(data, (size_t)numChannels, (size_t)numSamples) { } template void push(dsp::AudioBlock b) { jassert(b.getNumChannels() == buffer.getNumChannels()); const auto trimmed = b.getSubBlock(b.getNumSamples() - std::min(b.getNumSamples(), buffer.getNumSamples())); const auto bufferLength = (int64)buffer.getNumSamples(); for (auto samplesRemaining = (int64)trimmed.getNumSamples(); samplesRemaining > 0;) { const auto writeOffset = writeIx % bufferLength; const auto numSamplesToWrite = std::min(samplesRemaining, bufferLength - writeOffset); auto destSubBlock = buffer.getSubBlock((size_t)writeOffset, (size_t)numSamplesToWrite); const auto sourceSubBlock = trimmed.getSubBlock(trimmed.getNumSamples() - (size_t)samplesRemaining, (size_t)numSamplesToWrite); destSubBlock.copyFrom(sourceSubBlock); samplesRemaining -= numSamplesToWrite; writeIx += numSamplesToWrite; } } template void push(Span s) { auto* ptr = s.begin(); dsp::AudioBlock b(&ptr, 1, s.size()); push(b); } void read(int64 readIx, dsp::AudioBlock output) const { const auto numChannelsToUse = std::min(buffer.getNumChannels(), output.getNumChannels()); jassert(output.getNumChannels() == buffer.getNumChannels()); const auto bufferLength = (int64)buffer.getNumSamples(); for (auto outputOffset = (size_t)0; outputOffset < output.getNumSamples();) { const auto inputOffset = (size_t)((readIx + (int64)outputOffset) % bufferLength); const auto numSamplesToRead = std::min(output.getNumSamples() - outputOffset, (size_t)bufferLength - inputOffset); auto destSubBlock = output.getSubBlock(outputOffset, numSamplesToRead) .getSubsetChannelBlock(0, numChannelsToUse); destSubBlock.copyFrom(buffer.getSubBlock(inputOffset, numSamplesToRead) .getSubsetChannelBlock(0, numChannelsToUse)); outputOffset += numSamplesToRead; } } int64 getWriteIndex() const noexcept { return writeIx; } private: HeapBlock data; dsp::AudioBlock buffer; int64 writeIx = 0; };