summaryrefslogtreecommitdiff
path: root/src/audio/ring_buffer.h
blob: d6c41ce3f0aa9bb19eefbc134b2b3c3df2ed1b11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// This file is part of the 64k demo project.
// It implements a lock-free ring buffer for audio streaming.
// Bridges main thread (variable tempo) and audio thread (fixed rate).

#pragma once

#include <atomic>
#include <cstdint>

// Ring buffer capacity: 200ms @ 32kHz stereo
// = 200ms * 32000 samples/sec * 2 channels / 1000ms = 12800 samples
// This is exactly 25 DCT frames (25 * 512 = 12800)
#define RING_BUFFER_LOOKAHEAD_MS 200
#define RING_BUFFER_SAMPLE_RATE 32000
#define RING_BUFFER_CHANNELS 2
#define RING_BUFFER_CAPACITY_SAMPLES \
  ((RING_BUFFER_LOOKAHEAD_MS * RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS) / 1000)

class AudioRingBuffer {
 public:
  AudioRingBuffer();
  ~AudioRingBuffer();

  // Thread-safe write (main thread)
  // Returns number of samples actually written
  int write(const float* samples, int count);

  // Thread-safe read (audio thread)
  // Returns number of samples actually read
  // If not enough samples available, fills remainder with silence
  int read(float* samples, int count);

  // Query buffer state
  int available_write() const;  // Samples that can be written
  int available_read() const;   // Samples that can be read

  // Get total samples consumed (for timing)
  int64_t get_total_read() const { return total_read_.load(std::memory_order_acquire); }

  // Clear buffer (for seeking)
  void clear();

 private:
  float buffer_[RING_BUFFER_CAPACITY_SAMPLES];
  int capacity_;  // Total capacity in samples

  std::atomic<int> write_pos_;  // Write position (0 to capacity-1)
  std::atomic<int> read_pos_;   // Read position (0 to capacity-1)
  std::atomic<int64_t> total_read_;  // Total samples read (for playback time)
};