sceAudio: implement sceAudioOneshotOutput, and cover the rest of the channel rules

Another pass looking for gaps, all of it now recorded by audio/blocking/channels
and audio/blocking/oneshot.

sceAudioOneshotOutput was the last unimplemented entry in the module, returning
"library not linked" to anyone who called it. It plays one buffer on a channel it
never reserves, so the channel frees itself when the buffer runs out, and its
argument checks are their own set: any positive sample count, aligned or not, no
upper bound, a negative volume rejected rather than skipped, and no busy check at
all. No game is known to use it; it is implemented because tracing it turned out
to be cheap, not because anything needed it.

The channels test confirms four behaviors: sceAudioChReserve(-1) skips a released
channel that is still playing while a reserve of it succeeds, a second channel
joining a running mixer doesn't lose a block unlike a first, mono counts down in
the same 64-sample steps over the same time as stereo, and the panned blocking
output has no extra delay on the high channels.

Also: the SRC resampler now interpolates into the next buffer at a buffer join
instead of holding the last sample, since the codec reads the two descriptors as
one stream. That only shows up at non-native rates and no test can see it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Henrik RydgårdandClaude Opus 5 committed 2026-09-10 17:03:07 -06:00
1 parent bfbede717f
commit 84bd8459e9
7 files changed
+89 -10

No files matched your search

+12
View File
@@ -150,6 +150,18 @@ checks is observable.
Accepted SRC frequencies are 8000, 11025, 12000, 16000, 22050, 24000, 32000 and 48000, plus
whatever the output is currently running at - which is how 44100 and 0 get through.
## sceAudioOneshotOutput
The odd one out: it plays a single buffer on a channel it never reserves. The channel stays
free as far as everything else is concerned, so `sceAudioChRelease` on it answers `80260008`,
and it returns to the pool by itself once the buffer runs out. It returns the channel number,
takes any positive sample count - alignment and the 0xFFC0 ceiling do not apply - and unlike
the other outputs a negative volume is an error rather than "leave it alone". There is no busy
check either: a second one-shot while the first is playing just replaces it.
No game is known to call it. It is implemented because the behavior turned out to be simple
once traced, not because anything needed it.
## sceVaudio is a third shape
`sceVaudio` reserves the same channel as Output2 and SRC, but its own release is not the same