feat(windows): sound, through XAudio2

audio_win.ll implements audio.ll's snd_* contract over XAudio2 from IR: a
source voice per clip, restart on play, LoopCount for loops, SetVolume,
SetFrequencyRatio and a balance pan through SetOutputMatrix, with the COM
slots taken from the SDK's xaudio2.h. Clips are RIFF WAVE read through
lp_pak_open (weakly referenced), so a packed sound loads directly. ludicc links
it with xaudio2 and ole32, and silences xinput.lib's importeddllmain warning.

Verified: ludic-dev test 135/135, selfhost-test 32/32; on the PC a harness
loads, plays, pans, loops and stops clips, and Maroon Lake windowed reports
"sound: 31 of 31 clips loaded".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-13 02:42:48 +03:00
parent 00d25dcc3e
commit 3300fb3957
4 changed files with 646 additions and 231 deletions

View file

@ -22,9 +22,12 @@ type: feat
in SDL order with rescaled deadzones, and the software `win_present`. `win32_gl.ll` puts
the WGL context on that window with vsync and borderless full screen; a headless build
links `gl_win_nowin.ll` instead. The process is per-monitor DPI aware.
- **Not yet** — `Audio.*` links and is silent (`audio_win.ll`), the splash and
`App.set_icon` do nothing, and `Http.*` is still a macOS platform layer; a Windows build
that uses it stops with a message saying so.
- **Sound** — `audio_win.ll` is `audio.ll`'s contract over XAudio2: one source voice per
clip, loops, volume, rate and a balance pan through the output matrix, RIFF WAVE in PCM or
float. It reads a clip through the asset pack, so a bundled game's first `Audio.load`
succeeds - AVAudioPlayer takes a filesystem path, which is why macOS cannot.
- **Not yet** — the splash and `App.set_icon` do nothing, and `Http.*` is still a macOS
platform layer; a Windows build that uses it stops with a message saying so.
- **`Gl.*` on Windows** — `gl_win.ll` makes a WGL 4.1 core context on a hidden window's DC,
and `gl_thunks_win.ll` (generated by `ludic-dev glgen` beside `gl_thunks.ll`) calls
every entry point through a table `@lgl_win_load` fills from `wglGetProcAddress`, falling