diff --git a/src/res/sources/game.fur b/src/res/sources/game.fur new file mode 100644 index 0000000..0f18e0b Binary files /dev/null and b/src/res/sources/game.fur differ diff --git a/src/res/sources/game.vgm b/src/res/sources/game.vgm new file mode 100644 index 0000000..c8039a9 Binary files /dev/null and b/src/res/sources/game.vgm differ diff --git a/src/res/sources/gameparse.py b/src/res/sources/gameparse.py new file mode 100644 index 0000000..a43f203 --- /dev/null +++ b/src/res/sources/gameparse.py @@ -0,0 +1,241 @@ +# DMGTRIS +# Copyright (C) 2023 - Randy Thiemann + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from construct import Struct, Const, Int32ul, Int16ul, Int8ul, Bytes + +vgm_header = Struct( + "magic" / Const(b"Vgm "), + "eof_offset" / Int32ul, + "version" / Int32ul, + "sn76489_clock" / Int32ul, + "ym2413_clock" / Int32ul, + "gd3_offset" / Int32ul, + "total_samples" / Int32ul, + "loop_offset" / Int32ul, + "loop_samples" / Int32ul, + "rate" / Int32ul, + "sn_fb" / Int16ul, + "sn_w" / Int8ul, + "sn_c" / Int8ul, + "ym2612_clock" / Int32ul, + "ym2151_clock" / Int32ul, + "vgm_data_offset" / Int32ul, + "seg_pcm_clock" / Int32ul, + "seg_pcm_intf_reg" / Int32ul, + "rf5c68_clock" / Int32ul, + "ym2203_clock" / Int32ul, + "ym2608_clock" / Int32ul, + "ym2610_clock" / Int32ul, + "ym3812_clock" / Int32ul, + "ym3526_clock" / Int32ul, + "y8950_clock" / Int32ul, + "ymf262_clock" / Int32ul, + "ymf278b_clock" / Int32ul, + "ymf271_clock" / Int32ul, + "ymz280b_clock" / Int32ul, + "rf5c164_clock" / Int32ul, + "pwm_clock" / Int32ul, + "ay8910_clock" / Int32ul, + "ay8910_type" / Int8ul, + "ay8910_flags" / Int8ul, + "ym2203_ay8910_flags" / Int8ul, + "ym2608_ay8910_flags" / Int8ul, + "volume_mod" / Int8ul, + "reserved_0" / Bytes(1), + "loop_base" / Int8ul, + "loop_modifier" / Int8ul, + "dmg_clock" / Int32ul, + "nes_apu_clock" / Int32ul, + "multi_pcm_clock" / Int32ul, + "upd7759_clock" / Int32ul, + "okim6258_clock" / Int32ul, + "okim6258_flags" / Int8ul, + "k054539_flags" / Int8ul, + "c140_chip_type" / Int8ul, + "reserved_1" / Bytes(1), + "okim6295_clock" / Int32ul, + "k051649_k052539_clock" / Int32ul, + "k054539_clock" / Int32ul, + "huc6280_clock" / Int32ul, + "c140_clock" / Int32ul, + "k053260_clock" / Int32ul, + "pokey_clock" / Int32ul, + "qsound_clock" / Int32ul, + "scsp_clock" / Int32ul, + "extra_hdr_offset" / Int32ul, + "wonder_swan_clock" / Int32ul, + "vsu_clock" / Int32ul, + "saa1099_clock" / Int32ul, + "es5503_clock" / Int32ul, + "es5505_es5506_clock" / Int32ul, + "es5503_num_channels" / Int8ul, + "es5505_es5506_num_channels" / Int8ul, + "c352_clock_div" / Int8ul, + "reserved_2" / Bytes(1), + "x1_010_clock" / Int32ul, + "c352_clock" / Int32ul, + "ga20_clock" / Int32ul, + "reserved_3" / Bytes(28) +) + +b3_command = Struct( + "command" / Const(b'\xB3'), + "reg" / Int8ul, + "data" / Int8ul +) + +register_names = [ + "REG_UNK", # 0x00 + "REG_UNK", # 0x01 + "REG_UNK", # 0x02 + "REG_UNK", # 0x03 + "REG_UNK", # 0x04 + "REG_UNK", # 0x05 + "REG_UNK", # 0x06 + "REG_UNK", # 0x07 + "REG_UNK", # 0x08 + "REG_UNK", # 0x09 + "REG_UNK", # 0x0A + "REG_UNK", # 0x0B + "REG_UNK", # 0x0C + "REG_UNK", # 0x0D + "REG_UNK", # 0x0E + "REG_UNK", # 0x0F + "REG_NR10_CH1_SWEEP", # 0x10 + "REG_NR11_CH1_LENDT", # 0x11 + "REG_NR12_CH1_VOLEV", # 0x12 + "REG_NR13_CH1_FRQLO", # 0x13 + "REG_NR14_CH1_FRQHI", # 0x14 + "REG_UNK", # 0x15 + "REG_NR21_CH2_LENDT", # 0x16 + "REG_NR22_CH2_VOLEV", # 0x17 + "REG_NR23_CH2_FRQLO", # 0x18 + "REG_NR24_CH2_FRQHI", # 0x19 + "REG_NR30_CH3_DACEN", # 0x1A + "REG_NR31_CH3_LENGT", # 0x1B + "REG_NR32_CH3_VOLUM", # 0x1C + "REG_NR33_CH3_FRQLO", # 0x1D + "REG_NR34_CH3_FRQHI", # 0x1E + "REG_UNK", # 0x1F + "REG_NR41_CH4_LENGT", # 0x20 + "REG_NR42_CH4_VOLEV", # 0x21 + "REG_NR43_CH4_FQRND", # 0x22 + "REG_NR44_CH4_CNTRL", # 0x23 + "REG_NR50_MVOLVINPN", # 0x24 + "REG_NR51_MASTERPAN", # 0x25 + "REG_NR52_MASTERCTL", # 0x26 + "REG_UNK", # 0x27 + "REG_UNK", # 0x28 + "REG_UNK", # 0x29 + "REG_UNK", # 0x2A + "REG_UNK", # 0x2B + "REG_UNK", # 0x2C + "REG_UNK", # 0x2D + "REG_UNK", # 0x2E + "REG_UNK", # 0x2F + "REG_WAVE_PATTERN_0", # 0x30 + "REG_WAVE_PATTERN_1", # 0x31 + "REG_WAVE_PATTERN_2", # 0x32 + "REG_WAVE_PATTERN_3", # 0x33 + "REG_WAVE_PATTERN_4", # 0x34 + "REG_WAVE_PATTERN_5", # 0x35 + "REG_WAVE_PATTERN_6", # 0x36 + "REG_WAVE_PATTERN_7", # 0x37 + "REG_WAVE_PATTERN_8", # 0x38 + "REG_WAVE_PATTERN_9", # 0x39 + "REG_WAVE_PATTERN_A", # 0x3A + "REG_WAVE_PATTERN_B", # 0x3B + "REG_WAVE_PATTERN_C", # 0x3C + "REG_WAVE_PATTERN_D", # 0x3D + "REG_WAVE_PATTERN_E", # 0x3E + "REG_WAVE_PATTERN_F", # 0x3F +] + +def chunks(lst, n): + for i in range(0, len(lst), n): + yield lst[i:i + n] + +class DB: + l = [] + + def __init__(self): + self.l = [] + + def __str__(self): + out = [] + for chunk in chunks(self.l, 8): + out.append(f" db {', '.join(chunk)}") + return "\n".join(out) + "\n" + + def __repr__(self): + return str(self) + + def __len__(self): + return len(self.l) + + def add(self, *args): + if len(args) == 1: + self.l.append(f"${args[0]:02X}") + else: + self.l.append(register_names[args[0]]) + self.l.append(f"${args[1]:02X}") + + def trim(self): + while self.l[-1] == "$FF": + self.l.pop() + +for c, v in enumerate(register_names): + if v != "REG_UNK": + print(f"DEF {v} EQU ${c:02X}") + +print() +print("sMusicGame::") + +with open("game.vgm", "rb") as f: + data = f.read() + header = vgm_header.parse(data) + data_offset = 0x34 + header.vgm_data_offset + data = data[data_offset:] + db = DB() + ctr = 0 + last = None + while len(data) > 0: + if data.startswith(b'\x67\x66'): + data = data[3:] + data = data[Int32ul.parse(data) + 4:] + elif data.startswith(b'\xB3'): + b3 = b3_command.parse(data) + if last == 0x62: + print(db) + db = DB() + db.add(b3.reg + 0x10, b3.data) + last = 0xB3 + data = data[3:] + elif data.startswith(b'\x62'): + db.add(0xFF) + last = 0x62 + data = data[1:] + elif data.startswith(b'\x66'): + if len(db) > 0: + db.trim() + db.add(0xFE) + print(db, end="") + break + else: + print(f"Unknown command: ${data[0]:02X}") + data = data[1:] + +print("sMusicGameEnd::")