diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-08 11:23:03 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-08 11:23:03 +0100 |
| commit | 47d738f36a3eb262456082e35369cb26485df575 (patch) | |
| tree | d83d8259f0d87df20861030f4fa544195e61d358 /src | |
| parent | 392d03c0c05f24be3210a04d9a50cd9714d1e265 (diff) | |
feat(timing): Decouple graphics loop from audio clock for smooth performance
This commit addresses the choppy graphics issue reported after the audio synchronization fixes. The graphics rendering loop is now driven by the platform's independent clock () to ensure a consistent frame rate, while still using audio playback time for synchronization cues like beat detection and visual peak indicators.
Key changes include:
- In and :
- Introduced derived from for the main loop.
- Main loop exit conditions and calls now use .
- Audio timing (, ) remains separate and is used for audio processing and synchronization events.
- Debug output clarifies between graphics and audio time sources.
- Corrected scope issues for and in .
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.cc | 60 | ||||
| -rw-r--r-- | src/test_demo.cc | 81 |
2 files changed, 78 insertions, 63 deletions
diff --git a/src/main.cc b/src/main.cc index 51060ce..a4cc67d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -233,49 +233,59 @@ int main(int argc, char** argv) { gpu_resize(last_width, last_height); } - const double physical_time = - platform_state.time + seek_time; // Offset logic time + // Graphics frame time - derived from platform's clock + const double current_physical_time = platform_state.time + seek_time; + // Audio playback time - master clock for audio events + const float current_audio_time = audio_get_playback_time(); + // Delta time for audio processing, based on audio clock + const float audio_dt = current_audio_time - g_last_audio_time; + g_last_audio_time = current_audio_time; // Auto-exit when demo finishes (if duration is specified) - if (demo_duration > 0.0f && physical_time >= demo_duration) { + if (demo_duration > 0.0f && current_physical_time >= demo_duration) { #if !defined(STRIP_ALL) - printf("Demo finished at %.2f seconds. Exiting...\n", physical_time); + printf("Demo finished at %.2f seconds. Exiting...\n", current_physical_time); #endif break; } - // 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); + // This fill_audio_buffer call is crucial for audio system to process + // events based on the *current audio time* and *graphics physical time* context + fill_audio_buffer(audio_dt, current_physical_time); + // --- Graphics Update --- const float aspect_ratio = platform_state.aspect_ratio; - // Adjusted multiplier for visuals (preventing constant 1.0 saturation) - // Use real-time peak for proper audio-visual synchronization + // Peak value derived from audio, but used for visual effect intensity const float raw_peak = audio_get_realtime_peak(); const float visual_peak = fminf(raw_peak * 8.0f, 1.0f); - // Calculate beat information for synchronization - // 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; + // Beat calculation should use audio time to align with audio events. + // The graphics loop time (current_physical_time) is used for frame rate. + const float beat_time = current_audio_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 (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; + // Use graphics time for the print interval to avoid excessive output if audio clock is slow + static float last_graphics_print_time = -1.0f; + if (current_physical_time - last_graphics_print_time >= 0.5f) { // Print every 0.5 seconds + if (tempo_test_enabled) { + printf( + "[GraphicsT=%.2f, AudioT=%.2f, MusicT=%.2f, Beat=%d, Frac=%.2f, Peak=%.2f, Tempo=%.2fx]\n", + current_physical_time, current_audio_time, g_music_time, beat_number, beat, + visual_peak, g_tempo_scale); + } else { + printf("[GraphicsT=%.2f, AudioT=%.2f, Beat=%d, Frac=%.2f, Peak=%.2f]\n", + current_physical_time, current_audio_time, beat_number, beat, visual_peak); + } + last_graphics_print_time = current_physical_time; } -#endif /* !defined(STRIP_ALL) */ - gpu_draw(visual_peak, aspect_ratio, sync_time, beat); + // Draw graphics using the graphics frame time and synchronized audio events + gpu_draw(visual_peak, aspect_ratio, graphics_frame_time, beat); + + // Update audio systems (tracker, synth, etc.) based on audio time progression audio_update(); } @@ -283,4 +293,4 @@ int main(int argc, char** argv) { gpu_shutdown(); platform_shutdown(&platform_state); return 0; -} +}
\ No newline at end of file diff --git a/src/test_demo.cc b/src/test_demo.cc index bb92446..887258b 100644 --- a/src/test_demo.cc +++ b/src/test_demo.cc @@ -145,6 +145,8 @@ int main(int argc, char** argv) { int height = 720; const char* log_peaks_file = nullptr; bool log_peaks_fine = false; + // Seek time needs to be declared here to be accessible globally for the loop. + float seek_time = 0.0f; #if !defined(STRIP_ALL) // Early exit for invalid options @@ -227,6 +229,7 @@ int main(int argc, char** argv) { if (tempo_test_enabled) { // Each bar = 2 seconds at 120 BPM (4 beats) const float bar_duration = 2.0f; + // Use physical_time for tempo modulation progression const int bar_number = (int)(physical_time / bar_duration); const float bar_progress = fmodf((float)physical_time, bar_duration) / @@ -265,21 +268,19 @@ int main(int argc, char** argv) { if (log_peaks_file) { peak_log = fopen(log_peaks_file, "w"); if (peak_log) { - fprintf(peak_log, "# Audio peak log from test_demo\n"); - fprintf(peak_log, "# Mode: %s\n", + fprintf(peak_log, "// Audio peak log from test_demo\n"); + fprintf(peak_log, "// Mode: %s\n", log_peaks_fine ? "fine (per-frame)" : "beat-aligned"); - fprintf(peak_log, "# To plot with gnuplot:\n"); + fprintf(peak_log, "// To plot with gnuplot:\n"); fprintf(peak_log, - "# gnuplot -p -e \"set xlabel 'Time (s)'; set ylabel 'Peak'; " - "plot '%s' using 2:3 with lines title 'Raw Peak'\"\n", + "// gnuplot -p -e \"set xlabel 'Time (s)'; set ylabel 'Peak'; plot '%s' using 2:3 with lines title 'Raw Peak'\"\n", log_peaks_file); if (log_peaks_fine) { - fprintf(peak_log, - "# Columns: frame_number clock_time raw_peak beat_number\n"); + fprintf(peak_log, "// Columns: frame_number clock_time raw_peak beat_number\n"); } else { - fprintf(peak_log, "# Columns: beat_number clock_time raw_peak\n"); + fprintf(peak_log, "// Columns: beat_number clock_time raw_peak\n"); } - fprintf(peak_log, "#\n"); + fprintf(peak_log, "//\n"); } else { fprintf(stderr, "Warning: Could not open log file '%s'\n", log_peaks_file); @@ -301,35 +302,36 @@ int main(int argc, char** argv) { gpu_resize(last_width, last_height); } - const double physical_time = platform_state.time; + // Graphics frame time - derived from platform's clock + const double current_physical_time = platform_state.time + seek_time; + // Audio playback time - master clock for audio events + const float current_audio_time = audio_get_playback_time(); + // Delta time for audio processing, based on audio clock + const float audio_dt = current_audio_time - g_last_audio_time; + g_last_audio_time = current_audio_time; - // Auto-exit at end (based on physical time for reliability) - if (demo_duration > 0.0f && physical_time >= demo_duration) { + // Auto-exit at end (based on physical time for graphics loop consistency) + if (demo_duration > 0.0f && current_physical_time >= demo_duration) { #if !defined(STRIP_ALL) - printf("test_demo finished at %.2f seconds.\n", physical_time); + printf("test_demo finished at %.2f seconds. Exiting...\n", current_physical_time); #endif break; } - // 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; + // This fill_audio_buffer call is crucial for audio system to process + // events based on the *current audio time* and *graphics physical time* context + fill_audio_buffer(audio_dt, current_physical_time); - fill_audio_buffer(audio_dt, physical_time); - - // Audio-visual synchronization: Use audio playback time (not physical - // time!) This accounts for ring buffer latency automatically (no hardcoded - // constants) - - // Audio/visual sync parameters + // --- Graphics Update --- const float aspect_ratio = platform_state.aspect_ratio; - // Peak is measured at audio playback time, so it matches audio_time + + // Peak value derived from audio, but used for visual effect intensity const float raw_peak = audio_get_realtime_peak(); const float visual_peak = fminf(raw_peak * 8.0f, 1.0f); - // Beat calculation uses AUDIO TIME (what's being heard), not physical time - const float beat_time = audio_time * 120.0f / 60.0f; + // Beat calculation should use audio time to align with audio events. + // The graphics loop time (current_physical_time) is used for frame rate. + const float beat_time = current_audio_time * 120.0f / 60.0f; const int beat_number = (int)beat_time; const float beat = fmodf(beat_time, 1.0f); @@ -345,30 +347,33 @@ int main(int argc, char** argv) { raw_peak, beat_number); } else if (beat_number != last_beat_logged) { // Log only at beat boundaries - fprintf(peak_log, "%d %.6f %.6f\n", beat_number, audio_time, raw_peak); + fprintf(peak_log, "%d %.6f %.6f\n", beat_number, current_audio_time, raw_peak); last_beat_logged = beat_number; } } frame_number++; - // Debug output every 0.5 seconds (based on audio time for consistency) - static float last_print_time = -1.0f; - if (audio_time - last_print_time >= 0.5f) { + // Debug output every 0.5 seconds (based on graphics time for consistency) + static float last_graphics_print_time = -1.0f; + if (current_physical_time - last_graphics_print_time >= 0.5f) { if (tempo_test_enabled) { printf( - "[AudioT=%.2f, PhysT=%.2f, MusicT=%.2f, Beat=%d, Frac=%.2f, " - "Peak=%.2f, Tempo=%.2fx]\n", - audio_time, (float)physical_time, g_music_time, beat_number, beat, + "[GraphicsT=%.2f, AudioT=%.2f, MusicT=%.2f, Beat=%d, Frac=%.2f, Peak=%.2f, Tempo=%.2fx]\n", + current_physical_time, current_audio_time, g_music_time, beat_number, beat, visual_peak, g_tempo_scale); } else { - printf("[AudioT=%.2f, Beat=%d, Frac=%.2f, Peak=%.2f]\n", audio_time, - beat_number, beat, visual_peak); + printf("[GraphicsT=%.2f, AudioT=%.2f, Beat=%d, Frac=%.2f, Peak=%.2f]\n", + current_physical_time, current_audio_time, beat_number, beat, visual_peak); } - last_print_time = audio_time; + last_graphics_print_time = current_physical_time; } #endif - gpu_draw(visual_peak, aspect_ratio, audio_time, beat); + // Draw graphics using the graphics frame time and synchronized audio events + const float graphics_frame_time = (float)current_physical_time; + gpu_draw(visual_peak, aspect_ratio, graphics_frame_time, beat); + + // Update audio systems (tracker, synth, etc.) based on audio time progression audio_update(); } |
