Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # vgm_to_bytebeat (see https://battleofthebits.org/arena/Entry/vgm+engine/39556/)
- import sys
- def rev_end(num, run=0, pos=0):
- if not num:
- return run
- return rev_end(num[1:], run | (num[0] << (pos * 8)), pos + 1)
- def convert(b):
- d = b + 35
- if d >= 92:
- d += 1
- return d
- if len(sys.argv) < 3:
- print('Usage: {} <infile> <outfile>'.format(sys.argv[0]))
- sys.exit(1)
- infile = open(sys.argv[1], 'rb')
- vgm_data = infile.read()
- infile.close()
- if vgm_data[0x00:0x04] != b'Vgm ':
- raise Exception('Not VGM file?')
- vgm_eof = rev_end(vgm_data[0x04:0x08])
- vgm_ver = rev_end(vgm_data[0x08:0x0a])
- if vgm_ver >= 0x0150:
- vgm_data_offset = rev_end(vgm_data[0x34:0x38]) + 0x34
- else:
- vgm_data_offset = 0x40
- outfile = open(sys.argv[2], 'wb')
- tone = [0, 0, 0, 0]
- vol = [0xf, 0xf, 0xf, 0xf]
- latch_ch = 0
- latch_vol = False
- index = vgm_data_offset
- while index < vgm_eof:
- inc = 1
- cmd = vgm_data[index]
- if cmd == 0x00:
- print('0x00 - nop?')
- elif cmd == 0x50:
- data = vgm_data[index+1]
- print('0x50 - write 0x{:02x}'.format(data))
- if data & 0x80:
- latch_ch = (data & 0x60) >> 5
- latch_vol = bool(data & 0x10)
- print(' latch ch{} {} = 0x{:02x}'.format(latch_ch, 'vol' if latch_vol else 'noise' if latch_ch == 3 else 'tone', data & 0x0f))
- if latch_vol:
- vol[latch_ch] = data & 0x0f
- else:
- if latch_ch == 3:
- tone[latch_ch] = data & 0x07
- else:
- tone[latch_ch] = (tone[latch_ch] & 0xfff0) | (data & 0x000f)
- else:
- print(' data 0x{:02x}'.format(data & 0x3f))
- if latch_vol:
- vol[latch_ch] = data & 0x0f
- else:
- if latch_ch == 3:
- tone[latch_ch] = data & 0x07
- else:
- tone[latch_ch] = (tone[latch_ch] & 0x000f) | ((data & 0x003f) << 4)
- inc = 2
- elif 0x61 <= cmd <= 0x63:
- print('0x{:02x} - wait frame'.format(cmd))
- inc = 3 if cmd == 0x61 else 1
- times = 1
- if cmd == 0x61:
- samps = rev_end(vgm_data[index+1:index+3])
- frames = samps / 735
- times = round(frames)
- if frames != times:
- print('!! WARNING !! - non-NTSC frame wait ({} frames), timing will be off!'.format(frames))
- elif cmd == 0x63:
- print('!! WARNING !! - non-NTSC frame wait, timing will be off!')
- print(' ', tone, vol)
- tone_high = [(t & 0x3c0) >> 6 for t in tone[0:3]]
- tone_low = [(t & 0x03f) for t in tone[0:3]]
- tone_data = [x for y in zip(tone_high, tone_low) for x in y] + [tone[3]]
- outdata = tone_data + vol
- print(' {}'.format(outdata))
- outbytes = bytes(convert(b) for b in outdata)
- for _ in range(times):
- outfile.write(outbytes)
- print(' {} (x{})'.format(str(outbytes, 'ascii'), times))
- elif cmd == 0x66:
- print('0x66 - end of sound data')
- break
- else:
- print('!! WARNING !! - unknown command 0x{:02x} @ 0x{:08x}'.format(cmd, index))
- index += inc
- outfile.close()
Add Comment
Please, Sign In to add comment