fix(audio): process Aux buffers and isolate splitter filter history #1544
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!1544
Loading…
Reference in a new issue
No description provided.
Delete branch "pr/audio-effect-processing"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Aux audio currently bypasses the game's CPU effect workers, and splitter routes need independent filter histories to avoid contaminating other outputs. This fix was implemented with GPT-6 Astra medium & xhigh.
Exchange complete planar PCM32 frames through bounded Aux send/return rings, preserve effect insertion order, and keep biquad history per voice and splitter destination. Queued parameter updates, underrun silence, overflow handling and channel remapping have authored regression fixtures. Upstream audio output, volume, background muting and wave-buffer release behavior are retained.
Refreshed against upstream
0a28ff29. The diff contains audio implementation and regression fixtures, plus the existing one-line SDL ownership getter in the isolated Wayland fixture, needed for the current Clang warning checks. The new audio tests declare their compiler requirement to the repository runner. This PR is independent of the renderer and scene API changes.Validation: full Linux source suite on
b2885b46: 361 passed, 0 failed, 14 skipped. After merging0a28ff29and aligning compiler declarations, 24 affected checks passed, 0 failed, 0 skipped on final head5bf7df2d. The skips in the full run cover platform/game/GPU requirements and unavailable optional tools. The Aux and biquad tests compile the actual production functions and exercise synthetic signals without an audio device or game assets. No game or audio output was started for this refresh. Existing silent gameplay checks do not establish audible effect quality, latency or surround output; focused listening on this PR head and Windows runtime validation remain unverified.Final refresh: merged upstream
ddafc1f9; 11 affected builder/update/fixture checks passed afterward.The final source includes upstream
2e62a977; its release-only changes passed both affected release/update checks.Merged current main (
1392ea3) and resolved the conflicts, preserving upstream replacements where they supersede our changes. Migrated local tests to the new per-test runner declarations. Independent source suites and the combined suite pass; fresh Linux gameplay results and limitations are recorded in the updated description. Hyrule Field and a warm Forest run completed the short movement tests, but camera hitches remain; earlier memory-guard stops and the incomplete Market event are not reported as passes. AI-assisted development: GPT-6-Astra (medium and xhigh).Refreshed again to main
117eae7and resolved the new Anti-Lag source-fixture conflict. Complete Linux source suite re-run: 304 passed, 0 failed, 18 skipped. Existing gameplay evidence remains explicitly tied to its tested build.Thanks for this. I read the full diff against current main. The splitter half looks right to me. The Aux half is plausible, but it changes what is audible in a way no test here can check, so I'd like an in-game listen before this goes in.
What looks good
split_bq_zinVoice), and the epochs reset it when the route or the on/off state changes. That's the correct model: #1063 keeps onebq_zper splitter destination, shared by every voice that feeds it, which is exactly the contamination this PR avoids. Pullingbiquad_frameout ofrender_voiceleaves the voice path unchanged.FRAME * nframes, so the send side never enqueues part of a frame, and a guest that writes whole frames can't misalign the return ring either. Every buffer index is checked againstm->buffersbefore use.aux_frameand the splitter path add no allocation and no new lock. Everything runs under the existingau_lock. The new stack use (about 46 KB inaux_frame) is fine for the renderer thread. The static footprint grows by about 2.3 MB (split_bq_zx 512 voices), which is acceptable.effect_order) is a good call.What worries me
audio_mix_deadlinemakes it catch up back-to-back after any stall (up to 3 s). The game's worker gets no chance to run between those frames, so every frame of a burst after a hitch underruns and the Aux-routed buffers drop out. You mention camera hitches in your gameplay notes, so this is a real situation. Before, the same buffers passed through dry and kept playing. If the game routes a whole bus through an Aux, a hitch now cuts that bus out briefly. A small pre-roll (start returning only once one or two frames are queued) would hide most of this, at the cost of a frame of latency.OP_AUX_ENABLEresets both rings every time it's applied, even when the state doesn't change (inline).HOS_AUDIO_DUMPof the same spot on main and on this branch would do), whether anything goes quiet or gets doubled, and whether hitches or loading cause dropouts. One Windows run would help too.Smaller points
OP_SPLIT_BIQUADis dropped unlessdest_mix[d]already equals the mix. A game that sets the filter before the firstSetSplitterMixVolumefor that destination (which is wheredest_mixgets set lazily) loses the filter without any sign. Probably fine, but worth a trace line.underrunsandoverrunscounters are never reported. A rate-limitedAUTline would make the in-game check above much easier.aux_ring_readandaux_ring_writecanmemcpyfrom a NULLdatawith size 0 when capacity is 0. That's harmless in practice, but an early return when!r->capacityis cleaner.Overlap
SetSplitterBiquadFilterParameterHLEs and rewriteseffects_frame. The two can't both land as they are (duplicate symbols, conflicting splitter state). I'd keep the per-voice history from this PR and have #1063 rebase its plain reverb, delay and mix biquad on top of theorderscheme here. Worth agreeing between you which one goes first.win32_posix.c). There's no textual overlap. It doesn't change the renderer clock, so it neither helps nor hurts point 1.CI: only the title check has run. The Windows builder, AppImage and game-free source regression workflows are waiting for approval (
action_required), and the branch is 46 commits behind main. So the newtest_audio_aux/test_audio_biquadtests haven't run in CI yet.On underrun this zero-fills the output buffers. That's right for hardware, but here the renderer catches up in back-to-back bursts after a stall (
audio_mix_deadline), so a hitch now becomes a dropout of everything routed through this Aux, where main played it dry. A one- or two-frame pre-roll before the first read (and after a reset) would absorb host scheduling jitter. See point 1 in the review body.This clears both rings on every
SetAuxEnabledthat reaches an update, includingtrue->true. If the game re-asserts enabled each update (common in effect-manager loops), the return ring is emptied every frame and the Aux output stays silent. Suggest resetting only when the state actually changes:GitHub shows this as mergeable, but it no longer builds its own tests on current main. I merged the head (
5713010) into origin/main locally.tests/test_audio_aux.pyandtests/test_audio_biquad.pyboth fail to compile withimplicit declaration of function 'env_on'. Both pass at the PR head.The cause is #2042, which landed after your last main merge (
2e62a97). It changedhost/nn_audio.cto read its switches withenv_on(AUTat line 132,HOS_AUDIO_NO_REVERB,HOS_AUDIO_STATSand others). Your fixtures cut code out of that file but don't includegpu/vk/compat/hookshot_env.h. Do it the waytests/test_audio_voice_biquad.pydoes: anENV_ON_Hpath passed with-include.hckrman101's points at this same head are all still open:
OP_AUX_ENABLEresets both rings even when the state doesn't change;HOS_AUDIO_DUMPof the same spot would do);Quick follow-up, since nothing has been pushed since my review (still
5713010).I can confirm @Joey-Magnus's build break.
host/nn_audio.con main now callsenv_on(AUT,HOS_AUDIO_NO_REVERB,HOS_AUDIO_STATS,HOS_AUDIO_IMMEDIATE), and neithertests/test_audio_aux.pynortests/test_audio_biquad.pypasses-include gpu/vk/compat/hookshot_env.hthe waytests/test_audio_voice_biquad.pydoes (ENV_ON_H). So both new checks stop compiling once this meets main. The branch is now 117 commits behind main, so a merge of main plus that one-line fixture change should cover it.My earlier points are unchanged and still open: the Aux underrun dropouts during catch-up bursts (pre-roll),
OP_AUX_ENABLEresetting the rings when the state doesn't change, the in-game before/after listen, and agreeing the order with #1063.CI: only the title check has run. The build and source-suite workflows are still waiting for approval, so the new tests haven't run in CI.
github-sync referenced this pull request2026-11-12 06:22:54 +00:00