Module midifile
[hide private]
[frames] | no frames]

Source Code for Module midifile

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2005 Joe Pham <djpham@bitpim.org> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: midifile.py 3608 2006-10-06 02:51:56Z djpham $ 
  9   
 10  import common 
 11   
 12   
 13  module_debug=False 
 14   
15 -class MIDIEvent(object):
16 META_EVENT=0 17 SYSEX_EVENT=1 18 SYSEX1_EVENT=2 19 MIDI_EVENT=3 20 LAST_MIDI_EVENT=4 21 type_str=('Meta', 'SYSEX', 'SYSEX cont', 'MIDI', 'Last MIDI') 22
23 - def __init__(self, file, offset, last_cmd=None):
24 self.__f=file 25 self.__start=self.__ofs=offset 26 self.__time_delta=self.__get_var_len() 27 b=self.__get_int() 28 if b==0xff: 29 # meta event 30 self.__get_meta_event() 31 elif b==0xf0 or b==0xf7: 32 # sysex event 33 self.__get_sysex_event(b) 34 else: 35 # MIDI Channel event 36 self.__get_midi_event(b, last_cmd) 37 self.__total_len=self.__ofs-self.__start
38
39 - def __get_int(self):
40 i=int(self.__f.GetByte(self.__ofs)) 41 self.__ofs+=1 42 return i
43
44 - def __get_bytes(self, len):
45 data=self.__f.GetBytes(self.__ofs, len) 46 self.__ofs+=len 47 return data
48
49 - def __get_var_len(self):
50 t=0 51 b=self.__get_int() 52 while (b&0x80): 53 t=(t<<7)|(b&0x7f) 54 b=self.__get_int() 55 return (t<<7)|(b&0x7f)
56
57 - def __get_meta_event(self):
58 self.__type=self.META_EVENT 59 self.__cmd=self.__get_int() 60 self.__len=self.__get_var_len() 61 if self.__len: 62 self.__param1=self.__get_bytes(self.__len) 63 else: 64 self.__param1=None 65 self.__param2=None
66
67 - def __get_sysex_event(self, cmd):
68 if cmd==0xf0: 69 self.__type=self.SYSEX_EVENT 70 else: 71 self.__type=self.SYSEX1_EVENT 72 self.__cmd=cmd 73 self.__len=self.__get_var_len() 74 if self.__len: 75 self.__param1=self.__get_bytes(self.__len) 76 else: 77 self.__param1=None 78 self.__param2=None
79
80 - def __get_midi_event(self, cmd, last_cmd):
81 if cmd&0x80: 82 # not a running command 83 i=cmd 84 self.__type=self.MIDI_EVENT 85 self.__param1=self.__get_int() 86 else: 87 i=last_cmd 88 self.__type=self.LAST_MIDI_EVENT 89 self.__param1=cmd 90 self.__cmd=(i&0xf0)>>4 91 self.__midi_channel=i&0x0f 92 if self.__cmd==0x0c or self.__cmd==0x0d: 93 self.__len=1 94 self.__param2=None 95 else: 96 self.__len=2 97 self.__param2=self.__get_int()
98
99 - def __get_type(self):
100 return self.__type
101 type=property(fget=__get_type) 102
103 - def __get_time_delta(self):
104 return self.__time_delta
105 time_delta=property(fget=__get_time_delta) 106
107 - def __get_total_len(self):
108 return self.__total_len
109 total_len=property(fget=__get_total_len) 110
111 - def __get_cmd(self):
112 return self.__cmd
113 cmd=property(fget=__get_cmd) 114
115 - def __get_midi_channel(self):
116 return self.__midi_channel
117 midi_channel=property(fget=__get_midi_channel) 118
119 - def __get_param_len(self):
120 return self.__len
121 param_len=property(fget=__get_param_len) 122
123 - def __get_params(self):
124 return self.__param1, self.__param2
125 params=property(fget=__get_params) 126
127 - def __str__(self):
128 if self.type==self.MIDI_EVENT or \ 129 self.type==self.LAST_MIDI_EVENT: 130 return '0x%04x: %s cmd: 0x%x, Channel: %d, Len: %d'%\ 131 (self.time_delta, self.type_str[self.type], 132 self.cmd, self.midi_channel, self.param_len) 133 else: 134 return '0x%04x: %s cmd: 0x%x, Len: %d'%\ 135 (self.time_delta, self.type_str[self.type], 136 self.cmd, self.param_len)
137
138 -class MIDITrack(object):
139 - def __init__(self, file, offset):
140 self.__f=file 141 self.__ofs=offset 142 if module_debug: 143 print 'New Track @ ofs:', offset 144 if self.__f.GetBytes(self.__ofs, 4)!='MTrk': 145 raise TypeError, 'not an MIDI track' 146 self.__len=self.__f.GetMSBUint32(self.__ofs+4) 147 ofs=self.__ofs+8 148 ofs_end=ofs+self.__len 149 last_cmd=None 150 self.__time_delta=0 151 self.__mpqn=None 152 while ofs<ofs_end: 153 e=MIDIEvent(file, ofs, last_cmd) 154 if module_debug: 155 print e 156 ofs+=e.total_len 157 self.__time_delta+=e.time_delta 158 if e.type==e.META_EVENT: 159 if e.cmd==0x51: 160 # set tempo 161 p1, p2=e.params 162 self.__mpqn=(ord(p1[0])<<16)|(ord(p1[1])<<8)|ord(p1[2]) 163 if e.type==e.MIDI_EVENT or e.type==e.LAST_MIDI_EVENT: 164 last_cmd=(e.cmd<<4)|e.midi_channel 165 else: 166 last_cmd=e.cmd 167 self.__total_len=ofs-self.__ofs 168 if module_debug: 169 print 'self.__ofs', self.__ofs+8, 'self.__len:', self.__len, 'ofs: ', ofs 170 print 'time delta:', self.__time_delta, 'MPQN: ', self.__mpqn
171
172 - def __get_time_delta(self):
173 return self.__time_delta
174 time_delta=property(fget=__get_time_delta)
175 - def __get_total_len(self):
176 return self.__total_len
177 total_len=property(fget=__get_total_len)
178 - def __get_mpqn(self):
179 return self.__mpqn
180 mpqn=property(fget=__get_mpqn)
181
182 -class MIDIFile(object):
183 - def __init__(self, file_wraper):
184 try: 185 self.__valid=False 186 self.__file=file_wraper 187 if self.__file.GetBytes(0, 4)!='MThd' or \ 188 self.__file.GetMSBUint32(4)!=6: 189 # not a valid MIDI header 190 return 191 self.__valid=True 192 self.__type=self.__file.GetMSBUint16(8) 193 self.__num_tracks=self.__file.GetMSBUint16(10) 194 self.__time_division=self.__file.GetMSBUint16(12) 195 self.__tracks=[] 196 self.__mpqn=2000000 197 file_ofs=14 198 time_delta=0 199 for i in range(self.__num_tracks): 200 trk=MIDITrack(self.__file, file_ofs) 201 self.__tracks.append(trk) 202 file_ofs+=trk.total_len 203 time_delta=max(time_delta, trk.time_delta) 204 if trk.mpqn is not None: 205 self.__mpqn=trk.mpqn 206 self.__duration=(self.__mpqn*time_delta/self.__time_division)/1000000.0 207 if module_debug: 208 print 'type:', self.__type 209 print 'time division:', self.__time_division 210 print 'num of tracks:', self.__num_tracks 211 print 'MPQN:', self.__mpqn 212 print 'longest time delta: ', time_delta 213 print 'duration:', self.__duration 214 except: 215 self.__valid=False
216
217 - def __get_valid(self):
218 return self.__valid
219 valid=property(fget=__get_valid) 220
221 - def __get_type(self):
222 return self.__type
223 type=property(fget=__get_type) 224
225 - def __get_num_tracks(self):
226 return self.__num_tracks
227 num_tracks=property(fget=__get_num_tracks) 228
229 - def __get_duration(self):
230 return self.__duration
231 duration=property(fget=__get_duration)
232