Add audio-fidelity validator + fix mirror render under-run
Build coop_audio_validate, a tool that turns "the mirror audio sounds off" into numbers. It plays a known sine (coop_tone, 44.1 kHz on a 48 kHz endpoint -- the Godot/Brotato case), injects the hook as the host does, and runs a fidelity analyzer (coop/tone_analysis.hpp: pitch error in cents, SNR/THD, click + dropout counts), dumping a .wav to listen to. Modes: --render drives the real AudioMirror and measures its rendered output; --baseline/--selfcheck give the measurement floor; --listen <pid> records a live coop_host's output; --wav analyzes a recording. Analyzer + WAV I/O are unit-tested (tone_analysis_test) against synthesized defects. Using it, the capture ring measures pristine (~68 dB, 0 gaps) while the render path dropped to ~18 dB with gaps -- localizing a real defect in AudioMirror::run_hooked: it re-primed (withheld the feed until ~30 ms had rebuffered) on any partial fill (to_write < avail). A partial fill is normal producer jitter, and withholding the feed drains the device, so a one-frame ring dip became a full ~30 ms drop-out; on a jittery game it fired constantly. Fix: feed whatever is available each tick and re-prime only on a genuine starvation (device empty AND ring empty). The policy is factored into a pure RenderPacer reused by run_hooked + run_loopback and proven by render_pacer_test (the old policy withholds available data ~168x and drains to one period from silence on a jittery schedule; the new one never withholds). ctest 17/17. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,22 @@ add_executable(rate_estimator_test rate_estimator_test.cpp)
|
||||
target_include_directories(rate_estimator_test PRIVATE ${CMAKE_SOURCE_DIR}/hook/src)
|
||||
add_test(NAME rate_estimator_test COMMAND rate_estimator_test)
|
||||
|
||||
# Unit test for the audio fidelity analyzer (pitch error in cents, SNR/THD, click +
|
||||
# dropout detection) and the WAV reader/writer. Synthesizes adversarial signals (clean /
|
||||
# wrong-rate pitch shift / injected clicks / silence gaps) and asserts the metrics. Pure
|
||||
# header logic, no device. Underpins the coop_audio_validate diagnostic tool.
|
||||
add_executable(tone_analysis_test tone_analysis_test.cpp)
|
||||
target_link_libraries(tone_analysis_test PRIVATE coop_common)
|
||||
add_test(NAME tone_analysis_test COMMAND tone_analysis_test)
|
||||
|
||||
# Unit test for the audio-mirror render pacing policy (host/src/audio/render_pacer.hpp).
|
||||
# Simulates a producer/consumer device timeline and asserts the shipping RenderPacer rides
|
||||
# through producer jitter that makes the old re-prime-on-partial-fill policy glitch
|
||||
# repeatedly (the under-run / "metallic" bug coop_audio_validate found). Header-only, no device.
|
||||
add_executable(render_pacer_test render_pacer_test.cpp)
|
||||
target_include_directories(render_pacer_test PRIVATE ${CMAKE_SOURCE_DIR}/host/src)
|
||||
add_test(NAME render_pacer_test COMMAND render_pacer_test)
|
||||
|
||||
# Unit test for the per-game audio override store (persist/reload, case-insensitive
|
||||
# lookup, differing-overwrite detection). Reuses the shipping source. No device.
|
||||
add_executable(audio_overrides_test
|
||||
@@ -207,6 +223,8 @@ coop_output_subdir(tests
|
||||
mkb_ring_test
|
||||
mkb_map_test
|
||||
audio_mix_test
|
||||
tone_analysis_test
|
||||
render_pacer_test
|
||||
rate_estimator_test
|
||||
audio_overrides_test
|
||||
audio_loopback_test
|
||||
|
||||
Reference in New Issue
Block a user