summaryrefslogtreecommitdiff
path: root/src/audio
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio')
-rw-r--r--src/audio/audio.cc6
-rw-r--r--src/audio/audio.h6
-rw-r--r--src/audio/ring_buffer.cc5
-rw-r--r--src/audio/ring_buffer.h12
-rw-r--r--src/audio/tracker.cc10
5 files changed, 31 insertions, 8 deletions
diff --git a/src/audio/audio.cc b/src/audio/audio.cc
index 67345cf..74536e5 100644
--- a/src/audio/audio.cc
+++ b/src/audio/audio.cc
@@ -172,6 +172,12 @@ float audio_get_playback_time() {
(RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS);
}
+float audio_get_render_time() {
+ const int64_t total_samples = g_ring_buffer.get_total_written();
+ return (float)total_samples /
+ (RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS);
+}
+
float audio_get_realtime_peak() {
if (g_audio_backend == nullptr) {
return 0.0f;
diff --git a/src/audio/audio.h b/src/audio/audio.h
index 14fe615..e063a57 100644
--- a/src/audio/audio.h
+++ b/src/audio/audio.h
@@ -27,8 +27,14 @@ void audio_start(); // Starts the audio device callback
void audio_render_ahead(float music_time, float dt);
// Get current playback time (in seconds) based on samples consumed
+// This is the ring buffer READ position (what's being played NOW)
float audio_get_playback_time();
+// Get current render time (in seconds) based on samples written
+// This is the ring buffer WRITE position (where we're currently rendering)
+// Use this for calculating sample-accurate trigger offsets
+float audio_get_render_time();
+
// Get peak amplitude of samples currently being played (real-time sync)
// Returns: Peak amplitude in range [0.0, 1.0+]
// Use this for visual effects to ensure audio-visual synchronization
diff --git a/src/audio/ring_buffer.cc b/src/audio/ring_buffer.cc
index a7e5d9e..7cedb56 100644
--- a/src/audio/ring_buffer.cc
+++ b/src/audio/ring_buffer.cc
@@ -9,7 +9,7 @@
AudioRingBuffer::AudioRingBuffer()
: capacity_(RING_BUFFER_CAPACITY_SAMPLES), write_pos_(0), read_pos_(0),
- total_read_(0) {
+ total_read_(0), total_written_(0) {
memset(buffer_, 0, sizeof(buffer_));
}
@@ -81,6 +81,9 @@ int AudioRingBuffer::write(const float* samples, int count) {
write_pos_.store(remainder, std::memory_order_release);
}
+ // Track total samples written for render timing
+ total_written_.fetch_add(to_write, std::memory_order_release);
+
return to_write;
}
diff --git a/src/audio/ring_buffer.h b/src/audio/ring_buffer.h
index b19c1ea..324447a 100644
--- a/src/audio/ring_buffer.h
+++ b/src/audio/ring_buffer.h
@@ -42,6 +42,11 @@ class AudioRingBuffer {
return total_read_.load(std::memory_order_acquire);
}
+ // Get total samples written (for render timing)
+ int64_t get_total_written() const {
+ return total_written_.load(std::memory_order_acquire);
+ }
+
// Clear buffer (for seeking)
void clear();
@@ -49,7 +54,8 @@ class AudioRingBuffer {
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)
+ 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)
+ std::atomic<int64_t> total_written_; // Total samples written (for render timing)
};
diff --git a/src/audio/tracker.cc b/src/audio/tracker.cc
index 93a1c49..1cccc57 100644
--- a/src/audio/tracker.cc
+++ b/src/audio/tracker.cc
@@ -239,8 +239,9 @@ void tracker_update(float music_time_sec) {
}
// Step 2: Update all active patterns and trigger individual events
- // Get current audio playback position for sample-accurate timing
- const float current_playback_time = audio_get_playback_time();
+ // Get current audio RENDER position (write position) for sample-accurate timing
+ // This is where we're currently writing to the ring buffer (~400ms ahead of playback)
+ const float current_render_time = audio_get_render_time();
const float SAMPLE_RATE = 32000.0f; // Audio sample rate
for (int i = 0; i < MAX_SPECTROGRAMS; ++i) {
@@ -265,8 +266,9 @@ void tracker_update(float music_time_sec) {
const float event_trigger_time = active.start_music_time +
(event.unit_time * unit_duration_sec);
- // Calculate sample-accurate offset from current playback position
- const float time_delta = event_trigger_time - current_playback_time;
+ // Calculate sample-accurate offset from current RENDER position (write pos)
+ // This is where we're currently writing to the buffer, not where playback is
+ const float time_delta = event_trigger_time - current_render_time;
int sample_offset = (int)(time_delta * SAMPLE_RATE);
// Clamp to 0 if negative (event is late, play immediately)