From 1b56d95aa0f39146a37043a36cf19f46b00f68c3 Mon Sep 17 00:00:00 2001 From: "U-Fish-PC\\Daniel" Date: Sun, 13 Oct 2013 10:49:07 -0400 Subject: Add pokered music commands --- pokemontools/crystal.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pokemontools/crystal.py b/pokemontools/crystal.py index 45eb306..5d602c9 100644 --- a/pokemontools/crystal.py +++ b/pokemontools/crystal.py @@ -2453,7 +2453,22 @@ def create_music_command_classes(debug=False): return klasses music_classes = create_music_command_classes() - +class callchannel(Command): + id = 0xFD + macro_name = "callchannel" + size = 3 + param_types = { + 0: {"name": "address", "class": PointerLabelParam}, + } + +class loopchannel(Command): + id = 0xFE + macro_name = "loopchannel" + size = 4 + param_types = { + 0: {"name": "count", "class": SingleByteParam}, + 1: {"name": "address", "class": PointerLabelParam}, + } effect_commands = { 0x1: ['checkturn'], -- cgit v1.2.3 From c57e0f0706608a4acba89182945bec975a43acfd Mon Sep 17 00:00:00 2001 From: "U-Fish-PC\\Daniel" Date: Sun, 13 Oct 2013 10:50:09 -0400 Subject: Add pokered music tools --- pokemontools/redmusicdisasm.py | 306 +++++++++++++++++++++++++++++++++++++++++ pokemontools/redsfxdisasm.py | 149 ++++++++++++++++++++ pokemontools/redsfxheaders.py | 43 ++++++ 3 files changed, 498 insertions(+) create mode 100755 pokemontools/redmusicdisasm.py create mode 100755 pokemontools/redsfxdisasm.py create mode 100755 pokemontools/redsfxheaders.py diff --git a/pokemontools/redmusicdisasm.py b/pokemontools/redmusicdisasm.py new file mode 100755 index 0000000..ad370cd --- /dev/null +++ b/pokemontools/redmusicdisasm.py @@ -0,0 +1,306 @@ +import config +config = config.Config() +rom = bytearray(open(config.rom_path, "r").read()) + +songs = [ + "PalletTown", + "Pokecenter", + "Gym", + "Cities1", + "Cities2", + "Celadon", + "Cinnabar", + "Vermilion", + "Lavender", + "SSAnne", + "MeetProfOak", + "MeetRival", + "MuseumGuy", + "SafariZone", + "PkmnHealed", + "Routes1", + "Routes2", + "Routes3", + "Routes4", + "IndigoPlateau", + "GymLeaderBattle", + "TrainerBattle", + "WildBattle", + "FinalBattle", + "DefeatedTrainer", + "DefeatedWildMon", + "DefeatedGymLeader", + "TitleScreen", + "Credits", + "HallOfFame", + "OaksLab", + "JigglypuffSong", + "BikeRiding", + "Surfing", + "GameCorner", + "IntroBattle", + "Dungeon1", + "Dungeon2", + "Dungeon3", + "CinnabarMansion", + "PokemonTower", + "SilphCo", + "MeetEvilTrainer", + "MeetFemaleTrainer", + "MeetMaleTrainer", + "UnusedSong", + #"SurfingPikachu", + #"MeetJessieJames", + #"YellowUnusedSong", + ] + +music_commands = { + 0xd0: ["notetype", {"type": "nibble"}, 2], + 0xe0: ["octave", 1], + 0xe8: ["unknownmusic0xe8", 1], + 0xea: ["vibrato", {"type": "byte"}, {"type": "nibble"}, 3], + 0xeb: ["pitchbend", {"type": "byte"}, {"type": "byte"}, 3], + 0xec: ["duty", {"type": "byte"}, 2], + 0xed: ["tempo", {"type": "byte"}, {"type": "byte"}, 3], + 0xee: ["unknownmusic0xee", {"type": "byte"}, 2], + 0xf0: ["stereopanning", {"type": "byte"}, 2], + 0xf8: ["unknownmusic0xf8", 1], + 0xfc: ["dutycycle", {"type": "byte"}, 2], + 0xfd: ["callchannel", {"type": "label"}, 3], + 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_", + } + +def printnoisechannel(songname, songfile, startingaddress, bank, output): + noise_commands = { + 0xfd: ["callchannel", {"type": "label"}, 3], + 0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4], + 0xff: ["endchannel", 1], + } + + noise_instruments = { + 0x01: "snare1", + 0x02: "snare2", + 0x03: "snare3", + 0x04: "snare4", + 0x05: "snare5", + 0x06: "triangle1", + 0x07: "triangle2", + 0x08: "snare6", + 0x09: "snare7", + 0x0a: "snare8", + 0x0b: "snare9", + 0x0c: "cymbal1", + 0x0d: "cymbal2", + 0x0e: "cymbal3", + 0x0f: "mutedsnare1", + 0x10: "triangle3", + 0x11: "mutedsnare2", + 0x12: "mutedsnare3", + 0x13: "mutedsnare4", + } + + # pass 1, build a list of all addresses pointed to by calls and loops + address = startingaddress + labels = [] + labelsleft= [] + while 1: + byte = rom[address] + if byte < 0xc0: + command_length = 2 + elif byte < 0xe0: + command_length = 1 + else: + command_length = noise_commands[byte][-1] + if byte == 0xfd or byte == 0xfe: + label = rom[address + command_length - 1] * 0x100 + rom[address + command_length - 2] + labels.append(label) + if label > address % 0x4000 + 0x4000: labelsleft.append(label) + address += command_length + if len(labelsleft) == 0 and (byte == 0xfe and rom[address - command_length + 1] == 0 and rom[address - 1] * 0x100 + rom[address - 2] < address % 0x4000 + 0x4000 or byte == 0xff): break + while address % 0x4000 + 0x4000 in labelsleft: labelsleft.remove(address % 0x4000 + 0x4000) + # once the loop ends, start over from first address + if rom[address] == 0xff: address += 1 + end = address + address = startingaddress + byte = rom[address] + output += "Music_{}_Ch4: ; {:02x} ({:0x}:{:02x})\n".format(songname, address, bank, address % 0x4000 + 0x4000) + # pass 2, print commands and labels for addresses that are in labels + while address != end: + if address % 0x4000 + 0x4000 in labels and address != startingaddress: + output += "\nMusic_{}_branch_{:02x}:\n".format(songname, address) + if byte < 0xc0: + output += "\tdnote {}, {}".format(byte % 0x10 + 1, noise_instruments[rom[address + 1]]) + command_length = 2 + elif byte < 0xd0: + output += "\trest {}".format(byte % 0x10 + 1) + command_length = 1 + elif byte < 0xe0: + output += "\tdspeed {}".format(byte % 0x10) + command_length = 1 + else: + command = noise_commands[byte] + output += "\t{}".format(command[0]) + command_length = 1 + params = 1 + # print all params for current command + while params != len(noise_commands[byte]) - 1: + param_type = noise_commands[byte][params]["type"] + address += command_length + command_length = param_lengths[param_type] + param = rom[address] + if param_type == "byte": + output += " {}".format(param) + else: + param += rom[address + 1] * 0x100 - 0x4000 + (bank * 0x4000) + if param == startingaddress: output += " Music_{}_Ch4".format(songname) + else: output += " Music_{}_branch_{:02x}".format(songname, param) + params += 1 + if params != len(noise_commands[byte]) - 1: output += "," + output += "\n" + address += command_length + byte = rom[address] + output += "; {}".format(hex(address)) + songfile.write(output) + +for i, songname in enumerate(songs): + songfile = open("music/" + songname.lower() + ".asm", 'a') + if songname == "PalletTown": header = 0x822e + if songname == "GymLeaderBattle": header = 0x202be + if songname == "TitleScreen": header = 0x7c249 + if songname == "SurfingPikachu": header = 0x801cb + bank = header / 0x4000 + startingaddress = rom[header + 2] * 0x100 + rom[header + 1] - 0x4000 + (0x4000 * bank) + curchannel = 1 + lastchannel = (rom[header] >> 6) + 1 + exception = False + if songname == "MeetRival" or songname == "Cities1": + startingaddress -= 7 + exception = True + if songname == "UnusedSong": + bank = 2 + startingaddress = 0xa913 + lastchannel = 2 + output = '' + while 1: + # pass 1, build a list of all addresses pointed to by calls and loops + address = startingaddress + labels = [] + labelsleft = [] + if songname == "MeetRival": + if curchannel == 1: + labels.append(0x719b) + labelsleft.append(0x719b) + if curchannel == 2: + labels.append(0x721d) + labelsleft.append(0x721d) + if curchannel == 3: + labels.append(0x72b5) + labelsleft.append(0x72b5) + while 1: + byte = rom[address] + if byte < 0xd0: + command_length = 1 + elif byte < 0xe0: + command_length = 2 + elif byte < 0xe8: + command_length = 1 + else: + command_length = music_commands[byte][-1] + if byte == 0xfd or byte == 0xfe: + label = rom[address + command_length - 1] * 0x100 + rom[address + command_length - 2] + labels.append(label) + if label > address % 0x4000 + 0x4000: labelsleft.append(label) + address += command_length + if len(labelsleft) == 0 and (exception == False or address > startingaddress + 7) and (byte == 0xfe and rom[address - command_length + 1] == 0 and rom[address - 1] * 0x100 + rom[address - 2] < address % 0x4000 + 0x4000 or byte == 0xff): break + while address % 0x4000 + 0x4000 in labelsleft: labelsleft.remove(address % 0x4000 + 0x4000) + # once the loop breaks, start over from first address + if rom[address] == 0xff: address += 1 + end = address + if curchannel != lastchannel and songname != "UnusedSong": end = rom[header + 5] * 0x100 + rom[header + 4] + (0x4000 * (bank - 1)) + address = startingaddress + byte = rom[address] + # if song has an alternate start to channel 1, print a label and set startingaddress to true channel start + if exception: + output += "Music_{}_branch_{:02x}:\n".format(songname, address) + startingaddress += 7 + # pass 2, print commands and labels for addresses that are in labels + while address != end: + if address == startingaddress: + if exception: output += "\n" + output += "Music_{}_Ch{}: ; {:02x} ({:0x}:{:02x})\n".format(songname, curchannel, address, bank, address % 0x4000 + 0x4000) + elif address % 0x4000 + 0x4000 in labels: + output += "\nMusic_{}_branch_{:02x}:\n".format(songname, address) + if 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 += " Music_{}_Ch{}".format(songname, curchannel) + else: output += " Music_{}_branch_{:02x}".format(songname, param) + params += 1 + if params != len(music_commands[byte]) - 1: output += "," + output += "\n" + address += command_length + byte = rom[address] + header += 3 + if curchannel == lastchannel: + output += "; {}".format(hex(address)) + songfile.write(output) + break + curchannel += 1 + output += "\n\n" + startingaddress = end + exception = False + if curchannel == 4: + printnoisechannel(songname, songfile, startingaddress, bank, output) + header += 3 + break \ No newline at end of file diff --git a/pokemontools/redsfxdisasm.py b/pokemontools/redsfxdisasm.py new file mode 100755 index 0000000..b84becb --- /dev/null +++ b/pokemontools/redsfxdisasm.py @@ -0,0 +1,149 @@ +import config +config = config.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: ["unknownmusic0xe8", 1], + 0xe9: ["unknownmusic0xe9", 1], + 0xea: ["vibrato", {"type": "byte"}, {"type": "nibble"}, 3], + 0xeb: ["pitchbend", {"type": "byte"}, {"type": "byte"}, 3], + 0xec: ["duty", {"type": "byte"}, 2], + 0xed: ["tempo", {"type": "byte"}, {"type": "byte"}, 3], + 0xee: ["unknownmusic0xee", {"type": "byte"}, 2], + 0xef: ["unknownmusic0xef", 1], + 0xf0: ["stereopanning", {"type": "byte"}, 2], + 0xf1: ["unknownmusic0xf1", 1], + 0xf2: ["unknownmusic0xf2", 1], + 0xf3: ["unknownmusic0xf3", 1], + 0xf4: ["unknownmusic0xf4", 1], + 0xf5: ["unknownmusic0xf5", 1], + 0xf6: ["unknownmusic0xf6", 1], + 0xf7: ["unknownmusic0xf7", 1], + 0xf8: ["unknownmusic0xf8", 1], + 0xf9: ["unknownmusic0xf9", 1], + 0xfa: ["unknownmusic0xfa", 1], + #0xfb: ["unknownmusic0xfb", 1], + 0xfc: ["dutycycle", {"type": "byte"}, 2], + 0xfd: ["callchannel", {"type": "label"}, 3], + 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", 'a') + startingaddress = rom[header + 2] * 0x100 + rom[header + 1] + (0x4000 * (bank - 1)) + curchannel = 1 + lastchannel = (rom[header] >> 6) + 1 + output = '' + while 1: + # pass 1, build a list of all addresses pointed to by calls and loops + address = startingaddress + labels = [] + labelsleft = [] + while 1: + byte = rom[address] + if byte < 0xd0: + command_length = 1 + elif byte < 0xe0: + command_length = 2 + elif byte < 0xe8: + command_length = 1 + else: + command_length = music_commands[byte][-1] + if byte == 0xfd or byte == 0xfe: + label = rom[address + command_length - 1] * 0x100 + rom[address + command_length - 2] + labels.append(label) + if label > address % 0x4000 + 0x4000: labelsleft.append(label) + address += command_length + if len(labelsleft) == 0 and (byte == 0xfe and rom[address - command_length + 1] == 0 and rom[address - 1] * 0x100 + rom[address - 2] < address % 0x4000 + 0x4000 or byte == 0xff): break + while address % 0x4000 + 0x4000 in labelsleft: labelsleft.remove(address % 0x4000 + 0x4000) + # once the loop breaks, start over from first address + end = address + if curchannel != lastchannel: end = rom[header + 5] * 0x100 + rom[header + 4] + (0x4000 * (bank - 1)) + address = startingaddress + byte = rom[address] + # pass 2, print commands and labels for addresses that are in labels + while address != end: + if address == startingaddress: + output += "{}_Ch{}: ; {:02x} ({:0x}:{:02x})\n".format(sfxname, curchannel, address, bank, address % 0x4000 + 0x4000) + elif address % 0x4000 + 0x4000 in labels: + output += "\n{}_branch_{:02x}:\n".format(sfxname, address) + if 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 + byte = rom[address] + header += 3 + if curchannel == lastchannel: + output += "; {}".format(hex(address)) + sfxfile.write(output) + break + output += "\n\n" + startingaddress = end + curchannel += 1 \ No newline at end of file diff --git a/pokemontools/redsfxheaders.py b/pokemontools/redsfxheaders.py new file mode 100755 index 0000000..7b04701 --- /dev/null +++ b/pokemontools/redsfxheaders.py @@ -0,0 +1,43 @@ +import config +config = config.Config() +rom = bytearray(open(config.rom_path, "r").read()) + +headerlist = ( + ["sfxheaders02.asm", 0x8003, 0x822e], + ["sfxheaders08.asm", 0x20003, 0x202be], + ["sfxheaders1f.asm", 0x7c003, 0x7c249], + ) + +numberofchannels = { + 0x0: 1, + 0x4: 2, + 0x8: 3, + 0xC: 4, + } + +def printsfxheaders(filename, address, end): + file = open(filename, 'w') + bank = address / 0x4000 + byte = rom[address] + sfx = 1 + channel = 1 + file.write("SFX_Headers_{:02x}:\n".format(bank)) + file.write("\tdb $ff, $ff, $ff ; padding\n") + while address != end: + left = numberofchannels[byte >> 4] + file.write("\nSFX_{:02x}_{:02x}: ; {:02x} ({:0x}:{:02x})\n".format(bank, sfx, address, bank, address % 0x4000 + 0x4000)) + while left != 0: + pointer = rom[address + 2] * 0x100 + rom[address + 1] + if byte >> 4 != 0: file.write(" db ( ${:0x}0 | CH{:0x} )\n".format(byte >> 4, byte % 0x10)) + else: file.write("\tdb CH{:0x}\n".format(byte)) + file.write("\tdw SFX_{:02x}_{:02x}_Ch{}\n".format(bank, sfx, channel)) + address += 3 + byte = rom[address] + channel += 1 + left -= 1 + channel = 1 + sfx += 1 + file.write("\n; {}".format(hex(address))) + +for header in headerlist: + printsfxheaders(header[0], header[1], header[2]) \ No newline at end of file -- cgit v1.2.3 From ed174d243287d8c1fdae31d0b30e014d554c0241 Mon Sep 17 00:00:00 2001 From: "U-Fish-PC\\Daniel" Date: Tue, 22 Oct 2013 02:24:37 -0400 Subject: Update redmusicdisasm and redsfxdisasm --- pokemontools/redmusicdisasm.py | 23 +++++++----- pokemontools/redsfxdisasm.py | 80 ++++++++++++++++-------------------------- 2 files changed, 45 insertions(+), 58 deletions(-) diff --git a/pokemontools/redmusicdisasm.py b/pokemontools/redmusicdisasm.py index ad370cd..3ed5a4d 100755 --- a/pokemontools/redmusicdisasm.py +++ b/pokemontools/redmusicdisasm.py @@ -1,5 +1,5 @@ -import config -config = config.Config() +import configuration +config = configuration.Config() rom = bytearray(open(config.rom_path, "r").read()) songs = [ @@ -49,22 +49,26 @@ songs = [ "MeetFemaleTrainer", "MeetMaleTrainer", "UnusedSong", - #"SurfingPikachu", - #"MeetJessieJames", - #"YellowUnusedSong", ] - +""" +songs = [ + "YellowIntro", + "SurfingPikachu", + "MeetJessieJames", + "YellowUnusedSong", + ] +""" music_commands = { 0xd0: ["notetype", {"type": "nibble"}, 2], 0xe0: ["octave", 1], - 0xe8: ["unknownmusic0xe8", 1], + 0xe8: ["togglecall", 1], 0xea: ["vibrato", {"type": "byte"}, {"type": "nibble"}, 3], 0xeb: ["pitchbend", {"type": "byte"}, {"type": "byte"}, 3], 0xec: ["duty", {"type": "byte"}, 2], 0xed: ["tempo", {"type": "byte"}, {"type": "byte"}, 3], 0xee: ["unknownmusic0xee", {"type": "byte"}, 2], 0xf0: ["stereopanning", {"type": "byte"}, 2], - 0xf8: ["unknownmusic0xf8", 1], + 0xf8: ["executemusic", 1], 0xfc: ["dutycycle", {"type": "byte"}, 2], 0xfd: ["callchannel", {"type": "label"}, 3], 0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4], @@ -189,6 +193,7 @@ for i, songname in enumerate(songs): if songname == "PalletTown": header = 0x822e if songname == "GymLeaderBattle": header = 0x202be if songname == "TitleScreen": header = 0x7c249 + if songname == "YellowIntro": header = 0x7c294 if songname == "SurfingPikachu": header = 0x801cb bank = header / 0x4000 startingaddress = rom[header + 2] * 0x100 + rom[header + 1] - 0x4000 + (0x4000 * bank) @@ -212,6 +217,8 @@ for i, songname in enumerate(songs): if curchannel == 1: labels.append(0x719b) labelsleft.append(0x719b) + labels.append(0x71a2) + labelsleft.append(0x71a2) if curchannel == 2: labels.append(0x721d) labelsleft.append(0x721d) diff --git a/pokemontools/redsfxdisasm.py b/pokemontools/redsfxdisasm.py index b84becb..3f145cf 100755 --- a/pokemontools/redsfxdisasm.py +++ b/pokemontools/redsfxdisasm.py @@ -1,5 +1,5 @@ -import config -config = config.Config() +import configuration +config = configuration.Config() rom = bytearray(open(config.rom_path, "r").read()) banks = { @@ -11,28 +11,13 @@ banks = { music_commands = { 0xd0: ["notetype", {"type": "nibble"}, 2], 0xe0: ["octave", 1], - 0xe8: ["unknownmusic0xe8", 1], - 0xe9: ["unknownmusic0xe9", 1], + 0xe8: ["togglecall", 1], 0xea: ["vibrato", {"type": "byte"}, {"type": "nibble"}, 3], - 0xeb: ["pitchbend", {"type": "byte"}, {"type": "byte"}, 3], 0xec: ["duty", {"type": "byte"}, 2], 0xed: ["tempo", {"type": "byte"}, {"type": "byte"}, 3], - 0xee: ["unknownmusic0xee", {"type": "byte"}, 2], - 0xef: ["unknownmusic0xef", 1], 0xf0: ["stereopanning", {"type": "byte"}, 2], - 0xf1: ["unknownmusic0xf1", 1], - 0xf2: ["unknownmusic0xf2", 1], - 0xf3: ["unknownmusic0xf3", 1], - 0xf4: ["unknownmusic0xf4", 1], - 0xf5: ["unknownmusic0xf5", 1], - 0xf6: ["unknownmusic0xf6", 1], - 0xf7: ["unknownmusic0xf7", 1], - 0xf8: ["unknownmusic0xf8", 1], - 0xf9: ["unknownmusic0xf9", 1], - 0xfa: ["unknownmusic0xfa", 1], - #0xfb: ["unknownmusic0xfb", 1], + 0xf8: ["executemusic", 1], 0xfc: ["dutycycle", {"type": "byte"}, 2], - 0xfd: ["callchannel", {"type": "label"}, 3], 0xfe: ["loopchannel", {"type": "byte"}, {"type": "label"}, 4], 0xff: ["endchannel", 1], } @@ -62,45 +47,38 @@ 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", 'a') + 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: - # pass 1, build a list of all addresses pointed to by calls and loops address = startingaddress - labels = [] - labelsleft = [] + 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: - byte = rom[address] - if byte < 0xd0: + 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) command_length = 1 - elif byte < 0xe0: + elif byte == 0x10 and not executemusic: + output += "\tunknownsfx0x{:02x} {}".format(byte, rom[address + 1]) command_length = 2 - elif byte < 0xe8: - command_length = 1 - else: - command_length = music_commands[byte][-1] - if byte == 0xfd or byte == 0xfe: - label = rom[address + command_length - 1] * 0x100 + rom[address + command_length - 2] - labels.append(label) - if label > address % 0x4000 + 0x4000: labelsleft.append(label) - address += command_length - if len(labelsleft) == 0 and (byte == 0xfe and rom[address - command_length + 1] == 0 and rom[address - 1] * 0x100 + rom[address - 2] < address % 0x4000 + 0x4000 or byte == 0xff): break - while address % 0x4000 + 0x4000 in labelsleft: labelsleft.remove(address % 0x4000 + 0x4000) - # once the loop breaks, start over from first address - end = address - if curchannel != lastchannel: end = rom[header + 5] * 0x100 + rom[header + 4] + (0x4000 * (bank - 1)) - address = startingaddress - byte = rom[address] - # pass 2, print commands and labels for addresses that are in labels - while address != end: - if address == startingaddress: - output += "{}_Ch{}: ; {:02x} ({:0x}:{:02x})\n".format(sfxname, curchannel, address, bank, address % 0x4000 + 0x4000) - elif address % 0x4000 + 0x4000 in labels: - output += "\n{}_branch_{:02x}:\n".format(sfxname, address) - if byte < 0xc0: + 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: @@ -138,12 +116,14 @@ for bank in banks: 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 = end + startingaddress = address curchannel += 1 \ No newline at end of file -- cgit v1.2.3 From 71204998edd39b6bdb531b66294ede643dd452fe Mon Sep 17 00:00:00 2001 From: "U-Fish-PC\\Daniel" Date: Fri, 1 Nov 2013 10:25:40 -0400 Subject: Update red music tools --- pokemontools/redsfxdisasm.py | 5 +---- pokemontools/redsfxheaders.py | 13 +++---------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/pokemontools/redsfxdisasm.py b/pokemontools/redsfxdisasm.py index 3f145cf..9e9f01b 100755 --- a/pokemontools/redsfxdisasm.py +++ b/pokemontools/redsfxdisasm.py @@ -65,10 +65,7 @@ for bank in banks: 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) - command_length = 1 - elif byte == 0x10 and not executemusic: + if byte == 0x10 and not executemusic: output += "\tunknownsfx0x{:02x} {}".format(byte, rom[address + 1]) command_length = 2 elif byte < 0x30 and not executemusic: diff --git a/pokemontools/redsfxheaders.py b/pokemontools/redsfxheaders.py index 7b04701..c854c20 100755 --- a/pokemontools/redsfxheaders.py +++ b/pokemontools/redsfxheaders.py @@ -1,5 +1,5 @@ -import config -config = config.Config() +import configuration +config = configuration.Config() rom = bytearray(open(config.rom_path, "r").read()) headerlist = ( @@ -8,13 +8,6 @@ headerlist = ( ["sfxheaders1f.asm", 0x7c003, 0x7c249], ) -numberofchannels = { - 0x0: 1, - 0x4: 2, - 0x8: 3, - 0xC: 4, - } - def printsfxheaders(filename, address, end): file = open(filename, 'w') bank = address / 0x4000 @@ -24,7 +17,7 @@ def printsfxheaders(filename, address, end): file.write("SFX_Headers_{:02x}:\n".format(bank)) file.write("\tdb $ff, $ff, $ff ; padding\n") while address != end: - left = numberofchannels[byte >> 4] + left = (byte >> 6) + 1 file.write("\nSFX_{:02x}_{:02x}: ; {:02x} ({:0x}:{:02x})\n".format(bank, sfx, address, bank, address % 0x4000 + 0x4000)) while left != 0: pointer = rom[address + 2] * 0x100 + rom[address + 1] -- cgit v1.2.3