- Python 99.7%
- Shell 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .github | ||
| docs | ||
| ps5at9 | ||
| tests | ||
| third_party | ||
| tools | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| ps5_at9.py | ||
| README.md | ||
| THIRD_PARTY_NOTICES.md | ||
PS5 AT9 Converter
Turn any MP3, WAV, AIFF or FLAC file into the snd0.at9 selection music of a
PlayStation 5 app with one command and no external tools.
Note
The encoder's output is validated against Sony's reference ATRAC9 decoder and plays as selection music on PS5 hardware. Please report problems through GitHub issues.
Project foundations
PS5 AT9 Converter contains its own ATRAC9 encoder, written from the bitstream
documented by LibAtrac9, so it
needs neither Sony's at9tool nor FFmpeg. Its MP3, FLAC and WAV/AIFF decoders
follow ISO/IEC 11172-3, ISO/IEC 13818-3 and RFC 9639. Loudness is measured to
ITU-R BS.1770-4. The only dependency is numpy.
Features
- One command turns an MP3, WAV, AIFF or FLAC file into a finished
snd0.at9. - Native ATRAC9 encoder: 48 kHz stereo at 72 to 192 kb/s (192 by default).
- Excerpt selection with
--startand--duration, or--duration maxfor the longest excerpt that fits. - Loudness normalisation to −28 LUFS and a true-peak limiter at −2 dBTP.
- Whole-track loop metadata with short fades, so the loop does not click.
- Refuses to write files above the 2 MiB PS5 limit.
- Writes
loudnessSnd0intoparam.json, and optionally a WAV preview of the decoded result. - Runs on Windows, Linux and macOS with Python 3.9 or newer. The output is byte-identical on every platform.
How it works
- Decode. The input is decoded: MP3 (MPEG-1/2/2.5 layer III, with gapless LAME/Xing trimming), WAV/RF64, AIFF/AIFF-C or FLAC. Only the selected excerpt is decoded.
- Format. The excerpt is converted to 48 kHz stereo with a windowed-sinc resampler. Mono is duplicated and 5.1 is downmixed.
- Loudness. Integrated loudness is set to −28 LUFS. A smooth look-ahead limiter keeps the 4× oversampled true peak at or below −2 dBTP, and 10 ms fades are added at both ends.
- Encode. For every 256-sample frame, the encoder computes the exact bit cost and noise of each allocation the decoder can derive. A psychoacoustic masking model picks the one that sounds best, and each 512-byte superframe is shared between its four frames.
- Write. The RIFF container is written with the same
fmt,fact,smplanddatalayout asat9tool -e -br 192 -wholeloop, and the size is checked against the 2,097,152-byte limit.
The format details are in the ATRAC9 profile and the encoder design in how the encoder works.
Requirements
-
Python 3.9 or newer on Windows, Linux or macOS.
-
numpy 1.20 or newer:
python -m pip install numpy
Download and run
Download ps5-at9-converter.pyz and SHA256SUMS.txt from the
latest release,
verify the checksum, then run:
python ps5-at9-converter.pyz --input song.mp3 --output snd0.at9
From a clone of this repository, ./ps5_at9.py does the same. On Windows, use
py instead of python.
Input song.mp3 (44100 Hz, 2 channels)
Excerpt 0:00.000 - 0:15.000 (15.000 s)
Loudness -17.3 LUFS -> -28.0 LUFS (gain -10.7 dB), true peak -10.8 dBTP
Encoding ATRAC9 192 kb/s, 48 kHz stereo
Wrote snd0.at9 (360,616 bytes, 17.2% of the 2 MiB limit, whole-track loop)
param set "loudnessSnd0": "-28.00" under "pubtools" in sce_sys/param.json
Copy the file to sce_sys/snd0.at9 in the app image. Then set the loudness
under the existing pubtools object of sce_sys/param.json, or pass
--param-json path/to/param.json to let the tool write it:
{
"pubtools": {
"loudnessSnd0": "-28.00"
}
}
Rebuild or redeploy the app. Then fully restart ShadowMountPlus, or the console, before checking updated presentation assets.
Options
| Option | Default | Purpose |
|---|---|---|
-i, --input FILE |
required | Source audio: MP3, WAV, AIFF or FLAC. |
-o, --output FILE |
snd0.at9 |
Output file. |
--start TIME |
0 |
Excerpt start, in seconds or [hh:]mm:ss. |
--duration TIME |
15 |
Excerpt length, or max for the longest excerpt that fits 2 MiB. |
--loudness LUFS |
-28 |
Target integrated loudness. |
--true-peak DBTP |
-2 |
True-peak ceiling. |
--no-normalize |
off | Keep the source level and only limit peaks. |
--fade-in SEC, --fade-out SEC |
0.01 |
Fade lengths. |
--bitrate KBPS |
192 |
72, 96, 120, 144, 168 or 192. |
--no-loop |
off | Omit the whole-track loop metadata. |
--param-json PATH |
none | Write the measured loudness to pubtools.loudnessSnd0. |
--preview WAV |
none | Also write the decoded result, which is what the console plays. |
--allow-oversize |
off | Write the file even above the 2 MiB limit. |
--workers N |
all CPUs | Number of encoder processes. |
-q, --quiet |
off | Print errors only. |
# 30 seconds starting at 1:05, and update param.json
./ps5_at9.py -i song.flac -o sce_sys/snd0.at9 --start 1:05 --duration 30 --param-json sce_sys/param.json
# the longest excerpt that fits, with gentle fades, plus a WAV to listen to
./ps5_at9.py -i song.mp3 --duration max --fade-in 1 --fade-out 3 --preview preview.wav
At 192 kb/s the longest excerpt that fits 2 MiB is 87.35 seconds. Lower bit rates allow longer excerpts, for example 116.47 seconds at 144 kb/s.
Validation
- Decoder conformance. Sony's reference decoder (
at9tool -d) decodes the encoder's output bit-exactly the same as the built-in decoder. The test set has 64 files: all six bit rates, silence, very short input, full-scale square and sine waves, noise, sweeps, clicks and ten music excerpts. The check also showed that Sony's decoder only accepts superframes whose unused tail is filled with0x01bytes, so the encoder does that. - Container. The header is byte-identical to
at9tool -e -br 192 -wholeloopoutput for the same sample count. - Quality. Ten 15-second music excerpts were prepared like the manual
at9toolworkflow. On them, the objective PEAQ score averages −0.34 ODG, against −0.61 forat9toolat the same 192 kb/s (EAQUAL, basic model; 0 is transparent). - Input decoders. MP3 decoding matches FFmpeg to about 120 dB SNR with the same gapless length, and FLAC decoding is bit-exact.
- Hardware. A 53-second file encoded at 192 kb/s plays as the home-screen selection music of a homebrew app on a PS5. The lower bit rates are verified against Sony's decoder only.
- Speed. A 15-second excerpt takes about 6 to 15 seconds on a desktop PC, depending on the number of CPU cores.
The validation workflow is described in development and validation.
Source layout
| Path | Purpose |
|---|---|
ps5_at9.py |
Command-line entry point. |
ps5at9/cli.py |
Conversion pipeline and options. |
ps5at9/atrac9_encoder.py |
ATRAC9 encoder. |
ps5at9/atrac9.py |
ATRAC9 definitions and reference decoder, used by --preview and the tests. |
ps5at9/at9file.py |
.at9 RIFF reader and writer. |
ps5at9/mp3.py, flac.py, wav.py, audio_io.py |
Input decoders and format detection. |
ps5at9/dsp.py |
Resampling, loudness, true peak, limiter and fades. |
ps5at9/*_tables.py |
Constant tables generated by tools/gen_*.py. |
tests/ |
Unit tests; tests/data holds synthetic vectors made by tools/make_test_vectors.sh. |
docs/ |
Format, encoder and validation notes. |
Development
python -m pip install numpy
python -m unittest discover -s tests
See CONTRIBUTING.md before opening a pull request.
Releases
Every push and pull request runs the unit tests and a conversion on Windows,
Linux and macOS in GitHub Actions. Version tags matching v* publish a GitHub
Release with ps5-at9-converter.pyz, a source ZIP and SHA256SUMS.txt.
Limitations
- The output is fixed to the PS5 selection-music profile: ATRAC9, 48 kHz, stereo.
- OGG, AAC, M4A and other formats need to be converted to WAV or FLAC first.
- The encoder uses neither intensity stereo nor band extension. At 192 kb/s it codes up to 18 kHz, like Sony's encoder at the same rate.
- Hardware playback is confirmed at 192 kb/s only.
Credits
Thanks to John Törnblom (ps5-payload-dev) for the PS5 Payload SDK, which much of the PS5 homebrew scene is built on. Third-party components, authors and licenses are listed in THIRD_PARTY_NOTICES.md.
License
Copyright © 2026 BlackBearReloaded. Licensed under GPL-3.0-or-later; see LICENSE. Third-party components keep their own licenses. Binary releases are built from the tagged source in this repository.
Disclaimer
- No affiliation. This is an independent homebrew project. It is not affiliated with, endorsed by, or sponsored by Sony Interactive Entertainment. "PlayStation", "PS5" and related marks are trademarks of Sony Interactive Entertainment Inc. ATRAC9 is a trademark of Sony Group Corporation.
- No proprietary material. No Sony SDK, firmware, encryption keys or decrypted system modules are included.
- No warranty. This project is provided "as is", without warranty of any kind, to the extent permitted by law. See sections 15 and 16 of the GPL.
- Legal use only. Use it only with hardware, accounts and content you own. This project does not support or enable piracy.
AI assistance
This project was developed with AI assistance from OpenAI and/or Anthropic tools.