An audio-modding tool for Metal Gear Solid 2: Master Collection (2023) on PC, built on a game-plugin architecture designed to support more games in the future (Substance, MGS3, ZoE, …) — each game registers its own set of tabs.
Open the game's audio, listen, export to WAV, and (for dialogue and launcher music) replace it with your own. A game selector at the top switches which tabs are shown; today it lists the one stable game, Master Collection.
MGS2 Master Collection — stable. Every tab works on real game data:
dialogue browsing/export/replacement (SDT), sound-bank scan and replacement
(SDX), the Global Sound Archive (the game's iconic UI/item/alarm sounds,
decoded from BP_SE.DAT — see below), the cue sequencer (SDX SE cues), and
launcher music replacement (BGM · Launcher) — confirmed working (the
launcher plays the replaced audio), including the Unity FSB5/Addressables-CRC
handling that makes replaced bundles load.
On the in-game (gameplay) music. There is no separate music file in the game's data for the gameplay BGM. The launcher music (Unity bundles) is the only file-based, replaceable music; the gameplay music is produced by the engine at runtime rather than stored as a standalone file the tool could open, so it is out of scope here.
- SDT · Dialogues — character voice lines (replaceable, for custom dubs).
- BGM · Launcher — the launcher's music: the 6 scenario tracks (ARMS
DEPOT, BATTLE, INFILTRATION…) plus the main-menu and credits themes,
stored as Unity AssetBundles. Listen, export to WAV, and replace a track
with your own WAV — the tool rebuilds a valid
.bundleand shows each file's exact path inside the game folder. Note: these bundles drive the launcher, not the in-game gameplay music. Requires the optionalUnityPydependency. - SDX · Sound banks — the stage sample banks (footsteps, doors, weapons…). Full scan mode: index every bank in the game, group identical sounds, edit one and rewrite all copies at once.
- Global Sound Archive — the game's iconic global sounds: item selection
and pickup, using an item, interface blips, the alert-phase alarm. They live
in
Misc/<lang>/BP_SE.DAT, which the game loads once at startup and keeps resident — so they appear in no.sdx, and nothing could reach them until now. Point the tab at your game folder and it lists all 106 sounds to listen to, export (one or all), or replace with your own WAV. Replacements keep each sound's exact size, and the archive is backed up to.bakbefore the first write. - Séquenceur · Cues SDX — the raven-accurate synth that renders the SE cue
sequences hidden in the
.sdxbanks. These are the raw sound effects the engine assembles at runtime; the cue engine is faithfully reproduced from theKieronJ/ravenreference — tempo, pitch viafreq_tbl, per-instrument tuning/pan/ADSR, sweep, glissandi, portamento, vibrato and reverb. Seedocs/AUDIT_SDX.mdfor the fidelity audit anddocs/FORMATS.mdfor the format itself. - VOIX JP · JP Voices — swap the native Japanese voices into a US install so the game speaks Japanese while your subtitles stay in the game's language. Point it at the game folder and it copies each JP voice file over its US namesake, detecting and skipping codec calls (which embed multilingual subtitle text) so a wholesale swap never turns subtitles Japanese by accident. Requires both the US and JP Better Audio mods. Covers dialogue, cutscenes and codec voices; in-game gameplay barks have no Japanese source in the install and are out of scope for now.
Two
.sdtaudio formats are supported. The Better Audio Mod ships PS-ADPCM (PS3 HD Collection audio) — decoded in pure Python. The stock Steam.sdtfiles use Konami XWMA (a multiplexed container with anAMWX/WMA v2 stream) — the SDT tab de-interleaves and decodes those too, via ffmpeg. So the tool works whether or not you have the Better Audio Mod installed. Replacing stock XWMA audio is supported via xWMAEncode (your WAV is re-encoded, rebuilt into the Konami container, and re-muxed at the original size). PS-ADPCM replacement stays pure-Python. See Requirements for ffmpeg / xWMAEncode.
- Python 3.10+
- PyQt6 —
pip install PyQt6(only needed for the graphical interface) - UnityPy —
pip install UnityPy(optional; only needed by the Master Collection BGM · Launcher tab, which reads/rebuilds Unity AssetBundles) - ffmpeg — optional; only needed to decode stock (un-modded)
.sdtaudio, which is Konami XWMA/WMA. Install it (e.g.winget install ffmpeg) and put it on your PATH, or point the SDT tab at yourffmpeg.exe. Not needed for Better Audio Mod (PS-ADPCM) files. - xWMAEncode.exe — optional; only needed to replace stock XWMA audio.
ffmpeg can't be used for this: its WMA needs codec-private data the Konami
container can't store, so the game rejects it. Point the SDT tab at your
xWMAEncode.exe(the path is remembered). It is a small Microsoft tool that cannot be redistributed with this project (it is not on the DirectX SDK's redistributable list), so you supply your own — see Getting xWMAEncode.exe below. - MGS2MC Better Audio Mod for
the
.sdtdialogue files - A legal copy of the game. Use only files from your own installation.
The engine underneath (mgs2_audio.codec, mgs2_audio.formats) is pure Python
with no third-party Python packages — the command line works without PyQt6.
Two features reach outside that core when you use them: the BGM tab needs the
UnityPy package, and decoding stock XWMA audio shells out to the ffmpeg
binary. Both are optional; everything else is stdlib-only.
Only needed if you want to replace stock (Konami XWMA) dialogue. It ships in Microsoft's DirectX SDK (June 2010) but is not redistributable, so grab it yourself — you do not need to install the whole SDK:
- Download
DXSDK_Jun10.exefrom Microsoft's download center. - If the installer fails with error
S1023(common on modern Windows, because a newer Visual C++ 2010 Redistributable is already installed), don't fight it — just openDXSDK_Jun10.exewith 7-Zip (right-click → 7-Zip → Open archive) and extract the single fileDXSDK\Utilities\bin\x86\xWMAEncode.exe. No installation required. - Put
xWMAEncode.exeanywhere you like and point the SDT tab at it the first time you replace an XWMA file; the tool remembers the path afterwards.
Download the project, then:
pip install PyQt6
python run.py- Voice folder — point it at a folder of
.sdtfiles. The list appears instantly, even for a thousand of them. - Database folder — where your tags and notes are stored, kept separate from the game files.
- Single-click a file to tag it, double-click to load and hear it.
- Mark it done, give it a free-text tag, a speaker, and notes.
- Pick your recording, generate the modified
.sdt, and drop it back in the game.
Search by name, tag, speaker or notes; filter by done / to do or by tag. Tagging is entirely manual — the tool never guesses whether a line is finished.
Every tab can be tagged, not just SDT — SDX and Séquenceur also keep a done/tag/notes panel and their own database file. The database folder is picked once per game (a control in the app header, next to the game selector).
Open a single bank, or scan the whole game: point it at your MGS2 folder and
it finds us/stage on its own, indexes every bank, and groups identical sounds.
Open a .sdx bank and its cue pieces appear in a list. Click one and it is
synthesised and played, right there. Export a piece, or every piece at once. Two
options change the synthesis: stereo (uses each track's pan) and tune
(uses each instrument's base rate, 44 100 Hz).
The .sdx banks carry more than samples: they carry the score. List a bank's
cues and render them to WAV:
python -m mgs2_audio.cli seq cues pk000002.sdx --min-notes 20
python -m mgs2_audio.cli seq render pk000002.sdx melody.wav
python -m mgs2_audio.cli seq render pk000002.sdx out/ --all --min-notes 8Without --cue, the busiest cue is rendered — usually the music. Rendering is a
small software SPU: one voice per track, samples that loop while a note holds,
volume, pan, pitch bend, portamento and transpose.
It will sound thinner than the game. The PlayStation applied reverb in hardware, and that was never stored in any file.
No Qt, no GUI, scriptable:
python -m mgs2_audio.cli sdt info vc000101.sdt
python -m mgs2_audio.cli sdt export vc000101.sdt out.wav
python -m mgs2_audio.cli sdt replace vc000101.sdt dub.wav out.sdt
python -m mgs2_audio.cli sdx list pk000000.sdx
python -m mgs2_audio.cli sdx scan "C:/Games/.../MGS2"
python -m mgs2_audio.cli sdx export-key "C:/Games/.../MGS2" <key> sound.wav
python -m mgs2_audio.cli sdx replace-all "C:/Games/.../MGS2" <key> mine.wavscan accepts the game folder, a language folder, or the stage folder itself.
- Record at the file's own rate if you can — 44100 Hz for
.sdt, 22050 Hz for.sdx. Otherwise the tool resamples. - Length is fixed. Longer audio is trimmed, shorter is padded with silence. The output keeps the original's exact byte size, which the game requires.
- On a stereo
.sdt, your mono recording is placed on both channels. - Replacing stock XWMA dialogue: your WAV is automatically conformed to the original clip's channel count and sample rate before encoding — a stereo WAV put where the game expects mono is rejected in-game (even though a lenient player would preview it fine), so the tool matches the original for you. If the re-encoded audio can't fit the original's byte capacity the replacement is refused with a clear message; shorten the recording or it drops to a lower bitrate automatically.
- Back up before your first
replace-all..bakfiles are written automatically, but a copy ofstage/costs nothing.
run.py launch the GUI
mgs2_audio/
codec/ PS-ADPCM, MS-ADPCM and WAV. Knows nothing about MGS2.
formats/ sdt.py, sdx.py, sequence.py, bgm.py, xwma.py (stock Konami
XWMA), seo2.py (BP_SE.DAT global sounds), mcbgm.py (MC Unity
music bundles) — the game's file formats.
detect.py does structural auto-detection.
library/ the tagging databases.
render.py a small software SPU: plays a sequencer cue.
core/ GamePlugin ABC, PageSpec, REGISTRY — the plugin interface.
base.py GamePlugin, PageSpec, AudioFormat, AudioContainer
registry.py Plugin discovery and global registry
games/ Each game is a subpackage that registers itself.
mgs2_mc/ MGS2 Master Collection (SDT, BGM, SDX, GSA, Sequencer)
ui/ PyQt6 interface (app.py = shell, one page per tab).
cli.py the command line.
docs/FORMATS.md the reverse-engineering notes.
tests/ pytest suite, no game files needed.
Each layer only knows about the ones below it. Games are self-contained
plugins discovered at import time — the UI shell never imports game-specific
code directly. Adding a new game means creating a new subpackage in
mgs2_audio/games/<id>/ with a Plugin class that extends GamePlugin.
Read docs/FORMATS.md first if you want to understand the
files, contribute, or build something else on this. The code can be rewritten;
that knowledge took much longer to find.
Run the tests with:
pip install pytest
python -m pytestThey build synthetic .sdt and .sdx files from scratch — no game data needed,
and this default run stays deliberately light (a few seconds, no brute-force
PS-ADPCM encoding of anything but real test content). A handful of tests
additionally validate against real game files if you have them under
tests/mgs2_substance_2003/ — those are opt-in (python -m pytest --realdata)
since parsing a 1+ GB file is slow and genuinely CPU-heavy; they're skipped by
default so a plain test run never pins a core for that long.
The suite is split one file per subsystem, so pytest tests/test_X.py runs
only what's relevant to X — no need for the full suite (or --realdata)
while iterating on one area. Cheaper on the CPU, and faster to read.
| Working on… | Run |
|---|---|
| PS-ADPCM / MS-ADPCM codecs | pytest tests/test_codec.py |
.sdt format (dialogue) / vox.dat |
pytest tests/test_sdt.py |
.sdx format (sound banks) |
pytest tests/test_sdx.py |
bgm.dat / movie.dat / demo.dat |
pytest tests/test_bgm.py |
MC music bundles (formats/mcbgm.py) |
pytest tests/test_mcbgm.py |
Stock XWMA .sdt (formats/xwma.py) |
pytest tests/test_xwma.py |
BP_SE.DAT global sounds (formats/seo2.py) |
pytest tests/test_seo2.py |
The sequencer / render.py (SPU, reverb) |
pytest tests/test_sequence.py |
Tagging databases (library/db.py) |
pytest tests/test_library.py |
The app shell (ui/app.py, db_folder) |
pytest tests/test_app.py |
A single test also works (handy while chasing one failure):
pytest tests/test_bgm.py::test_quad_matches_separate_stereo_decode.
Reach for the full pytest (or --realdata) run before a release, or
whenever a change might have touched more than one subsystem — not as the
default while developing.
- Encoding is slow. The PS-ADPCM encoder is pure Python and brute-forces the
best filter and shift for every 28 samples of real audio. Generating a long
dub can take a while and may look frozen. Silence is fast-pathed (a
.sdtreplacement always pads or trims to the target's exact byte size, and the padding/trimmed-away portion is often mostly silence), but the real recorded audio itself still goes through the full search. Decoding is fast. - Scanning the whole game reads ~200 banks of about 1 MB each. Give it a minute; the progress bar is honest, and you can cancel.
- Stereo dubs are duplicated across both channels. True left/right stereo replacement is not supported.
replace-allwrites to your game files in place (with.bakbackups).- Windows-focused. It should run anywhere PyQt6 does; other platforms are untested.
Unofficial, fan-made, and not affiliated with, endorsed by, or connected to Konami Digital Entertainment. Metal Gear Solid 2: Sons of Liberty and all related names, characters and assets are trademarks and copyrights of Konami.
- No game files are included. This project contains only original code.
- Use your own copy. You are responsible for how you use it.
- For personal, non-commercial modding.
- Back up your files. Provided as-is, without warranty of any kind; the author is not responsible for any damage or data loss arising from its use.
The file formats were determined through independent analysis for interoperability. If you are a rights holder with a concern about this project, please open an issue and it will be addressed.
- KieronJ/raven — the PS2 sound-driver
reference that made the
.sdxcue sequencer faithful (tempo, pitch tables, ADSR, reverb…). - RockeyLol/RIFF-XWMA-Konami-XWMA-Converter
— for documenting the Konami XWMA (
AMWX) container format, which is what identified the stock MGS2 audio format and makes decoding/re-encoding it possible.
MIT — do what you like with it, keep the notice.