The DS3 Codex
Chapter IX

Sound & music

DS3 plays everything through FMOD Ex and FMOD Designer's event system. The samples are hidden twice over: their bits are reversed and XORed, and their Vorbis streams are stripped of the headers a decoder needs. Footsteps change their name with the ground you walk on.

Each step is a letter and nine digits. The last two belong to the ground: soil, cobblestone, water to the ankle. The armour on your back gets a sound of its own.Codex · c000002005, foot-grass-r

In short
  • FMOD Ex 4.44.61, built by FromSoftware, with FMOD Designer projects (.fev) over sample banks (.fsb, FSB5, all Vorbis).
  • Banks are encrypted with a reversed bit order and a 31-byte XOR key, and each sample's Vorbis setup header is left out, to be found in a table compiled into fmodex64.dll.
  • Animation events name sounds. Footsteps and armour rattles swap in the material code of the floor or the armour. Hits go through HitEffectSeParam.
  • Music and wind are MSB sound regions. The Cemetery of Ash has none: it's silent, as in the game.

1The files

ProjectEventsWhat
main2,717Everything shared: the player (c0000…), hits (z…), menus (f…), objects (o…), effects (s…)
smain21Menu music, a few effects
m4066Firelink's map sounds, one ambience loop
sm40 (loose bank)20Streamed ambience (wind) and music: m400000000-3 Iudex Gundyr, m400100000/1 Firelink Shrine
vm40, rm401,948, 6NPC voices, cutscene sounds
c<id>~50-100A character's own sounds, loaded with it (fdp_c%04d.fev)

Event names are a type letter and nine digits (%c%09d) exe. The letter is the TAE's sound type: a environment, c character, f menu, o object, p cutscene, s SFX, m music, v voice, g ghost.

2Opening the banks

Encryption

Every byte has its bits reversed, then is XORed with a 31-byte key. The key shows through the zero runs of the header and sample table data. It's FMOD's own FSB encryption, with FromSoftware's key.

Stripped Vorbis

FSB5 keeps only the audio packets. The identification header is rebuilt from the rate and channels (FMOD always uses 256- and 2048-sample blocks), the comment header is empty, and the setup header (codebooks, floors, residues) comes from 161 headers compiled into fmodex64.dll, keyed by a CRC32 each sample stores. Some are a base header with a patch over its tail exe.

Our bank reader rebuilds each sample as a standard Ogg Vorbis file. All 1,516 samples of the banks we use decode cleanly in FFmpeg. Loop points come along: the bonfire loops from 137,216 to 542,719.

3Event projects

A .fev is a RIFF file whose LGCY chunk is FMOD Designer's own binary project. Its layout was read from fmod_event64.dll's reader for version 0x45, decompiled in a Ghidra project of its own exe. Every DS3 project parses to its last byte.

event   name, volume, pitch, randomisation, priority, max playbacks, mode (3D | world-relative | custom rolloff),
        3D max distance, speaker levels, …
        layers → { parameter, sounds → sound definition, envelopes }
        parameters ("(distance)", "Shahei"), user properties (playDistance, stopDistance, NoHDR …)
sound definitions: play mode, volume and pitch with their randomisation, waveforms → { weight, bank, index }

4Which sound a character plays

TAE events 128-132 (PlaySound_CenterBody, _ByDummypoly, _Weapon…) carry a sound type and id:

In the clipExampleEvent played
type 8, floor materialrun step 2001c0000 + the id with its last two digits replaced by the floor's material: c000002005 on grass, c000002021 in ankle-deep water
type 9, armour material100 beside each stepthe same with the armour's: iron → c000000156 "body-armor"
type 1, characterswing 4200c000004200 "swing-sword-large"

The material code is the HitMtrlParam row through SeMaterialConvertParam (identity for 1-49). Which digits are replaced and what happens when a combination has no event are guesses until read in the exe.

Waveform of running footsteps
Six seconds of our engine's mix, recorded while running from the spawn: each spike is a footfall, c000002003 on soil, then c000002001 on cobblestone, each with the armour's c000000056 a frame earlier.

5Hits

victim material (NpcParam: hollow 110 "Flesh _ Weakness")
  → SeMaterialConvertParam → 60
  → HitEffectSeParam row 60: 160 ids in (small, large, large) triplets, by attack material and power
  → z000000060 "iron-cut-meatS_bloodB"   ·   z000001060 "iron-cut-meatL_bloodA/B"

Every id in the rows has a z event in main. A sword hitting a wall plays the wall material's: stone "sparkx", wood "iron-cut-wood", water "mizusibuki".

6Music and ambience by place

MSB sound regions (a type, an id, and up to 16 child regions whose union is the region) place the music and the wind. m40 has 19:

Region (translated)TypeEvent
ボス戦闘BGM_グンダ "boss battle BGM, Gundyr" and variantsmusicm400000000…
拠点BGM "hub BGM", 火防女BGM "Fire Keeper BGM"musicm400100000, m400100001
火防女_レベルアップ呪文 "Fire Keeper's level-up chant"voice(vm40)
強風 / 弱風 "strong / light wind" ×8environmenta300000100 (stereo)
Spectrogram of the start of the Gundyr fight
Spectrogram of 40 s from the sword pull in our engine: the pull and Gundyr rising, then the fight with its music, m400000000, started by common event 20005831. The knight just stands there; Gundyr kills him at 23 s, and the mix fades.

7In our engine

The importer writes one sound bank of ours (.sbank) per project. The engine decodes with stb_vorbis as it plays, resamples linearly to 48 kHz stereo, mixes on the 30 Hz tick and queues on SDL3's audio stream.

What's DS3's

Every event, sample, volume, pitch and randomisation; the distance curves and pan level; max playbacks; loops; the TAE sound events with the floor and armour swap; hit sounds through HitEffectSeParam; the sound regions with the event script's initial state; Gundyr's music by his common event.

Our stand-ins

The listener is the camera; waves are picked at random in every play mode; a master limiter instead of FMOD's HDR mixing; music fades over 2 s. Not done: the occlusion lowpass, reverb (the MSB's sound spaces), the hub's music, objects' and the bonfire's sounds.

Faithful

Checked by logging every event started: running from the spawn plays soil, then cobblestone, with the armour at each footfall. A hollow fight plays its steps, voice and swings, the knight's swing, and the hits on both sides.