"""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)