summaryrefslogtreecommitdiff
path: root/src/audio
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio')
-rw-r--r--src/audio/audio.cc30
-rw-r--r--src/audio/audio.h6
-rw-r--r--src/audio/tracker.cc13
3 files changed, 48 insertions, 1 deletions
diff --git a/src/audio/audio.cc b/src/audio/audio.cc
index d044b00..a220fbb 100644
--- a/src/audio/audio.cc
+++ b/src/audio/audio.cc
@@ -57,11 +57,35 @@ void audio_init() {
g_audio_backend->init();
}
+float audio_get_required_prefill_time() {
+ return (float)RING_BUFFER_LOOKAHEAD_MS / 1000.0f;
+}
+
+bool audio_is_prefilled() {
+ const int buffered = g_ring_buffer.available_read();
+ const float buffered_time =
+ (float)buffered / (RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS);
+ const float required = audio_get_required_prefill_time();
+ return buffered_time >= (required - 0.001f); // 1ms tolerance
+}
+
void audio_start() {
if (g_audio_backend == nullptr) {
printf("Cannot start: audio not initialized.\n");
return;
}
+
+#if !defined(STRIP_ALL)
+ if (!audio_is_prefilled()) {
+ const int buffered = g_ring_buffer.available_read();
+ const float buffered_ms = (float)buffered /
+ (RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS) *
+ 1000.0f;
+ printf("WARNING: Audio buffer not pre-filled (%.1fms < %.1fms)\n",
+ buffered_ms, audio_get_required_prefill_time() * 1000.0f);
+ }
+#endif
+
g_audio_backend->start();
}
@@ -73,6 +97,12 @@ void audio_render_ahead(float music_time, float dt, float target_fill) {
// Render in small chunks to keep synth time synchronized with tracker
// Chunk size: one frame's worth of audio (~16.6ms @ 60fps)
+ // TODO(timing): CRITICAL BUG - Truncation here may cause 180ms drift over 63
+ // beats (int) cast loses fractional samples: 0.333 samples/frame * 2560
+ // frames = 853 samples = 27ms But observed drift is 180ms, so this is not the
+ // only source (27ms < 180ms) NOTE: This is NOT a float vs double precision
+ // issue - floats handle <500s times fine See also: tracker.cc BPM timing
+ // calculation
const int chunk_frames = (int)(dt * RING_BUFFER_SAMPLE_RATE);
const int chunk_samples = chunk_frames * RING_BUFFER_CHANNELS;
diff --git a/src/audio/audio.h b/src/audio/audio.h
index 9d521e6..beb994f 100644
--- a/src/audio/audio.h
+++ b/src/audio/audio.h
@@ -23,6 +23,12 @@ struct SpecHeader {
void audio_init();
void audio_start(); // Starts the audio device callback
+// Get required pre-fill time (matches ring buffer lookahead)
+float audio_get_required_prefill_time();
+
+// Check if buffer is sufficiently pre-filled
+bool audio_is_prefilled();
+
// Ring buffer audio rendering (main thread fills buffer)
// target_fill: Target buffer fill time in seconds (default:
// RING_BUFFER_LOOKAHEAD_MS/1000)
diff --git a/src/audio/tracker.cc b/src/audio/tracker.cc
index 1c0a9b2..38c814d 100644
--- a/src/audio/tracker.cc
+++ b/src/audio/tracker.cc
@@ -193,7 +193,8 @@ static int get_free_pattern_slot() {
// sample-accurate timing)
// volume_mult: Additional volume multiplier (for humanization)
static void trigger_note_event(const TrackerEvent& event,
- int start_offset_samples, float volume_mult = 1.0f) {
+ int start_offset_samples,
+ float volume_mult = 1.0f) {
#if defined(DEBUG_LOG_TRACKER)
// VALIDATION: Check sample_id bounds
if (event.sample_id >= g_tracker_samples_count) {
@@ -234,6 +235,16 @@ static void trigger_note_event(const TrackerEvent& event,
}
void tracker_update(float music_time_sec, float dt_music_sec) {
+ // TODO(timing): CRITICAL BUG - Events trigger ~180ms early over 63 beats @
+ // BPM=90 Observed: Beat 63 snare at 41.82s in WAV, should be at 42.00s (180ms
+ // drift) NOTE: This is NOT a float vs double precision issue - floats handle
+ // <500s times fine Root cause unknown - suspects:
+ // 1. Systematic bias in time calculation (not random accumulation)
+ // 2. Truncation in audio.cc:103 chunk_frames = (int)(dt * sample_rate)
+ // 3. BPM calculation precision below (unit_duration_sec)
+ // 4. Mismatch between tracker time and actual sample rendering
+ // See also: audio.cc sample rendering truncation
+
// Unit-less timing: 1 unit = 4 beats (by convention)
const float BEATS_PER_UNIT = 4.0f;
const float unit_duration_sec =