xi2

a plain text language that compiles to MIDI
git clone https://git.ce9e.org/xi2.git

commit
2212b6af11098bba9f5a1d9d725c8ef07275e3e1
parent
52a39ae061e30d562851fa0df32f4beccf1fb45c
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2023-09-18 14:52
style: tabs to spaces

Diffstat

M iparser.py 158 ++++++++++++++++++++++++++++++------------------------------
M midi.py 222 ++++++++++++++++++++++++++++++------------------------------
M xi2.py 122 ++++++++++++++++++++++++++++++------------------------------

3 files changed, 251 insertions, 251 deletions


diff --git a/iparser.py b/iparser.py

@@ -11,90 +11,90 @@ class IParser:
   11    11 # creates midi events from intermediate code
   12    12 # and than uses midi to create midi bytecode
   13    13 
   14    -1 	def __init__(self, seq, ch=0, offset=60):
   15    -1 		self.midi = Midi()
   16    -1 		self.ch = ch
   17    -1 		self.offset = offset
   18    -1 		self.dt = 0
   19    -1 		self.dtStack = []
   20    -1 		self.stack = []
   21    -1 		self.parseSeq(seq)
   -1    14     def __init__(self, seq, ch=0, offset=60):
   -1    15         self.midi = Midi()
   -1    16         self.ch = ch
   -1    17         self.offset = offset
   -1    18         self.dt = 0
   -1    19         self.dtStack = []
   -1    20         self.stack = []
   -1    21         self.parseSeq(seq)
   22    22 
   23    -1 	def dtStep(self):
   24    -1 		a = 1.0
   25    -1 		for i in self.dtStack[1:]:
   26    -1 			a /= i
   27    -1 		return a	
   -1    23     def dtStep(self):
   -1    24         a = 1.0
   -1    25         for i in self.dtStack[1:]:
   -1    26             a /= i
   -1    27         return a
   28    28 
   29    -1 	def parseEl(self, e):
   30    -1 		if e.isdigit(): # note
   31    -1 			self.midi.noteOn(self.dt, self.ch, self.offset+int(e), 1)
   32    -1 			self.dt = self.dtStep()
   33    -1 		elif e == '-': # continue
   34    -1 			self.dt += self.dtStep()
   35    -1 		elif e == '': # break
   36    -1 			self.dt += self.dtStep()
   37    -1 		else: # lyrics
   38    -1 			self.midi.lyrics(self.dt, e.replace('_', ' '))
   39    -1 			self.dt = self.dtStep()
   -1    29     def parseEl(self, e):
   -1    30         if e.isdigit(): # note
   -1    31             self.midi.noteOn(self.dt, self.ch, self.offset+int(e), 1)
   -1    32             self.dt = self.dtStep()
   -1    33         elif e == '-': # continue
   -1    34             self.dt += self.dtStep()
   -1    35         elif e == '': # break
   -1    36             self.dt += self.dtStep()
   -1    37         else: # lyrics
   -1    38             self.midi.lyrics(self.dt, e.replace('_', ' '))
   -1    39             self.dt = self.dtStep()
   40    40 
   41    -1 	def parseSeq(self, seq):
   42    -1 		self.dtStack.append(len(seq))
   43    -1 		for e in seq:
   44    -1 			if type(e) == type(''):
   45    -1 				if e != '-': self.stop()
   46    -1 				self.stack.append(e)
   47    -1 				self.parseEl(e)
   48    -1 			elif type(e) == type([]):
   49    -1 				if not '-' in e: self.stop()
   50    -1 				self.stack.append(e)
   51    -1 				self.parseSet(e)
   52    -1 			elif type(e) == type(()):
   53    -1 				self.parseSeq(e)
   54    -1 			else:
   55    -1 				raise Exception("unknown element: " + e)
   56    -1 		self.dtStack.pop()
   -1    41     def parseSeq(self, seq):
   -1    42         self.dtStack.append(len(seq))
   -1    43         for e in seq:
   -1    44             if type(e) == type(''):
   -1    45                 if e != '-': self.stop()
   -1    46                 self.stack.append(e)
   -1    47                 self.parseEl(e)
   -1    48             elif type(e) == type([]):
   -1    49                 if not '-' in e: self.stop()
   -1    50                 self.stack.append(e)
   -1    51                 self.parseSet(e)
   -1    52             elif type(e) == type(()):
   -1    53                 self.parseSeq(e)
   -1    54             else:
   -1    55                 raise Exception("unknown element: " + e)
   -1    56         self.dtStack.pop()
   57    57 
   58    -1 	def parseSet(self, s):
   59    -1 		for e in s:
   60    -1 			if type(e) != type(''):
   61    -1 				raise Exception("only elements are allowed inside sets: " + e)
   62    -1 			elif e == '':
   63    -1 				raise Exception("Breaks are not allowed inside sets!")
   64    -1 			else:
   65    -1 				self.parseEl(e)
   66    -1 			self.dt = 0
   67    -1 		self.dt = self.dtStep()
   -1    58     def parseSet(self, s):
   -1    59         for e in s:
   -1    60             if type(e) != type(''):
   -1    61                 raise Exception("only elements are allowed inside sets: " + e)
   -1    62             elif e == '':
   -1    63                 raise Exception("Breaks are not allowed inside sets!")
   -1    64             else:
   -1    65                 self.parseEl(e)
   -1    66             self.dt = 0
   -1    67         self.dt = self.dtStep()
   68    68 
   69    -1 	def stop(self):
   70    -1 		if len(self.stack) == 0: return
   71    -1 		e = self.stack.pop()
   72    -1 		if type(e) == type(''):
   73    -1 			if e == '-':
   74    -1 				self.stop()
   75    -1 			elif e == '':
   76    -1 				pass # already stopped
   77    -1 			elif e.isdigit():
   78    -1 				self.midi.noteOff(self.dt, self.ch, self.offset+int(e), 1)
   79    -1 				self.dt = 0
   80    -1 			else:
   81    -1 				pass
   82    -1 		elif type(e) == type([]):
   83    -1 			if '-' in e:
   84    -1 				self.stop()
   85    -1 			for ee in e:
   86    -1 				# we already checked the validity of the set when parsing.
   87    -1 				# we only need to check if this is a note, lyrics or '-'
   88    -1 				if ee.isdigit():	
   89    -1 					self.midi.noteOff(self.dt, self.ch, self.offset+int(ee), 1)
   90    -1 					self.dt = 0
   91    -1 		else:
   92    -1 			raise Exception("Unexpected object on stack: " + e)
   -1    69     def stop(self):
   -1    70         if len(self.stack) == 0: return
   -1    71         e = self.stack.pop()
   -1    72         if type(e) == type(''):
   -1    73             if e == '-':
   -1    74                 self.stop()
   -1    75             elif e == '':
   -1    76                 pass # already stopped
   -1    77             elif e.isdigit():
   -1    78                 self.midi.noteOff(self.dt, self.ch, self.offset+int(e), 1)
   -1    79                 self.dt = 0
   -1    80             else:
   -1    81                 pass
   -1    82         elif type(e) == type([]):
   -1    83             if '-' in e:
   -1    84                 self.stop()
   -1    85             for ee in e:
   -1    86                 # we already checked the validity of the set when parsing.
   -1    87                 # we only need to check if this is a note, lyrics or '-'
   -1    88                 if ee.isdigit():
   -1    89                     self.midi.noteOff(self.dt, self.ch, self.offset+int(ee), 1)
   -1    90                     self.dt = 0
   -1    91         else:
   -1    92             raise Exception("Unexpected object on stack: " + e)
   93    93 
   94    94 if __name__ == '__main__':
   95    -1 	a = [(('0', '1'), '2'), '4', '5', '-', '', ['0', '4', '7'], '', '', '0', ['3', '-']]
   -1    95     a = [(('0', '1'), '2'), '4', '5', '-', '', ['0', '4', '7'], '', '', '0', ['3', '-']]
   96    96 
   97    -1 	f = MidiFile()
   98    -1 	ip = IParser(a, 0, 60)
   99    -1 	f.addTrack(ip.midi)
  100    -1 	f.write('test.mid')
   -1    97     f = MidiFile()
   -1    98     ip = IParser(a, 0, 60)
   -1    99     f.addTrack(ip.midi)
   -1   100     f.write('test.mid')

diff --git a/midi.py b/midi.py

@@ -7,119 +7,119 @@ timeDevision = 0x00c0 # two bytes
    7     7 class Midi:
    8     8 # creates midi bytecode from midi events
    9     9 
   10    -1 	def __init__(self):
   11    -1 		self._buf = ''
   12    -1 
   13    -1 	def __str__(self):
   14    -1 		return self._buf.encode('hex')
   15    -1 
   16    -1 	def __add__(self, other):
   17    -1 		m = Midi()
   18    -1 		m._buf = self._buf + other._buf
   19    -1 		return m
   20    -1 
   21    -1 	def write(self, name):
   22    -1 		f = open(name, 'w')
   23    -1 		f.write(self._buf)
   24    -1 		f.close()
   25    -1 
   26    -1 	def writeFixed(self, n, k):
   27    -1 		if type(n) == type(''):
   28    -1 			self._buf += (' '*k + n)[-k:]
   29    -1 		else:
   30    -1 			if k != 0:
   31    -1 				self.writeFixed(n / 0x100, k-1)
   32    -1 				self._buf += chr(n % 0x100)
   33    -1 
   34    -1 	def writeVariable(self, n, _rec=False):
   35    -1 		# b = bin(a)[2:]; eval('0b'+''.join([b[k*8:(k+1)*8][1:] for k in range(int(len(b)/8))]))
   36    -1 		if n == 0 and _rec: return 0 
   37    -1 		self.writeVariable(n / 0x80, True)
   38    -1 		if _rec:
   39    -1 			self._buf += chr(n % 0x80 + 0x80)
   40    -1 		else:
   41    -1 			self._buf += chr(n % 0x80)
   42    -1 
   43    -1 	def chEvent(self, dt, event, ch, p1, p2=-1):
   44    -1 		self.writeVariable(int(dt * timeDevision))
   45    -1 		self.writeFixed((event << 4) + ch, 1)
   46    -1 		self.writeFixed(p1, 1)
   47    -1 		if not p2 == -1:
   48    -1 			self.writeFixed(p2, 1)
   49    -1 
   50    -1 	def metaEvent(self, dt, event, length, data):
   51    -1 		self.writeVariable(int(dt * timeDevision))
   52    -1 		self.writeFixed(0xff, 1)
   53    -1 		self.writeFixed(event, 1)
   54    -1 		self.writeVariable(length)
   55    -1 		self.writeFixed(data, length)
   56    -1 
   57    -1 	def sysEx(self, dt, length, data):
   58    -1 		self.writeVariable(int(dt * timeDevision))
   59    -1 		self.writeFixed(0xf0, 1)
   60    -1 		self.writeVariable(length)
   61    -1 		self.writeFixed(data, length)
   62    -1 
   63    -1 	def setTempo(self, bpm):
   64    -1 		# midi uses microsec/quarter note
   65    -1 		msqn = 60000000/bpm
   66    -1 		self.metaEvent(0, 0x51, 3, msqn)
   67    -1 
   68    -1 	def noteOn(self, dt, ch, key, vol=1):
   69    -1 		self.chEvent(dt, 0x9, ch, key, int(vol * 0x7f))
   70    -1 
   71    -1 	def noteOff(self, dt, ch, key, vol=1):
   72    -1 		self.chEvent(dt, 0x8, ch, key, int(vol * 0x7f))
   73    -1 
   74    -1 	def lyrics(self, dt, s):
   75    -1 		self.metaEvent(dt, 0x05, len(s), s)
   76    -1 
   77    -1 	def progCh(self, dt, ch, prog):
   78    -1 		self.chEvent(dt, 0xC, ch, prog)
   79    -1 
   80    -1 	def ctrlEvent(self, dt, ctrl, v):
   81    -1 		self.chEvent(dt, 0xB, ch, ctrl, v)
   82    -1 
   83    -1 	def setVol(self, dt, ch, vol=1):
   84    -1 		self.ctrlEvent(dt, ch, 0x07, int(vol * 0x7f))
   -1    10     def __init__(self):
   -1    11         self._buf = ''
   -1    12 
   -1    13     def __str__(self):
   -1    14         return self._buf.encode('hex')
   -1    15 
   -1    16     def __add__(self, other):
   -1    17         m = Midi()
   -1    18         m._buf = self._buf + other._buf
   -1    19         return m
   -1    20 
   -1    21     def write(self, name):
   -1    22         f = open(name, 'w')
   -1    23         f.write(self._buf)
   -1    24         f.close()
   -1    25 
   -1    26     def writeFixed(self, n, k):
   -1    27         if type(n) == type(''):
   -1    28             self._buf += (' '*k + n)[-k:]
   -1    29         else:
   -1    30             if k != 0:
   -1    31                 self.writeFixed(n / 0x100, k-1)
   -1    32                 self._buf += chr(n % 0x100)
   -1    33 
   -1    34     def writeVariable(self, n, _rec=False):
   -1    35         # b = bin(a)[2:]; eval('0b'+''.join([b[k*8:(k+1)*8][1:] for k in range(int(len(b)/8))]))
   -1    36         if n == 0 and _rec: return 0
   -1    37         self.writeVariable(n / 0x80, True)
   -1    38         if _rec:
   -1    39             self._buf += chr(n % 0x80 + 0x80)
   -1    40         else:
   -1    41             self._buf += chr(n % 0x80)
   -1    42 
   -1    43     def chEvent(self, dt, event, ch, p1, p2=-1):
   -1    44         self.writeVariable(int(dt * timeDevision))
   -1    45         self.writeFixed((event << 4) + ch, 1)
   -1    46         self.writeFixed(p1, 1)
   -1    47         if not p2 == -1:
   -1    48             self.writeFixed(p2, 1)
   -1    49 
   -1    50     def metaEvent(self, dt, event, length, data):
   -1    51         self.writeVariable(int(dt * timeDevision))
   -1    52         self.writeFixed(0xff, 1)
   -1    53         self.writeFixed(event, 1)
   -1    54         self.writeVariable(length)
   -1    55         self.writeFixed(data, length)
   -1    56 
   -1    57     def sysEx(self, dt, length, data):
   -1    58         self.writeVariable(int(dt * timeDevision))
   -1    59         self.writeFixed(0xf0, 1)
   -1    60         self.writeVariable(length)
   -1    61         self.writeFixed(data, length)
   -1    62 
   -1    63     def setTempo(self, bpm):
   -1    64         # midi uses microsec/quarter note
   -1    65         msqn = 60000000/bpm
   -1    66         self.metaEvent(0, 0x51, 3, msqn)
   -1    67 
   -1    68     def noteOn(self, dt, ch, key, vol=1):
   -1    69         self.chEvent(dt, 0x9, ch, key, int(vol * 0x7f))
   -1    70 
   -1    71     def noteOff(self, dt, ch, key, vol=1):
   -1    72         self.chEvent(dt, 0x8, ch, key, int(vol * 0x7f))
   -1    73 
   -1    74     def lyrics(self, dt, s):
   -1    75         self.metaEvent(dt, 0x05, len(s), s)
   -1    76 
   -1    77     def progCh(self, dt, ch, prog):
   -1    78         self.chEvent(dt, 0xC, ch, prog)
   -1    79 
   -1    80     def ctrlEvent(self, dt, ctrl, v):
   -1    81         self.chEvent(dt, 0xB, ch, ctrl, v)
   -1    82 
   -1    83     def setVol(self, dt, ch, vol=1):
   -1    84         self.ctrlEvent(dt, ch, 0x07, int(vol * 0x7f))
   85    85 
   86    86 class MidiFile(Midi):
   87    87 
   88    -1 	def __init__(self):
   89    -1 		Midi.__init__(self)
   90    -1 		self._tracks = []
   91    -1 
   92    -1 	def update(self):
   93    -1 		self._buf = ''
   94    -1 		self.writeFixed(0x4D546864, 4) # chunk ID "MThd"
   95    -1 		self.writeFixed(6, 4) # chunk size
   96    -1 		self.writeFixed(1, 2) # format type
   97    -1 		self.writeFixed(len(self._tracks), 2) # numer of tracks
   98    -1 		self.writeFixed(timeDevision, 2) # time devision
   99    -1 		for track in self._tracks:
  100    -1 			self.writeFixed(0x4D54726B, 4) # chunk ID "MTtr"
  101    -1 			self.writeFixed(len(track._buf)+4, 4) # chunk size
  102    -1 			self._buf += track._buf
  103    -1 			self.metaEvent(0, 0x2f, 0, '') # endTrack event
  104    -1 
  105    -1 	def addTrack(self, data, update=True):
  106    -1 		self._tracks.append(data)
  107    -1 		if update:
  108    -1 			self.update()
   -1    88     def __init__(self):
   -1    89         Midi.__init__(self)
   -1    90         self._tracks = []
   -1    91 
   -1    92     def update(self):
   -1    93         self._buf = ''
   -1    94         self.writeFixed(0x4D546864, 4) # chunk ID "MThd"
   -1    95         self.writeFixed(6, 4) # chunk size
   -1    96         self.writeFixed(1, 2) # format type
   -1    97         self.writeFixed(len(self._tracks), 2) # numer of tracks
   -1    98         self.writeFixed(timeDevision, 2) # time devision
   -1    99         for track in self._tracks:
   -1   100             self.writeFixed(0x4D54726B, 4) # chunk ID "MTtr"
   -1   101             self.writeFixed(len(track._buf)+4, 4) # chunk size
   -1   102             self._buf += track._buf
   -1   103             self.metaEvent(0, 0x2f, 0, '') # endTrack event
   -1   104 
   -1   105     def addTrack(self, data, update=True):
   -1   106         self._tracks.append(data)
   -1   107         if update:
   -1   108             self.update()
  109   109 
  110   110 if __name__ == '__main__':
  111    -1 	# Example:
  112    -1 	f = MidiFile()
  113    -1 	f.addTrack(Midi())
  114    -1 	t = Midi()
  115    -1 	t.setVol(0, 1, 1)
  116    -1 	t.ctrlEvent(0, 1, 0x00, 0) # setting bank
  117    -1 	t.noteOn(0.5, 1, 60)
  118    -1 	t.noteOff(1, 1, 60)
  119    -1 	t.noteOn(0, 1, 62)
  120    -1 	t.noteOff(1, 1, 62)
  121    -1 	t.noteOn(0, 1, 64)
  122    -1 	t.noteOff(1, 1, 64)
  123    -1 	f.addTrack(t)
  124    -1 	print f
  125    -1 	f.write('test.mid')
   -1   111     # Example:
   -1   112     f = MidiFile()
   -1   113     f.addTrack(Midi())
   -1   114     t = Midi()
   -1   115     t.setVol(0, 1, 1)
   -1   116     t.ctrlEvent(0, 1, 0x00, 0) # setting bank
   -1   117     t.noteOn(0.5, 1, 60)
   -1   118     t.noteOff(1, 1, 60)
   -1   119     t.noteOn(0, 1, 62)
   -1   120     t.noteOff(1, 1, 62)
   -1   121     t.noteOn(0, 1, 64)
   -1   122     t.noteOff(1, 1, 64)
   -1   123     f.addTrack(t)
   -1   124     print f
   -1   125     f.write('test.mid')

diff --git a/xi2.py b/xi2.py

@@ -16,9 +16,9 @@ parser.add_argument('outfile')
   16    16 args = parser.parse_args()
   17    17 
   18    18 def length(data):
   19    -1 	data = re.sub('{[^}]*}', '', data)
   20    -1 	data = re.sub('\([^\)]*\)', '', data)
   21    -1 	return len(data.split(',')) - 1
   -1    19     data = re.sub('{[^}]*}', '', data)
   -1    20     data = re.sub('\([^\)]*\)', '', data)
   -1    21     return len(data.split(',')) - 1
   22    22 
   23    23 f = open(args.infile)
   24    24 lines = f.readlines()
@@ -38,16 +38,16 @@ ll = re.sub('//[^\n]*\n', '', ll)
   38    38 # expand macros
   39    39 ll = re.sub('\n', '\\\\n', ll)
   40    40 while re.search('(\[[^\]]*\]):(.*)', ll):
   41    -1 	match = re.search('(\[[^\]]*\]):(.*)', ll)
   42    -1 	(key, after) = match.groups()
   43    -1 	if after.startswith('<<'):
   44    -1 		eol = after.split('\\n',1)[0][2:]
   45    -1 		val = after.split(eol,2)[1]
   46    -1 		ll = re.sub(re.escape("%s:<<%s%s%s" % (key, eol, val, eol)), '', ll)
   47    -1 	else:
   48    -1 		val = after.split('\\n',1)[0]
   49    -1 		ll = re.sub(re.escape("%s:%s" % (key, val)), '', ll)
   50    -1 	ll = re.sub(re.escape(key), val, ll)
   -1    41     match = re.search('(\[[^\]]*\]):(.*)', ll)
   -1    42     (key, after) = match.groups()
   -1    43     if after.startswith('<<'):
   -1    44         eol = after.split('\\n',1)[0][2:]
   -1    45         val = after.split(eol,2)[1]
   -1    46         ll = re.sub(re.escape("%s:<<%s%s%s" % (key, eol, val, eol)), '', ll)
   -1    47     else:
   -1    48         val = after.split('\\n',1)[0]
   -1    49         ll = re.sub(re.escape("%s:%s" % (key, val)), '', ll)
   -1    50     ll = re.sub(re.escape(key), val, ll)
   51    51 ll = re.sub('\\\\n', '\n', ll)
   52    52 
   53    53 # remove trailing newlines
@@ -60,46 +60,46 @@ ll = re.sub('\\\\n', '\n', ll)
   60    60 ll = re.sub('\n*$', '', ll)
   61    61 
   62    62 def parse(t):
   63    -1 	string = '';
   64    -1 	stack = [[]]
   65    -1 	for c in t:
   66    -1 		#print stack, string, c
   67    -1 		if c == '{':
   68    -1 			stack.append([])
   69    -1 		elif c == '}':
   70    -1 			stack[-1].append(string)
   71    -1 			string = tuple(stack.pop())
   72    -1 		elif c == '(':
   73    -1 			stack.append([])
   74    -1 		elif c == ')':
   75    -1 			stack[-1].append(string)
   76    -1 			string = stack.pop()
   77    -1 		elif c == ',':
   78    -1 			stack[-1].append(string)
   79    -1 			string = ''
   80    -1 		else:
   81    -1 			string += c
   82    -1 	return stack[0]
   -1    63     string = '';
   -1    64     stack = [[]]
   -1    65     for c in t:
   -1    66         #print stack, string, c
   -1    67         if c == '{':
   -1    68             stack.append([])
   -1    69         elif c == '}':
   -1    70             stack[-1].append(string)
   -1    71             string = tuple(stack.pop())
   -1    72         elif c == '(':
   -1    73             stack.append([])
   -1    74         elif c == ')':
   -1    75             stack[-1].append(string)
   -1    76             string = stack.pop()
   -1    77         elif c == ',':
   -1    78             stack[-1].append(string)
   -1    79             string = ''
   -1    80         else:
   -1    81             string += c
   -1    82     return stack[0]
   83    83 
   84    84 # join track parts from different sets
   85    85 tracks = dict()
   86    86 for s in ll.split('\n\n'):
   87    -1 	if len(tracks) == 0: l = 0
   88    -1 	else: l = max([len(t) for t in tracks])
   89    -1 	for track in s.split('\n'):
   90    -1 		try:
   91    -1 			(name, data) = track.split(':', 1)
   92    -1 		except Exception, e:
   93    -1 			print track
   94    -1 			raise e
   95    -1 		data = parse(data)
   96    -1 		if not tracks.has_key(name):
   97    -1 			tracks[name] = [''] * l
   98    -1 		tracks[name] += data
   99    -1 	if len(tracks) == 0: l = 0
  100    -1 	else: l = max([len(t) for t in tracks])
  101    -1 	for (name,data) in tracks.iteritems():
  102    -1 		data += [''] * (l - len(data))
   -1    87     if len(tracks) == 0: l = 0
   -1    88     else: l = max([len(t) for t in tracks])
   -1    89     for track in s.split('\n'):
   -1    90         try:
   -1    91             (name, data) = track.split(':', 1)
   -1    92         except Exception, e:
   -1    93             print track
   -1    94             raise e
   -1    95         data = parse(data)
   -1    96         if not tracks.has_key(name):
   -1    97             tracks[name] = [''] * l
   -1    98         tracks[name] += data
   -1    99     if len(tracks) == 0: l = 0
   -1   100     else: l = max([len(t) for t in tracks])
   -1   101     for (name,data) in tracks.iteritems():
   -1   102         data += [''] * (l - len(data))
  103   103 
  104   104 # create midi
  105   105 mf = MidiFile()
@@ -111,18 +111,18 @@ mf.addTrack(m)
  111   111 
  112   112 ch = 0
  113   113 for name, track in tracks.iteritems():
  114    -1 	m = Midi()
  115    -1 	# write meta info
  116    -1 	m.metaEvent(0, 0x04, len(name), name)
  117    -1 	try: prog = int(name)
  118    -1 	except ValueError: prog = 0
  119    -1 	m.progCh(0, ch, prog)
  120    -1 	# write data
  121    -1 	ip = IParser(track, ch=ch, offset=args.offset)
  122    -1 	m += ip.midi
  123    -1 	# write
  124    -1 	mf.addTrack(m)
  125    -1 	ch += 1
   -1   114     m = Midi()
   -1   115     # write meta info
   -1   116     m.metaEvent(0, 0x04, len(name), name)
   -1   117     try: prog = int(name)
   -1   118     except ValueError: prog = 0
   -1   119     m.progCh(0, ch, prog)
   -1   120     # write data
   -1   121     ip = IParser(track, ch=ch, offset=args.offset)
   -1   122     m += ip.midi
   -1   123     # write
   -1   124     mf.addTrack(m)
   -1   125     ch += 1
  126   126 
  127   127 # write to file
  128   128 mf.write(args.outfile)