How the SharpEmu Atrac9 Decoder Processes Superframes: A Complete Technical Guide
The Atrac9 decoder in SharpEmu processes superframes by iterating through individual frames, applying spectral de-quantization, intensity stereo reconstruction, and IMDCT transformation to convert encoded bitstreams into 16-bit PCM audio buffers.
SharpEmu implements a comprehensive Atrac9 decoder to handle ATRAC9-encoded audio streams found in PlayStation game formats. The decoder operates on superframes, which are aggregate units containing multiple individual frames, to reconstruct high-fidelity PCM output. Understanding how the Atrac9Decoder class processes these superframes reveals the intricate DSP pipeline that transforms compressed spectral data into playable audio.
What Is an Atrac9 Superframe?
A superframe in the Atrac9 format consists of a configurable number of regular frames, specifically 1 << SuperframeIndex as defined in the stream configuration. According to the SharpEmu source code, each superframe contains Config.FramesPerSuperframe individual frames, with buffer sizes determined by Config.SuperframeBytes for input and Config.ChannelCount × Config.SuperframeSamples for output. This aggregation allows efficient batch processing of audio data while maintaining synchronization between channels.
The Superframe Decoding Pipeline
The decoding process follows a strict pipeline from bitstream validation to PCM output.
Initialization and Configuration
The Atrac9Decoder.Initialize(byte[] configData) method, located at Atrac9Decoder.cs:21-31, parses the 4-byte configuration header to build an Atrac9Config object. This initialization creates a reusable Frame object and prepares a BitReader instance for bit-level stream parsing. The configuration establishes critical parameters including sample rates, channel counts, and the superframe size metrics that govern the decoding loop.
Buffer Validation and Bitstream Setup
Before processing, the Decode method validates that the input buffer meets the minimum size requirement of Config.SuperframeBytes and that the output array can accommodate Config.ChannelCount × Config.SuperframeSamples 16-bit samples, as implemented in Atrac9Decoder.cs:50-72. The decoder then positions the BitReader at the start of the superframe data (Atrac9Decoder.cs:46-47), preparing for sequential frame extraction.
Frame Iteration and Parsing
The core processing occurs in DecodeSuperFrame, which iterates exactly Config.FramesPerSuperframe times according to the implementation at Atrac9Decoder.cs:74-83. For each iteration, the decoder:
- Sets the
Frame.FrameIndexto track position - Invokes
DecodeFrameto process the current frame - Aligns the bit-reader to the next byte boundary after frame completion
Within each frame, Unpack.UnpackFrame (defined in Unpack.cs) parses the raw bitstream into a Frame structure containing one or more Block objects, each representing sub-streams such as stereo pairs or LFE channels.
Spectral Processing and Channel Reconstruction
Each block undergoes a multi-stage DSP pipeline as orchestrated in Atrac9Decoder.cs:10-16:
- De-quantization:
Quantization.DequantizeSpectrareconstructs spectral coefficients from compressed values - Intensity Stereo:
Stereo.ApplyIntensityStereoreconstructs stereo imaging from encoded parameters - Scaling:
Quantization.ScaleSpectrumapplies scale factors to normalize spectral data - Band Extension:
BandExtension.ApplyBandExtensionreconstructs high-frequency content - IMDCT:
ImdctBlockcallsMdct.RunImdctto convert frequency-domain spectra into time-domain samples
The Mdct object within each Channel (see Channel.cs:12-15) writes the resulting floating-point PCM data into the channel's Pcm buffer.
Float-to-Short Conversion and Output
Following the IMDCT stage, the PcmFloatToShort method (implemented at Atrac9Decoder.cs:85-101) walks through each channel's floating-point buffer. It rounds each sample and clamps values to the signed 16-bit range using Helpers.Clamp16, writing the final results into the caller's short[][] pcmOut array. Upon completion of the loop, the output buffer contains fully decoded 16-bit PCM audio for the entire superframe duration.
Practical Implementation Example
The following C# example demonstrates decoding a single superframe using the SharpEmu Atrac9 decoder:
// Example: decode a single superframe
byte[] configData = File.ReadAllBytes("audio.atrac9.cfg"); // 4‑byte config
byte[] superframe = File.ReadAllBytes("audio.atrac9.sf"); // ≥ Config.SuperframeBytes
var decoder = new LibAtrac9.Atrac9Decoder();
decoder.Initialize(configData);
// Allocate PCM output buffer: [channels][samples]
short[][] pcm = new short[decoder.Config.ChannelCount][];
for (int c = 0; c < pcm.Length; c++)
pcm[c] = new short[decoder.Config.SuperframeSamples];
decoder.Decode(superframe, pcm);
// `pcm` now holds the decoded 16‑bit audio for the whole superframe.
For streaming applications, process superframes sequentially in a loop:
// Example: decoding a stream of superframes in a loop
var decoder = new LibAtrac9.Atrac9Decoder();
decoder.Initialize(configData);
while (stream.Position < stream.Length)
{
// Read exactly one superframe (size known from the config)
byte[] sf = new byte[decoder.Config.SuperframeBytes];
stream.Read(sf, 0, sf.Length);
short[][] outBuffer = new short[decoder.Config.ChannelCount][];
for (int i = 0; i < outBuffer.Length; i++)
outBuffer[i] = new short[decoder.Config.SuperframeSamples];
decoder.Decode(sf, outBuffer);
// …process or play `outBuffer`…
}
Summary
- Superframe Structure: Atrac9 superframes aggregate multiple frames (
1 << SuperframeIndex) into single processing units with sizes defined byConfig.SuperframeBytesandConfig.SuperframeSamples. - Validation Pipeline: The decoder validates input buffer lengths and output array capacities before processing, ensuring memory safety during bitstream operations.
- Frame Iteration:
DecodeSuperFrameiterates throughConfig.FramesPerSuperframeindividual frames, parsing each viaUnpack.UnpackFrameand processing through discreteBlockobjects. - DSP Chain: Each block undergoes de-quantization, intensity stereo reconstruction, scaling, band extension, and IMDCT transformation to produce floating-point PCM.
- Output Conversion: The
PcmFloatToShortmethod converts floating-point samples to 16-bit integers usingHelpers.Clamp16, delivering the final audio output.
Frequently Asked Questions
What is the difference between a frame and a superframe in Atrac9?
A frame represents a single unit of compressed audio data, while a superframe is an aggregate container holding multiple frames—specifically 1 << SuperframeIndex frames according to the stream configuration. The decoder processes superframes as atomic units, extracting individual frames sequentially to reconstruct continuous audio output.
How does the decoder handle buffer size validation?
The Decode method in Atrac9Decoder.cs:50-72 explicitly verifies that the input byte array length meets or exceeds Config.SuperframeBytes and that the output PCM array dimensions match Config.ChannelCount × Config.SuperframeSamples. This validation prevents buffer overruns and ensures sufficient space for decoded audio before bitstream processing begins.
What specific DSP operations are applied during frame decoding?
For each frame block, the decoder applies Quantization.DequantizeSpectra for spectral reconstruction, Stereo.ApplyIntensityStereo for stereo image restoration, Quantization.ScaleSpectrum for amplitude normalization, BandExtension.ApplyBandExtension for high-frequency synthesis, and Mdct.RunImdct for time-domain conversion. These operations transform encoded spectral data into raw floating-point PCM samples.
How does the decoder convert floating-point audio to 16-bit PCM?
After IMDCT processing, the PcmFloatToShort method (located at Atrac9Decoder.cs:85-101) iterates through each channel's floating-point buffer, rounds the samples, and clamps them to the signed 16-bit integer range using Helpers.Clamp16. This produces the final short[][] output array containing the decoded audio suitable for standard audio playback APIs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →