Files
psxrecomp/runtime/include/spu_shadow.h
T
Matthew Stanley 3f3cfb7571 Integrate EU RC4 runtime and overlay tooling changes
Import the supplied developer handoff against 03e635e8. Include regional capability controls, texture validation, SHA acceleration with portable fallback, SPU CD/XA correction, and overlay export/staging fixes. Validated with rebuilt EU runtime, guarded AOT audit and focused regressions.
2026-10-21 16:54:05 -07:00

78 lines
3.3 KiB
C

/* spu_shadow.h — verified-enhancement float re-render of the SPU voice mix.
*
* A higher-fidelity reimplementation of the PS1 SPU's per-voice ADPCM playback
* that runs ALONGSIDE the faithful spu.c hardware model. Where the hardware
* resamples each voice with a 4-point Gaussian table (deliberately muffled) and
* truncates the mix to int16 at every step, the shadow keeps everything in
* float and resamples with a 4-point cubic (Catmull-Rom) kernel — no muffling,
* no intermediate requantization.
*
* It is NOT ground truth. The canon spu.c mix stays the authoritative output
* AND the verify oracle. The shadow is fed, sample-for-sample, into a
* ShadowVerifier against the canon stream; it only substitutes after a proven
* window and reverts LOUDLY (logs DEGRADED) after failed comparison windows.
* CD/XA input bypasses the voice-only shadow immediately. Opt-in via PSX_AUDIO_SHADOW=1, default OFF — with it off, spu_render
* output is byte-identical to upstream (this module is never entered).
*
* This file consumes the live per-voice state that spu.c already maintains via
* a small read-only accessor (spu_shadow_voice_snapshot); it does not duplicate
* the SPU register decode. ADSR envelope, key-on/off, and SPU RAM contents all
* come from the canon model, so the shadow can never diverge in WHICH note
* plays — only in the interpolation/headroom of HOW it is rendered.
*
* See docs/internal/PRINCIPLES.md "Verified-Enhancement HLE Is Allowed; Load-Bearing HLE Is
* Not" and docs/SHADOW_ENHANCEMENTS.md. ShadowVerifier attribution: see
* audio_shadow.h.
*/
#ifndef PSXRECOMP_SPU_SHADOW_H
#define PSXRECOMP_SPU_SHADOW_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Config/launcher gate. Sets the enable state the feature uses when the
* PSX_AUDIO_SHADOW env var is NOT set (env still wins for debug). Call before
* spu_init() so spu_shadow_reset() records the right state. Default OFF. */
void spu_shadow_set_enabled(int on);
/* Returns true if the shadow is enabled. Precedence: PSX_AUDIO_SHADOW env
* (if set) overrides the config value set via spu_shadow_set_enabled(). */
bool spu_shadow_enabled(void);
/* Called once per spu_init() to (re)create verifier + per-voice resampler
* state. Cheap; safe to call when disabled (no-op). */
void spu_shadow_reset(void);
/* Drive the shadow for one render block. `canon` is the int16 stereo mix that
* spu.c just produced (frames*2 samples, the authoritative output). The shadow
* re-renders the same block in float from live voice state, feeds (canon,
* shadow) to the verifier per frame, and — only while proven — overwrites
* `canon` in place with the float mix (clamped to int16). If the verifier
* reverts, it logs a DEGRADED line and leaves `canon` untouched.
*
* No-op (canon untouched, byte-identical) when the feature is disabled. */
void spu_shadow_process(int16_t* canon, int frames);
/* Diagnostics for the debug server / tests. */
typedef struct {
int enabled;
int proven;
uint64_t pauses;
float last_r; /* last window correlation */
float last_ratio; /* last window level ratio */
float gain; /* calibrated shadow gain */
char last_revert[160];
} SpuShadowInfo;
void spu_shadow_get_info(SpuShadowInfo* out);
#ifdef __cplusplus
}
#endif
#endif /* PSXRECOMP_SPU_SHADOW_H */