summaryrefslogtreecommitdiff
path: root/src/audio/ring_buffer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio/ring_buffer.cc')
-rw-r--r--src/audio/ring_buffer.cc104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/audio/ring_buffer.cc b/src/audio/ring_buffer.cc
new file mode 100644
index 0000000..25cf853
--- /dev/null
+++ b/src/audio/ring_buffer.cc
@@ -0,0 +1,104 @@
+// This file is part of the 64k demo project.
+// It implements a lock-free ring buffer for audio streaming.
+
+#include "ring_buffer.h"
+#include <algorithm>
+#include <cstring>
+
+AudioRingBuffer::AudioRingBuffer()
+ : capacity_(RING_BUFFER_CAPACITY_SAMPLES),
+ write_pos_(0),
+ read_pos_(0),
+ total_read_(0) {
+ memset(buffer_, 0, sizeof(buffer_));
+}
+
+AudioRingBuffer::~AudioRingBuffer() {
+ // Nothing to clean up (static buffer)
+}
+
+int AudioRingBuffer::available_write() const {
+ const int write = write_pos_.load(std::memory_order_acquire);
+ const int read = read_pos_.load(std::memory_order_acquire);
+
+ if (write >= read) {
+ return capacity_ - (write - read) - 1; // -1 to avoid full/empty ambiguity
+ } else {
+ return read - write - 1;
+ }
+}
+
+int AudioRingBuffer::available_read() const {
+ const int write = write_pos_.load(std::memory_order_acquire);
+ const int read = read_pos_.load(std::memory_order_acquire);
+
+ if (write >= read) {
+ return write - read;
+ } else {
+ return capacity_ - (read - write);
+ }
+}
+
+int AudioRingBuffer::write(const float* samples, int count) {
+ const int avail = available_write();
+ const int to_write = std::min(count, avail);
+
+ if (to_write <= 0) {
+ return 0;
+ }
+
+ const int write = write_pos_.load(std::memory_order_acquire);
+ const int space_to_end = capacity_ - write;
+
+ if (to_write <= space_to_end) {
+ // Write in one chunk
+ memcpy(&buffer_[write], samples, to_write * sizeof(float));
+ write_pos_.store((write + to_write) % capacity_, std::memory_order_release);
+ } else {
+ // Write in two chunks (wrap around)
+ memcpy(&buffer_[write], samples, space_to_end * sizeof(float));
+ const int remainder = to_write - space_to_end;
+ memcpy(&buffer_[0], samples + space_to_end, remainder * sizeof(float));
+ write_pos_.store(remainder, std::memory_order_release);
+ }
+
+ return to_write;
+}
+
+int AudioRingBuffer::read(float* samples, int count) {
+ const int avail = available_read();
+ const int to_read = std::min(count, avail);
+
+ if (to_read > 0) {
+ const int read = read_pos_.load(std::memory_order_acquire);
+ const int space_to_end = capacity_ - read;
+
+ if (to_read <= space_to_end) {
+ // Read in one chunk
+ memcpy(samples, &buffer_[read], to_read * sizeof(float));
+ read_pos_.store((read + to_read) % capacity_, std::memory_order_release);
+ } else {
+ // Read in two chunks (wrap around)
+ memcpy(samples, &buffer_[read], space_to_end * sizeof(float));
+ const int remainder = to_read - space_to_end;
+ memcpy(samples + space_to_end, &buffer_[0], remainder * sizeof(float));
+ read_pos_.store(remainder, std::memory_order_release);
+ }
+
+ total_read_.fetch_add(to_read, std::memory_order_release);
+ }
+
+ // Fill remainder with silence if not enough samples available
+ if (to_read < count) {
+ memset(samples + to_read, 0, (count - to_read) * sizeof(float));
+ }
+
+ return to_read;
+}
+
+void AudioRingBuffer::clear() {
+ write_pos_.store(0, std::memory_order_release);
+ read_pos_.store(0, std::memory_order_release);
+ // Note: Don't reset total_read_ - it tracks absolute playback time
+ memset(buffer_, 0, sizeof(buffer_));
+}