Xenon 2

How it works · write-up

Sprite AVI resolution and sound validation — 2026-10-05

xenondoc/SPRITE_AVI_RESOLUTION_AUDIO_20261005.MD · 5 KB · updated 2026-10-05

--xenon-sprite-scale 4 selects a 1280×800 drawable area. The official launcher uses -SpriteScale 4; campaign validation uses --sprite-scale 4. Default scale remains 2 (640×400). Scale changes presentation and capture, preserving the 320×200 game coordinates. Use --xenon-hires true / -HdSprites / --hd-sprites to select the 4× atlas independently.

Both AVI recorders now use the game's mixed stereo PCM from Sound_Update_VBL. Previously the sprite recorder emitted silent PCM. Its GPU downloads can arrive several frames late, so a bounded eight-VBL audio history pairs the sound with the captured frame. Each detached encoder job contains one video frame and its audio chunk, preserving the existing OpenDML pairing. The history is allocated only while sprite recording is armed or active and is reset on restart.

Live checks

Hatari was visible. Paired captures used resident C control through validate_campaign.py native-run; the sprite-only check used the official hatari_dev.ps1 run launcher. Release Hatari and the native DLL were rebuilt with the official script. All captures below have valid video/audio indexes and decodable first and last images.

Check Sprite size Video / PCM chunks PCM chunks matching original
R566, HD + high FPS 1280×800 499 / 499 499, zero mismatches
Sprite-only, no original recorder 1280×800 180 / 180 Not applicable; all 180 contain nonzero PCM
R567, default renderer 640×400 400 / 400 400, zero mismatches
R568, HD + high FPS, 1,411,524,272 bytes 1280×800 1011 / 1011 1011, zero mismatches
R569, stop/start on the same instance 1280×800 169 / 169 169, zero mismatches

R568 crosses the 1 GiB segment boundary: both RIFF segments and both sets of video/audio indexes validate. Audio is PCM S16LE, stereo, 44100 Hz in these runs. The original AVI remains 640×400. Audio comparison accounts for the one-VBL tag offset between sprite capture and the authentic recorder; this is separate from the authentic picture's render latency.

Recording folders:

  • E:/xenon_runs/sprite-hd-audio-20261005-r566.validation/
  • D:/src/hatari/work/sprite-avi-size-audio-20261005/ — sprite-only-finalized.avi
  • E:/xenon_runs/sprite-default-audio-20261005-r567.validation/
  • E:/xenon_runs/sprite-hd-opendml-audio-20261005-r568.validation/
  • E:/xenon_runs/sprite-restart-audio-20261005-r569.validation/

Each paired folder contains its matching .x2events, -original.avi, -sprite.avi, VBL sidecars, and source snapshot. Audit JSON files are in work/sprite-avi-size-audio-20261005/.

The initial sprite-only probe exposed an existing shutdown bug: --run-vbls called exit(0) directly and left the AVI's RIFF size unfinalized. It now requests normal shutdown, draining GPU readbacks and encoder workers. The initial sprite-only.avi is an invalid diagnostic artifact; the 180-frame sprite-only-finalized.avi is the successful retest.

Reusable checks

python xenon_tools/audit_sprite_avi.py sprite.avi --original original.avi --size 1280 800 --output audit.json
# From xenon_tools/:
python -m unittest test_campaign test_hatari_avi test_sprite_avi_audit

All 28 targeted tests pass. They cover launcher scale forwarding, manifest arguments, image decoding, audio index payloads, PCM presence, VBL audio pairing, incorrect dimensions, and mismatched sound. No autopilot tactics changed.

When using native-run --connect, renderer launch settings are unknown to the validator and are recorded as null instead of falsely claiming default settings. The AVI headers remain the authoritative capture dimensions.

Mono ST audio follow-up

ST/Mega ST captures now write one 16-bit PCM channel in both AVIs. The emulator's ST mixer supplies identical left/right samples, so storing only the left channel preserves the sound and halves the audio payload. Later machines retain two-channel output. The channel count is fixed at recording start; the live audio mixer and GPU/audio pairing are unchanged.

Audio headers, byte rates, block alignment, and sample sizes follow the selected channel count. An existing OpenDML bug was also corrected: audio super-index durations previously counted bytes; they now count sample frames.

Visible resident-C validation: E:/xenon_runs/mono-avi-20261005-r570.validation/mono-avi-20261005-r570.x2events. Both AVIs contain 195 video frames, 195 PCM chunks, and 142501 sample frames. ffprobe confirms one channel, PCM S16LE, 44100 Hz, and 16 bits per sample. All 195 paired audio chunks match, both AVI structures validate, and each audio super-index duration equals 142501 sample frames. The sprite image remains 1280×800. The recording finalized without cleanup errors.

The audit now reads each AVI's PCM format instead of assuming stereo. All 29 targeted tests pass, including mono sample counts and retained stereo fixtures. Release Hatari and the replay DLL were built with the official PS1 script.