# Positional audio / HRTF research (v0.28) *Shard of mgsv-modding-pack — generated 2026-08-16. 1 files. Provenance is on every entry as `source:path`.* The state of the positional-audio reverse-engineering effort: verified runtime milestones, the Fox->Wwise identity chain, known addresses/structures, corrections, and open targets. Build-specific (085c2f82). Read this before any MGSV spatial/HRTF audio work — it's the difference between starting from scratch and starting from a working chain. ## Positional audio research (local) — verified Ghidra+runtime evidence ### `audio_research_local:positional-audio-research.md` #### MGSV positional audio / HRTF — runtime + static research (v0.28) *Captured against MGSV TPP 1.0.15.4, SHA-256 `085c2f82d1c963c40b3d2d55786661dfee2b18cbbf388a710c00fa76c5e9bb45` — the pack's reference build (image base 0x140000000). Every address here is valid only against that binary. This is real reverse-engineering evidence with explicit confidence labels: VERIFIED_RUNTIME (observed working in-game), VERIFIED_STATIC (proven in the decompilation), CANDIDATE/OPEN (not yet nailed down). Preserve those labels when citing.* **Headline:** positional audio is not a feasibility question anymore. Real Fox world coordinates + a usable listener transform + pre-final-mix Wwise PCM have already driven audible horizontal HRTF correctly in ordinary third-person gameplay. What remains is tightening one identity bridge, not proving the concept. --- ##### Current findings MGSV POSITIONAL AUDIO / HRTF — CURRENT FINDINGS Updated 2026-08-16 EXECUTIVE STATUS The feasibility question is solved: MGSV exposes real Fox Engine emitter world coordinates, a usable listener transform, and individual/pre-final-mix Wwise PCM. Real world geometry has already driven audible horizontal HRTF correctly in normal third-person gameplay. The current research problem is no longer “can MGSV do positional audio?” It is: Fox SoundSourceBody -> exact Wwise identity -> exact active render context / mono render node -> PCM -> listener-relative geometry -> HRTF The first half of that identity chain is now deterministic. MILESTONES v0.25 — VERIFIED_RUNTIME PASS Real Fox world XYZ + listener transform drove MIT KEMAR HRTF. Front/back/left/right were audibly correct in ordinary third-person gameplay. Stationary emitter mapping was kept alive safely by validating the cached render context's event-family object about every 250 ms, with a short safety expiry if validation stopped. v0.26 — VERIFIED_RUNTIME PASS, BUT ARCHITECTURALLY SUPERSEDED Automatic mapping could bind a Wwise render context to a unique recent Fox body sharing the event hash. It worked on controlled generator/steam tests. It is incomplete and unsafe as a universal identity mechanism because events can be reused and several Fox bodies may share one event. Keep it only as historical/fallback research, not as the desired final mapper. v0.27 — VERIFIED_RUNTIME PARTIAL PASS Wwise PostGateway -> game-object lookup -> playback action was instrumented. The return from Wwise PostGateway tracks the Wwise playing ID seen later in PLAY_ACTION. The initial attempt to map body+0x80 through a static 0xE0 record table failed because the global at 0x142B9E8B0 was mistakenly treated as the table itself rather than a pointer to the table. v0.28 — VERIFIED_RUNTIME MAJOR PASS A thread-local nested-call bridge was placed around SoundSourceBody.PostEventInternal. Every Fox source event captured in the run had a same-event Wwise PostGateway call nested synchronously inside it: 53 source events, 53 TLS event matches. This directly binds Fox body + Fox event to the Wwise object key and PostGateway result without event-uniqueness guessing. The Wwise action path remained stable: 3069 PLAY_ACTION rows matched by playing ID, with zero object-pointer fallback matches required in the final summaries. CONTROLLED SOURCES Generator: event 0xDC384714 known physical SoundSourceBody identity in each process/run known world coordinates from earlier controlled tests: approximately (347.879211, 5.171548, -84.742981) Steam/gas: event 0xDC26FE36 known physical SoundSourceBody identity in each process/run known world coordinates from earlier controlled tests: approximately (194.892944, 9.256834, -80.158669) V0.28 EXACT CONTROLLED IDENTITY EXAMPLES Steam in the v0.28 run: Fox body 0x155F677E0 event 0xDC26FE36 nested Wwise object key 0x31F Wwise PostGateway result / playing ID 0x358 Wwise game object 0x1C00DC60 PLAY_ACTION playing 0x358 and retained body 0x155F677E0 Generator in the v0.28 run: Fox body 0x1561153E0 event 0xDC384714 nested Wwise object key 0x57A Wwise PostGateway result / playing ID 0x5BE Wwise game object 0x1C012418 PLAY_ACTION playing 0x5BE and retained body 0x1561153E0 SOURCE HANDLE / TOKEN AT SoundSourceBody+0x80 The body pointer is the stable physical emitter identity. The 32-bit value at body+0x80 is mutable across PostEvent calls. v0.28 observed: source_events=53 source_changed_across_call=53 source_zero_before_nonzero_after=48 For all 53 SOURCE_RECORD rows in this run: (source_after >> 8) + 1 == nested_object_key This exact numerical relationship held 53/53. The low byte has not been assigned a proven semantic meaning. The Ghidra audit also proves that body+0x80 is intentionally consumed as a handle by the SoundCore-side lookup/update path. It should not be treated as stable physical emitter identity, but it is not random. WORLD GEOMETRY SoundSourceBody.TransformSync exposes an 8-float transform payload: f0..f3 = orientation quaternion f4 = world X f5 = world Y f6 = world Z f7 = auxiliary/padding/transform value depending on capture Earlier runtime tests established that the world coordinates are real Fox coordinates and that the quaternion/world-to-listener-local conversion is audibly correct in normal third-person gameplay. LISTENER Useful listener bridge: 0x140437B60. Current normal-gameplay orientation math should not be flipped or rewritten without a specific special-camera failure. Future coverage should test aiming, binoculars, vehicles, cinematics and scripted cameras separately. PCM / HRTF PATH Useful individual/pre-final-mix render path: 0x140352330. Useful HRTF insertion path: 0x1403A77B0. Controlled useful topology: Route-B mono source -> stereo destination, commonly 1024-frame blocks. Low-level channel accumulation is visible at 0x1403D67B0. HRTF DATASET Current prototype uses MIT KEMAR HRIR data. Horizontal ring is -180..+180 degrees in 5-degree steps, approximately elevation 0 degrees, resampled to 48 kHz with 128 taps. Elevation is calculated but elevated HRIR selection is not yet implemented. CURRENT MISSING LINK The deterministic chain currently reaches: SoundSourceBody -> event -> Wwise object key -> Wwise playing ID -> Wwise game object/play action The next missing bridge is: Wwise playing ID / Wwise game object -> exact active render context/node at 0x140352330 / matrix route at 0x1403A77B0. Once that is proven, the old event-uniqueness mapper can be removed from the final architecture. --- ##### Known addresses and structures MGSV AUDIO — KNOWN ADDRESSES / STRUCTURES Target executable: MGSV TPP 1.0.15.4 Image base: 0x140000000 SHA-256: 085c2f82d1c963c40b3d2d55786661dfee2b18cbbf388a710c00fa76c5e9bb45 FOX / GAME SIDE 0x140971300 TppSoundDaemon.PostEvent3D entry area 0x140971410 TppSoundDaemon shared PostEvent dispatch / 0x30 queue record builder 0x141D72A00 SoundSourceBody::PostEvent wrapper 0x141D728F0 SoundSourceBody.PostEventInternal 0x141D72C40 SoundSourceBody.TransformSync 0x140437B60 Camera.ActiveToSoundCoreListenerBridge WWISE / AUDIO SIDE 0x14033C050 Wwise PostGateway used by v0.27/v0.28 identity telemetry 0x14034CA50 Wwise game-object lookup hook used by v0.27/v0.28 0x140347E00 Wwise playback/action dispatch hook used by v0.27/v0.28 0x140351370 active render processing caller 0x140352330 useful Wwise active render node 0x1403A77B0 source-to-destination matrix mix 0x1403A1470 sink pump data/silence virtual dispatch 0x1403D5F20 channel-mask/matrix routing helper 0x1403D67B0 low-level float channel accumulator HANDLE TABLE / MANAGER 0x142B9E8B0 global POINTER VARIABLE to a 256-slot table; DO NOT treat this address as the table base 0x140328A00 constructs 0x100 records of size 0xE0 and stores table pointer in DAT_142B9E8B0 0x140329640 canonical handle lookup: low byte selects 0xE0 slot; record+0x30 must equal full handle 0x1403390C0 handle-based update path used by TransformSync branch 0x140339160 second handle-based update path used by TransformSync branch POSTGATEWAY SUPPORT / NEXT STATIC TARGETS 0x14033FF70 decompiled PostGateway caller; stores return and event/object inputs 0x140336820 decompiled PostGateway caller; follows success with 0x140342060 then 0x140337180 0x140336A20 decompiled PostGateway caller; stores returned ID at +0x50 then calls 0x140342060 0x140342060 NOT decompiled in FAST output; high-value target fed playing-ID + event after a successful post 0x140337180 queues an 8-byte value into a protected dynamic list; called after 0x140342060 in several post paths SOURCE BODY FIELDS / OBSERVATIONS SoundSourceBody +0x80 = mutable 32-bit handle/token; valid engine handle after establishment, not stable physical identity SoundSourceBody +0x84 = additional field passed alongside event posting; exact semantics not yet assigned SoundSourceBody +0x90 / +0xA0 = TransformSync branch-control fields in static decomp 3D QUEUE RECORD AT 0x140971410 record size = 0x30 +0x00..+0x0C orientation/transform dwords +0x10 world X +0x14 world Y +0x18 world Z +0x1C fourth transform value +0x20 event ID +0x24 auxiliary 32-bit field +0x28 byte/flag SOURCE TRANSFORM PAYLOAD 8 consecutive 32-bit values f0..f3 = quaternion f4/f5/f6 = world X/Y/Z f7 = auxiliary/padding/transform value RENDER PATH STRUCTURAL CLUES At 0x140352330: render parameter +0x40 -> owner/back-pointer-like object owner +0x10 -> pointer; +0x18 on pointed object yields context-like object used by render helpers context-like +0x176 = flags observed by static path context-like +0x1E8 = lazily initialized pointer used by render/matrix helper path owner +0x160 = byte/count used in one matrix-routing branch owner +0x78 = table/list region used in that branch Earlier runtime bridge clues that remain useful but should not be treated as universal identity: context +0x160 -> event-family object in known generator/steam render contexts alternate helicopter-era observation: context +0x168 -> child +0x20 -> event-like value at +0x2C8 These event paths are useful diagnostics, not the desired final source identity bridge. --- ##### Evidence status, corrections, retired hypotheses MGSV AUDIO — EVIDENCE STATUS, CORRECTIONS, RETIRED HYPOTHESES VERIFIED_RUNTIME - Real world source XYZ exists and is usable. - SoundSourceBody* is a useful physical-emitter identity. - Listener transform at the camera/SoundCore bridge works for normal third-person world-to-listener conversion. - Real Fox geometry drove audible left/right/front/back horizontal HRTF correctly in v0.25. - Useful individual/pre-final-mix Wwise PCM exists around 0x140352330. - 0x1403A77B0 is a practical mono-to-stereo HRTF insertion point in the tested Route-B path. - v0.28 TLS nested-call bridge matched all 53 captured Fox source posts to same-event Wwise posts. - Wwise PostGateway result tracks playing ID through later PLAY_ACTION rows. - body+0x80 changed across all 53 v0.28 source calls; 48 started at zero and became nonzero. - For all 53 v0.28 source calls, (source_after >> 8)+1 == nested Wwise object key. VERIFIED_STATIC - 0x140971410 allocates and fills a 0x30 3D-event record with event at +0x20 and transform values at +0x00..+0x1C. - 0x141D728F0 can write/update body+0x80 through an indirect manager call, then calls TransformSync and posts using the resulting token. - 0x141D72C40 copies an 8-value transform payload and uses body+0x80 in its SoundCore update path. - DAT_142B9E8B0 is a pointer variable to a 256 x 0xE0 record table, not the record array itself. - 0x140329640 performs low-byte slot lookup and full-handle validation at record+0x30. - ActiveRenderNode 0x140352330 directly calls matrix mix 0x1403A77B0 and reaches it through additional helper paths. - 0x1403D5F20 / 0x1403D67B0 implement channel-mask/matrix-based sample accumulation. CORRECTION: REGISTERED TABLE OLD: treat absolute 0x142B9E8B0 as the first table record. NEW: 0x142B9E8B0 is a global pointer variable. Dereference it to obtain the actual table base. STATUS: old base interpretation REFUTED; table/handle mechanism itself VERIFIED_STATIC. CORRECTION: A54F174F OLD: “helicopter event” / near-confirmed helicopter-family event. NEW: NOT helicopter-specific. It was associated with a strong elevated body during a helicopter test, but the same hash appears repeatedly during no-helicopter/control runs around Mother Base. The event hash alone cannot identify helicopter audio. STATUS: helicopter-specific label RETIRED. Keep only the historical fact that it was seen on the elevated candidate in that test. SUPERSEDED: EVENT-UNIQUENESS AUTO MAPPER v0.26's “same event + exactly one recent Fox body” method worked for simple controlled emitters but is not a safe universal identity rule. v0.28's synchronous nested-call bridge is stronger and deterministic for captured SoundSourceBody posts. DO NOT REOPEN WITHOUT CONTRADICTORY EVIDENCE - Basic third-person listener handedness/signs/quaternion conversion: audibly validated. - Existence of real source world XYZ. - Existence of useful pre-final-mix PCM. - Feasibility of geometry-driven HRTF. STILL CANDIDATE / OPEN - 0xE38A904F as soldier/local-interaction or voice-related event: not isolated enough. - Exact semantic meaning of the low byte of body+0x80 handle. - Exact record field containing Wwise object key after corrected table dereference; old hypothesis was +0x00 and should be re-tested. - Deterministic playing-ID/game-object -> active render context/node bridge. - Elevation-dependent HRIR selection. - Special camera/listener modes and vehicle/cinematic coverage. --- ##### Next research targets MGSV AUDIO — NEXT RESEARCH TARGETS Priority order after v0.28 + Ghidra FAST audit. 1. FIX THE TABLE DIAGNOSTIC BEFORE DISCARDING IT v0.27/v0.28 used the wrong base. Correct formula: uintptr_t table = *(uintptr_t*)0x142B9E8B0; uint32_t handle = *(uint32_t*)(body + 0x80); record = table + ((handle & 0xFF) * 0xE0); valid = (*(uint32_t*)(record + 0x30) == handle); Re-test the old +0x00 candidate field against v0.28's exact nested object_key. If +0x00 equals the object key, this gives a second deterministic static/runtime identity path and explains the handle format more completely. 2. RESTORE TRANSFORM TRACKING BY BODY POINTER v0.28 identity telemetry produced source_transforms=0 because transform logging was unnecessarily coupled to the changing +0x80 token. Track geometry by SoundSourceBody* directly. The body is the physical identity; the handle is a mutable audio-registration token. 3. TARGET 0x140342060 IN GHIDRA Several PostGateway callers immediately call 0x140342060 with successful playing ID + event data. The FAST audit did not decompile it. Decompile it and inspect callers/callees/data structures for fields that survive into the render list. 4. TARGET WWISE HOOK FUNCTIONS DIRECTLY IN GHIDRA 0x14033C050 PostGateway 0x14034CA50 game-object lookup 0x140347E00 playback/action dispatch Add them as explicit seeds so they are decompiled rather than only appearing as depth-boundary callees/callers. 5. BRIDGE PLAYING ID / OBJECT TO ACTIVE RENDER CONTEXT Current exact identity: SoundSourceBody -> event -> Wwise object key -> playing ID -> Wwise game object / play action Needed: playing ID or Wwise game object -> active context/node used at 0x140352330 / 0x1403A77B0 A telemetry-only v0.29 should retain the v0.28 nested identity and observe active Route-B mono contexts without writing audio. Search known context/object children for exact playing ID, exact Wwise object pointer, or exact object key. Report only stable matches and offsets. 6. ONCE RENDER IDENTITY IS PROVEN, SIMPLIFY FINAL ARCHITECTURE Remove event-uniqueness mapping from the primary path. Desired final chain: SoundSourceBody* -> current world transform -> synchronous post identity / handle table -> Wwise object key -> playing ID -> active render node/context -> mono PCM -> listener transform -> listener-relative azimuth/elevation -> HRTF 7. LATER COVERAGE - elevated HRIR dataset / interpolation - aiming/binocular camera - vehicles - cinematics/scripted cameras - non-world UI/radio/music exclusion policy - lifecycle/world-transition cache invalidation and pointer safety --- ##### Provenance PACK PROVENANCE Runtime source: mgsv_audio_identity_v028(1).log Ghidra source: MGSV_AudioChain_Audit_FAST_20260816_033335.zip extracted report Ghidra report summary: call-graph functions 23687, nearby functions 81, global heuristic candidates 0 Curated direct call edges: 893 Curated offset hits: 279 Curated indirect calls: 17 Selected decomp files copied: 40 V0.28 SOURCE_RECORD rows: 53 V0.28 source-after/key numerical relation: 53/53