Files
lintunes/scripts/kaleidostrobe/coverage.py
T
trav e38c751e39 v0.53.0: Kaleidostrobe, the 2002 iTunes visualizer, as the fourth style
Reverse-engineered from its PowerPC binary and checked against the original
running under emulation: textures byte for byte and every triangle, over
3,600 frames. 25 fps like the plugin; its colour maps and wave images are
extracted from its own code; tests/kaleidostrobe_golden.npz was recorded
from the original.
2026-10-14 12:02:22 -07:00

46 lines
2.2 KiB
Python

import sys; sys.path.insert(0, __file__.rsplit('/',1)[0]); sys.path.insert(0, str(__import__('pathlib').Path(__file__).resolve().parents[2]))
import numpy as np
from plugin import Plugin
from lintunes.kaleidostrobe import engine as E
TEXIDX, CURTEX, CURFRAME, WAVEINC = 0x457f8, 0x13dbc, 0x13dc0, 0x257f0
p = Plugin(seed=1); k = p.k
rng = np.random.default_rng(3)
bad = 0
for n in E.DELTA_TABLE:
for tex in (0, 1):
state = {}
# the emulator's static counters may already have moved during
# Plugin(); sync by reading them is fiddly, so zero them first
k.u.mem_write(0x13b2c, b'\0' * (0x13be4 - 0x13b2c))
for it in range(4):
src = rng.integers(0, 256, (128, 128), dtype=np.uint8)
base = TEXIDX + tex * 0x8000
k.u.mem_write(base, src.tobytes())
k.w32(CURTEX, tex); k.w32(CURFRAME + 4 * tex, 1)
k.call(f'_calcDelta{n:03d}')
theirs = np.frombuffer(k.mem(base + 0x4000, 0x4000), np.uint8).reshape(128, 128)
ours = E.delta(n, src, state)
d = int((theirs != ours).sum())
if d:
bad += 1; print(f'delta {n:03d} tex {tex} iter {it}: {d} differ')
print('deltas checked')
for seed in (5, 99, 31337):
for idx in range(len(E.WAVE_TABLE)):
k.rng.srand(seed); r = E.ParkMiller(seed)
tex = idx % 2
k.w32(CURTEX, tex); k.w32(CURFRAME + 4 * tex, 0)
n = E.WAVE_TABLE[idx]
k.call(f'_initWaveShape{n:03d}')
theirs = np.frombuffer(k.mem(TEXIDX + tex * 0x8000, 0x4000), np.uint8).reshape(128, 128)
eng = E.Kaleidostrobe.__new__(E.Kaleidostrobe)
t = E.tables(); eng.waves, eng.wave_inc = t['waves'], t['wave_inc']
eng.rng = r; eng.buffers = np.zeros((2, 2, 128, 128), np.uint8)
eng.wave_scale = [0.0, 0.0]; eng.cur_wave = [idx, idx]
eng._init_wave(tex)
d = int((theirs != eng.buffers[tex, 0]).sum())
inc = k.rf(WAVEINC + 4 * tex)
if d or abs(inc - eng.wave_scale[tex]) > 1e-7 or k.rng.x != r.x:
bad += 1; print(f'wave {n:03d} seed {seed}: {d} differ, inc {inc} vs {eng.wave_scale[tex]}, rng {k.rng.x == r.x}')
print('waves checked; failures:', bad)