summaryrefslogtreecommitdiff
path: root/pokemontools/redsfxdisasm.py
blob: 9e9f01ba1122bafcfdcc5aef06c0c7aa4a422798 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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