Advertisement
dannye33

tcg2musicdisasm.py

Dec 26th, 2019
236
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.79 KB | None | 0 0
  1. rom = bytearray(open("tcg2.gbc", "r").read())
  2. headers = 0x1481
  3. banks = 0x1dd444
  4.  
  5. songs = [
  6.     ["TitleScreen",    0x1ea368,  True],
  7.     ["DuelTheme1",     0x1e20fe,  True],
  8.     ["DuelTheme2",     0x1e2737,  True],
  9.     ["DuelTheme3",     0x1e2f4d,  True],
  10.     ["PauseMenu",      0x1e3287, False],
  11.     ["PCMainMenu",     0x1e3486,  True],
  12.     ["DeckMachine",    0x1e35cf,  True],
  13.     ["CardPop",        0x1e3735,  True],
  14.     ["Overworld",      0x1e3eb7,  True],
  15.     ["PokemonDome",    0x1e64e2,  True],
  16.     ["ChallengeHall",  0x1e5c5f,  True],
  17.     ["Club1",          0x1e60f1,  True],
  18.     ["Club2",          0x1f5865,  True],
  19.     ["Club3",          0x1e6a72,  True],
  20.     ["Ronald",         0x1e7027,  True],
  21.     ["Imakuni",        0x1e72bc,  True],
  22.     ["HallOfHonor",    0x1e74d4,  True],
  23.     ["Unused",              0x0,  True],
  24.     ["Unused",              0x0,  True],
  25.     ["HereComesGR",    0x1ead0d,  True],
  26.     ["GROverworld",    0x1eb67b,  True],
  27.     ["Fort1",          0x1edefc,  True],
  28.     ["Fort2",          0x1ee797,  True],
  29.     ["Fort3",          0x1ef1ec,  True],
  30.     ["Fort4past",          0x1f213c,  True],
  31.     ["GRCastle",       0x1f2d24,  True],
  32.     ["Unused",              0x0,  True],
  33.     ["GRChallengeCup", 0x1f3411,  True],
  34.     ["GameCorner",     0x1e7bfa,  True],
  35.     ["GRBlimp",        0x1e7fd6,  True],
  36.     ["GRDuelTheme1",   0x1f6517,  True],
  37.     ["GRDuelTheme2",   0x1efff9,  True],
  38.     ["GRDuelTheme3",   0x1f76dc,  True],
  39.     ["Unused",              0x0,  True],
  40.     ["Ishihara",       0x1de32a,  True],
  41.     ["Imakuni2",       0x1f3f40,  True],
  42.     ["Credits",        0x1dfd99,  True],
  43.     ["Unused",              0x0,  True],
  44.     ["Unused",              0x0,  True],
  45.     ["MatchStart1",    0x1eb6c1, False],
  46.     ["MatchStart2",    0x1eb77a, False],
  47.     ["MatchStart3",    0x1eb8cc, False],
  48.     ["MatchVictory",   0x1eb999,  True],
  49.     ["MatchLoss",      0x1eba48,  True],
  50.     ["DarkDiddly",     0x1ebade,  True],
  51.     ["Unused",              0x0,  True],
  52.     ["BoosterPack",    0x1ebb76,  True],
  53.     ["Medal",          0x1ebc57,  True],
  54.     ["Unused",              0x0,  True],
  55.     ["Diddly1",        0x1ebd67,  True],
  56.     ["Diddly2",        0x1ebe5d,  True],
  57.     ["Diddly3",        0x1ebeae,  True],
  58.     ["Diddly4",        0x1ebefa,  True],
  59.     ["Diddly5",        0x1ebf3e,  True],
  60.     ["Unused",              0x0,  True],
  61.     ["Unused",              0x0,  True],
  62.     ["Unused",              0x0,  True],
  63.     ["Diddly6",        0x1f783b,  True],
  64.     ]
  65.  
  66. channels = {
  67.     1: 1,
  68.     3: 2,
  69.     7: 3,
  70.     15: 4,
  71.     }
  72.  
  73. music_commands = {
  74.     0xd0: ["speed", {"type": "byte"}, 2],
  75.     0xd1: ["octave", 1],
  76.     0xd7: ["inc_octave", 1],
  77.     0xd8: ["dec_octave", 1],
  78.     0xd9: ["tie", 1],
  79.     0xdc: ["musicdc", {"type": "byte"}, 2],
  80.     0xdd: ["MainLoop", 1],
  81.     0xde: ["EndMainLoop", 1],
  82.     0xdf: ["Loop", {"type": "byte"}, 2],
  83.     0xe0: ["EndLoop", 1],
  84.     #0xe1: ["music_jp", {"type": "label"}, 3],
  85.     0xe2: ["music_call", {"type": "label"}, 3],
  86.     0xe3: ["music_ret", 1],
  87.     0xe4: ["musice4", {"type": "byte"}, 2],
  88.     0xe5: ["duty", {"type": "duty"}, 2],
  89.     0xe6: ["volume", {"type": "byte"}, 2],
  90.     0xe7: ["wave", {"type": "byte"}, 2],
  91.     0xe8: ["musice8", {"type": "byte"}, 2],
  92.     0xe9: ["musice9", {"type": "byte"}, 2],
  93.     0xea: ["vibrato_rate", {"type": "byte"}, 2],
  94.     0xeb: ["vibrato_delay", {"type": "byte"}, 2],
  95.     0xec: ["musicec", {"type": "byte"}, 2],
  96.     #0xed: ["musiced", {"type": "byte"}, 2],
  97.     0xee: ["musicee", {"type": "byte"}, 2],
  98.     0xef: ["musicef", {"type": "byte"}, 2],
  99.     0xf0: ["musicf0", {"type": "byte"}, 2],
  100.     0xf1: ["musicf1", {"type": "byte"}, 2],
  101.     0xf2: ["musicf2", 1],
  102.     0xf3: ["musicf3", 1],
  103.     #0xf4: ["musicf4", 1],
  104.     0xff: ["music_end", 1],
  105.     }
  106.  
  107. param_lengths = {
  108.     "nibble": 1,
  109.     "byte": 1,
  110.     "duty": 1,
  111.     "label": 2,
  112.     }
  113.  
  114. music_notes = {
  115.     0x1: "C_",
  116.     0x2: "C#",
  117.     0x3: "D_",
  118.     0x4: "D#",
  119.     0x5: "E_",
  120.     0x6: "F_",
  121.     0x7: "F#",
  122.     0x8: "G_",
  123.     0x9: "G#",
  124.     0xa: "A_",
  125.     0xb: "A#",
  126.     0xc: "B_",
  127.     }
  128.  
  129. noise_instruments = {
  130.     0x1: "bass",
  131.     0x2: "noise2",
  132.     0x3: "snare1",
  133.     #0x4: "noise4",
  134.     0x5: "snare2",
  135.     0x6: "noise6",
  136.     0x7: "snare3",
  137.     0x8: "noise8",
  138.     0x9: "snare4",
  139.     0xa: "noisea",
  140.     0xb: "noiseb",
  141.     0xc: "snare5",
  142.     }
  143.  
  144. for cursong, song in enumerate(songs):
  145.     songname = song[0]
  146.     if songname != "Unused":
  147.         exception = song[2]
  148.         songfile  = open("music/" + songname.lower() + ".asm", 'w')
  149.         bank = rom[banks + cursong]
  150.         headerptr = headers + 0x4000 * bank + 2 * cursong
  151.         header = rom[headerptr + 1] * 0x100 + rom[headerptr] + 0x4000 * (bank - 1)
  152.         curchannel = 1
  153.         lastchannel = channels[rom[header]]
  154.         header += 1
  155.         output = ''
  156.         while 1:
  157.             startingaddress = rom[header + 1] * 0x100 + rom[header] - 0x4000 + (0x4000 * bank)
  158.             end = rom[header + 3] * 0x100 + rom[header + 2] - 0x4000 + (0x4000 * bank)
  159.             if curchannel == lastchannel: end = song[1]
  160.             if curchannel == 1 and exception:
  161.                 curchannel = 2
  162.                 startingaddress = rom[header + 3] * 0x100 + rom[header + 2] - 0x4000 + (0x4000 * bank)
  163.                 end = rom[header + 1] * 0x100 + rom[header] - 0x4000 + (0x4000 * bank)
  164.             elif curchannel == 3 and exception:
  165.                 curchannel = 1
  166.                 startingaddress = rom[header - 1] * 0x100 + rom[header - 2] - 0x4000 + (0x4000 * bank)
  167.                 if lastchannel == 2:
  168.                     end = song[1]
  169.                     exception = False
  170.                 if lastchannel == 3:
  171.                     end = end = rom[header + 3] * 0x100 + rom[header + 2] - 0x4000 + (0x4000 * bank)
  172.             elif curchannel == 2 and exception:
  173.                 if lastchannel == 3:
  174.                     end = song[1]
  175.                 curchannel = 3
  176.                 exception = False
  177.             address = startingaddress
  178.             labels = []
  179.             # pass 1, build a list of all addresses pointed to by calls
  180.             while address != end:
  181.                 byte = rom[address]
  182.                 if byte < 0xd0:
  183.                     command_length = 1
  184.                 else:
  185.                     if byte > 0xd0 and byte < 0xd7: byte = 0xd1
  186.                     command_length = music_commands[byte][-1]
  187.                     if byte == 0xe2: labels.append(rom[address + 2] * 0x100 + rom[address + 1])
  188.                 address += command_length
  189.             # once the loop breaks, start over from first address
  190.             address = startingaddress
  191.             # pass 2, print commands and labels for addresses that are in labels
  192.             while address != end:
  193.                 byte = rom[address]
  194.                 if address == startingaddress:
  195.                     output += "Music_{}_Ch{}: ; {:02x} ({:0x}:{:02x})\n".format(songname, curchannel, address, bank, address % 0x4000 + 0x4000)
  196.                 elif address % 0x4000 + 0x4000 in labels:
  197.                     output += "\nBranch_{:02x}:\n".format(address)
  198.                 if byte < 0x10:
  199.                     output += "\trest {}".format(byte % 0x10 + 1)
  200.                     command_length = 1
  201.                 elif byte < 0xd0:
  202.                     if curchannel != 4:
  203.                         output += "\tnote {}, {}".format(music_notes[byte >> 4], byte % 0x10 + 1)
  204.                     else:
  205.                         output += "\tnote {}, {}".format(noise_instruments[byte >> 4], byte % 0x10 + 1)
  206.                     command_length = 1
  207.                 else:
  208.                     if byte > 0xd0 and byte < 0xd7:
  209.                         command = music_commands[0xd1]
  210.                         output += "\t{} {}".format(command[0], byte % 0x10)
  211.                         byte = 0xd1
  212.                     else:
  213.                         command = music_commands[byte]
  214.                         output += "\t{}".format(command[0])
  215.                     command_length = 1
  216.                     params = 1
  217.                     # print all params for current command
  218.                     while params != len(command) - 1:
  219.                         param_type = command[params]["type"]
  220.                         address += command_length
  221.                         command_length = param_lengths[param_type]
  222.                         param = rom[address]
  223.                         if param_type == "nibble":
  224.                             output += " {}, {}".format(param >> 4, param % 0x10)
  225.                         elif param_type == "byte":
  226.                             output += " {}".format(param)
  227.                         elif param_type == "duty":
  228.                             output += " {}".format(param >> 6)
  229.                         else:
  230.                             param += rom[address + 1] * 0x100 - 0x4000 + (bank * 0x4000)
  231.                             output += " Branch_{:02x}".format(param)
  232.                         params += 1
  233.                         if params != len(command) - 1: output += ","
  234.                 output += "\n"
  235.                 address += command_length
  236.             header += 2
  237.             if songname == "Diddly5" and not exception:
  238.                 curchannel += 1
  239.             if curchannel == lastchannel and not exception:
  240.                 output += "; {}".format(hex(address))
  241.                 songfile.write(output)
  242.                 break
  243.             curchannel += 1
  244.             output += "; {}".format(hex(address))
  245.             output += "\n\n"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement