27 KiB
libSceNgs2.native technical debt
Unknown function info
-
NGS2 voice validation returns
0x804A8203for an invalid voice in Control, RunCommands, GetState, GetStateFlags, GetPortInfo and QueryInfo, following the type-4 handle error in prosper's PS5 module analysis. Control checks a null parameter list first (0x804A8360); GetState resolves the voice before output validation, and GetState rejects sizes below 8 before a null output. Existing rack-specific exact state sizes, other argument precedence and command layouts are retained; arbitrary-sized state copies and full console behavior remain unverified. These values follow module analysis, not new console execution. -
NGS2 system and rack handle errors use
0x804A8201and0x804A8202, following the native handle-type error helper recorded in prosper's PS5 module analysis. sceNgs2RackGetVoiceHandle resolves the rack before checking the output pointer, matching the export in firmware 1.00 through 12.70 reported in #5916. Other exports retain their existing validation order; complete invalid-input precedence and console execution remain unverified. -
NGS2 render buffer capacity is treated as available storage for one configured grain. PPSA01880 passes 303104 bytes for 256 stereo float frames (2048 bytes); rendering writes or clears only those frames and preserves the remaining capacity. Non-null silent outputs now undergo the same supported-format and minimum-size checks as audible outputs, with channel counts limited to 1 through 8. Unused null outputs remain ignored. The console's handling of surplus capacity and invalid silent output descriptors has not been measured; invalid descriptors throw rather than return guessed SDK errors.
-
NGS2 ATRAC9 waveform loops accepts one integer forward
smplloop. Inclusive RIFF endpoints and encoder-delay adjustment follow vgmstream riff.c. PPSA03747 supplies a 60-byte sampler chunk with one loop,samplerData24, start 256, inclusive end 299224 and delay 256 for 298969 audible samples. The chunk size and loop count bound the records;samplerDatais not interpreted. Output positions are assumed to use audible samples and an exclusive end. Blocks split into an optional intro, a repeated range and an optional tail; zero play count means infinite repeats, positive play count includes the first pass. ATRAC9 ranges include a preceding codec frame for decoder history. The output block layout, repeat-count mapping and error codes are unverified on hardware. Multiple, reverse, alternating and fractional loops throw. -
NGS2 submixer UserFx (control
0x20000004) invokes the title's callback after input mixing on every playing grain, including silence. The 40-byte control and 48-byte process context follow shadPS4. PPSA03747 installs a peak-meter callback; its code confirms the channel pointers, user data 0, channel count, grain size and sample-rate offsets and returns 0. Other user data words are preserved. Flags are assumed to be 1 after registration/restart and 0 thereafter, following UserFx2's first-process convention; this callback does not inspect them. Null handlers disable the effect, setup clears it, and nonzero callback results throw. These lifecycle and error semantics are unverified on console hardware. -
NGS2 voice callback after setup (libSceNgs2.native) - a sampler or mixer setup clears the voice callback with the rest of the voice state. PPSA18216 registers a block-end callback for a streamed music voice, later sets the same voice up again for one-shot ATRAC9 blocks with user data 0, and registers the callback again before it streams again; its callback dereferences the block's user data, so it must not run for the one-shot blocks. A setup made from inside the voice's own callback clears that callback as well, so a callback that sets its voice up again and queues the next block runs once instead of for every block; PPSA18216 never sets a voice up from inside its callback, so that ordering is unverified. Unverified on console hardware.
-
NGS2 ATRAC9 streaming keeps waveform duration and skip counts across compressed input blocks. The shared
APPENDflag (2), calledONLY_DATAin the compressed-data reference, ignores an ATRAC9 continuation block's sample, skip and repeat counts, following KytyPS5; PPSA03747 confirms a 262044-byte initial buffer declaring 11310532 samples, followed by 16384-byte buffers with flags 3. Incomplete superframes are retained until more input arrives. Input-block completion callbacks allow refills; the final callback of a logical waveform waits for its buffered PCM to drain, preserving the existing complete-block repeat behaviour. This buffering, callback timing, decoded-byte accounting and starvation silence are unverified on hardware. A closed ATRAC9 stream ending before its declared samples throws; fragmented ATRAC9 waveforms with repeats are unsupported. PCM streaming retains its existing append validation and early-close behaviour. -
NGS2 mastering voice gain (libSceNgs2.native) - the param id 0x30000004 is taken from PPSA22520 and the layout from shadPS4's
OrbisNgs2MasteringVoiceGainParam; no reference gives the units or range. The levels are assumed to be linear factors applied when the mastering voice is mixed into the render buffer, so the voice's own samples stay unscaled; the LFE level applies to channel 3 of 6- and 8-channel voices, assuming the L R C LFE order of the AudioOut2 entries above, and the full-band level to the rest. Negative levels are accepted, and a new setup resets both levels to 1 -
NGS2 stereo mastering voice into a surround buffer (libSceNgs2.native) - PPSA21402 renders a 2-channel mastering voice into a 6- or 8-channel render buffer, which the mixing stage rejected. The console's conversion is unknown: the left and right channels are assumed to go to the first two buffer channels (front left and right) and the remaining channels stay silent, with no centre, LFE or surround content. Any other channel count mismatch still throws
-
NGS2 voices without a format (libSceNgs2.native) - a sampler voice whose setup has no format (all zero) accepts an add of no waveform blocks without
APPEND, which only appliesRESETand theCONTINUEstate, and matrix levels with no levels, which clear that matrix. PPSA36591 sets such a voice up, adds no blocks and sets no levels when a button is pressed at its title screen. Whether the console returns success or an error there is not measured; blocks with data,APPENDand an empty matrix on a voice with a format are still refused -
NGS2 silent waveform blocks (libSceNgs2.native): flag
0x10(namedSILENCEhere; no public reference names it) lets a waveform block declare samples without data. PPSA04867 adds one block with flags0x11,data_size0 andnum_samples16385, then another with flags0x11and a fully specified 0x800-byte, 1024-sample mono block, which takes the ordinary path. A dataless block under the flag outputsnum_samplesframes of silence, reports them throughdecoded_data_size, and finishes like a complete block; a dataless block without the flag still throws as not fitting its data. The flag's real name, its interaction with ATRAC9 and repeats, and the console'swaveform_datafor silent blocks are unverified on hardware -
NGS2 streaming PCM waveforms (libSceNgs2.native) - PPSA21402 streams its music by adding one block whose
num_samplesis the whole track and whosedata_sizeis a 16 KiB first piece, withCONTINUE, and then adds each following piece with flag0x2(calledAPPENDhere) and the samenum_samples. No reference describes flag0x2. A 16-bit PCM block without skipped samples or repeats whosenum_samplesexceed its data is assumed to start such a stream; flag0x2is assumed to append the block's data to the last streaming block, ignoring itsnum_samples; the voice is assumed to output silence without advancing while it has played all appended data andCONTINUEis set; and the waveform is assumed to end atnum_samplesor, onceCONTINUEis cleared, at the end of the appended data.sceNgs2VoiceGetStatereports the bytes played asdecoded_data_size, which the title uses to release its queued data, and the read position aswaveform_data. Appending to a block that is not a stream, or other formats, skipped samples, repeats and partial frames, throw -
NGS2 matrix levels (libSceNgs2.native) - levels are clamped to -4..4 and NaN is kept, as the PS4 firmware 11.00
libSceNgs2.sprxstores them; not yet confirmed on the PS5 library. That library rejects a level count of 0 and keeps the matrix; the PS5 error code is unknown, so a count of 0 throws, except on a sampler voice without a format, where it clears the matrix (see NGS2 voices without a format).sceNgs2VoiceRunCommandsis not in that library, so its matrix levels command is assumed to clamp the same way -
NGS2 sampler voice state flag EMPTY (libSceNgs2.native) - a playing sampler voice that still accepts blocks (
CONTINUE) and has played all queued blocks reportsINUSE|PLAYING|EMPTY(0x20) and keeps playing, so blocks added later play on. PPSA18391 (engine: Clickteam Fusion) readsstate_flags & 0x22 != 2fromsceNgs2VoiceGetStateas the end of a sound and only then reuses the voice. When the console sets and clears EMPTY, and whether it also reports it for other voice types, is unverified on hardware. -
NGS2 port matrix (libSceNgs2.native) - a port without a matrix, or with a selected matrix whose levels were never set, mixes through a default channel map: mono reaches both stereo channels at -3 dB and the 5.1 and 7.1 centre, stereo folds to mono at -3 dB per side, and wider sources fold down with 0.5 and -3 dB gains. The map and the equivalence of an unset matrix with no matrix were measured from the PS4 firmware 11.00
libSceNgs2.sprx, not yet from the PS5 library. That library only accepts submixer and mastering voices with 1, 2, 6 or 8 channels, so the map into 3, 4, 5 or 7 channels throws. A matrix set with fewer levels than the destination needs still mixes only the rows it has -
NGS2 custom submixer rack (libSceNgs2.native, rack 0x4002) - structure layouts from shadPS4's
ngs2_custom.h; module id 0x1f for UserFx2 and 0x1d for UserFx, voice parameter ids0x40001f00 | module indexand0x40001d00 | module index, the process flags (1 on the first process call after setup, 2 after a parameter change, 0 otherwise) and the call order (setup per voice at rack creation, process after the inputs are mixed, cleanup at destruction) come only from KytyPS5 and shadPS4. Only UserFx and UserFx2 modules on a single buffer are accepted: other module ids, more buffers, a module control handler, different input and output channel counts, setup flags and default rack options throw. Each module's state is a separate buffer, not thestate_offsetslice of the voice state, andsceNgs2VoiceGetStatestill throws for this rack. As in KytyPS5, UserFx2 process runs only on grains where an input produced samples, so an effect tail stops with the input and a pending flag 2 waits for the next audible grain -
NGS2 custom module ids (libSceNgs2.native) - a custom rack with a module id other than 0x13 (sampler rack), 0x1d and 0x1f (submixer rack) throws. Trails in the Sky 2nd Chapter (PPSA35169) creates a rack with module id 0x20 (
NGS2: custom module id 0x20 is not implemented, #4246); which module it is, and its structure, are unknown. -
NGS2 reverb rack (libSceNgs2.native, rack 0x2001) - follows the PS4 firmware 11.00
libSceNgs2.sprx, read and checked against its output at 11.025 to 48 kHz, including parameter changes during playback (differences at float rounding level); not yet compared with the PS5 library. Structure layouts come from shadPS4'sngs2_reverb.hand the param ids 0x20010000 (setup) and 0x20010001 (I3DL2) from PPSA22520. Only the defaultreverb_sizeof 1 is handled, with its 14400-sample reflection buffer; other sizes and the library's half-rate mode throw. System sample rates below about 7.5 kHz, where an allpass delay would have no samples, throw. Setup only accepts equal input and output channel counts -
sceNgs2ReportRegisterHandler, sceNgs2ReportUnregisterHandler (libSceNgs2.native, NIDs
uBIN24Tv2MI,nPzb7Ly-VjE) keep a registry of report handlers. Register rejects a null handler with an invalid argument and returnsINVALID_OUT_ADDRESSfor a null out handle, then stores the report type, handler and user data under a freshly allocated opaque handle; unregister removes and frees the matching record and throws for a handle that is not registered. The signatures (report type, handler, user data, out handle) and (report handle) follow SharpProspero and shadPS4'sngs2_report.h, and the 24-byteNgs2ReportDataHeaderpassed to a handler is itsOrbisNgs2ReportDataHeader. No report is produced yet, so no registered handler is ever invoked and PPSA04540, which imports both and registers a CPU load handler (type 5), still receives none. -
sceNgs2SystemSetSampleRate, sceNgs2SystemSetUserData, sceNgs2SystemGetUserData, sceNgs2SystemLock, sceNgs2SystemUnlock (libSceNgs2.native) - shadPS4 only checks the system handle (
INVALID_SYSTEM_HANDLE) and SharpProspero names what each call does; neither gives the other limits. A sample rate of 0 and a null user data pointer throw, any other rate is accepted, and changing the rate while a sampler filter is enabled throws because the filter coefficients were computed for the old rate.sceNgs2SystemLockandsceNgs2SystemUnlockfollow prosper's notes on the PS5 module: Lock takes a per-system lock and counts nested holds, Unlock releases one hold from any thread and returns 0 without a hold, andsceNgs2SystemRenderonly tries the lock: while another thread holds it, Render clears one grain of each output, leaves the render count and voices unchanged and returns 0. The other calls do not wait for the system lock. Peace Walker (PPSA18216) holds it while it spins on a flag that its audio thread clears only aftersceNgs2SystemRenderand eightsceNgs2VoiceGetStateFlagscalls, so on the console neither can wait for it. Whether the console's voice and rack calls take the lock at all is not known.sceNgs2RackLockstill holds the library's lock untilsceNgs2RackUnlock, as before -
sceNgs2RackSetUserData, sceNgs2RackGetUserData (libSceNgs2.native) - the signatures follow SharpProspero and shadPS4, which only logs them; neither gives an error. A handle that is not a live rack answers
INVALID_RACK_HANDLEbefore a null user data pointer is checked, and the null pointer throws, as insceNgs2SystemGetUserData. A new rack starts with 0. Not measured on a console -
sceNgs2RackGetInfo (libSceNgs2.native) - field order from shadPS4's
OrbisNgs2RackInfowith the 64-byte name of the other info structures (216 bytes);typeis assumed to be the rack id divided by 0x1000,min_grain_samples64 (the system minimum) andstate_flags1;uidcomes from a per-process rack counter,render_countis the owning system's render count andactive_voice_countcounts voices that are not empty (paused and stopped voices included). The last process ratio and tick andactive_channel_work_countare left zero -
sceNgs2VoiceQueryInfo (libSceNgs2.native) - only info id 0x4001 is known: PPSA22520 passes an 8-byte buffer and branches on the first word being 1 or 2, so it is assumed to be the voice channel count (0 before the voice is set up); the second word is zeroed and other ids throw
-
sceNgs2VoiceControl patch (libSceNgs2.native) - a destination rack handle with input id 0 resolves to that rack's first voice; this matches the Dead Cells call in #4334, but selection for racks with multiple voices has not been checked against a console. Nonzero destination input ids still throw.
sceNgs2VoiceGetPortInforeports the resolved voice handle and zero delay. -
sceNgs2ParseWaveformFile (libSceNgs2.native) - the signature
(path, offset, info)is taken from the call site of PPSA21402, which sets only three argument registers; the file is read fromoffsetto its end, the data and block offsets are taken to be relative to the start of the file, not ofoffset, and an unreadable file throws. The audio unit fields of a 16-bit PCM waveform are assumed to be one sample frame per unit and per frame;INVALID_WAVEFORM_DATAfor adatachunk that runs past the buffer or ends inside a frame is assumed, and looped PCM and other PCM formats throw -
sceNgs2VoiceControl sampler filter (libSceNgs2.native) - param
0x1000000a, its layout and meaning follow KytyPS5 only: location 1 type 1 is an RBJ low-pass biquad at the system sample rate after resampling, scaled bylevel, a setchannel_maskbit bypasses that channel, type 0 turns the filter off. Other locations and types throw. The voice keeps playing a filter tail after its last block until the history is zero, with outputs below 1e-20 flushed to zero (a KytyPS5 choice); the console's tail length is unknown -
sceNgs2PanInit / sceNgs2PanGetVolumeMatrix (libSceNgs2.native) - follow the PS4 firmware 11.00
libSceNgs2.sprx, read and checked against its output for 2, 4, 5 and 7 speakers into 1, 2, 6 and 8 channels; not yet confirmed on the PS5 library. Speakers are taken in the order L R, L R Ls Rs, L R C Ls Rs or L R C Ls Rs Lb Rb and kept in a fixed circular order, not sorted; without angles the defaults are 90/270, 40/110/250/320, 0/40/110/250/320 and 0/40/110/150/210/250/320 degrees. As in that library, defaults converted to radians keep the wrap-around entry in degrees, so angles past the last speaker pan almost fully to it. Error codes are not known for the PS5, so invalid arguments throw, including a speaker angle equal to the unit angle, on which that library loops forever. Angles so large that adding or subtracting a turn leaves them unchanged throw for the same reason -
sceNgs2GeomResetListenerParam, sceNgs2GeomResetSourceParam (libSceNgs2.native) - the structures (12, 16, 16, 60, 96, 108, 32 and 308 bytes) come from KytyPS5's
ngs2.cppand match shadPS4'sngs2_geom.hfield for field, but only KytyPS5 gives the behaviour - shadPS4 logs and returns success without writing the output. The defaults (orient front +Z, orient up +Y, sound speed 343, cone 1/360/1/360, rolloff 0/1000000/1/1, doppler factor, full-band, LFE and maximum level 1, two speakers and matrix format 2) are unverified on a PS5 title; KytyPS5 and iStark/PS5PCEM agree on them. PPSA15552 (Dead Cells) callssceNgs2GeomResetSourceParamafter creating its racks. A null output address returnsINVALID_OUT_ADDRESSas elsewhere in the library rather than throwing as KytyPS5 does.sceNgs2GeomApplyis now a minimal pass-through that follows KytyPS5'sNgs2GeomApply(shadPS4 only stubs it): pitch 1, source position, volume the larger of the source minimum and maximum level, and a diagonal of the source maximum level (1 when it is not positive) overmatrix_formatchannels (0 is two, at most 8). The listener andflagsare ignored, so source attenuation, distance rolloff, panning and Doppler stay unimplemented; neither KytyPS5 nor this has been measured on a PS5, and a null output address returnsINVALID_OUT_ADDRESSwhere KytyPS5 exits -
sceNgs2GeomCalcListener builds an orthonormal world-to-listener transform. The row-major matrix, front-axis priority and flag 1 for right-handed input follow PS5PCEM; they have not been measured on PS5 hardware. Velocity stays in world coordinates and positive finite sound speed is preserved. Orientation vectors are normalised and up is made perpendicular to front, so non-unit and slightly tilted vectors are accepted. When front and up are parallel, up is replaced by
(0,1,0)or(1,0,0)so the basis stays defined: PPSA15552 (Dead Cells) passesorient_front={0,0,1}withorient_up={0,0,1}after moving the listener, which PS5PCEM rejects; the console error code is unknown. Unknown flags, zero orientation vectors, nonfinite input and an unrepresentable translation still throw without changing the output; console error codes are unknown, and a nonpositive sound speed throws where PS5PCEM and KytyPS5 default it to 343. KytyPS5 always writes the identity matrix, so the transform rests on PS5PCEM plus that Dead Cells case. Dead Cells (PPSA15552) reaches this call after the custom sampler rack in #4334. This does not implement source attenuation, panning or Doppler insceNgs2GeomApply. -
NGS2 custom sampler rack (libSceNgs2.native, rack 0x4001) - implements bounded support for the custom sampler rack and its built-in module 0x13 (Custom Voice Filter), unblocking PPSA15552 (Dead Cells) startup. Structure layouts come from shadPS4's ngs2_custom.h (OrbisNgs2CustomVoiceFilterParam, 40 bytes) and live trace correlation from prosper's hle_audio.cpp (0x40001300 command and parameters like 10000.0f and 0.707f). Routes parameter updates via the 0x40001300 command family into the Biquad filter engine. Filter type 0 clears the destination filter; type 1 configures the RBJ low-pass biquad frequency, Q and level. Other filter types and unmodeled configurations throw.
-
sceNgs2VoiceGetState custom sampler (libSceNgs2.native, rack 0x4001) - only the size and one field come from a title. PPSA15552 (Dead Cells) calls it on custom sampler voices with a 48-byte buffer at two sites (eboot
0x1740f90,0x1741009) and reads only the 64-bit value at offset 16: the first site keeps it and the second subtracts the kept value, so it is filled with the voice's decoded sample count. Other sizes returnINVALID_OUT_SIZEas for the other racks. The state flags fill the common voice state; the remaining fields stay zero. shadPS4'sOrbisNgs2CustomSamplerVoiceStateis about 80 bytes and does not match the size this title passes, so the field names and the console's value are unverified
Functional
- NGS2 rack lock and voice callbacks (libSceNgs2.native) -
sceNgs2RackLockgives the calling thread the rack, nested. Rack locks, renders and rack or system destroys exclude each other across threads and systems, including during a render's voice callbacks; a thread nests them, also from its own callbacks, and a callback that waits for another thread's rack lock or render never returns. Other NGS2 calls from other threads go ahead, and a block-end or repeat callback runs with the internal lock released. The console's behaviour for other threads' calls during a rack lock is not measured. PPSA36591 holds a rack lock on its main thread while it waits for one of its own locks, held by a thread insceNgs2VoiceGetStateFlags; it froze while the rack lock held the internal lock.sceNgs2RackUnlockof a rack this thread has not locked returns0x804A8202; the console code is unknown. UserFx process handlers keep the internal lock. - NGS2 destroy from its own render (libSceNgs2.native) -
sceNgs2RackDestroyof a rack of the system being rendered, orsceNgs2SystemDestroyof that system, called from one of that render's voice callbacks throws, also when the callback renders another system whose own callback makes the call, because the render would go on using the destroyed rack. The console's behaviour is not measured. - sceNgs2RackGetVoiceHandle voice index (libSceNgs2.native) - an index at or beyond the rack's voice count returns
0x804A8305and leaves the output handle untouched, after the null-output and rack-handle checks that keep their order and codes. The value is read from the PS5libSceNgs2.native.sprxexportMwmHz8pAdAo(firmware 10.01 at0x11f10, 12.70 at0x12130, and every module from 1.00 to 12.70 checked in #5916): an index at or past the rack's voice count returns it through the same error helper that answers0x804A8010for a null output, and the output handle is written only on success. The rack is checked before the output pointer, and an invalid rack returns0x804A8202. Heretic + Hexen (PPSA26525), DOOM + DOOM II (PPSA21444) and STAR WARS: Dark Forces Remaster (PPSA19728) create a one-voice reverb rack, take voice 0 and ask for voices 1 to 3 at start-up, log the failures and go on