"""Build a small synthetic Arkham City folder (WADs, a stream pack) for tests that must not depend on real game data. Layout rules follow docs/formats/wad.md; WEMs come from ackit's own encoder.""" import os import struct import numpy as np from ackit import encoder SPEECH_ENTRY = 0xB49CDF48 # CHR_RadioScanner (3 variations here) SINGLE_ENTRY = 0x3F21770E # an entry with one WEM PACK_ID = 0xEDF036D6 # 'Music' stream pack MEDIA = (0x003CB311, 0x393BC53A, 0x40000001) AMB_ENTRY = 0x98A82EFF # AMB_Steel_B3 def tone(seconds, rate=24000, freq=440.0, ch=1): t = np.arange(int(seconds * rate)) / rate x = (0.3 * np.sin(2 * np.pi * freq * t) * (0.6 + 0.4 * np.sin(2 * np.pi * 2 * t))).astype(np.float32) return np.repeat(x[:, None], ch, axis=1), rate def wem(seconds, freq, rate=24000, ch=1): x, sr = tone(seconds, rate, freq, ch) return encoder.encode(x, sr, rate, ch)[0] def _a(x, n): return (x + n - 1) // n * n def write_wad(path, payloads): """payloads: {hash: bytes}""" s32 = lambda h: struct.unpack(" (bnk bytes, wad payload) for {media id: wem}. One gap gets non-zero bytes, like the real 'Music' pack, to test byte-exact reverts.""" ids = sorted(media) payload = bytearray() table = [] for i, m in enumerate(ids): start = _a(len(payload), 0x800) gap = bytearray(start - len(payload)) if i == 1 and len(gap) > 4: gap[1:4] = b"\x11\x22\x33" payload += gap table.append((m, len(media[m]), len(payload))) payload += media[m] payload += bytes(_a(len(payload), 0x800) - len(payload)) bank = b"BKHD" + struct.pack(" event -> action -> streamed Sound object.""" data = bytearray() didx = b"" for m in sorted(media): data += bytes(_a(len(data), 16) - len(data)) didx += struct.pack("