summaryrefslogtreecommitdiff
path: root/pokemontools/redsfxdisasm.py
diff options
context:
space:
mode:
Diffstat (limited to 'pokemontools/redsfxdisasm.py')
-rwxr-xr-xpokemontools/redsfxdisasm.py126
1 files changed, 126 insertions, 0 deletions
diff --git a/pokemontools/redsfxdisasm.py b/pokemontools/redsfxdisasm.py
new file mode 100755
index 0000000..9e9f01b
--- /dev/null
+++ b/pokemontools/redsfxdisasm.py
@@ -0,0 +1,126 @@
+import configuration
+config = configuration.Config()
+rom = bytearray(open(config.rom_path, "r").read())
+
+banks = {
+ 0x02: 0x60,
+ 0x08: 0x78,
+ 0x1f: 0x68,
+ }
+
+music_commands = {
+ 0xd0: ["notetype", {"type": "nibble"}, 2],
+ 0xe0: ["octave", 1],
+ 0xe8: ["togglecall", 1],
+ 0xea: ["vibrato", {"type": "byte"}, {"type": "nibble"}, 3],
+ 0xec: ["duty", {"type": "byte"}, 2],
+ 0xed: ["tempo", {"type": "byte"}, {"type": "byte"}, 3],
+ 0xf0: ["stereopanning", {"type": "byte"}, 2],
+ 0xf8: ["executemusic", 1],
+ 0xfc: ["dutycycle", {"type": "byte"}, 2],
+ 0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4],
+ 0xff: ["endchannel", 1],
+ }
+
+param_lengths = {
+ "nibble": 1,
+ "byte": 1,
+ "label": 2,
+ }
+
+music_notes = {
+ 0x0: "C_",
+ 0x1: "C#",
+ 0x2: "D_",
+ 0x3: "D#",
+ 0x4: "E_",
+ 0x5: "F_",
+ 0x6: "F#",
+ 0x7: "G_",
+ 0x8: "G#",
+ 0x9: "A_",
+ 0xa: "A#",
+ 0xb: "B_",
+ }
+
+for bank in banks:
+ header = bank * 0x4000 + 3
+ for sfx in range(1,banks[bank]):
+ sfxname = "SFX_{:02x}_{:02x}".format(bank, sfx)
+ sfxfile = open("music/sfx/" + sfxname.lower() + ".asm", 'w')
+ startingaddress = rom[header + 2] * 0x100 + rom[header + 1] + (0x4000 * (bank - 1))
+ end = 0
+ curchannel = 1
+ lastchannel = (rom[header] >> 6) + 1
+ channelnumber = rom[header] % 0x10
+ output = ''
+ while 1:
+ address = startingaddress
+ if curchannel != lastchannel:
+ end = rom[header + 5] * 0x100 + rom[header + 4] + (0x4000 * (bank - 1))
+ byte = rom[address]
+ if byte == 0xf8 or (bank == 2 and sfx == 0x5e): executemusic = True
+ else: executemusic = False
+ output += "{}_Ch{}: ; {:02x} ({:0x}:{:02x})\n".format(sfxname, curchannel, address, bank, address % 0x4000 + 0x4000)
+ while 1:
+ if address == 0x2062a or address == 0x2063d or address == 0x20930:
+ output += "\n{}_branch_{:02x}:\n".format(sfxname, address)
+ if byte == 0x10 and not executemusic:
+ output += "\tunknownsfx0x{:02x} {}".format(byte, rom[address + 1])
+ command_length = 2
+ elif byte < 0x30 and not executemusic:
+ if channelnumber == 7:
+ output += "\tunknownnoise0x20 {}, {}, {}".format(byte % 0x10, rom[address + 1], rom[address + 2])
+ command_length = 3
+ else:
+ output += "\tunknownsfx0x20 {}, {}, {}, {}".format(byte % 0x10, rom[address + 1], rom[address + 2], rom[address + 3])
+ command_length = 4
+ elif byte < 0xc0:
+ output += "\tnote {}, {}".format(music_notes[byte >> 4], byte % 0x10 + 1)
+ command_length = 1
+ elif byte < 0xd0:
+ output += "\trest {}".format(byte % 0x10 + 1)
+ command_length = 1
+ else:
+ if byte < 0xe0:
+ command = music_commands[0xd0]
+ output += "\t{} {},".format(command[0], byte % 0x10)
+ byte = 0xd0
+ elif byte < 0xe8:
+ command = music_commands[0xe0]
+ output += "\t{} {}".format(command[0], 0xe8 - byte)
+ byte = 0xe0
+ else:
+ command = music_commands[byte]
+ output += "\t{}".format(command[0])
+ command_length = 1
+ params = 1
+ # print all params for current command
+ while params != len(music_commands[byte]) - 1:
+ param_type = music_commands[byte][params]["type"]
+ address += command_length
+ command_length = param_lengths[param_type]
+ param = rom[address]
+ if param_type == "nibble":
+ output += " {}, {}".format(param >> 4, param % 0x10)
+ elif param_type == "byte":
+ output += " {}".format(param)
+ else:
+ param += rom[address + 1] * 0x100 - 0x4000 + (bank * 0x4000)
+ if param == startingaddress: output += " {}_Ch{}".format(sfxname, curchannel)
+ else: output += " {}_branch_{:02x}".format(sfxname, param)
+ params += 1
+ if params != len(music_commands[byte]) - 1: output += ","
+ output += "\n"
+ address += command_length
+ if byte == 0xff or address == end: break
+ byte = rom[address]
+ header += 3
+ channelnumber = rom[header]
+ if curchannel == lastchannel:
+ output += "; {}".format(hex(address))
+ sfxfile.write(output)
+ break
+ output += "\n\n"
+ startingaddress = address
+ curchannel += 1 \ No newline at end of file