diff options
Diffstat (limited to 'pokemontools/redsfxdisasm.py')
| -rwxr-xr-x | pokemontools/redsfxdisasm.py | 126 | 
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 | 
