mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
The first cut reset the cores and brought back only RAM, registers and the mixer scalars, and mapped the era's volume levels across raw. Both halves were wrong. Volume levels are 31-bit in these eras and 15-bit today, so a full-volume legacy level overflows the mixer's s32 volume multiply and turns the whole mix into broadband static — loud enough to amplify even a paused game's silence into noise, which is what made the defect look independent of the SPU2 payload. And the dropped voice, streaming and DMA state belongs to a transfer the restored IOP driver still believes is in flight: left at reset, the driver waits forever for a completion interrupt no counter will deliver. Map everything instead: voices (envelope levels scaled 31->15 bits, the era's Releasing flag folded into the phase exactly as its Calculate() folded it, decode restarting at the current block), the ADMA/DMA counters (host pointers left null for the engine's own savestate heal, except the read-path pointer, which the heal misses — rebuilt from the channel TADR register), and the SPDIF/ring-position/playmode tail. Now that this is a field-by-field mapping rather than a memory copy, it moves out of spu2freeze.cpp into its own translation unit, leaving that file byte-identical to upstream's. The era layout tables are ours to carry and upstream keeps editing that file, so the two are better apart. Verified headless against graded audio captures: a mid-gameplay 0x9A2C resume state (Dragon Quest VIII) comes back with its music grading music-like (spectral flatness 0.007) where the partial restore graded noise (0.38+), and pause-menu saves come back silent because their sound driver parks every voice at zero pitch and volume until unpaused. 92 core and 1714 recompiler tests green.