Skip to content

fix(audioout): play every AudioOut2 port buffer set between pushes, one per grain - #2536

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
orbz22:fix/audioout2-queue-port-buffers
Oct 10, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
orbz22:fix/audioout2-queue-port-buffers

Conversation

@orbz22

@orbz22 orbz22 commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

What

An AudioOut2 port kept one PCM pointer: each sceAudioOut2PortSetAttributes with attribute 0 overwrote it, and every push mixed whatever it pointed to. Two things went wrong when a title does not set exactly one buffer per push:

  • Several buffers set between two pushes: all but the last were dropped.
  • A push without a new buffer: the last buffer was mixed again, every grain, until the port was given another one.

PPSA12544 (Hollow Knight: Silksong) feeds its gameplay sound through an object port (type 6, created in game). Each set points at the next grain of a 64-grain ring buffer (the pointer advances by exactly 256 frames, 2048 bytes, and wraps at 128 KiB). The sets arrive in bursts: often two or three between pushes, then none for one to four pushes. So most grains were lost, and the stale one was replayed 187.5 times a second. Players hear a harsh buzz on loud sounds and after a sound ends: the needle falling in the opening sequence, and fights.

This change:

  • Queue: buffers set between pushes are queued per port and mixed one per grain, in order, at most 16 queued (the oldest is dropped beyond that).
  • Push without a new buffer:
    • A port that has always been given the same buffer repeats it, as before. The title rewrites it in place, and audio_out2_timing relies on this: it points once and changes the contents between pushes.
    • A port whose buffers move on to other addresses plays silence for that grain.
  • TechnicalDebt records this under Unknown function info. The console's behaviour for several sets per push, and for a push without a new buffer, is not documented; this is inferred from PPSA12544.

Tested

Windows 11, WinLibs GCC 15.2, RTX 3060 Laptop.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes (Claude Code)

🤖 Generated with Claude Code

…ne per grain

A port kept only the last PCM buffer set before a push and played it again
at every later push without a new one. PPSA12544 sets one grain of a ring
buffer per call on its object port, often two or three between pushes and
then none for a few, so all but the last of each burst were dropped and the
stale grain repeated: a buzz on loud sounds and after a sound stopped.

Buffers set between pushes are now queued and played in order, at most 16
queued. A push without a new buffer repeats the last one only for a port
that has always been given the same buffer (rewritten in place, as the
timing tests do); a port whose buffers move on plays silence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the intake paused Closed while PR intake is limited to authors with at least 10 PRs merged into main label Oct 10, 2026
@github-actions

Copy link
Copy Markdown

Thank you for your interest in the project! We are sorry, but we cannot accept more PRs while we work through the existing backlog. This PR has been automatically closed and labeled "intake paused". This is not a judgment of the quality of your changes.

@github-actions github-actions Bot closed this Oct 10, 2026
@oneandonlydean oneandonlydean removed the intake paused Closed while PR intake is limited to authors with at least 10 PRs merged into main label Oct 10, 2026
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked on the PR merged onto main: libSceAudioOut builds and all 7 audio_out* tests pass (including audio_out2_timing); audio_out2_port_buffers aborts without the source change and passes with it. The inferred queue/repeat behaviour is recorded under Unknown function info in TechnicalDebt; merging.

@adriadam10
adriadam10 merged commit 95fe142 into boykopovar:main Oct 10, 2026
25 checks passed
@orbz22

orbz22 commented Oct 10, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for merging. A correction to my description: in PPSA12544, port 3 is type 6, which is AUDIO_OUT2_PORT_TYPE_PAD_VIBRATION in AudioOut2PadMix.hpp. It is not an object port. The buffers on it are the DualSense haptics waveform, not gameplay sound.

  • Why I heard it through the speakers: my build predated fix(audioout): drop vibration ports when no pad audio device is open #2032. Without a DualSense USB audio device, every port went to the main mix, the vibration port included. On current main (be40308, plus feat(relinker): add --module-dir for modules loaded at run time #846 for the plugins) that port is dropped in this case. In a 250 s run through the opening and into Moss Grotto, only the main port (type 0) is mixed, and nothing reaches full scale: the peak is 0.35 after the master gain.
  • What the queue still does for this title: the change does not depend on the port type. It matters here when a DualSense is on USB and the vibration port plays on the controller. Without the queue, the controller would get the same stale grain 187.5 times a second. I have not tested that case.
  • TechnicalDebt: the line merged with this PR says "object port (type 6)". It should say "vibration port (type 6)". New PRs from me are closed by the intake rule, so I'm noting it here for whoever next edits that file.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants