Mix for 5.1 when the default output has 5.1 speakers #1182
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!1182
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/surround-5.1"
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?
Fixes #1124.
What
Hookshot now gives the game the default output's real channel count, so it mixes 5.1 when the output has 5.1.
SDL_GetAudioDeviceFormat, or SDL2'sSDL_GetDefaultAudioInfo. That call is looked up at runtime, so an older SDL still plays, in stereo.WAVE_FORMAT_EXTENSIBLEwith the speaker mask.HOS_AUDIO_CHANNELS=2or6, documented with the otherHOS_AUDIO_*switches at the top ofnn_audio.c.Why
The game asks once for the output's channel count (
GetActiveAudioDeviceChannelCountForOutput) and pans for that many speakers. Hookshot always answered 2, so nothing was ever placed behind the player. On a 5.1 system the whole game came from the front speakers; in the issue, Epona's hooves in the intro are "but a whisper" instead of behind you.How it was tested
8b2e1d3.audio: 5.1 for the game (the default output has 6 channels). In gameplay all six channels carry sound, centre, LFE and rears included.tests/test_audio_output_errors.pyfollows the newrender_framesignature. On this branch (rebased on1f6fbdb),python -I -B tests/run_all.pygives 131 passed, 0 failed, 17 skipped on Linux.During testing I also hit a speaker channel going silent at random, in stereo too. That is a separate bug with a separate fix in #1181. This PR doesn't depend on it.
🤖 Generated with Claude Code
Nice one, this looks right to me. What I checked:
GetActiveAudioDeviceChannelCountForOutputnow returnsau_speakers(), and the sink order FL FR FC LFE RL RR goes straight through to the device. That's the same order as Windows' 0x3F mask and SDL's 5.1 layout, and the stereo downmix coefficients are unchanged.blocks/pcmare sized for 6 channels,dwBufferLengthis two frames at the opened channel count, and thememcpyoffsets, the dump header (align/brate) and the per-frame dump writes all followout_channels.render_frameis called without_channels, so a stereo fallback after the game was told 6 just downmixes.pull3fix is real.SDL_PutAudioStreamDatarejects partial sample frames, 4096 % 12 = 4, andwantalways comes in whole frames, so the loop still ends at 0.SDL_AudioSpec {format, channels, freq}withSDL_GetAudioDeviceFormat(0xFFFFFFFF, ...), and SDL2'sSDL_AudioSpecwithSDL_GetDefaultAudioInfo(&name, &spec, 0)plusSDL_freeon the name. Looking these up lazily viaGetProcAddresskeeps an older SDL2 working.-lole32is already inHOST_LIBS. The GUIDs are local, so there's no uuid lib dependency, andCoInitializeExis balanced (an RPC_E_CHANGED_MODE thread still works with the existing apartment).surround/fallbacktest cases exercise the real output section (it's extracted from#define NBLOCKS, soOUT_MAX_CHis included).Only small things, nothing blocking:
au_speakersholdsau_lockacross the device query (inline comment).waveOutOpenerrors before the stereo round. That's harmless, just noisier logs.output_frame/render_frame.@ -657,1 +760,4 @@if (wout || channels == 2 || dump) break;hos_log("audio: no device took 5.1: stereo instead");channels = 2;}Nit: this holds the mixer lock across the COM/SDL device query. On Windows,
Activate/GetMixFormatcan take a noticeable moment, for example when an HDMI or Bluetooth endpoint is waking up. Every other audio HLE that takesau_lockwaits on it meanwhile. It only happens once at startup, so it's fine as is. If you want to avoid it, you could do the query outside the lock and just publishknown(both threads would compute the same value anyway).Please add menu options so we can pick 2.0 or 5.1 output.
@Uncloak2 for now this PR picks it automatically: 5.1 when your default output device has 5.1 (or more) speakers, stereo otherwise. If you want to force one, set
HOS_AUDIO_CHANNELS=2(stereo) orHOS_AUDIO_CHANNELS=6(5.1), e.g. as a line inhookshot_env.txtnext to the game.An in-game option (Auto / Stereo / 5.1 in the Insert menu) would be a nice follow-up. The game only reads the channel count when it starts, so it'd need a restart like Output resolution, but it can be saved in
hookshot_options.inithe same way. I'd keep it out of this PR so this one stays small.