- 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 1314 -1 def __init__(self, seq, ch=0, offset=60):15 -1 self.midi = Midi()16 -1 self.ch = ch17 -1 self.offset = offset18 -1 self.dt = 019 -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 2223 -1 def dtStep(self):24 -1 a = 1.025 -1 for i in self.dtStack[1:]:26 -1 a /= i27 -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 2829 -1 def parseEl(self, e):30 -1 if e.isdigit(): # note31 -1 self.midi.noteOn(self.dt, self.ch, self.offset+int(e), 1)32 -1 self.dt = self.dtStep()33 -1 elif e == '-': # continue34 -1 self.dt += self.dtStep()35 -1 elif e == '': # break36 -1 self.dt += self.dtStep()37 -1 else: # lyrics38 -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 4041 -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 5758 -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 = 067 -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 6869 -1 def stop(self):70 -1 if len(self.stack) == 0: return71 -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 stopped77 -1 elif e.isdigit():78 -1 self.midi.noteOff(self.dt, self.ch, self.offset+int(e), 1)79 -1 self.dt = 080 -1 else:81 -1 pass82 -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 = 091 -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 9697 -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 910 -1 def __init__(self):11 -1 self._buf = ''12 -113 -1 def __str__(self):14 -1 return self._buf.encode('hex')15 -116 -1 def __add__(self, other):17 -1 m = Midi()18 -1 m._buf = self._buf + other._buf19 -1 return m20 -121 -1 def write(self, name):22 -1 f = open(name, 'w')23 -1 f.write(self._buf)24 -1 f.close()25 -126 -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 -134 -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 037 -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 -143 -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 -150 -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 -157 -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 -163 -1 def setTempo(self, bpm):64 -1 # midi uses microsec/quarter note65 -1 msqn = 60000000/bpm66 -1 self.metaEvent(0, 0x51, 3, msqn)67 -168 -1 def noteOn(self, dt, ch, key, vol=1):69 -1 self.chEvent(dt, 0x9, ch, key, int(vol * 0x7f))70 -171 -1 def noteOff(self, dt, ch, key, vol=1):72 -1 self.chEvent(dt, 0x8, ch, key, int(vol * 0x7f))73 -174 -1 def lyrics(self, dt, s):75 -1 self.metaEvent(dt, 0x05, len(s), s)76 -177 -1 def progCh(self, dt, ch, prog):78 -1 self.chEvent(dt, 0xC, ch, prog)79 -180 -1 def ctrlEvent(self, dt, ctrl, v):81 -1 self.chEvent(dt, 0xB, ch, ctrl, v)82 -183 -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 8788 -1 def __init__(self):89 -1 Midi.__init__(self)90 -1 self._tracks = []91 -192 -1 def update(self):93 -1 self._buf = ''94 -1 self.writeFixed(0x4D546864, 4) # chunk ID "MThd"95 -1 self.writeFixed(6, 4) # chunk size96 -1 self.writeFixed(1, 2) # format type97 -1 self.writeFixed(len(self._tracks), 2) # numer of tracks98 -1 self.writeFixed(timeDevision, 2) # time devision99 -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 size102 -1 self._buf += track._buf103 -1 self.metaEvent(0, 0x2f, 0, '') # endTrack event104 -1105 -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 bank117 -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 f125 -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)