Skip to content

Audio (hle-audio.ts)

Implements sceAudio (PCM output channels), sceAtrac (ATRAC3+ decode), and sceAudiocodec. The handlers read the engine from kernel.audioEngine, so audio calls silently no-op until the frontend sets up audio and the browser's AudioContext is unlocked by a user gesture; the game's audio thread keeps running in the meantime.

sceAudio (PCM output)

SignatureWhat it does
sceAudioChReserve(chan: int, sampleCount: u32, format: u32): u32Reserves a PCM channel and returns its index. Always succeeds even when audio is off: it records the channel state (the blocking output calls read sampleCount to know how long to wait), and with no engine at all it hands back a fake index so the game proceeds.
sceAudioChRelease(chan: u32): u32Frees a reserved channel and returns 0.
sceAudioOutput(chan: u32, vol: int, samplePtr: u32): u32Reads sampleCount samples from RAM and adds them to the channel queue, then returns the queued sample count. Non-blocking, single volume for both speakers.
sceAudioOutputBlocking(chan: u32, vol: int, samplePtr: u32): u32Same as sceAudioOutput but blocks the thread for the buffer duration and returns 0. Blocks even when audio is off so the audio thread does not spin forever.
sceAudioOutputPanned(chan: u32, leftvol: int, rightvol: int, samplePtr: u32): u32Like sceAudioOutput with separate left and right volume. Non-blocking.
sceAudioOutputPannedBlocking(chan: u32, leftvol: int, rightvol: int, samplePtr: u32): u32Like sceAudioOutputPanned but blocks for the buffer duration and returns 0.
sceAudioChangeChannelVolume(chan: u32, leftvol: u32, rightvol: u32): u32Stores the left and right volume on the channel and returns 0.
sceAudioChangeChannelConfig(chan: u32, format: u32): u32Stores the channel format (mono/stereo) and returns 0.
sceAudioSetChannelDataLen(chan: u32, len: u32): u32Sets the channel's sample count and returns 0.
sceAudioGetChannelRestLen(chan: u32): intReturns the number of samples still queued for playback (from the engine, or 0 when audio is off).
sceAudioGetChannelRestLength(chan: u32): intSame as sceAudioGetChannelRestLen; a separate NID with identical behavior.

sceAudioSRC (sample-rate-converted output)

SignatureWhat it does
sceAudioSRCChReserve(sampleCount: u32, freq: u32, format: u32): u32Reserves the single SRC output channel at the given sample rate and returns 0.
sceAudioSRCChRelease(): u32Frees the SRC channel and returns 0.
sceAudioSRCOutputBlocking(vol: u32, buf: u32): u32Reads stereo PCM from buf, adds it to SRC channel 8, and blocks for the buffer duration (at the reserved SRC rate). Returns the queued sample count, or 0 when the engine is off.

sceAudioOutput2 (single shared stereo channel, index 9)

SignatureWhat it does
sceAudioOutput2Reserve(sampleCount: u32): u32Reserves the shared stereo Output2 channel and returns 0.
sceAudioOutput2Release(): u32Frees the Output2 channel and returns 0.
sceAudioOutput2OutputBlocking(vol: u32, dataPtr: u32): u32Reads stereo s16 PCM from dataPtr, adds it to channel 9, and blocks for the buffer duration. Returns the queued sample count, or 0 when the engine is off.
sceAudioOutput2GetRestSample(): u32Returns the number of samples still queued (from the engine, or 0 when audio is off).

sceAtrac (ATRAC3+)

Decoding goes through the ATRAC decoder (@ffmpeg/ffmpeg); see Audio assets. Up to 6 ATRAC IDs exist at once.

SignatureWhat it does
sceAtracSetDataAndGetID(buffer: u32, bufferSize: int): intParses the AT3 header at buffer, allocates a free ATRAC ID, starts an async decode of the whole buffer, and returns the new ID (or an error when no ID is free).
sceAtracSetHalfwayBufferAndGetID(buffer: u32, readSize: u32, bufferSize: u32): intSame as above for a partially-filled streaming buffer: sets the context ALL_DATA_LOADED when readSize == bufferSize, otherwise HALFWAY_BUFFER. Returns the new ID.
sceAtracGetAtracID(codecType: int): u32Allocates an empty ATRAC ID for low-level decode (no data yet). Errors on an unknown codec type.
sceAtracSetData(atracID: int, buffer: u32, bufferSize: u32): u32Re-reads the buffer into an existing ID and starts a fresh decode. Returns 0, or a bad-ID error.
sceAtracSetHalfwayBuffer(atracID: int, buffer: u32, readSize: u32, bufferSize: u32): u32Like sceAtracSetData for a partial streaming buffer on an existing ID; sets the context HALFWAY_BUFFER. Returns 0.
sceAtracAddStreamData(atracID: int, bytesToAdd: u32): u32Called when the game has written more compressed data into its ring buffer. Re-reads the buffer from RAM and decodes again. Returns an ALL_DATA_LOADED error if the stream was already fully loaded.
sceAtracDecodeData(atracID: int, outAddr: u32, numSamplesAddr: u32, finishFlagAddr: u32, remainAddr: u32): u32Writes the next decoded PCM frame (or silence) to outAddr and updates the sample-count, finish-flag, and remain-frame out-params. If the decode is still running it blocks the thread and writes the output from the wake callback. Handles loop wrapping via the loop count.
sceAtracGetRemainFrame(atracID: int, remainAddr: u32): u32Writes the frames still left in the buffer (or -1 for ALL_DATA_LOADED) and returns 0. Bad-ID error if the context is gone.
sceAtracGetStreamDataInfo(atracID: int, writePtrAddr: u32, writableBytesAddr: u32, readOffsetAddr: u32): u32Writes the streaming write-pointer, writable byte count, and read offset so the game knows where to refill its ring. For a streaming context it computes these from the ring state; for a fully-loaded context the writable count and read offset are 0. Returns 0.
sceAtracGetNextSample(atracID: int, outNAddr: u32): u32Writes the number of samples the next sceAtracDecodeData will produce (the frame size). Returns 0.
sceAtracGetSoundSample(atracID: int, outEndSampleAddr: u32, outLoopStartSampleAddr: u32, outLoopEndSampleAddr: u32): u32Writes the track's end sample plus the loop start/end samples from the parsed header. Returns 0.
sceAtracGetMaxSample(atracID: int, maxSamplesAddr: u32): u32Writes the max samples per decode call (the frame size). Returns 0.
sceAtracGetNextDecodePosition(atracID: int, outposAddr: u32): u32Writes the current decode position in samples and returns 0.
sceAtracGetChannel(atracID: int, channelAddr: u32): u32Writes the channel count (1 or 2) and returns 0.
sceAtracGetBitrate(atracID: int, outBitrateAddr: u32): u32Writes a fixed bitrate (132) and returns 0. Not derived from the real stream.
sceAtracGetLoopStatus(atracID: int, loopNumAddr: u32, statusAddr: u32): u32Writes the stored loop count and a status of 0, then returns 0.
sceAtracSetLoopNum(atracID: int, loopNum: int): u32Stores the loop count (-1 = forever, N > 0 = N times). Errors with NO_LOOP_INFORMATION when the track has no loop points.
sceAtracGetSecondBufferInfo(atracID: int, fileOffsetAddr: u32, desiredSizeAddr: u32): u32Writes zeros for both out-params and returns 0; we never use a second buffer.
sceAtracGetOutputChannel(atracID: int, outputChanPtr: u32): intWrites a fixed output channel count of 2 and returns 0.
sceAtracIsSecondBufferNeeded(atracID: int): intValidates the ID's status, then returns 1 only for STREAMED_LOOP_WITH_TRAILER. Since we buffer the whole stream this is normally 0.
sceAtracReleaseAtracID(atracID: int): u32Deletes the context and returns the slot to the free pool. Bad-ID error if it was already freed.
sceAtracReinit(at3Count: int, at3plusCount: int): intReassigns the codec type of the ID slots (AT3+ slots cost double). Returns BUSY if any ID is still in use; (0, 0) deinitializes.
sceAtracResetPlayPosition(atracID: int, sample: int, bytesWrittenFirstBuf: int, bytesWrittenSecondBuf: int): u32Sets the decode position to sample (clamped to the track length) and returns 0.
sceAtracGetInternalErrorInfo(atracID: int, errorAddr: u32): u32Writes 0 (no error) and returns 0.
sceAtracGetBufferInfoForResetting(atracID: int, sample: int, bufferInfoAddr: u32): u32Writes a zeroed 16-byte buffer-info struct and returns 0. Registered under both NIDs: the misspelled export sceAtracGetBufferInfoForReseting (0xca3ca3d2) and the correct spelling (0x2dd3e298), same handler.

sceAtrac stubs

No-op stubs (return 0, or 1 where noted) for functions we do not implement: _sceAtracGetContextAddress (returns 1), sceAtracLowLevelDecode, sceAtracLowLevelInitDecoder, sceAtracReleaseResources, sceAtracSetAA3DataAndGetID, sceAtracSetAA3HalfwayBufferAndGetID, sceAtracSetMOutData, sceAtracSetMOutDataAndGetID, sceAtracSetMOutHalfwayBuffer, sceAtracSetMOutHalfwayBufferAndGetID, sceAtracSetSecondBuffer, sceAtracStartEntry.

sceAudiocodec

The lower-level codec interface some games use instead of sceAtrac. Calls operate on a 128-byte SceAudiocodecCodec struct in RAM whose pointer is ctxPtr; codec is 0x1000 (AT3+), 0x1001 (AT3), 0x1002 (MP3), or 0x1003 (AAC).

SignatureWhat it does
sceAudiocodecCheckNeedMem(ctxPtr: u32, codec: int): intWrites the per-codec working-memory size into the struct and returns 0. Bad-argument error for an unknown codec.
sceAudiocodecGetEDRAM(ctxPtr: u32, codec: int): intWrites a fake EDRAM allocation and aligned address into the struct and returns 0. No real EDRAM is reserved.
sceAudiocodecReleaseEDRAM(ctxPtr: u32, id: int): intDrops our per-context decoder state for ctxPtr and returns 0.
sceAudiocodecInit(ctxPtr: u32, codec: int): intWrites the firmware-version and error fields, creates the per-context decoder state (an MP3 frame accumulator for MP3), and returns 0.
sceAudiocodecInitMono(ctxPtr: u32, codec: int): intSame as sceAudiocodecInit; used by sceAtrac for the MOut functions.
sceAudiocodecGetInfo(ctxPtr: u32, codec: int): intFor MP3, fills the expected MP3 response fields in the struct; returns 0.
sceAudiocodecGetOutputBytes(ctxPtr: u32, codec: int, outBytesAddr: u32): intWrites the per-codec output frame size in bytes and returns 0.
sceAudiocodecDecode(ctxPtr: u32, codec: int): intReads one compressed frame from the struct's input pointer, decodes it async (MP3 goes through the frame accumulator for the bit reservoir), blocks the thread, then writes the PCM (or silence on failure) to the output pointer and updates the sample-count fields.

Other stubs

This module also holds a large number of no-op stubs (over 100) for less-common audio functions, grouped by API: sceAudio input and routing helpers, sceVaudio, sceAac, sceMp3, and sceMp4.