#=====================================================================================================
import os
import sys
import zlib
from struct import *
from array import *
from glob import *
#=====================================================================================================

#=====================================================================================================
def printtrackdata(trackdata):
	str = ''
	channel_banks = [None]*16
	channel_voices = [None]*16
	offset = 0x0C
	bank_list = set([])
	voice_list = [set([]),set([]),set([]),set([]),set([]),set([]),set([]),set([]),
	              set([]),set([]),set([]),set([]),set([]),set([]),set([]),set([])]
	gate_table = [ 0x200, 0x800, 0x1000, 0x2000]
	delta_table = [ 0x100, 0x200, 0x800, 0x1000]
	note_list = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
	ctrl_list = { 0x01: 'MODULATION_WHEEL ', 0x02: 'EXPRESSION       ', 0x07: 'MAIN_VOLUME      ',
	              0x0A: 'DIRECT_PAN       ', 0x0B: 'EXPRESSION       ', 0x10: 'MIXER_CHANGE     ',
				  0x11: 'EFFECT_PAN       ', 0x20: 'TONE_BANK        ', 0x40: 'DAMPER           ',
				  0x46: 'EFFECT_PAN       ', 0x47: 'EFFECT_RETURN    ', 0x50: 'QSOUND_POSITION  ',
				  0x51: '3D_DISTANCE      ', 0x52: '3D_AZIMUTH       ', 0x53: '3D_ELEVATION     ',
				  0x5B: 'EFFECT_CHANGE    ', 0x78: 'ALL_SOUND_OFF    ', 0x7B: 'ALL_NOTE_OFF     '}
	cstep = 0
	while offset < len(trackdata):
		event = trackdata[offset]
		if event < 0x40:    # NOTE
			channel = event & 0x0F
			key = trackdata[offset+1]
			note = note_list[key%12]
			octave = key//12 - 1
			volume = trackdata[offset+2]
			if event in range(0x00,0x10):
				gate = trackdata[offset+3]
				step = trackdata[offset+4]
				str += '[0x%05X] %02X %02X %02X %02X %02X       NOTE              : channel=%d note=%s(%d) key=%d volume=%d gate=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],trackdata[offset+4],channel,note,octave,key,volume,gate,step)
				offset += 5
			if event in range(0x10,0x20):
				gate = trackdata[offset+3]
				step = unpack('>H',trackdata[offset+4:offset+6])[0]
				str += '[0x%05X] %02X %02X %02X %02X %02X %02X    NOTE              : channel=%d note=%s(%d) key=%d volume=%d gate=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],trackdata[offset+4],trackdata[offset+5],channel,note,octave,key,volume,gate,step)
				offset += 6
			if event in range(0x20,0x30):
				gate = unpack('>H',trackdata[offset+3:offset+5])[0]
				step = trackdata[offset+5]
				str += '[0x%05X] %02X %02X %02X %02X %02X %02X    NOTE              : channel=%d note=%s(%d) key=%d volume=%d gate=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],trackdata[offset+4],trackdata[offset+5],channel,note,octave,key,volume,gate,step)
				offset += 6
			if event in range(0x30,0x40):
				gate = unpack('>H',trackdata[offset+3:offset+5])[0]
				step = unpack('>H',trackdata[offset+5:offset+7])[0]
				str += '[0x%05X] %02X %02X %02X %02X %02X %02X %02X NOTE              : channel=%d note=%s(%d) key=%d volume=%d gate=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],trackdata[offset+4],trackdata[offset+5],trackdata[offset+6],channel,note,octave,key,volume,gate,step)
				offset += 7
		elif event == 0x81:    # REFERENCE
			roffset = unpack('>H',trackdata[offset+1:offset+3])[0]
			rlength = trackdata[offset+3]
			str += '[0x%05X] %02X %02X %02X %02X          REFERENCE         : offset=0x%04X length=%d\n' % \
			(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],roffset,rlength)
			offset += 4
		elif event == 0x82:    # LOOP
			mode = trackdata[offset+1]
			if mode < 0x80:
				step = trackdata[offset+2]
				str += '[0x%05X] %02X %02X %02X             LOOP              : mode=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],mode,step)
				offset += 3
			else:
				step = unpack('>H',trackdata[offset+2:offset+4])[0]
				str += '[0x%05X] %02X %02X %02X %02X          LOOP              : mode=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],mode,step)
				offset += 4
		elif event == 0x83:    # END_OF_TRACK
			str += '[0x%05X] %02X                   END_OF_TRACK      : \n' % \
			(offset,trackdata[offset])
			break
		elif event == 0x84:    # TEMPO_CHANGE
			tempo = unpack('>H',trackdata[offset+1:offset+3])[0]
			str += '[0x%05X] %02X %02X %02X %02X          TEMPO_CHANGE      : tempo=%d \n' % \
			(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],tempo)
			offset += 4
		elif event in range(0x88,0x8C):    # EXT_GATE
			gate = gate_table[event&0x3]
			str += '[0x%05X] %02X                   EXT_GATE          : gate=%d\n' % \
			(offset,trackdata[offset],gate)
			offset += 1
		elif event in range(0x8C,0x90):    # EXT_DELTA
			delta = delta_table[event&0x3]
			str += '[0x%05X] %02X                   EXT_DELTA         : delta=%d\n' % \
			(offset,trackdata[offset],delta)
			offset += 1
		elif event in range(0xA0,0xB0):    # POLY_KEY_PRESSURE
			channel = event & 0xF
			key = trackdata[offset+1]
			value = trackdata[offset+2]
			step = trackdata[offset+3]
			str += '[0x%05X] %02X %02X %02X %02X          POLY_KEY_PRESSURE : channel=%d key=%d value=%d step=%d\n' % \
			(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],channel,key,value,step)
			offset += 4
		elif event in range(0xB0,0xC0):    # CONTROL_CHANGE
			channel = event & 0xF
			ctrl_val = trackdata[offset+1] & 0x7F
			mode = trackdata[offset+1] >> 7
			if ctrl_val == 0x20:    # BANK_SELECT
				bank = trackdata[offset+2] & 0xF
				channel_banks[channel] = bank
			if ctrl_val in ctrl_list:
				control = ctrl_list[ctrl_val]
			else:
				control = 'OTHER_CONTROL    '
			value = trackdata[offset+2]
			if mode:
				step = unpack('>H',trackdata[offset+3:offset+5])[0]
				str += '[0x%05X] %02X %02X %02X %02X %02X       %s : channel=%d value=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],trackdata[offset+4],control,channel,value,step)
				offset += 5
			else:
				step = trackdata[offset+3]
				str += '[0x%05X] %02X %02X %02X %02X          %s : channel=%d value=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],control,channel,value,step)
				offset += 4
		elif event in range(0xC0,0xD0):    # PROGRAM_CHANGE
			channel = event & 0xF
			voice = trackdata[offset+1] & 0x7F
			mode = trackdata[offset+1] >> 7
			if channel_banks[channel] != None:
				bank_list.add(channel_banks[channel])
				voice_list[channel_banks[channel]].add(channel_voices[channel])
			if mode:
				step = unpack('>H',trackdata[offset+2:offset+4])[0]
				str += '[0x%05X] %02X %02X %02X %02X          PROGRAM_CHANGE    : channel=%d voice=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],channel,voice,step)
				offset += 4
			else:
				step = trackdata[offset+2]
				str += '[0x%05X] %02X %02X %02X             PROGRAM_CHANGE    : channel=%d voice=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],channel,voice,step)
				offset += 3
		elif event in range(0xD0,0xE0):    # CHANNEL_PRESSURE
			channel = event & 0xF
			value = trackdata[offset+1] & 0x7F
			mode = trackdata[offset+1] >> 7
			if mode:
				step = unpack('>H',trackdata[offset+2:offset+4])[0]
				str += '[0x%05X] %02X %02X %02X %02X          CHANNEL_PRESSURE  : channel=%d value=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],channel,value,step)
				offset += 4
			else:
				step = trackdata[offset+2]
				str += '[0x%05X] %02X %02X %02X             CHANNEL_PRESSURE  : channel=%d value=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],channel,value,step)
				offset += 3
		elif event in range(0xE0,0xF0):    # PITCH_BEND
			channel = event & 0xF
			value = trackdata[offset+1] & 0x7F
			mode = trackdata[offset+1] >> 7
			if mode:
				step = unpack('>H',trackdata[offset+2:offset+4])[0]
				str += '[0x%05X] %02X %02X %02X %02X          PITCH_BEND        : channel=%d value=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],trackdata[offset+3],channel,value,step)
				offset += 4
			else:
				step = trackdata[offset+2]
				str += '[0x%05X] %02X %02X %02X             PITCH_BEND        : channel=%d value=%d step=%d\n' % \
				(offset,trackdata[offset],trackdata[offset+1],trackdata[offset+2],channel,value,step)
				offset += 3
		else:    # OTHER_EVENT
			str += '[0x%05X] %02X                   OTHER_EVENT       : \n' % \
			(offset,trackdata[offset])
			offset += 1
	return str
#=====================================================================================================

if __name__ == '__main__':
	nseq = 'trackdata.bin'
	fseq = open(nseq,'rb')
	trackdata = array('B',fseq.read())
	fseq.close()
	print printtrackdata(trackdata)
