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.
69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
"""Drive the emulated plugin through VisualPluginHandler like iTunes did."""
|
|
import struct, sys
|
|
sys.path.insert(0, __file__.rsplit('/', 1)[0])
|
|
from emu import KS
|
|
|
|
def fourcc(s): return struct.unpack('>I', s.encode())[0]
|
|
|
|
HANDLER = '_VisualPluginHandler'
|
|
|
|
|
|
class Plugin:
|
|
def __init__(self, seed=1, rect=(0, 0, 480, 640), ticks=1000):
|
|
k = self.k = KS(seed)
|
|
k.ticks = ticks
|
|
k.port_rect = rect
|
|
self.msg = k.alloc(0x100)
|
|
self.port = k.alloc(0x100)
|
|
self.render = k.alloc(0x802)
|
|
# init
|
|
k.call(HANDLER, fourcc('init'), self.msg, 0)
|
|
self.pd = k.r32(self.msg + 0x18)
|
|
# show: port, rect, options
|
|
k.w32(self.msg, self.port)
|
|
k.u.mem_write(self.msg + 4, struct.pack('>4h', *rect))
|
|
k.w32(self.msg + 0xc, 0)
|
|
k.call(HANDLER, fourcc('show'), self.msg, self.pd)
|
|
# play
|
|
k.w32(self.msg, 0); k.w32(self.msg + 4, 0)
|
|
k.call(HANDLER, fourcc('vply'), self.msg, self.pd)
|
|
|
|
def frame(self, wave=None, spec=None, dt_us=40001, dticks=None):
|
|
"""One 'vrnd'. wave/spec: 2x512 uint8 lists (or None for silence)."""
|
|
k = self.k
|
|
k.micro += dt_us
|
|
k.ticks += dticks if dticks is not None else round(dt_us * 60 / 1e6)
|
|
data = bytearray(0x802)
|
|
data[0] = 2
|
|
data[0x401] = 2
|
|
if wave is not None:
|
|
data[1:0x401] = bytes(wave[0]) + bytes(wave[1])
|
|
else:
|
|
data[1:0x401] = bytes([128]) * 1024
|
|
if spec is not None:
|
|
data[0x402:0x802] = bytes(spec[0]) + bytes(spec[1])
|
|
k.u.mem_write(self.render, bytes(data))
|
|
k.w32(self.msg, self.render)
|
|
k.w32(self.msg + 4, 0)
|
|
start = len(k.gl)
|
|
k.call(HANDLER, fourcc('vrnd'), self.msg, self.pd)
|
|
return k.gl[start:]
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import random
|
|
p = Plugin()
|
|
print('pd', hex(p.pd), 'gl calls during show:', len(p.k.gl))
|
|
for name, args in p.k.gl[:40]:
|
|
print(' ', name, args)
|
|
rnd = random.Random(0)
|
|
for i in range(3):
|
|
wave = [[rnd.randrange(64, 192) for _ in range(512)] for _ in range(2)]
|
|
spec = [[rnd.randrange(0, 200) for _ in range(512)] for _ in range(2)]
|
|
calls = p.frame(wave, spec)
|
|
print('frame', i, len(calls))
|
|
from collections import Counter
|
|
print(Counter(n for n, a in calls))
|
|
for c in calls[:60]:
|
|
print(' ', c)
|