diff options
Diffstat (limited to 'src/main.cc')
| -rw-r--r-- | src/main.cc | 69 |
1 files changed, 37 insertions, 32 deletions
diff --git a/src/main.cc b/src/main.cc index 32f3c99..51060ce 100644 --- a/src/main.cc +++ b/src/main.cc @@ -89,9 +89,9 @@ int main(int argc, char** argv) { // Music time state for variable tempo static float g_music_time = 0.0f; static float g_tempo_scale = 1.0f; // 1.0 = normal speed - static double g_last_physical_time = 0.0; + static float g_last_audio_time = 0.0f; - auto fill_audio_buffer = [&](double t) { + auto fill_audio_buffer = [&](float audio_dt, double physical_time) { // Variable tempo system - acceleration phases for demo effect // Phase 1 (0-5s): Steady 1.0x // Phase 2 (5-10s): Steady 1.0x @@ -100,17 +100,17 @@ int main(int argc, char** argv) { // Phase 5 (20-25s): Decelerate from 1.0x to 0.5x // Phase 6 (25s+): Steady 1.0x (reset after deceleration) const float prev_tempo = g_tempo_scale; - if (t < 10.0) { + if (physical_time < 10.0) { g_tempo_scale = 1.0f; // Steady at start - } else if (t < 15.0) { + } else if (physical_time < 15.0) { // Phase 3: Linear acceleration - const float progress = (float)(t - 10.0) / 5.0f; + const float progress = (float)(physical_time - 10.0) / 5.0f; g_tempo_scale = 1.0f + progress * 1.0f; // 1.0 → 2.0 - } else if (t < 20.0) { + } else if (physical_time < 20.0) { g_tempo_scale = 1.0f; // Reset to normal - } else if (t < 25.0) { + } else if (physical_time < 25.0) { // Phase 5: Linear deceleration - const float progress = (float)(t - 20.0) / 5.0f; + const float progress = (float)(physical_time - 20.0) / 5.0f; g_tempo_scale = 1.0f - progress * 0.5f; // 1.0 → 0.5 } else { g_tempo_scale = 1.0f; // Reset to normal @@ -120,29 +120,25 @@ int main(int argc, char** argv) { #if !defined(STRIP_ALL) // Debug output when tempo changes significantly if (fabsf(g_tempo_scale - prev_tempo) > 0.05f) { - printf("[Tempo] t=%.2fs, tempo=%.3fx, music_time=%.3fs\n", (float)t, - g_tempo_scale, g_music_time); + printf("[Tempo] t=%.2fs, tempo=%.3fx, music_time=%.3fs\n", + (float)physical_time, g_tempo_scale, g_music_time); } #endif - // Calculate delta time - const float dt = (float)(t - g_last_physical_time); - g_last_physical_time = t; - // CRITICAL: Update tracker BEFORE advancing music_time // This ensures events trigger in the correct frame, not one frame early // Pass current music_time (not future time) to tracker - g_audio_engine.update(g_music_time); + g_audio_engine.update(g_music_time, audio_dt * g_tempo_scale); // Fill ring buffer with upcoming audio (look-ahead rendering) // CRITICAL: Scale dt by tempo to render enough audio during // acceleration/deceleration At 2.0x tempo, we consume 2x audio per physical // second, so we must render 2x per frame - audio_render_ahead(g_music_time, dt * g_tempo_scale); + audio_render_ahead(g_music_time, audio_dt * g_tempo_scale); // Advance music time AFTER rendering audio for this frame // This prevents events from triggering one frame early - g_music_time += dt * g_tempo_scale; + g_music_time += audio_dt * g_tempo_scale; }; #if !defined(STRIP_ALL) @@ -153,7 +149,7 @@ int main(int argc, char** argv) { // We step at ~60hz const double step = 1.0 / 60.0; for (double t = 0.0; t < seek_time; t += step) { - fill_audio_buffer(t); + fill_audio_buffer(step, t); audio_render_silent((float)step); } @@ -164,11 +160,13 @@ int main(int argc, char** argv) { // PRE-FILL: Fill ring buffer with initial 200ms before starting audio device // This prevents underrun on first callback - g_audio_engine.update(g_music_time); - audio_render_ahead(g_music_time, 1.0f / 60.0f); // Fill buffer with lookahead + g_audio_engine.update(g_music_time, 1.0f / 60.0f); + audio_render_ahead(g_music_time, + 1.0f / 60.0f); // Fill buffer with lookahead // Start audio (or render to WAV file) audio_start(); + g_last_audio_time = audio_get_playback_time(); // Initialize after start #if !defined(STRIP_ALL) // In WAV dump mode, run headless simulation and write audio to file @@ -177,7 +175,7 @@ int main(int argc, char** argv) { const float demo_duration = GetDemoDuration(); const float max_duration = (demo_duration > 0.0f) ? demo_duration : 60.0f; - const float update_dt = 1.0f / 60.0f; // 60Hz update rate + const float update_dt = 1.0f / 60.0f; // 60Hz update rate const int frames_per_update = (int)(32000 * update_dt); // ~533 frames const int samples_per_update = frames_per_update * 2; // Stereo @@ -188,7 +186,7 @@ int main(int argc, char** argv) { while (physical_time < max_duration) { // Update music time and tracker (using tempo logic from // fill_audio_buffer) - fill_audio_buffer(physical_time); + fill_audio_buffer(update_dt, physical_time); // Read rendered audio from ring buffer if (ring_buffer != nullptr) { @@ -235,18 +233,23 @@ int main(int argc, char** argv) { gpu_resize(last_width, last_height); } - const double current_time = + const double physical_time = platform_state.time + seek_time; // Offset logic time // Auto-exit when demo finishes (if duration is specified) - if (demo_duration > 0.0f && current_time >= demo_duration) { + if (demo_duration > 0.0f && physical_time >= demo_duration) { #if !defined(STRIP_ALL) - printf("Demo finished at %.2f seconds. Exiting...\n", current_time); + printf("Demo finished at %.2f seconds. Exiting...\n", physical_time); #endif break; } - fill_audio_buffer(current_time); + // Calculate stable audio dt for jitter-free tracker updates + const float audio_time = audio_get_playback_time(); + const float audio_dt = audio_time - g_last_audio_time; + g_last_audio_time = audio_time; + + fill_audio_buffer(audio_dt, physical_time); const float aspect_ratio = platform_state.aspect_ratio; @@ -256,21 +259,23 @@ int main(int argc, char** argv) { const float visual_peak = fminf(raw_peak * 8.0f, 1.0f); // Calculate beat information for synchronization - const float beat_time = (float)current_time * g_tracker_score.bpm / 60.0f; + // MASTER CLOCK: Use audio playback time for perfect visual sync + const float sync_time = audio_get_playback_time(); + const float beat_time = sync_time * g_tracker_score.bpm / 60.0f; const int beat_number = (int)beat_time; const float beat = fmodf(beat_time, 1.0f); // Fractional part (0.0 to 1.0) #if !defined(STRIP_ALL) // Print beat/time info periodically for identifying sync points static float last_print_time = -1.0f; - if (current_time - last_print_time >= 0.5f) { // Print every 0.5 seconds - printf("[T=%.2f, Beat=%d, Frac=%.2f, Peak=%.2f]\n", (float)current_time, - beat_number, beat, visual_peak); - last_print_time = (float)current_time; + if (sync_time - last_print_time >= 0.5f) { // Print every 0.5 seconds + printf("[T=%.2f, MusicT=%.2f, Beat=%d, Frac=%.2f, Peak=%.2f]\n", + sync_time, g_music_time, beat_number, beat, visual_peak); + last_print_time = sync_time; } #endif /* !defined(STRIP_ALL) */ - gpu_draw(visual_peak, aspect_ratio, (float)current_time, beat); + gpu_draw(visual_peak, aspect_ratio, sync_time, beat); audio_update(); } |
