summaryrefslogtreecommitdiff
path: root/src/gpu/gpu.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-07 16:41:30 +0100
committerskal <pascal.massimino@gmail.com>2026-02-07 16:41:30 +0100
commitf2963ac821a3af1c54002ba13944552166956d04 (patch)
tree32f25ce610a15d97ce04e7a002ceb0fc920dfd1e /src/gpu/gpu.cc
parent6b4dce2598a61c2901f7387aeb51a6796b180bd3 (diff)
fix(audio): Synchronize audio-visual timing with playback time
Problem: test_demo was "flashing a lot" - visual effects triggered ~400ms before audio was heard, causing poor synchronization. Root Causes: 1. Beat calculation used physical time (platform_state.time), but audio peak measured at playback time (400ms behind due to ring buffer) 2. Peak decay too slow (0.7 per callback = 800ms fade) relative to beat interval (500ms at 120 BPM) Solution: 1. Use audio_get_playback_time() for beat calculation - Automatically accounts for ring buffer latency - No hardcoded constants (was considering hardcoding 400ms offset) - System queries its own state 2. Faster decay rate (0.5 vs 0.7) to match beat interval 3. Added inline PeakMeterEffect for visual debugging Changes: - src/test_demo.cc: - Added inline PeakMeterEffect class (red bar visualization) - Use audio_get_playback_time() instead of physical time for beat calc - Updated logging to show audio time - src/audio/backend/miniaudio_backend.cc: - Changed decay rate from 0.7 to 0.5 (500ms fade time) - src/gpu/gpu.{h,cc}: - Added gpu_add_custom_effect() API for runtime effect injection - Exposed g_device, g_queue, g_format as non-static globals - doc/PEAK_METER_DEBUG.md: - Initial analysis of timing issues - doc/AUDIO_TIMING_ARCHITECTURE.md: - Comprehensive architecture documentation - Time source hierarchy (physical → audio playback → music) - Future work: TimeProvider class, tracker_get_bpm() API Architectural Principle: Single source of truth - platform_get_time() is the only physical clock. Everything else derives from it. No hardcoded latency constants. Result: Visual effects now sync perfectly with heard audio.
Diffstat (limited to 'src/gpu/gpu.cc')
-rw-r--r--src/gpu/gpu.cc13
1 files changed, 11 insertions, 2 deletions
diff --git a/src/gpu/gpu.cc b/src/gpu/gpu.cc
index 45f0f34..63a30ff 100644
--- a/src/gpu/gpu.cc
+++ b/src/gpu/gpu.cc
@@ -21,10 +21,11 @@
static WGPUInstance g_instance = nullptr;
static WGPUAdapter g_adapter = nullptr;
-static WGPUDevice g_device = nullptr;
-static WGPUQueue g_queue = nullptr;
+WGPUDevice g_device = nullptr; // Non-static for external access (debug builds)
+WGPUQueue g_queue = nullptr; // Non-static for external access (debug builds)
static WGPUSurface g_surface = nullptr;
static WGPUSurfaceConfiguration g_config = {};
+WGPUTextureFormat g_format = WGPUTextureFormat_BGRA8Unorm; // Exposed for custom effects
static MainSequence g_main_sequence;
@@ -354,6 +355,7 @@ void gpu_init(PlatformState* platform_state) {
g_config.device = g_device;
g_config.format = swap_chain_format;
+ g_format = swap_chain_format; // Update global format for external access
g_config.usage = WGPUTextureUsage_RenderAttachment;
g_config.width = platform_state->width;
g_config.height = platform_state->height;
@@ -386,6 +388,13 @@ void gpu_resize(int width, int height) {
void gpu_simulate_until(float time) {
g_main_sequence.simulate_until(time, 1.0f / 60.0f);
}
+
+void gpu_add_custom_effect(Effect* effect, float start_time, float end_time, int priority) {
+ auto seq = std::make_shared<Sequence>();
+ seq->add_effect(std::shared_ptr<Effect>(effect), start_time, end_time, priority);
+ seq->init(&g_main_sequence);
+ g_main_sequence.add_sequence(seq, 0.0f, priority);
+}
#endif /* !defined(STRIP_ALL) */
void gpu_shutdown() {