Audio output in the Insert menu: Auto, Stereo or 5.1 #1240

Merged
janvitos merged 1 commit from feat/audio-output-menu into main 2026-11-09 22:38:39 +00:00
janvitos commented 2026-11-09 18:43:11 +00:00 (Migrated from github.com)

A follow-up to #1182, as suggested in its review: an Audio output row in the Insert menu (Gameplay) with Auto, Stereo and 5.1.

What

  • Auto (the default) is #1182's behaviour: 5.1 when the default output device has 5.1 or more speakers, else stereo.
  • Stereo or 5.1 chooses one whatever the device has. 5.1 on stereo speakers is mixed down, as before.
  • Saved as audio_output= in hookshot_options.ini. host/nn_audio.c reads it from the file, the way nn_applet.c reads the Handheld profile, because the game asks for its speakers only once, at its start. The row says "(restart)", like Output resolution.
  • HOS_AUDIO_CHANNELS=2 or 6 still wins over the menu.
  • readme: the options table and a short note under it.

How it was tested

  • Machine: Linux (CachyOS), RTX 4070 SUPER, default output stereo.

  • In game: a game build with this host change, on the v2.0.8-rc.5 source plus #1182, with headless runs. In each run the log line and the dumped audio's channel count match:

    audio_output HOS_AUDIO_CHANNELS The game is told Dump
    1 — stereo (the Insert menu's Audio output) 2 ch
    2 — 5.1 (the Insert menu's Audio output) 6 ch
    0 — stereo (the default output has 2 channels) 2 ch
    1 6 5.1 (HOS_AUDIO_CHANNELS) 6 ch
  • Not tested: the menu row itself wasn't seen in game. This PC has no Vulkan toolchain, so the build used the release's prebuilt Vulkan back end.

  • New test: tests/test_audio_output_menu.py compiles the real au_speakers and au_menu_output together with the menu's ini_key and tx_audio_output. It writes the row's choice under the key the menu would save, so a renamed row or key fails it. It covers Auto with a 2-, 6- and 8-channel device, Stereo, 5.1, hand-edited 3 and -1 (clamped as the menu reads them), and HOS_AUDIO_CHANNELS over the menu. It's registered in run_all.py with --cxx g++. I checked that it fails when the host ignores the menu, when the key is misspelled or when the row is renamed.

  • Windows: host/nn_audio.c passes a syntax check with mingw-w64 and has the same warnings as main's.

  • Suite: on this branch (on 09e4eb5), python -I -B tests/run_all.py gives 144 passed, 2 failed, 17 skipped on Linux. Both failures are the same on unchanged main here:

    • nx2/test_nup_read_name.py needs zstandard, which isn't installed here.
    • tests/test_output_resolution.py aborts on its first case.

🤖 Generated with Claude Code

A follow-up to #1182, as suggested in its review: an **Audio output** row in the Insert menu (Gameplay) with Auto, Stereo and 5.1. ## What - **Auto** (the default) is #1182's behaviour: 5.1 when the default output device has 5.1 or more speakers, else stereo. - **Stereo** or **5.1** chooses one whatever the device has. 5.1 on stereo speakers is mixed down, as before. - **Saved** as `audio_output=` in `hookshot_options.ini`. `host/nn_audio.c` reads it from the file, the way `nn_applet.c` reads the Handheld profile, because the game asks for its speakers only once, at its start. The row says "(restart)", like Output resolution. - **`HOS_AUDIO_CHANNELS=2` or `6`** still wins over the menu. - **readme:** the options table and a short note under it. ## How it was tested - **Machine:** Linux (CachyOS), RTX 4070 SUPER, default output stereo. - **In game:** a game build with this host change, on the v2.0.8-rc.5 source plus #1182, with headless runs. In each run the log line and the dumped audio's channel count match: | `audio_output` | `HOS_AUDIO_CHANNELS` | The game is told | Dump | |---|---|---|---| | 1 | — | stereo (the Insert menu's Audio output) | 2 ch | | 2 | — | 5.1 (the Insert menu's Audio output) | 6 ch | | 0 | — | stereo (the default output has 2 channels) | 2 ch | | 1 | 6 | 5.1 (HOS_AUDIO_CHANNELS) | 6 ch | - **Not tested:** the menu row itself wasn't seen in game. This PC has no Vulkan toolchain, so the build used the release's prebuilt Vulkan back end. - **New test:** `tests/test_audio_output_menu.py` compiles the real `au_speakers` and `au_menu_output` together with the menu's `ini_key` and `tx_audio_output`. It writes the row's choice under the key the menu would save, so a renamed row or key fails it. It covers Auto with a 2-, 6- and 8-channel device, Stereo, 5.1, hand-edited 3 and -1 (clamped as the menu reads them), and `HOS_AUDIO_CHANNELS` over the menu. It's registered in `run_all.py` with `--cxx g++`. I checked that it fails when the host ignores the menu, when the key is misspelled or when the row is renamed. - **Windows:** `host/nn_audio.c` passes a syntax check with mingw-w64 and has the same warnings as main's. - **Suite:** on this branch (on 09e4eb5), `python -I -B tests/run_all.py` gives 144 passed, 2 failed, 17 skipped on Linux. Both failures are the same on unchanged main here: - `nx2/test_nup_read_name.py` needs `zstandard`, which isn't installed here. - `tests/test_output_resolution.py` aborts on its first case. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
janvitos commented 2026-11-09 19:09:54 +00:00 (Migrated from github.com)

The two failing checks are tests/test_output_resolution.py, which also fails on main's own CI (fe611e4, Linux and Windows). tests/test_audio_output_menu.py passes on both, and both Vulkan back-end builds pass.

The two failing checks are `tests/test_output_resolution.py`, which also fails on main's own CI (fe611e4, Linux and Windows). `tests/test_audio_output_menu.py` passes on both, and both Vulkan back-end builds pass.
hckrman101 (Migrated from github.com) reviewed 2026-11-09 19:18:27 +00:00
hckrman101 (Migrated from github.com) left a comment

Nice follow-up, and the host side looks right: the ini is read once inside au_speakers, HOS_AUDIO_CHANNELS wins over the menu, Auto falls back to #1182's device check, old ini files without the key give Auto, and the value is clamped to 0..2. 5.1 on a stereo device just gets mixed down like before. The test is thorough and is registered in run_all.py with --cxx g++. The readme matches the behaviour.

It needs a rebase though: this PR is currently conflicting with main, and the row will not compile as written on current main. Main's Row now has a hint function pointer before the restart and preset_exempt flags (see the Output resolution and Microphone rows), so the trailing true lands in the hint slot. Two comments below on what to change.

The Python source checks failures on this PR are the known ones on main (test_output_resolution.py, test_program_cache_cleanup.py), not yours.

Nice follow-up, and the host side looks right: the ini is read once inside `au_speakers`, `HOS_AUDIO_CHANNELS` wins over the menu, Auto falls back to #1182's device check, old ini files without the key give Auto, and the value is clamped to 0..2. 5.1 on a stereo device just gets mixed down like before. The test is thorough and is registered in `run_all.py` with `--cxx g++`. The readme matches the behaviour. It needs a rebase though: this PR is currently conflicting with main, and the row will not compile as written on current main. Main's `Row` now has a `hint` function pointer before the `restart` and `preset_exempt` flags (see the Output resolution and Microphone rows), so the trailing `true` lands in the hint slot. Two comments below on what to change. The Python source checks failures on this PR are the known ones on main (`test_output_resolution.py`, `test_program_cache_cleanup.py`), not yours.
hckrman101 (Migrated from github.com) commented 2026-11-09 19:18:28 +00:00

Once restart is set on the row, main appends " (after restart)" to the label itself when the value differs from the one at start, and the other restart rows (Output resolution) have plain value text. So this can be plain "Auto", "Stereo", "5.1" and the test's tx_audio_output expectations adjusted to match; otherwise it would read "Auto (restart) (after restart)".

Once `restart` is set on the row, main appends " (after restart)" to the label itself when the value differs from the one at start, and the other restart rows (Output resolution) have plain value text. So this can be plain "Auto", "Stereo", "5.1" and the test's `tx_audio_output` expectations adjusted to match; otherwise it would read "Auto (restart) (after restart)".
hckrman101 (Migrated from github.com) commented 2026-11-09 19:18:27 +00:00

On current main the fields after help are hint, then restart, then preset_exempt, so this needs to be ..., nullptr, true, true} (restart and preset_exempt), or a small hn_audio_output with MENU_HINTS if you want a per-value line. Setting restart = true is also what puts the row in the "Restart needed" list and makes closing the menu offer a restart, which this row doesn't get otherwise.

On current main the fields after `help` are `hint`, then `restart`, then `preset_exempt`, so this needs to be `..., nullptr, true, true}` (restart and preset_exempt), or a small `hn_audio_output` with `MENU_HINTS` if you want a per-value line. Setting `restart = true` is also what puts the row in the "Restart needed" list and makes closing the menu offer a restart, which this row doesn't get otherwise.
janvitos commented 2026-11-09 19:33:40 +00:00 (Migrated from github.com)

Thanks. Rebased onto main (ac3bd44) as 4856258:

  • The row now ends hn_audio_output, true, true}: a restart row, still preset-exempt, so a change shows "(after restart)", joins the Restart needed list, and closing the menu offers the restart.
  • The values are plain Auto, Stereo, 5.1, with a hint line each (hn_audio_output via MENU_HINTS).
  • menu_restart.h's comment now counts six restart rows (kMax is 8).
  • The test checks the row's hint, restart and preset_exempt fields and the hints against main's Row.
Thanks. Rebased onto main (ac3bd44) as 4856258: - The row now ends `hn_audio_output, true, true}`: a restart row, still preset-exempt, so a change shows "(after restart)", joins the Restart needed list, and closing the menu offers the restart. - The values are plain `Auto`, `Stereo`, `5.1`, with a hint line each (`hn_audio_output` via `MENU_HINTS`). - `menu_restart.h`'s comment now counts six restart rows (`kMax` is 8). - The test checks the row's hint, restart and preset_exempt fields and the hints against main's `Row`.
hckrman101 (Migrated from github.com) reviewed 2026-11-09 20:06:55 +00:00
hckrman101 (Migrated from github.com) commented 2026-11-09 20:06:55 +00:00

Fixed, the row now ends hn_audio_output, true, true} and matches Row.

Fixed, the row now ends `hn_audio_output, true, true}` and matches Row.
hckrman101 (Migrated from github.com) reviewed 2026-11-09 20:06:56 +00:00
hckrman101 (Migrated from github.com) commented 2026-11-09 20:06:56 +00:00

Plain labels now, thanks.

Plain labels now, thanks.
hckrman101 (Migrated from github.com) approved these changes 2026-11-09 20:06:58 +00:00
hckrman101 (Migrated from github.com) left a comment

Thanks, all points are fixed: the row ends hn_audio_output, true, true} (hint, restart, preset_exempt, in main's Row order), so it shows "(after restart)", joins the Restart needed list and the close offers the restart; the labels are plain; the test checks the row fields and hints; no conflicts. The two failing checks are main's known ones.

One non-blocking thing: #1270 adds an Audio tab to the Insert menu (Volume, Mute in background), and this row would fit naturally there. Worth coordinating with its author on which PR moves the row, whichever lands second.

Thanks, all points are fixed: the row ends `hn_audio_output, true, true}` (hint, restart, preset_exempt, in main's Row order), so it shows "(after restart)", joins the Restart needed list and the close offers the restart; the labels are plain; the test checks the row fields and hints; no conflicts. The two failing checks are main's known ones. One non-blocking thing: #1270 adds an Audio tab to the Insert menu (Volume, Mute in background), and this row would fit naturally there. Worth coordinating with its author on which PR moves the row, whichever lands second.
Commenting is not possible because the repository is archived.
No description provided.