Skip to content

feat(libSceNgs2.native): reverb rack following the PS4 libSceNgs2 reverb - #960

Closed
JAB-dev wants to merge 1 commit into
boykopovar:mainfrom
JAB-dev:feat/ngs2-reverb-rack
Closed

JAB-dev wants to merge 1 commit into
boykopovar:mainfrom
JAB-dev:feat/ngs2-reverb-rack

Conversation

@JAB-dev

@JAB-dev JAB-dev commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Closed pending a reference. The reverb is now taken from the PS4 firmware 11.00 libSceNgs2.sprx (see the reference section). The PS5 library is still being checked.

What

sceNgs2RackCreate throws for rack id 0x2001 (reverb). This adds the rack, with the reverb the console library renders.

  • Options: SceNgs2ReverbRackOption (rack option, max_channels, reverb_size). The defaults come from KytyPS5: 8 channels and reverb_size 1.
  • Voice params:
    • 0x20010000 setup takes input and output channel counts and flags. It accepts 1, 2, 6 or 8 channels; other counts are invalid arguments. Non-zero flags and differing input and output counts throw.
    • 0x20010001 takes SceNgs2ReverbI3DL2Param (88 bytes). The layout of both params, and of the voice state, matches shadPS4's ngs2_reverb.h. Values are clamped to the library's ranges, as it does; NaN throws.
    • sceNgs2VoiceGetState returns the common voice state.
  • Rendering, as in the library:
    • The input is mixed to mono with the library's fixed gains (0.707 for stereo, 0.316 for 5.1, 0.267 for 7.1), without the LFE channel.
    • A 14400-sample buffer feeds four reflection taps placed by the reflection pattern tables (16 patterns), plus a late feed.
    • Sixteen damped comb filters with a pre-emphasis stage; their lengths follow density.
    • Each output channel takes a signed selection of the combs, then runs four allpasses driven by diffusion.
    • A two-pole room HF filter at hf_reference, then the wet and dry levels. The LFE channel passes dry.
    • New params crossfade over one grain, and wet and dry levels ramp. Until the title sends I3DL2 params, the setup defaults leave the wet output almost silent.
  • The points the PR was closed for:
    • The Freeverb-style approximation is gone.
    • density and reflection_pattern are used.
    • Before any I3DL2 param, the voice renders the library's setup defaults; it no longer passes its input through.
    • reverb_size is still not used. Only the default rack options are handled, and their 14400-sample buffer is used whatever reverb_size says.
  • Not implemented: the library's half-rate mode, and channel conversion, which throws. TechnicalDebt records both.

Reference

  • PS4 firmware 11.00 libSceNgs2.sprx, dumped and decrypted from a console. It was loaded on Windows with a small test loader and called directly; neither the loader nor the library is part of this PR. The reverb was read from its disassembly, and the test values are its output.
  • Against that library, the output matches to float rounding (110 to 180 dB SNR). That covers presets, every reflection pattern, short and long delays, 1, 2, 6 and 8 channels, noise input, 11.025 to 48 kHz and parameter changes during playback.
  • PS5 firmware 10.06 libSceNgs2.sprx (the module titles import as libSceNgs2): its code is still encrypted, so it hasn't been run yet. Its readable ELF headers match the PS4 library: the same .eh_frame_hdr size (3,460 bytes, 431 functions) and code plus read-only data within 1% (321,328 bytes against 323,432).

Tested

  • Windows 11, WinLibs GCC 15.2.0 r7, Release.

  • ngs2_render TestReverb uses 8 cases with the PS4 library's output, to 2e-7 + 1e-5 of each value:

    • the "cave" preset Animal Well uses;
    • a damped room;
    • 5.1;
    • a parameter change mid-stream;
    • clamped values;
    • short delays with pattern 15;
    • noise input with a change;
    • a density change.

    Channel 3 is skipped: the PS4 mastering voice low-passes the LFE channel, and AnyPS5's doesn't yet.

  • TestReverbSetup: 3, 4, 5 and 7 channels are rejected; channel conversion, flags and NaN throw; the setup defaults render a non-zero level below 1e-8.

  • On main the tests fail, because rack 0x2001 throws. 25 mutations of Reverb.cpp each make them fail.

  • Full ctest on this branch alone, merged with main: 409/409.

  • Seen in PPSA22520 (Animal Well): it creates the rack with default options, sets up a 2-in, 2-out voice, loads I3DL2 preset 9 ("cave" in the standard preset order) and patches it to its mastering voice. This version hasn't been played in game yet.

  • Linux not tested.

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

🤖 Generated with Claude Code

Rack 0x2001 is created with its option layout and KytyPS5's defaults, takes
the setup (0x20010000) and I3DL2 (0x20010001) voice params and reports the
common voice state. The voice mixes its inputs and runs a Freeverb-style
approximation driven by the I3DL2 parameters: room and room HF, early
reflections and their delay, late reverb and its pre-delay, decay time and
HF ratio, and diffusion. Out-of-range params throw, param changes keep the
tail, a stop or kill clears it, and the tail ends once it decays below
1e-20. The console's algorithm is unknown; the approximation is recorded in
TechnicalDebt. The test context buffer pool grows to 64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@oneandonlydean

Copy link
Copy Markdown
Collaborator

Thanks for the I3DL2 parameter work and the tests. I'm closing this one. The reverb isn't the console's algorithm:

  • it's a Freeverb-style approximation with tuned gains (INPUT_GAIN 0.015, OUTPUT_GAIN 3.0 and the early-tap gains);
  • density, reflection_pattern and reverb_size are accepted and then ignored;
  • before any I3DL2 parameter is set, the voice passes its input through.

The project's rule is that a function either does what the console does or throws, so rack 0x2001 should keep throwing until there's a reference for its output.

If you find a reference, such as a trace or a disassembly of the console's reverb, please reopen.

@TibixDev TibixDev mentioned this pull request Oct 8, 2026
7 of 9 tasks
@JAB-dev JAB-dev changed the title feat(libSceNgs2.native): reverb rack with I3DL2 parameters feat(libSceNgs2.native): reverb rack following the PS4 libSceNgs2 reverb Oct 8, 2026
@JAB-dev

JAB-dev commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Opened again as #2336. It now follows the PS4 firmware 11.00 libSceNgs2 reverb, read from its code and checked against its output, so it has the reference this was closed for.

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.

2 participants