Additive, cvar-gated instrumentation used to reverse-engineer Project
Sylpheed's cutscene-voice storage (movie -> continuous sound-stream cue
region). Default-off; no behaviour change.
- event_log.cc: MaybeEmitFileRead emits `file.read` events with the real
NtReadFile ByteOffset (from r10), length, handle->path, and buffer VA, so a
sound.pNN read offset can be mapped to a sound.pak TOC entry.
Gate: --phase_a_fileio_only=true --phase_a_event_log_path=<file>.
- cpu_flags.cc: phase_a_fileio_only cvar (+ xma_param_probe).
- xma_context_new.cc: XMA-PARAM probe in XmaContextNew::Decode (the decoder the
title actually uses) logging ctx/buffer/read-offset/channels/packets/byte_size
/signature — to confirm which bytes get decoded for a given cutscene.
Used to produce /tmp/rt_fileio.jsonl (RT01A playthrough), which cracked the
movie->voice mapping now implemented in sylpheed-reborn. Next: run the same
file.read trace on an unbound hokyu (e.g. hokyu_LS_s03A) to resolve which
VOICE_D the game streams for the 13 manifest-unbound resupply cutscenes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Snapshot for handoff. Contains the mission-audio + threading fixes and the
crash-investigation instrumentation (all diagnostic cvars default-OFF).
Fixes (behavioral):
- threading_posix.cc: reap-once guard on PosixCondition<Thread>::post_execution
(double pthread_join at mission teardown -> fault loop -> audio death + freeze).
- xma_decoder.cc: work_event_->Set() in Pause() so the idle XMA worker observes
paused_ and signals pause_fence_ (Pause() deadlock -> permanent audio death).
- audio_system / xma_context_master / xboxkrnl_audio / apu_flags / alsa: mission
audio keepalive + guest_audio_flags + watchdogs.
Instrumentation (additive, default-off): xboxkrnl_debug cache-throw diag +
guest-catch dispatcher, xex_module PE/PDATA/EH scans, kernel_state mem_watch
(NOTE: mem_watch DEFAULTS TRUE -- an always-on host poll thread; prime crash suspect).
NEW ORACLE (see HANDOFF-crash-oracle-2026-07-16.md): stock 6e5b8324f built with
our toolchain + zero custom code = NO crash, NO sound-stop, plays the Ready Room.
=> the Ready-Room out_of_range crash is introduced by THESE changes, not the game
and not the (LTO-broken) build chain. Bisection plan + suspect ranking in the note.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two Linux mission-audio fixes for Project Sylpheed (audio played in
intro/menu but died when a mission finished loading, never returning):
- alsa_audio_driver: when the guest stalls (mission "Preparing for Sortie"
load) and the ring buffer empties, feed silence to keep the PCM alive
instead of sleeping. Previously the small buffer drained, XRUN'd, and
playback never recovered (matches the known "audio muted permanently").
- xconfig: make the guest speaker config a cvar (guest_audio_flags,
default Digital Stereo) instead of hardcoded Dolby Digital surround.
(The practical fix on this box also needed log_mask=13 to stop kernel log
spam starving the audio pipeline during missions — config, not code.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Key fixes versus the previous implementation:
Packet walk across input-buffer boundaries: GetNextPacket and
GetNextPacketReadOffset now resolve the actual target packet inside
the next input buffer, instead of clamping to its first packet.
Resolves silent 'patches' in cinematics observed previously in AC6.
Co-authored-by: sal063 <ssalh0456@gmail.com>
Stall detection was triggering during multi-pass subframe consumption
(e.g. stereo with subframe_decode_count < total subframes), breaking
audio looping in games like Tomb Raider. Now only detects a stall when
no subframes were pending, so Consume-only iterations aren't mistaken
for no-progress cycles. Fixes Halo 4 without regressing Tomb Raider.
The decoder gate required a full frame of free blocks (4 mono / 8 stereo +
padding) before allowing a decode pass, but Consume() only writes
subframe_decode_count blocks per call. Games like TGM Ace with
subframe_decode_count=2 on a small ring buffer could never meet the old
threshold, causing a permanent decoder stall.
The 3-bit field at +24bit in DWORD 1 of the XMA context was named
subframe_skip_count but never actually used for skipping subframes.
Testing across multiple titles (PGR4, Halo Reach) shows the field
might control extra output buffer blocks that must be reserved per decoded
frame. Renaming the field to output_buffer_padding to reflect this
observed behavior and adding padding to the minimum output space threshold
Pdding blocks are reserved from the output budget after each frame is
fully consumed, preventing the decoder from overrunning the space
that the game expects to remain free.
This is still likely not entirely correct but reduces some of the
observed noise in current implementation.
- Fake: No decoding
- Master: 1:1 from base version of Xenia
- Old: Master with improvements
- New: Completely new decoder with better stability (but not compability)
Co-authored-by: Herman S. <429230+has207@users.noreply.github.com>
- Added codepath for "consume only" pass. This should resolve constant clicking in Source engine games.
- Added smaller performance improvements to decoder