How it works · write-up
Sprite AVI resolution and sound validation — 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.aviE:/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.