diff options
Diffstat (limited to 'src/audio')
| -rw-r--r-- | src/audio/audio.cc | 30 | ||||
| -rw-r--r-- | src/audio/audio.h | 6 | ||||
| -rw-r--r-- | src/audio/tracker.cc | 13 |
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 = |
