feat(audio): a Mono choice on the Audio output row #136

Merged
HumanBean merged 2 commits from simonwjackson/Longshot:feat/mono-audio into main 2026-11-14 00:58:32 +00:00
Contributor

Why

Players who hear with one ear, or use one earbud, can miss sounds panned to the other side. Mono plays the stereo average in both ears. It now belongs in the existing Audio output row, as HumanBean suggested, rather than in a second control.

Carried over from https://github.com/NotRexed/Hookshot/pull/2860.

What changed

  • vk_menu.cpp / vk_menu.h: Audio output now offers Auto / Stereo / 5.1 / Mono. Removed the separate Mono audio row and mono_audio field. Mono and Stereo share a restart-tracking value, so switching between them does not ask for a restart.
  • host/nn_audio.c: Mono selects a two-channel layout at startup and uses the PR's existing 32-bit stereo average live. Auto, Stereo and 5.1 never apply that average. Six-channel output remains untouched.
  • Main's row did not have a host option callback. ID 57 is therefore retained for the one row, renamed HOS_OPT_AUDIO_OUTPUT; HOS_OPT_MONO_AUDIO is gone.
  • Updated help (including its existing translations), README, audio tests and the menu restart-slot check.
  • gpu/vk/menu_i18n.h: the Mono hint (The stereo average in both ears. Changes live on stereo output; restart from 5.1.) in all 13 tables, and the Mono value label in the five whose word differs (ru, ja, ko, zh-Hans, zh-Hant; like Stereo, de/it/nl/pl/pt/es/fr keep Mono); each language's count in kLangs follows.
  • gpu/vk/vk_menu.cpp: the free function that reads the value a row's restart is tracked by is row_restart_value(const Row&), so it no longer shares a name with menu_restart::State::restart_value(slot, v), which sets a slot's start value; tests/test_audio_output_menu.py and tests/test_menu_restart_slots.py read the new name.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
Audio → Audio output; audio_output 0 Auto, 1 Stereo, 2 5.1, 3 Mono. Mono/Stereo switches live on stereo output; channel layout changes need restart. Auto never enables Mono. Auto (0), unchanged Keep Auto default; opt-in Mono One-sided hearing / one earbud Six-channel output stays untouched until a stereo layout is selected and the game restarted Windows, physical 5.1 speakers, listening by ear

Existing saved values keep their meanings; a file without audio_output still uses Auto. HOS_AUDIO_CHANNELS retains main's channel-layout override. No migration or fallback read of the superseded PR-only mono_audio key is added.

Measurements

main: e65cb1e00b (2026-11-13), the base of this PR now
this PR: feat/mono-audio @ 0fd02afbac (the measured commit, before the rebase; the head is now e457a41df0)

Why the numbers still hold for e457a41d: since 0fd02afb the PR's audio and menu code is unchanged apart from the menu's translations and a function rename (row_restart_value); main's changes since d9648863 (input hold-to-toggle, saves, VRAM mirror, setup, scripts, docs) do not touch host/nn_audio.c or the audio path. Not measured again on the rebased head.

Build fingerprint: mono-output-review (source 528a52f6). Original PR head: df5edcd34bda7ca8f1381d9bf4a8db8a186cf998.

Baseline: this PR @ 0fd02afb, Audio output Stereo

Compared with this PR @ 0fd02afb, Audio output Mono in the same live process. This isolates the new row’s live switch; main has no Mono choice. The older main/PR comparison below is historical, not a measurement of this new head.

Hardware: RX 7900 XT 20 GB, RADV Mesa 26.2.3; Ryzen 5 7600X, 32 GB RAM; NixOS 26.11 / Linux 7.2.7. Private headless Sway/Xwayland, copied Castle Town save, stationary at the wooden door. 1920×1080, 100% render resolution, game's upscaler, FG/HDR Off, Uncapped, VSync Auto, compute mesh fallback. HOS_AUDIO=0: nothing played through speakers. A fresh private source build; shader preparation used a 60-second prediction budget, with remaining pipelines built in play.

Method: warmed in the scene, then Stereo → Mono → Stereo → Mono, five seconds settling and 20 seconds sampled per choice. FPS is the median of the last five native presents-log samples. PCM is captured after mixing; counts are from the stereo sample pairs, with nonzero audio required. Audio stays on aka; only counts and screenshots are published.

Observation this PR @ 0fd02afb, Audio output Stereo this PR @ 0fd02afb, Audio output Mono
Native FPS medians, samples 1 / 2 56.0 / 56.6 56.6 / 56.4
Median of the two FPS medians 56.3 56.5
Stereo frames, samples 1 / 2 962,048 / 962,048 962,048 / 963,072
Unequal L/R frames, samples 1 / 2 960,175 / 960,120 0 / 0
Non-silent frames, samples 1 / 2 962,037 / 962,034 959,216 / 960,560
Native presents-log samples
stereo-1
[hos Presentation Thread] vk: 26520 presents, 55.8 fps; a frame: 1290 draws (0 skipped), 104 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1286 textures (3176 MB)
[hos Presentation Thread] vk: 26640 presents, 56.0 fps; a frame: 1283 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1310 textures (3389 MB)
[hos Presentation Thread] vk: 26760 presents, 55.6 fps; a frame: 1295 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1274 textures (3056 MB)
[hos Presentation Thread] vk: 26880 presents, 56.6 fps; a frame: 1295 draws (0 skipped), 107 dispatches, 158 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1273 textures (3046 MB)
[hos Presentation Thread] vk: 27000 presents, 56.5 fps; a frame: 1291 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1276 textures (3051 MB)
mono-2
[hos Presentation Thread] vk: 27960 presents, 56.6 fps; a frame: 1294 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1312 textures (3097 MB)
[hos Presentation Thread] vk: 28080 presents, 56.3 fps; a frame: 1296 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.1 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1311 textures (3088 MB)
[hos Presentation Thread] vk: 28200 presents, 56.9 fps; a frame: 1292 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1310 textures (3079 MB)
[hos Presentation Thread] vk: 28320 presents, 56.2 fps; a frame: 1294 draws (0 skipped), 107 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1310 textures (3079 MB)
[hos Presentation Thread] vk: 28440 presents, 56.9 fps; a frame: 1290 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1329 textures (3246 MB)
stereo-3
[hos Presentation Thread] vk: 29400 presents, 56.2 fps; a frame: 1294 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1313 textures (3098 MB)
[hos Presentation Thread] vk: 29520 presents, 56.6 fps; a frame: 1294 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1312 textures (3089 MB)
[hos Presentation Thread] vk: 29640 presents, 56.6 fps; a frame: 1292 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1312 textures (3089 MB)
[hos Presentation Thread] vk: 29760 presents, 56.3 fps; a frame: 1290 draws (0 skipped), 105 dispatches, 160 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1311 textures (3079 MB)
[hos Presentation Thread] vk: 29880 presents, 56.7 fps; a frame: 1295 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1311 textures (3079 MB)
mono-4
[hos Presentation Thread] vk: 30840 presents, 56.1 fps; a frame: 1294 draws (0 skipped), 107 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1319 textures (3106 MB)
[hos Presentation Thread] vk: 30960 presents, 56.7 fps; a frame: 1293 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1319 textures (3106 MB)
[hos Presentation Thread] vk: 31080 presents, 56.4 fps; a frame: 1292 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1319 textures (3097 MB)
[hos Presentation Thread] vk: 31200 presents, 55.8 fps; a frame: 1295 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1318 textures (3088 MB)
[hos Presentation Thread] vk: 31320 presents, 56.5 fps; a frame: 1295 draws (0 skipped), 107 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1320 textures (3106 MB)

The Audio tab screenshot shows the single row on Mono. The same process restored stereo separation and returned to zero unequal pairs on Mono. These numbers do not establish a cost on all hardware or in other scenes; no 1% lows are claimed.

Historical measurement, before the menu revision: main 316f9319 / original PR df5edcd3, two interleaved runs each in the same scene. Main FPS medians 53.50 / 54.20 (median 53.85); original PR Mono 53.80 / 54.00 (53.90). Main unequal PCM pairs 960,966 / 960,949; original PR Mono 0 / 0. The PR history retains those original logs and captures. No old screenshot is presented as the new Audio tab.

Testing

Tested: (by the author at 0fd02afb; nothing was run on the rebased head e457a41d yet, and nothing was built or run on the PC that rebased it)

  • Reproduced the missing-choice/wiring failure in both changed audio tests before implementation.
  • Focused audio, menu, README and option-ID checks: 25 passed, 1 inherited failure (test_menu_i18n.py). Includes extrema, silence, all non-Mono choices unchanged, live transitions, six-channel identity, missing/old/new saved values, environment precedence and restart-value normalization.
  • Full suite on zao under the shared lock: 516 passed, 2 failed, 16 skipped (508 seconds). Both failures reproduce on untouched main d9648863: the known test_linux_tools.py Nix PATH problem (readlink/dirname absent from /usr/bin:/bin), and test_menu_i18n.py, whose Debug-tools help translations were left behind when #138 added damage scaling (main has since fixed that table in #273). No new failures. test_display_pointer and test_texture_staging_publication pass on both trees.
  • git diff --check passes. Native fixtures compile with warnings as errors; the full Linux game and renderer build passed. No standalone formatter or typechecker is configured.
  • Live isolated gameplay and post-mix PCM proof above. Screenshot opened and inspected. Source hashes checked against the tested tree. No installed game, owner save, owner session or korri* unit changed.

Not tested: anything on e457a41d (the rebase onto e65cb1e0, the Mono hint and label translations and the row_restart_value rename are checked by reading only; the suite and a build are for CI or the author); the translated Mono hint on screen; Windows build/gameplay, physical 5.1 speakers, listening by ear, other GPU families and full playthroughs. Channel-layout restart behavior is covered by game-free checks; the live proof uses stereo output.

Needs other testers: Existing request T-7YW2, Windows / llvm-mingw / stereo output: compare Audio output Stereo and Mono, switch live, reload the saved choice, and report non-silent L/R equality counts and FPS. The request is not a passing result.

Screenshots

this PR @ 0fd02afb: Audio output set to Mono

Risk and rollback

Mono removes stereo positioning and can cancel opposite-phase samples. Choose Stereo to restore stereo live on a stereo output. For a different channel layout, restart as on main. Revert the PR to remove the feature.

Reviewer notes

Rebased onto main e65cb1e00b8116363326988ca05db15822f0924e as two linear commits: the PR's change (the original commit df5edcd3, the merge bc9285c2 and 0fd02afb squashed into one, Simon's authorship and trailers kept) and one commit for review 1187's suggestions (Mono translations, row_restart_value). The rebase met two conflicts, both additions side by side: gpu/vk/vk_api.h keeps #137's HOS_OPT_HOLD_TOGGLE = 54 and this PR's HOS_OPT_AUDIO_OUTPUT = 57 (IDs 54, 55, 57 stay unique), and docs/tested-configurations.md keeps both PRs' rows. No public MkwVkHost / MkwVkRenderer structure changed (only an enum is added to vk_api.h), so no MKWVK_API_VERSION bump. Auto→Mono shows "Restart needed" as Auto→Stereo does on main; left as it is on purpose. The translations, old and new, follow the existing machine-translated tables and have not had native-speaker review.

Issues

None.

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above). (Run by the author on 0fd02afb; not yet on the rebased head e457a41d: CI or the author.)
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • Screenshots for a change that shows on screen.
  • A row in docs/tested-configurations.md for each measured run.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Linux: built by the author at 0fd02afb. Windows: T-7YW2, no result yet.)
  • Docs updated.
## Why Players who hear with one ear, or use one earbud, can miss sounds panned to the other side. Mono plays the stereo average in both ears. It now belongs in the existing Audio output row, as HumanBean suggested, rather than in a second control. Carried over from https://github.com/NotRexed/Hookshot/pull/2860. ## What changed - `vk_menu.cpp` / `vk_menu.h`: Audio output now offers **Auto / Stereo / 5.1 / Mono**. Removed the separate Mono audio row and `mono_audio` field. Mono and Stereo share a restart-tracking value, so switching between them does not ask for a restart. - `host/nn_audio.c`: Mono selects a two-channel layout at startup and uses the PR's existing 32-bit stereo average live. Auto, Stereo and 5.1 never apply that average. Six-channel output remains untouched. - Main's row did not have a host option callback. ID 57 is therefore retained for the one row, renamed `HOS_OPT_AUDIO_OUTPUT`; `HOS_OPT_MONO_AUDIO` is gone. - Updated help (including its existing translations), README, audio tests and the menu restart-slot check. - `gpu/vk/menu_i18n.h`: the Mono hint (`The stereo average in both ears. Changes live on stereo output; restart from 5.1.`) in all 13 tables, and the `Mono` value label in the five whose word differs (ru, ja, ko, zh-Hans, zh-Hant; like `Stereo`, de/it/nl/pl/pt/es/fr keep `Mono`); each language's count in `kLangs` follows. - `gpu/vk/vk_menu.cpp`: the free function that reads the value a row's restart is tracked by is `row_restart_value(const Row&)`, so it no longer shares a name with `menu_restart::State::restart_value(slot, v)`, which sets a slot's start value; `tests/test_audio_output_menu.py` and `tests/test_menu_restart_slots.py` read the new name. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | Audio → Audio output; `audio_output` | 0 Auto, 1 Stereo, 2 5.1, **3 Mono**. Mono/Stereo switches live on stereo output; channel layout changes need restart. Auto never enables Mono. | Auto (0), unchanged | Keep Auto default; opt-in Mono | One-sided hearing / one earbud | Six-channel output stays untouched until a stereo layout is selected and the game restarted | Windows, physical 5.1 speakers, listening by ear | Existing saved values keep their meanings; a file without `audio_output` still uses Auto. `HOS_AUDIO_CHANNELS` retains main's channel-layout override. No migration or fallback read of the superseded PR-only `mono_audio` key is added. ## Measurements main: e65cb1e00b8116363326988ca05db15822f0924e (2026-11-13), the base of this PR now this PR: feat/mono-audio @ 0fd02afbac7aa1b96956d1d8158ba2a909ad587b (the measured commit, before the rebase; the head is now e457a41df059e89425ee5a41b09fcefbd80d664f) Why the numbers still hold for e457a41d: since 0fd02afb the PR's audio and menu code is unchanged apart from the menu's translations and a function rename (`row_restart_value`); main's changes since `d9648863` (input hold-to-toggle, saves, VRAM mirror, setup, scripts, docs) do not touch `host/nn_audio.c` or the audio path. Not measured again on the rebased head. Build fingerprint: `mono-output-review (source 528a52f6)`. Original PR head: `df5edcd34bda7ca8f1381d9bf4a8db8a186cf998`. Baseline: this PR @ 0fd02afb, Audio output Stereo Compared with this PR @ 0fd02afb, Audio output Mono in the same live process. This isolates the new row’s live switch; main has no Mono choice. The older main/PR comparison below is historical, not a measurement of this new head. Hardware: RX 7900 XT 20 GB, RADV Mesa 26.2.3; Ryzen 5 7600X, 32 GB RAM; NixOS 26.11 / Linux 7.2.7. Private headless Sway/Xwayland, copied Castle Town save, stationary at the wooden door. 1920×1080, 100% render resolution, game's upscaler, FG/HDR Off, Uncapped, VSync Auto, compute mesh fallback. `HOS_AUDIO=0`: nothing played through speakers. A fresh private source build; shader preparation used a 60-second prediction budget, with remaining pipelines built in play. Method: warmed in the scene, then Stereo → Mono → Stereo → Mono, five seconds settling and 20 seconds sampled per choice. FPS is the median of the last five native presents-log samples. PCM is captured after mixing; counts are from the stereo sample pairs, with nonzero audio required. Audio stays on aka; only counts and screenshots are published. | Observation | this PR @ 0fd02afb, Audio output Stereo | this PR @ 0fd02afb, Audio output Mono | |---|---|---| | Native FPS medians, samples 1 / 2 | 56.0 / 56.6 | 56.6 / 56.4 | | Median of the two FPS medians | 56.3 | 56.5 | | Stereo frames, samples 1 / 2 | 962,048 / 962,048 | 962,048 / 963,072 | | Unequal L/R frames, samples 1 / 2 | 960,175 / 960,120 | 0 / 0 | | Non-silent frames, samples 1 / 2 | 962,037 / 962,034 | 959,216 / 960,560 | <details><summary>Native presents-log samples</summary> ```text stereo-1 [hos Presentation Thread] vk: 26520 presents, 55.8 fps; a frame: 1290 draws (0 skipped), 104 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1286 textures (3176 MB) [hos Presentation Thread] vk: 26640 presents, 56.0 fps; a frame: 1283 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1310 textures (3389 MB) [hos Presentation Thread] vk: 26760 presents, 55.6 fps; a frame: 1295 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1274 textures (3056 MB) [hos Presentation Thread] vk: 26880 presents, 56.6 fps; a frame: 1295 draws (0 skipped), 107 dispatches, 158 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1273 textures (3046 MB) [hos Presentation Thread] vk: 27000 presents, 56.5 fps; a frame: 1291 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1276 textures (3051 MB) mono-2 [hos Presentation Thread] vk: 27960 presents, 56.6 fps; a frame: 1294 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1312 textures (3097 MB) [hos Presentation Thread] vk: 28080 presents, 56.3 fps; a frame: 1296 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.1 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1311 textures (3088 MB) [hos Presentation Thread] vk: 28200 presents, 56.9 fps; a frame: 1292 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1310 textures (3079 MB) [hos Presentation Thread] vk: 28320 presents, 56.2 fps; a frame: 1294 draws (0 skipped), 107 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1310 textures (3079 MB) [hos Presentation Thread] vk: 28440 presents, 56.9 fps; a frame: 1290 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1329 textures (3246 MB) stereo-3 [hos Presentation Thread] vk: 29400 presents, 56.2 fps; a frame: 1294 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1313 textures (3098 MB) [hos Presentation Thread] vk: 29520 presents, 56.6 fps; a frame: 1294 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1312 textures (3089 MB) [hos Presentation Thread] vk: 29640 presents, 56.6 fps; a frame: 1292 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1312 textures (3089 MB) [hos Presentation Thread] vk: 29760 presents, 56.3 fps; a frame: 1290 draws (0 skipped), 105 dispatches, 160 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1311 textures (3079 MB) [hos Presentation Thread] vk: 29880 presents, 56.7 fps; a frame: 1295 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1311 textures (3079 MB) mono-4 [hos Presentation Thread] vk: 30840 presents, 56.1 fps; a frame: 1294 draws (0 skipped), 107 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1319 textures (3106 MB) [hos Presentation Thread] vk: 30960 presents, 56.7 fps; a frame: 1293 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1319 textures (3106 MB) [hos Presentation Thread] vk: 31080 presents, 56.4 fps; a frame: 1292 draws (0 skipped), 105 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1319 textures (3097 MB) [hos Presentation Thread] vk: 31200 presents, 55.8 fps; a frame: 1295 draws (0 skipped), 106 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1318 textures (3088 MB) [hos Presentation Thread] vk: 31320 presents, 56.5 fps; a frame: 1295 draws (0 skipped), 107 dispatches, 159 passes, 157 barriers, 6 submits, 0.0 uploads (0.0 MB), 82 ub updates (57 overlays), GPU-bound wait 0.0 ms; 24463 pipelines (3072 ms), 0 programs (10 failed), 1320 textures (3106 MB) ``` </details> The Audio tab screenshot shows the single row on Mono. The same process restored stereo separation and returned to zero unequal pairs on Mono. These numbers do not establish a cost on all hardware or in other scenes; no 1% lows are claimed. Historical measurement, before the menu revision: main `316f9319` / original PR `df5edcd3`, two interleaved runs each in the same scene. Main FPS medians 53.50 / 54.20 (median 53.85); original PR Mono 53.80 / 54.00 (53.90). Main unequal PCM pairs 960,966 / 960,949; original PR Mono 0 / 0. The PR history retains those original logs and captures. No old screenshot is presented as the new Audio tab. ## Testing **Tested:** (by the author at 0fd02afb; nothing was run on the rebased head e457a41d yet, and nothing was built or run on the PC that rebased it) - Reproduced the missing-choice/wiring failure in both changed audio tests before implementation. - Focused audio, menu, README and option-ID checks: **25 passed, 1 inherited failure** (`test_menu_i18n.py`). Includes extrema, silence, all non-Mono choices unchanged, live transitions, six-channel identity, missing/old/new saved values, environment precedence and restart-value normalization. - Full suite on zao under the shared lock: **516 passed, 2 failed, 16 skipped** (508 seconds). Both failures reproduce on untouched main `d9648863`: the known `test_linux_tools.py` Nix PATH problem (`readlink`/`dirname` absent from `/usr/bin:/bin`), and `test_menu_i18n.py`, whose Debug-tools help translations were left behind when [#138](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/138) added damage scaling (main has since fixed that table in [#273](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/273)). No new failures. `test_display_pointer` and `test_texture_staging_publication` pass on both trees. - `git diff --check` passes. Native fixtures compile with warnings as errors; the full Linux game and renderer build passed. No standalone formatter or typechecker is configured. - Live isolated gameplay and post-mix PCM proof above. Screenshot opened and inspected. Source hashes checked against the tested tree. No installed game, owner save, owner session or `korri*` unit changed. **Not tested:** anything on e457a41d (the rebase onto e65cb1e0, the Mono hint and label translations and the `row_restart_value` rename are checked by reading only; the suite and a build are for CI or the author); the translated Mono hint on screen; Windows build/gameplay, physical 5.1 speakers, listening by ear, other GPU families and full playthroughs. Channel-layout restart behavior is covered by game-free checks; the live proof uses stereo output. **Needs other testers:** Existing request **T-7YW2**, Windows / llvm-mingw / stereo output: compare Audio output Stereo and Mono, switch live, reload the saved choice, and report non-silent L/R equality counts and FPS. The request is not a passing result. ## Screenshots ![this PR @ 0fd02afb: Audio output set to Mono](https://git.magicbean.dev/simonwjackson/Longshot/raw/commit/6fea84da192e2a5aaeefcddd0409a1e27d635178/audio-output-mono.png) ## Risk and rollback Mono removes stereo positioning and can cancel opposite-phase samples. Choose Stereo to restore stereo live on a stereo output. For a different channel layout, restart as on main. Revert the PR to remove the feature. ## Reviewer notes Rebased onto main `e65cb1e00b8116363326988ca05db15822f0924e` as two linear commits: the PR's change (the original commit df5edcd3, the merge bc9285c2 and 0fd02afb squashed into one, Simon's authorship and trailers kept) and one commit for review 1187's suggestions (Mono translations, `row_restart_value`). The rebase met two conflicts, both additions side by side: `gpu/vk/vk_api.h` keeps [#137](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/137)'s `HOS_OPT_HOLD_TOGGLE = 54` and this PR's `HOS_OPT_AUDIO_OUTPUT = 57` (IDs 54, 55, 57 stay unique), and `docs/tested-configurations.md` keeps both PRs' rows. No public `MkwVkHost` / `MkwVkRenderer` structure changed (only an enum is added to `vk_api.h`), so no `MKWVK_API_VERSION` bump. Auto→Mono shows "Restart needed" as Auto→Stereo does on main; left as it is on purpose. The translations, old and new, follow the existing machine-translated tables and have not had native-speaker review. ## Issues None. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [ ] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). (Run by the author on 0fd02afb; not yet on the rebased head e457a41d: CI or the author.) - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags noted, and the switch reference updated (docs/development.md, the README). - [x] Screenshots for a change that shows on screen. - [x] A row in `docs/tested-configurations.md` for each measured run. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [ ] Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths. (Linux: built by the author at 0fd02afb. Windows: T-7YW2, no result yet.) - [x] Docs updated.
feat(audio): add live mono audio for stereo output
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 3s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
df5edcd34b
Carried over from https://github.com/NotRexed/Hookshot/pull/2860.
Use option 57: Longshot main owns 53; keep the other carried options at 54–56.
Cherry-picked source: 13fa2b92b3a47e06f6c32430d8f6716cab1ba5d0.
Resolve rename/context conflicts without changing feature behaviour.
Keep measured configurations in the PR description, not the shared table.

Assisted-by: OpenAI GPT-6 Astra
Co-Authored-By: OpenAI GPT-6 Astra <[email protected]>
HumanBean left a comment

Code review only (I didn't build or run anything).

The change is small and correct. audio_mono sums in 32 bits, so full-scale samples can't overflow. It runs after the gain and before output_frame, so the device and the HOS_AUDIO_DUMP capture both get the mixed signal. It returns early when the row is Off or the output isn't 2 channels, so 5.1 is left alone. The row is saved through ini_key as mono_audio=, its README line is in menu order, and ID 57 is unique on current main (main hasn't touched these files since 316f9319, and a merge-tree against main is clean). Only an enum is added to vk_api.h, and MkwVkHost/MkwVkRenderer don't change, so MKWVK_API_VERSION doesn't need a bump. pr status suggests adding that box, but it doesn't apply.

I found no blockers in the code. The inline comments are nits. It stays WIP until the open boxes are settled: Longshot measurements (main against this PR, interleaved), the Windows test request, and the Windows build box. I'm leaving this as a comment, not an approval, because the PR is WIP.

Code review only (I didn't build or run anything). The change is small and correct. `audio_mono` sums in 32 bits, so full-scale samples can't overflow. It runs after the gain and before `output_frame`, so the device and the `HOS_AUDIO_DUMP` capture both get the mixed signal. It returns early when the row is Off or the output isn't 2 channels, so 5.1 is left alone. The row is saved through `ini_key` as `mono_audio=`, its README line is in menu order, and ID 57 is unique on current main (main hasn't touched these files since 316f9319, and a merge-tree against main is clean). Only an enum is added to `vk_api.h`, and `MkwVkHost`/`MkwVkRenderer` don't change, so `MKWVK_API_VERSION` doesn't need a bump. `pr status` suggests adding that box, but it doesn't apply. I found no blockers in the code. The inline comments are nits. It stays WIP until the open boxes are settled: Longshot measurements (main against this PR, interleaved), the Windows test request, and the Windows build box. I'm leaving this as a comment, not an approval, because the PR is WIP.
gpu/vk/vk_menu.h Outdated
@ -94,6 +94,7 @@ struct Options {
int discord = 1; // (longshot) the Discord status (host/discord_rpc.c): 1 on, shown while a Discord client runs on this PC
int debug_tools = 0; // (longshot) the Debug tab's tools (#785: flight, free camera, teleport, inventory): 0 off; HOS_OOT_CHEATS=1 also turns them on
int volume = 100; // (longshot) the game's sound in percent, 0 to 100 (host/nn_audio.c: HOS_OPT_VOLUME, 27)
int mono_audio = 0; // final stereo output only; 5.1 is unchanged
Owner

Nit: the neighbouring fields name their reader and option ID, e.g. // (longshot) ... (host/nn_audio.c: HOS_OPT_MONO_AUDIO, 57). Doing the same here (and adding HOS_OPT_MONO_AUDIO to the include comment at host/nn_audio.c:21) keeps the cross-reference greppable.

Nit: the neighbouring fields name their reader and option ID, e.g. `// (longshot) ... (host/nn_audio.c: HOS_OPT_MONO_AUDIO, 57)`. Doing the same here (and adding HOS_OPT_MONO_AUDIO to the include comment at host/nn_audio.c:21) keeps the cross-reference greppable.
host/nn_audio.c Outdated
@ -1336,2 +1345,4 @@
if (gain_frames-- <= 0) gain_want = audio_player_gain(), gain_frames = 20; /* (the menu read every 100 ms) */
gain = audio_apply_gain(pcm, FRAME, out_channels, gain, gain_want);
int rx_option(int id, int otherwise);
audio_mono(pcm, FRAME, out_channels, rx_option(HOS_OPT_MONO_AUDIO, 0));
Owner

Nit: this asks the menu on every 5 ms audio frame, while Volume and Mute in background are read every 100 ms through gain_frames ("the menu read every 100 ms"). It's cheap either way. Still, reading it next to gain_want (e.g. mono_want, refreshed in the same gain_frames branch) would follow the loop's pattern, and so would declaring rx_option once at file scope instead of a third block-scope declaration. If you do that, the source-reading check in tests/test_audio_mono.py needs the same update.

Nit: this asks the menu on every 5 ms audio frame, while Volume and Mute in background are read every 100 ms through `gain_frames` ("the menu read every 100 ms"). It's cheap either way. Still, reading it next to `gain_want` (e.g. `mono_want`, refreshed in the same `gain_frames` branch) would follow the loop's pattern, and so would declaring `rx_option` once at file scope instead of a third block-scope declaration. If you do that, the source-reading check in `tests/test_audio_mono.py` needs the same update.
@ -0,0 +56,4 @@
assert re.search(
r'\{TAB_AUDIO, "Mono audio", &opts.mono_audio, 0, 1, 1, tx_onoff,\s*'
r'"[^"]+", nullptr, false, true\}', read("gpu/vk/vk_menu.cpp"))
# Main has assigned the fork's original id 46 to Button prompts.
Owner

Stale comment: on Longshot the ID is 57 (53 is HOS_OPT_FPS_CAP), and the "id 46 / Button prompts" history is from the Hookshot branch. Either say what the assert checks (the Mono ID is unique among the explicit HOS_OPT_ IDs) or drop the comment.

Stale comment: on Longshot the ID is 57 (53 is HOS_OPT_FPS_CAP), and the "id 46 / Button prompts" history is from the Hookshot branch. Either say what the assert checks (the Mono ID is unique among the explicit `HOS_OPT_` IDs) or drop the comment.
Author
Contributor

Added a fresh interleaved main/PR Linux measurement session at the named commits, the last-five-sample FPS medians, feature proof and inspected screenshots. Windows testing requests are open; the description names the remaining gaps. The branch also rebases cleanly onto main 1be180bb with an identical stable patch ID and passing focused tests; the force-with-lease push is still gated, so the measured remote head stays pinned. No new baseline FPS is claimed for the local rebase.

Added a fresh interleaved main/PR Linux measurement session at the named commits, the last-five-sample FPS medians, feature proof and inspected screenshots. Windows testing requests are open; the description names the remaining gaps. The branch also rebases cleanly onto main 1be180bb with an identical stable patch ID and passing focused tests; the force-with-lease push is still gated, so the measured remote head stays pinned. No new baseline FPS is claimed for the local rebase.
simonwjackson changed title from WIP: feat(audio): add live mono audio for stereo output to feat(audio): add live mono audio for stereo output 2026-11-13 07:49:50 +00:00
Owner

Don't we already have a setting for 5.1 audio? maybe this should be in there

Don't we already have a setting for 5.1 audio? maybe this should be in there
HumanBean added this to the v3.0.0 milestone 2026-11-13 17:55:07 +00:00
Resolve adjacent audio and damage option declarations; retain both IDs.

Assisted-by: OpenAI GPT-6 Astra
Co-Authored-By: OpenAI GPT-6 Astra <[email protected]>
feat(audio): fold Mono into the Audio output row
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
Website / Website on Cloudflare (pull_request) Has been cancelled
0fd02afbac
Preserve Auto=0, Stereo=1 and 5.1=2; append Mono=3. Reuse option 57 for the row, retaining live stereo averaging and main’s restart-only layout changes. Do not ask for a restart between Mono and Stereo.

Update help, translations, README and source-reading tests. Verify live non-silent post-mix captures: Mono has zero unequal stereo pairs; Stereo restores separation.

Assisted-by: OpenAI GPT-6 Astra
Co-Authored-By: OpenAI GPT-6 Astra <[email protected]>
simonwjackson changed title from feat(audio): add live mono audio for stereo output to feat(audio): a Mono choice on the Audio output row 2026-11-13 21:09:39 +00:00
Author
Contributor

Yes—Mono is now a choice on Audio output alongside Auto, Stereo and 5.1, rather than a separate row. Existing saved values keep their meanings; Mono is 3, and Mono/Stereo switches live on stereo output. Pushed 0fd02af after merging main normally. The updated description includes the Audio tab screenshot and non-silent post-mix captures: Mono has 0 unequal L/R frames in both samples; Stereo restores separation. The full suite has no new failures; both inherited failures are reproduced on untouched main.

Yes—Mono is now a choice on Audio output alongside Auto, Stereo and 5.1, rather than a separate row. Existing saved values keep their meanings; Mono is 3, and Mono/Stereo switches live on stereo output. Pushed 0fd02af after merging main normally. The updated description includes the Audio tab screenshot and non-silent post-mix captures: Mono has 0 unequal L/R frames in both samples; Stereo restores separation. The full suite has no new failures; both inherited failures are reproduced on untouched main.
HumanBean left a comment

The code is sound. Folding Mono into Audio output is clean: saved values 0–2 keep their meanings, Mono only acts on a two-channel output, the 32-bit average can't overflow, and treating Mono like Stereo for restart tracking is right. The changes I'm asking for are in the checklist, not the code.

Must change before merge

  • The Windows host build box is reworded and ticked, but it isn't true yet. This PR changes host code (host/nn_audio.c, gpu/vk/vk_menu.cpp, gpu/vk/vk_api.h), so the template box Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths applies. pr status also points it out. The description replaces it with "Linux host build verified; Windows remains assigned to T-7YW2" and ticks that. Please put the template's wording back and leave the box unticked until the Windows build is done, with T-7YW2 named beside it. Another option is a local llvm-mingw cross-build, which needs no Windows machine. The C looks portable, so I expect it to pass, but the box has to say what was actually checked.
  • "Rebased on current main" is reworded too. It now says main was merged in. Since the PR is squash-merged, a merge commit does no harm, but please keep the template's text. Either rebase onto current main (514591a3, docs only since your merge) or leave the box unticked with the reason beside it.

Suggestions (non-blocking)

  • The new Mono hint, and the Mono value label, have no entries in the 13 translated tables. The other three Audio output hints are in all of them, so a translated menu shows this one hint in English (inline).
  • The new free function restart_value(const Row&) reads a value, while State::restart_value(slot, v) sets one. Both are in the same file, so a different name would read better (inline).
  • If the game started on Auto with a stereo device, switching to Mono shows "Restart needed" even though Mono already applies live. Auto→Stereo already behaves this way on main, so this is minor (inline).

CI for 0fd02afb was still pending when I reviewed it. I only read the code; I didn't run any checks.

The code is sound. Folding Mono into Audio output is clean: saved values 0–2 keep their meanings, Mono only acts on a two-channel output, the 32-bit average can't overflow, and treating Mono like Stereo for restart tracking is right. The changes I'm asking for are in the checklist, not the code. **Must change before merge** - **The Windows host build box is reworded and ticked, but it isn't true yet.** This PR changes host code (`host/nn_audio.c`, `gpu/vk/vk_menu.cpp`, `gpu/vk/vk_api.h`), so the template box *Host code builds on both Windows (llvm-mingw) and Linux, with UTF-8 paths* applies. `pr status` also points it out. The description replaces it with "Linux host build verified; Windows remains assigned to T-7YW2" and ticks that. Please put the template's wording back and leave the box unticked until the Windows build is done, with T-7YW2 named beside it. Another option is a local llvm-mingw cross-build, which needs no Windows machine. The C looks portable, so I expect it to pass, but the box has to say what was actually checked. - **"Rebased on current main" is reworded too.** It now says main was merged in. Since the PR is squash-merged, a merge commit does no harm, but please keep the template's text. Either rebase onto current main (`514591a3`, docs only since your merge) or leave the box unticked with the reason beside it. **Suggestions (non-blocking)** - The new Mono hint, and the `Mono` value label, have no entries in the 13 translated tables. The other three Audio output hints are in all of them, so a translated menu shows this one hint in English (inline). - The new free function `restart_value(const Row&)` reads a value, while `State::restart_value(slot, v)` sets one. Both are in the same file, so a different name would read better (inline). - If the game started on Auto with a stereo device, switching to Mono shows "Restart needed" even though Mono already applies live. Auto→Stereo already behaves this way on main, so this is minor (inline). CI for `0fd02afb` was still pending when I reviewed it. I only read the code; I didn't run any checks.
@ -1130,2 +1130,3 @@
MENU_HINTS(hn_audio_output, 0, "5.1 when the default output device has 5.1 or more speakers, else stereo.",
"Stereo, whatever the device has.", "5.1, whatever the device has. Mixed down on stereo speakers.")
"Stereo, whatever the device has.", "5.1, whatever the device has. Mixed down on stereo speakers.",
"The stereo average in both ears. Changes live on stereo output; restart from 5.1.")
Owner

This hint, and Mono in tx_audio_output, have no entries in the 13 tables in menu_i18n.h. The other three hn_audio_output hints are translated in every table, so a translated menu shows only this one in English. Please add the entries alongside the row help you already updated.

This hint, and `Mono` in `tx_audio_output`, have no entries in the 13 tables in `menu_i18n.h`. The other three `hn_audio_output` hints are translated in every table, so a translated menu shows only this one in English. Please add the entries alongside the row help you already updated.
@ -1606,2 +1607,4 @@
int restart_slot[kRows]; // (a row's slot in restart_state, -1 none)
const char* restart_names[mr::kMax];
// Mono and Stereo use the same channel layout; their live mix does not need a restart.
int restart_value(const Row& r) {
Owner

Nit: menu_restart::State::restart_value(slot, v) (used in prompts_at_once) sets a slot's start value, and this free restart_value(row) reads the value a row is tracked by. Having both names in one file makes restart_state.restart_value(...) and restart_value(r) easy to mix up. Maybe restart_tracked_value or restart_layout?

Nit: `menu_restart::State::restart_value(slot, v)` (used in `prompts_at_once`) *sets* a slot's start value, and this free `restart_value(row)` *reads* the value a row is tracked by. Having both names in one file makes `restart_state.restart_value(...)` and `restart_value(r)` easy to mix up. Maybe `restart_tracked_value` or `restart_layout`?
@ -1607,1 +1608,4 @@
const char* restart_names[mr::kMax];
// Mono and Stereo use the same channel layout; their live mix does not need a restart.
int restart_value(const Row& r) {
return r.value == &opts.audio_output && *r.value == 3 ? 1 : *r.value;
Owner

Minor: if the game started on Auto with a stereo device (start value 0), choosing Mono gives 1 != 0, so the row says a restart is needed even though Mono already applies live. Main does the same for Auto→Stereo, so this isn't new. It could be fixed by tracking Auto by the layout it resolved to. Not blocking.

Minor: if the game started on Auto with a stereo device (start value 0), choosing Mono gives 1 != 0, so the row says a restart is needed even though Mono already applies live. Main does the same for Auto→Stereo, so this isn't new. It could be fixed by tracking Auto by the layout it resolved to. Not blocking.
HumanBean force-pushed feat/mono-audio from 0fd02afbac
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
Website / Website on Cloudflare (pull_request) Has been cancelled
to e457a41df0
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
CI / Workflow lint (actionlint) (pull_request) Successful in 6s
Third-party parts / As their notes say (pull_request) Successful in 7s
PR description / Description follows the template (pull_request_target) Failing after 6s
Website / Website on Cloudflare (pull_request_target) Has been skipped
2026-11-14 00:53:25 +00:00
Compare
Owner

Review 1187 addressed, rebased and pushed: head is now e457a41d, on main e65cb1e00b8116363326988ca05db15822f0924e.

  • Rebased on current main: the history is linear now. The original commit, the merge bc9285c2 and 0fd02afb are squashed into one commit, with Simon still the author, and the review fixes are a second commit on top. Two conflicts came up, both additions side by side. In gpu/vk/vk_api.h, #137's HOS_OPT_HOLD_TOGGLE = 54 sits next to HOS_OPT_AUDIO_OUTPUT = 57. In docs/tested-configurations.md, both PRs' rows are kept. The box has the template's wording again and is ticked.
  • Host build box: it has the template's wording again and is unticked, with "Windows: T-7YW2" beside it. T-7YW2 has no result yet (it is still waiting for the testing wanted label), and no comment reports a Windows build. The box waits on T-7YW2.
  • Mono translations: the Mono hint is now in all 13 tables in gpu/vk/menu_i18n.h, with the same terms as the neighbouring Audio output entries. The Mono label is added where the word is written differently (ru, ja, ko, zh-Hans, zh-Hant). As with Stereo, the de/it/nl/pl/pt/es/fr tables keep the English word. Each language's count in kLangs is raised to match.
  • restart_value(const Row&) is renamed row_restart_value, and its three callers are updated. So are the checks that read it by text: tests/test_audio_output_menu.py and tests/test_menu_restart_slots.py.
  • Auto→Mono "Restart needed": unchanged on purpose, because main does the same for Auto→Stereo.

The description has the template's wording again on the other reworded boxes too. The run_all.py box is unticked because the author's run was on 0fd02afb, so CI or the author still has to run it on e457a41d. Measurements now explain why the 0fd02afb numbers still hold for the rebased head. No tests, checks or builds were run on the PC that did this rebase: the changes were checked by reading only.

Review 1187 addressed, rebased and pushed: head is now `e457a41d`, on main `e65cb1e00b8116363326988ca05db15822f0924e`. - **Rebased on current main:** the history is linear now. The original commit, the merge `bc9285c2` and `0fd02afb` are squashed into one commit, with Simon still the author, and the review fixes are a second commit on top. Two conflicts came up, both additions side by side. In `gpu/vk/vk_api.h`, [#137](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/137)'s `HOS_OPT_HOLD_TOGGLE = 54` sits next to `HOS_OPT_AUDIO_OUTPUT = 57`. In `docs/tested-configurations.md`, both PRs' rows are kept. The box has the template's wording again and is ticked. - **Host build box:** it has the template's wording again and is unticked, with "Windows: T-7YW2" beside it. T-7YW2 has no result yet (it is still waiting for the `testing wanted` label), and no comment reports a Windows build. The box waits on T-7YW2. - **Mono translations:** the Mono hint is now in all 13 tables in `gpu/vk/menu_i18n.h`, with the same terms as the neighbouring Audio output entries. The `Mono` label is added where the word is written differently (ru, ja, ko, zh-Hans, zh-Hant). As with `Stereo`, the de/it/nl/pl/pt/es/fr tables keep the English word. Each language's count in `kLangs` is raised to match. - **`restart_value(const Row&)`** is renamed `row_restart_value`, and its three callers are updated. So are the checks that read it by text: `tests/test_audio_output_menu.py` and `tests/test_menu_restart_slots.py`. - **Auto→Mono "Restart needed":** unchanged on purpose, because main does the same for Auto→Stereo. The description has the template's wording again on the other reworded boxes too. The `run_all.py` box is unticked because the author's run was on `0fd02afb`, so CI or the author still has to run it on `e457a41d`. Measurements now explain why the `0fd02afb` numbers still hold for the rebased head. No tests, checks or builds were run on the PC that did this rebase: the changes were checked by reading only.
HumanBean left a comment

Light re-review of 6606b94b + e457a41d against review 1187. The code is right. I'm not approving yet only because of two unticked boxes (below).

Rebase (6606b94b): its added and removed lines against e65cb1e0 are the same as 0fd02afb's against its base d9648863. Only context lines differ, at the two conflicts. vk_api.h keeps #137's HOS_OPT_HOLD_TOGGLE = 54 and adds HOS_OPT_AUDIO_OUTPUT = 57. The IDs 51–55 and 57 are all unique, and none of #137's lines are removed. tested-configurations.md keeps both PRs' rows.

Review fixes (e457a41d)

  • The hint key is exactly the fourth hn_audio_output string in vk_menu.cpp. It sorts between "The speakers…" and "The sticks…" in all 13 tables, and Mono sorts between "Monitor's shape" and "Motion". The translations read well and use the same terms as the Audio output hint beside them in each table (Moно/モノラル/모노/单声道/單聲道).
  • I counted the {" rows in each table, and every kLangs count matches (530, 536, 538, 533, 528, 531, 522, 531, 545, 538, 543, 538, 538).
  • Mono is left out where the word is the same, which matches how the tables handle Stereo (de/it/nl/pl don't have it). Nit: the description and the fix comment say pt/es/fr keep Stereo too, but they translate it (Estéreo, Stéréo). Those three skip Mono only because the word is spelled the same there, which is fine.
  • The row_restart_value rename is complete. The only restart_value( calls left are menu_restart::State::restart_value(slot, v) (vk_menu.cpp 1939/4253/4701, tests/test_menu_restart.cpp). The text cuts in test_audio_output_menu.py and test_menu_restart_slots.py match the new source.

Boxes: both unticked boxes are true as written. The Rebased box is true (e65cb1e0 is main's tip). But they block a merge as is (CONTRIBUTING: every For everyone box ticked, and every If applicable box kept must be done):

  • run_all.py on e457a41d: CI's Python source checks run only on workflow_dispatch, and they were skipped on this head. A maintainer dispatch (or the author's run) can settle it.
  • Host build on Windows: waiting on T-7YW2.

While the run_all box is unticked, the PR should be WIP (pr wip 136) or get that run soon. I'll approve once both are settled. No further code changes are needed.

Light re-review of `6606b94b` + `e457a41d` against review 1187. The code is right. I'm not approving yet only because of two unticked boxes (below). **Rebase (`6606b94b`)**: its added and removed lines against `e65cb1e0` are the same as `0fd02afb`'s against its base `d9648863`. Only context lines differ, at the two conflicts. `vk_api.h` keeps [#137](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/137)'s `HOS_OPT_HOLD_TOGGLE = 54` and adds `HOS_OPT_AUDIO_OUTPUT = 57`. The IDs 51–55 and 57 are all unique, and none of #137's lines are removed. `tested-configurations.md` keeps both PRs' rows. **Review fixes (`e457a41d`)** - The hint key is exactly the fourth `hn_audio_output` string in `vk_menu.cpp`. It sorts between "The speakers…" and "The sticks…" in all 13 tables, and `Mono` sorts between "Monitor's shape" and "Motion". The translations read well and use the same terms as the Audio output hint beside them in each table (Moно/モノラル/모노/单声道/單聲道). - I counted the `{"` rows in each table, and every `kLangs` count matches (530, 536, 538, 533, 528, 531, 522, 531, 545, 538, 543, 538, 538). - `Mono` is left out where the word is the same, which matches how the tables handle `Stereo` (de/it/nl/pl don't have it). Nit: the description and the fix comment say pt/es/fr keep `Stereo` too, but they translate it (`Estéreo`, `Stéréo`). Those three skip `Mono` only because the word is spelled the same there, which is fine. - The `row_restart_value` rename is complete. The only `restart_value(` calls left are `menu_restart::State::restart_value(slot, v)` (vk_menu.cpp 1939/4253/4701, tests/test_menu_restart.cpp). The text cuts in `test_audio_output_menu.py` and `test_menu_restart_slots.py` match the new source. **Boxes**: both unticked boxes are true as written. The *Rebased* box is true (`e65cb1e0` is main's tip). But they block a merge as is (CONTRIBUTING: every *For everyone* box ticked, and every *If applicable* box kept must be done): - `run_all.py` on `e457a41d`: CI's Python source checks run only on `workflow_dispatch`, and they were skipped on this head. A maintainer dispatch (or the author's run) can settle it. - Host build on Windows: waiting on T-7YW2. While the `run_all` box is unticked, the PR should be WIP (`pr wip 136`) or get that run soon. I'll approve once both are settled. No further code changes are needed.
HumanBean deleted branch feat/mono-audio 2026-11-14 00:58:33 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!136
No description provided.