summaryrefslogtreecommitdiff
path: root/src/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cc')
-rw-r--r--src/main.cc69
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();
}