1 """Midi file I/O and manipulation library.
2
3 Python MIDI
4
5 - Original author: Giles Hall
6 - Modified by Mark Granroth-Wilding, 2010-11
7
8 This package contains data structures and utilities for reading,
9 manipulating and writing MIDI data.
10
11 """
12 import copy
13 from cStringIO import StringIO
14 from struct import unpack, pack
15 from math import log
16
17 from .constants import NOTE_VALUE_MAP_SHARP, BEATVALUES, \
18 DEFAULT_MIDI_HEADER_SIZE
19 from .encoding import read_varlen, write_varlen
20
21
22 -class Event(object):
23 """
24 Base class for all MIDI events.
25
26 """
27 length = 0
28 name = "Generic MIDI Event"
29 statusmsg = 0x0
30
31
32 allow_running = True
33
38
40 self.type = self.__class__.__name__
41 """ Event type derived from class name """
42 self.channel = 0
43 """ Midi channel """
44 self.tick = 0
45 """ Time of the event in midi ticks """
46 self.msdelay = 0
47 """ Delay in ms """
48 self.data = ''
49 """ Data after status message """
50 self.track = 0
51 """ Track number (gets set when event is added to a stream) """
52 self.order = None
53 """ Sort order """
54
56 return copy.deepcopy(self)
57
59 """
60 Checks whether this is of an event identified by the given
61 status message.
62
63 """
64 return (cls.statusmsg == (statusmsg & 0xF0))
65 is_event = classmethod(is_event)
66
68 return "%s @%d %dms C%d T%d" % (self.name,
69 self.tick,
70 self.msdelay,
71 self.channel,
72 self.track)
73
75 if self.tick < other.tick: return -1
76 elif self.tick > other.tick: return 1
77 return 0
78
80 rtick = self.tick - tempo.tick
81 self.msdelay = int((rtick * tempo.mpt) + tempo.msdelay)
82
83 - def encode(self, last_tick=0, running=False):
84 """
85 Produces an encoding of this event for writing to a MIDI stream.
86 Includes the delta and status message.
87
88 @type last_tick: int/long
89 @param last_tick: tick value of the previous event that was
90 encoded in the stream. The timing of this event will be
91 stored as a delta, so we need to know when the last thing
92 happened.
93 @type running: bool
94 @param running: omits the status message if true, since it is
95 assumed that the status is carried over from the previous
96 event.
97
98 """
99 encstr = ''
100 if not running:
101 encstr += chr((self.statusmsg & 0xF0) | (0x0F & self.channel))
102 return self.encode_delta_tick(last_tick=last_tick) + encstr + self.encode_data()
103
104 - def decode(self, tick, statusmsg, track, runningstatus=''):
105 """
106 Reads MIDI data from the track stream, from which the tick
107 and status message have already been read. Removes as many
108 bytes from the track as this event type needs.
109 Sets instance variables according to data read from the stream.
110
111 @param tick: tick time of the event (already read from the stream)
112 @param statusmsg: the status message that was read from the
113 stream for this event. This is expected to be of the correct
114 type for this event type.
115 @param track: data stream from which to continue reading as
116 much data as is needed for this event.
117 @param runningstatus: if this event had a running status in the
118 input stream, the byte that was read off the stream to
119 try to get a status for this event (which turned out not
120 to be a status message) goes in here and gets treated as
121 the first byte of the data.
122
123 """
124 assert(self.is_event(statusmsg))
125 self.tick = tick
126 self.channel = statusmsg & 0x0F
127 self.data = ''
128 if runningstatus:
129 self.data += runningstatus
130 remainder = self.length - len(self.data)
131 if remainder:
132 self.data += str.join('',[track.next() for x in range(remainder)])
133 self.decode_data()
134
136 """
137 this function should be renamed "encode_delta_tick"; it doesn't
138 encode the tick value of the event.
139 Returns the varlen data to use to represent the timing of this
140 event relative to the last event.
141
142 @param last_tick: time of the previous event in the stream.
143
144 """
145 delta_tick = self.tick - last_tick
146 return write_varlen(delta_tick)
147
149 """
150 Takes the data that's been read into C{data} instance variable
151 and sets instance attributes from the values in it. What this
152 does is specific to the event type.
153
154 At the simplest, it could do nothing, just leaving the raw data
155 in C{data}, but more likely it will decode values from the
156 data.
157
158 """
159 pass
160
162 """
163 Produces byte data to represent this event on the basis of
164 instance variables. This is the data that will be written to
165 a MIDI stream (not including the tick and status message).
166
167 @return: byte data as a string
168
169 """
170 return self.data
171
214
217 """
218 EventFactory is a factory for getting MIDI events out of a data
219 stream.
220
221 """
222 EventRegistry = []
223 MetaEventRegistry = []
224
226 self.RunningStatus = None
227 self.RunningTick = 0
228
236 register_event = classmethod(register_event)
237
239 """
240 Reads bytes out of a data stream and returns a representation
241 of the next MIDI event. All events in a stream should be read
242 in turn using the same EventFactory, which keeps track
243 of things like running status.
244
245 @param track: data stream to read bytes from
246 @return: L{Event} subclass instance for the next MIDI event in
247 the track.
248
249 """
250
251 tick = read_varlen(track)
252 self.RunningTick += tick
253
254 stsmsg = ord(track.next())
255
256 if MetaEvent.is_event(stsmsg):
257
258 cmd = ord(track.next())
259 for etype in self.MetaEventRegistry:
260 if etype.is_meta_event(cmd):
261 evi = etype()
262 evi.decode(self.RunningTick, cmd, track)
263 return evi
264 else:
265 raise Warning, "Unknown Meta MIDI Event: " + `cmd`
266
267 else:
268 for etype in self.EventRegistry:
269 if etype.is_event(stsmsg):
270 self.RunningStatus = (stsmsg, etype)
271 evi = etype()
272 evi.decode(self.RunningTick, stsmsg, track)
273 return evi
274 else:
275 if self.RunningStatus:
276 cached_stsmsg, etype = self.RunningStatus
277 evi = etype()
278 evi.decode(self.RunningTick,
279 cached_stsmsg, track, chr(stsmsg))
280 return evi
281 else:
282 raise Warning, "Unknown MIDI Event: " + `stsmsg`
283
285 """
286 Abstract base class for L{NoteOnEvent} and L{NoteOffEvent}.
287
288 """
289 length = 2
290
291
292 pitch = 60
293 """ Note number (0-127) """
294 velocity = 64
295 """ How hard the note is played or how quickly it's released (0-127) """
296
303
307
310
312 """
313 Note-on event. Starts a note playing.
314
315 """
316 statusmsg = 0x90
317 name = 'Note On'
318
320 """
321 Note-off event. Stops a note playing.
322
323 """
324 statusmsg = 0x80
325 name = 'Note Off'
326
328 """
329 Changes the pressure of aftertouch on a note.
330
331 """
332 statusmsg = 0xA0
333 length = 2
334 name = 'After Touch'
335
336
337 pitch = 60
338 """ Note number (0-127) """
339 pressure = 0
340 """ How hard to apply aftertouch (0-127) """
341
347
351
354
356 """
357 Sets the value of one of the 128 controllers available to a device.
358
359 """
360
361
362 statusmsg = 0xB0
363 length = 2
364 name = 'Control Change'
365
366
367 control = 0
368 """ Which controller's value to set """
369 value = 0
370 """ Value to assign to the controller """
371
377
381
384
386 """
387 Creates an All Notes Off event. This is really a specialized control
388 change event and uses one of the reserved controller numbers.
389
390 """
391 ev = ControlChangeEvent()
392 ev.channel = channel
393
394 ev.control = 123
395
396 ev.value = 0
397 return ev
398
400 """
401 Changes the patch (voice) number of the instrument.
402
403 """
404 statusmsg = 0xC0
405 length = 1
406 name = 'Program Change'
407
408
409 value = 0
410 """ New patch number to select """
411
416
419
421 return chr(self.value)
422
424 """
425 Channel pressure (after-touch). Most often sent by pressing down
426 on the key after it "bottoms out". Different from polyphonic
427 after-touch. Use this message to send the single greatest pressure
428 value (of all the current depressed keys).
429
430 """
431 statusmsg = 0xD0
432 length = 1
433 name = 'Channel After Touch'
434
435
436 pressure = 0
437 """ Pressure value to set the channel's after touch to """
438
443
446
449
451 """
452 Change the pitch-bend wheel value. Given as a 14-bit value
453 (0-16,383), 8,192 being the neutral value.
454 """
455 statusmsg = 0xE0
456 length = 2
457 name = 'Pitch Wheel'
458
459
460 value = 0x2222
461 """ Pitch wheel position (0-16,383, middle 8,192). """
462
463
464
469
471 first = ord(self.data[0])
472 second = ord(self.data[1])
473 if (first & 0x80) or (second & 0x80):
474 raise Warning ("Pitch Wheel data out of range")
475 self.value = ((second << 7) | first) - 0x2000
476
478 value = self.value + 0x2000
479 first = chr(value & 0x7F)
480 second = chr((value >> 7) & 0xFF)
481 return first + second
482
484 """
485 System exclusive MIDI event. Generic event type for sending data
486 to a system in a format that it recognizes, but which may not be
487 recognized by any other device.
488
489 Some standards are defined for sub-event types of sysex. Tuning
490 messages are one example. This class implements encoding/decoding
491 for tuning messages.
492
493 Other sysex events are treated just as raw data, between the initial
494 F0 and the final F7.
495
496 @todo: we should possibly terminate the sysex data on finding any
497 1-initial byte. Sysex messages are supposed to end with a 0xF7, but
498 the data can only contain 0-initial bytes (7-bit values).
499
500 """
501 statusmsg = 0xF0
502 name = 'SysEx'
503 subtype = 0
504 allow_running = False
505
506 SUBTYPE_NONE = 0
507 SUBTYPE_SINGLE_NOTE_TUNING_CHANGE = 1
508
509
510 data = ''
511 """
512 Data stored in the SysEx. This can be any data in a format that
513 the device will recognise.
514 """
515
518 is_event = classmethod(is_event)
519
520 - def decode(self, tick, statusmsg, track, runningstatus=''):
538
539 - def encode(self, last_tick=0, running=False):
544
546 if len(self.data) >= 6 and \
547 ord(self.data[0]) == 0x7F and \
548 ord(self.data[2]) == 0x08 and \
549 ord(self.data[3]) == 0x02:
550
551
552 self.init_subtype(SysExEvent.SUBTYPE_SINGLE_NOTE_TUNING_CHANGE)
553
554 self.device_id = ord(self.data[1])
555 self.tuning_program = ord(self.data[4])
556 num_changes = ord(self.data[5])
557 change_data = self.data[6:]
558 if len(change_data) % 4 != 0:
559 raise MidiReadError, "incomplete tuning change data in single note tuning change"
560
561 self.changes = [(ord(change_data[i*4]),
562 ord(change_data[i*4+1]),
563 (ord(change_data[i*4+2])<<7) + ord(change_data[i*4+3])
564 ) for i in range(len(change_data)/4)]
565 if len(self.changes) != num_changes:
566 raise Warning, "tuning change event reported wrong number of changes"
567
579
591
598
600 """
601 Returns a SysExEvent which will encode single note tuning changes
602 according to the MIDI tuning messages standard.
603
604 note_changes should be a list of note changes, specified as triples:
605 - (<note number>, <semitone>, <cents>)
606 where:
607 - <key number> is a note number (0-127) to retune,
608 - <semitone> is the nearest equal-temperament semitone below the
609 desired frequency (also a note number, 0-127), and
610 - <cents> is a float >= 0 and < 100 representing the number of
611 cents above the semitone's pitch to retune it to.
612
613 """
614 ev = SysExEvent()
615 ev.init_subtype(SysExEvent.SUBTYPE_SINGLE_NOTE_TUNING_CHANGE)
616
617 if device_number is not None:
618 ev.device_number = device_number
619 if tuning_program is not None:
620 ev.tuning_program = tuning_program
621 ev.changes = [(key,semitone,int(float(cents)/100*(2**14))) for (key,semitone,cents) in note_changes]
622 return ev
623
626 """
627 Defines the pattern number of a Type 2 MIDI file or the number of
628 a sequence in a Type 0 or Type 1 MIDI file. Should always have a
629 delta time of 0.
630
631 """
632 name = 'Sequence Number'
633 metacommand = 0x00
634
635 -class TextEvent(MetaEvent):
636 """
637 Defines some text which can be used for any reason including track
638 notes, comments. The text string is usually ASCII text, but may be
639 any character.
640
641 """
642 name = 'Text'
643 metacommand = 0x01
644
646 return "%s [ %s ]" % \
647 (super(TextEvent, self).__str__(),
648 self.data)
649 - def encode_data(self):
651
653 """
654 Defines copyright information including the copyright symbol
655 (0xA9), year and author. Should always be in the first track chunk,
656 have a delta time of 0.
657
658 """
659 name = 'Copyright Notice'
660 metacommand = 0x02
661
663 """
664 Defines the name of a sequence when in a Type 0 or Type 2 MIDI file
665 or in the first track of a Type 1 MIDI file. Defines a track name
666 when it appears in any track after the first in a Type 1 MIDI file.
667
668 """
669 name = 'Track Name'
670 metacommand = 0x03
671 order = 3
672
677
679 """
680 Defines the name of an instrument being used in the current track
681 chunk. This event can be used with the MIDI Channel Prefix meta
682 event to define which instrument is being used on a specific channel.
683
684 """
685 name = 'Instrument Name'
686 metacommand = 0x04
687 order = 4
688
693
696 """
697 Defines the lyrics in a song and usually used to define a syllable
698 or group of works per quarter note. This event can be used as an
699 equivalent of sheet music lyrics or for implementing a karaoke-style
700 system.
701
702 """
703 name = 'Lyrics'
704 metacommand = 0x05
705
710
713 """
714 Marks a significant point in time for the sequence. Usually found
715 in the first track, but may appear in any. Can be useful for
716 marking the beginning/end of a new verse or chorus.
717
718 """
719 name = 'Marker'
720 metacommand = 0x06
721
723 """
724 Marks the start of some type of new sound or action. Usually found
725 in the first track, but may appear in any. Sometimes used by
726 sequencers to mark when playback of a sample or video should begin.
727
728 """
729 name = 'Cue Point'
730 metacommand = 0x07
731
735
737 """
738 Associates a MIDI channel with following meta events. Its effect
739 is terminated by another MIDI Channel Prefix event or any non-meta
740 event. Often used before an Instrument Name Event to specify which
741 channel an instrument name represents.
742
743 """
744 name = 'Channel Prefix'
745 metacommand = 0x20
746
751
753 """
754 Specifies which MIDI port should be used to output all subsequent
755 events.
756
757 """
758 name = 'MIDI Port/Cable'
759 metacommand = 0x21
760 order = 5
761
762
763 port = 0
764 """ MIDI port to switch to. """
765
770
772 if len(self.data) != 1:
773 raise MidiReadError, "port event data should be 1 byte long"
774 self.port = ord(self.data[0])
775
777 return chr(self.port)
778
782
784 """
785 Appears and the end of each track to mark the end.
786
787 Note that you don't need to add this to tracks in an L{EventStream} -
788 it gets added automatically.
789
790 """
791 name = 'End of Track'
792 metacommand = 0x2F
793 order = 2
794
796 """
797 Change the tempo of events played after this point. In the MIDI
798 data, the tempo is stored in microseconds per quarter note (MPQN),
799 but you may also specify it in beats per minute via the C{tempo}
800 attribute.
801
802 """
803 name = 'Set Tempo'
804 metacommand = 0x51
805 order = 1
806
807
808 tempo = 120
809 """ Tempo value in beats per minute (MM) """
810 mpqn = int(float(6e7) / 120)
811 """ Tempo value in microseconds per quarter note """
812
817
819 if item == 'mpqn':
820 self.__dict__['mpqn'] = value
821 self.__dict__['tempo'] = float(6e7) / value
822 elif item == 'tempo':
823 self.__dict__['tempo'] = value
824 self.__dict__['mpqn'] = int(float(6e7) / value)
825 else:
826 self.__dict__[item] = value
827
829 if len(self.data) != 3:
830 raise MidiReadError, "tempo event data should be 3 bytes long"
831 self.mpqn = (ord(self.data[0]) << 16) + (ord(self.data[1]) << 8) \
832 + ord(self.data[2])
833
835 self.mpqn = int(float(6e7) / self.tempo)
836 return chr((self.mpqn & 0xFF0000) >> 16) + \
837 chr((self.mpqn & 0xFF00) >> 8) + \
838 chr((self.mpqn & 0xFF))
839
841 """
842 Designates the SMPTE start time (hours, minutes, secs, frames,
843 subframes) of the track. Should be at the start of the track.
844 The hour should not be encoded with the SMPTE format as it is in
845 MIDI Time Code. In a format 1 file, the SMPTE OFFSET must be stored
846 with the tempo map (ie, the first track). The final byte contains
847 fractional frames in 100ths of a frame.
848
849 Data should be encoded as 5 bytes:
850 <hour> <min> <sec> <frame> <fractional-frames>.
851
852 @note: encoding is not currently implemented, so you need to do
853 it manually and set the C{data} attribute.
854
855 """
856 name = 'SMPTE Offset'
857 metacommand = 0x54
858
860 """
861 Expressed as 4 numbers:
862 <numerator> <denominator> <metronome> <thirtyseconds>.
863
864 <numerator> and <denominator> represent the parts of the
865 signature as notated on sheet music. The denominator must be a
866 power of 2: 2 = quarter note, 3 = eighth, etc.
867
868 <metronome> expresses the number of MIDI clocks in a metronome click.
869
870 <thirtyseconds> expresses the number of notated 32nd notes in a MIDI
871 quarter note (24 MIDI clocks).
872
873 This event allows a program to relate what MIDI thinks of as a
874 quarter, to something entirely different.
875
876 """
877 name = 'Time Signature'
878 metacommand = 0x58
879 order = 0
880
881
882 numerator = 4
883 """ Top part of the time signature. """
884 denominator = 4
885 """ Bottom part of the time signature (must be a power of 2). """
886 metronome = 24
887 """ Number of MIDI clocks in a metronome click. """
888 thirtyseconds = 8
889 """ Number of 32nd notes in 24 MIDI clocks. """
890
896
905
911
914 """
915 Sets the key signature, made up of a number of sharps/flats and
916 either major or minor.
917
918 """
919 name = 'Key Signature'
920 metacommand = 0x59
921
922
923 accidentals = 0
924 """ Number of sharps/flats. Positive sharps, negative flats. """
925 major = True
926 """ Major or minor: True for major, False for minor. """
927
934
938
939
942
946
948 """
949 Specifies information specific to a hardware or software sequencer.
950 The first data byte (or three bytes if the first byte is 0)
951 specifies the manufacturer's ID and the following bytes contain
952 information specified by the manufacturer.
953
954 Individual manufacturers may document this in their manuals.
955
956 """
957 name = 'Sequencer Specific'
958 metacommand = 0x7F
959
964
968
969 - def add(self, event):
977
979 self.sort()
980
981 last = None
982 for event in self:
983 if last:
984 event.msdelay = last.msdelay + \
985 int(last.mpt * (event.tick - last.tick))
986 last = event
987
989 if len(self) == 0:
990
991
992 def_tempo = SetTempoEvent()
993 def_tempo.tempo = 120
994
995 def_tempo.mpt = def_tempo.mpqn / 1000.0 / self.stream.resolution
996 return def_tempo
997 else:
998 last = self[0]
999 for tm in self[1:]:
1000 if tm.tick > offset:
1001 return last
1002 last = tm
1003 return last
1004
1007 self.stream = stream
1008 self.trackpool = stream.trackpool
1009 self.window_length = window
1010 self.window_edge = 0
1011 self.leftover = None
1012 self.events = self.stream.iterevents()
1013
1014
1015 self.ttpts = []
1016 for tempo in stream.tempomap[1:]:
1017 self.ttpts.append(tempo.tick)
1018
1019 self.ttpts.append(stream.endoftrack.tick)
1020 self.ttpts = iter(self.ttpts)
1021
1022 self.ttp = self.ttpts.next()
1023 self.tempomap = iter(self.stream.tempomap)
1024 self.tempo = self.tempomap.next()
1025 self.endoftrack = False
1026
1029
1031 if self.endoftrack:
1032 raise StopIteration
1033 lastedge = self.window_edge
1034 self.window_edge += int(self.window_length / self.tempo.mpt)
1035 if self.window_edge > self.ttp:
1036
1037 oldttp = self.ttp
1038 try:
1039 self.ttp = self.ttpts.next()
1040 except StopIteration:
1041
1042 self.window_edge = self.ttp
1043 self.endoftrack = True
1044 return
1045
1046
1047 msused = (oldttp - lastedge) * self.tempo.mpt
1048 msleft = self.window_length - msused
1049 self.tempo = self.tempomap.next()
1050 ticksleft = msleft / self.tempo.mpt
1051 self.window_edge = ticksleft + self.tempo.tick
1052
1054 ret = []
1055 self.__next_edge()
1056 if self.leftover:
1057 if self.leftover.tick > self.window_edge:
1058 return ret
1059 ret.append(self.leftover)
1060 self.leftover = None
1061 for event in self.events:
1062 if event.tick > self.window_edge:
1063 self.leftover = event
1064 return ret
1065 ret.append(event)
1066 return ret
1067
1070 """
1071 Class used to describe a collection of MIDI events, organized into
1072 tracks.
1073
1074 """
1076 self.format = 1
1077 self.tempomap = TempoMap(self)
1078 self._curtrack = None
1079 self.trackpool = []
1080 self.tracklist = {}
1081 self.timemap = []
1082 self.endoftracks = {}
1083 self.beatmap = []
1084 self.resolution = 220
1085 self.tracknames = {}
1086
1094
1096 return self.__resolution
1097 resolution = property(__get_resolution, __set_resolution, None,
1098 "Ticks per quarter note")
1099
1101
1102 self._curtrack = len(self)
1103 self.endoftrack = None
1104 self.tracklist[self._curtrack] = []
1105
1106
1107 if len(self) > 1:
1108 self.format = 1
1109
1111 return self._curtrack
1112
1114 return self.tracklist[tracknum]
1115
1117 return self.tracklist[self._curtrack]
1118
1122
1126
1130
1132 tracknum = self.tracklist[tracknum]
1133 self.repdeletelace_track_by_number(tracknum, track)
1134
1136 del self.tracklist[self._curtrack]
1137 self.__refresh()
1138
1140 del self.tracklist[tracknum]
1141 self.__refresh()
1142
1146
1162
1164 """
1165 Like add_event, but doesn't update the timemap after adding the event.
1166 You shouldn't usually use this, since it leaves the timemap in an
1167 inconsistent state, but it's used internally when adding a lot of
1168 events in a row. If you use it, you should ensure that _refresh_timemap
1169 gets called afterwards.
1170
1171 """
1172 if not isinstance(event, EndOfTrackEvent):
1173 event.track = self.curtrack
1174 self.trackpool.append(event)
1175 self.track.append(event)
1176 self.__adjust_endoftrack(event)
1177
1178 if isinstance(event, TrackNameEvent):
1179 self.__refresh_tracknames()
1180 if isinstance(event, SetTempoEvent):
1181 self.tempomap.add_and_update(event)
1182
1185
1187 self.trackpool.sort()
1188 for track in self.tracklist.values():
1189 track.sort()
1190
1191 - def textdump(self):
1192 for event in self.trackpool:
1193 print event
1194
1196 return iter(self.tracklist.values())
1197
1203
1204 @property
1206 """
1207 The length of the stream in midi ticks.
1208 Note that this is not the same as len(stream), which gives the
1209 number of tracks.
1210
1211 """
1212 if len(self.trackpool):
1213 return max(self.trackpool).tick
1214 else:
1215 return 0
1216
1218 return len(self.tracklist)
1219 trackcount = property(__get_trackcount)
1220
1223
1225 return self.tracklist[intkey]
1226
1232
1234 self.tracknames = {}
1235 for tracknum in self.tracklist:
1236 track = self.tracklist[tracknum]
1237 for event in track:
1238 if isinstance(event, TrackNameEvent):
1239 self.tracknames[event.data] = tracknum
1240 break
1241
1243 self.trackpool = []
1244 for track in self.tracklist.values():
1245 for event in track:
1246 self.trackpool.append(event)
1247 self.trackpool.sort()
1248
1250 self.tempomap = TempoMap(self)
1251
1252 for tracknum,track in self.tracklist.items():
1253 self.endoftracks[tracknum] = None
1254
1255 eots = []
1256 for event in track:
1257 if isinstance(event, SetTempoEvent):
1258 self.tempomap.add(event)
1259 elif isinstance(event, EndOfTrackEvent):
1260 eots.append(event)
1261
1262 eots.sort()
1263 if len(eots) > 1:
1264 for eot in eots[:-1]:
1265 track.remove(eot)
1266 self.trackpool.remove(eot)
1267 if len(eots):
1268 self.__adjust_endoftrack(eots[-1], track=tracknum)
1269 self.tempomap.update()
1270
1276 _refresh_timemap = __refresh_timemap
1277
1279 """
1280 Track defaults to the current track.
1281 The event itself is assumed to be in the track already.
1282
1283 """
1284 if track is None:
1285 track = self.curtrack
1286
1287 if self.endoftracks[track] is None:
1288 if isinstance(event, EndOfTrackEvent):
1289 eot_event = event
1290 else:
1291
1292
1293 eot_event = EndOfTrackEvent()
1294 eot_event.tick = event.tick
1295 eot_event.track = self.curtrack
1296 self.trackpool.append(eot_event)
1297 self.tracklist[track].append(eot_event)
1298 self.endoftracks[track] = eot_event
1299 else:
1300
1301 self.endoftracks[track].tick = max(event.tick+1, self.endoftracks[track].tick)
1302 if self.tempomap:
1303 tempo = self.tempomap.get_tempo(self.endoftracks[track].tick)
1304 self.endoftracks[track].adjust_msdelay(tempo)
1305
1307 return self.endoftracks[self.curtrack]
1309 self.endoftracks[self.curtrack] = eot
1310 endoftrack = property(__get_endoftrack, __set_endoftrack)
1311
1313 return self._curtrack
1315 if num not in self.tracklist:
1316 raise ValueError, "track number %d does not exist" % num
1317 self._curtrack = num
1318 curtrack = property(__get_track_num, __set_track_num,
1319 delete_current_track,
1320 """The track number of the current track""")
1321
1322 track = property(get_current_track, replace_current_track,
1323 delete_current_track,
1324 """The current track""")
1325
1327 """
1328 Remove the first occurence of an event matching the
1329 given event from the event stream. Raises a
1330 ValueError a match is not found in the stream.
1331
1332 @type track: int
1333 @param track: track number to look for the event in. If not
1334 given, all tracks are searched.
1335
1336 """
1337 if track is None:
1338 tracks = self.tracklist.values()
1339 else:
1340 tracks = [self.tracklist[track]]
1341
1342 for trck in tracks:
1343 if ev in trck:
1344 trck.remove(ev)
1345 self.__refresh()
1346 return
1347
1348 if track is None:
1349 track_mess = ""
1350 else:
1351 track_mess = ", track %d" % track
1352 raise ValueError, "remove_event: event %s not found in stream%s" % \
1353 (ev, track_mess)
1354
1356 """
1357 Removes the event instance from a stream, if it exists. Raises a
1358 ValueError a match is not found in the stream.
1359
1360 Note that this is different from L{remove_event}, which looks
1361 for a match to the argument, whereas this requires identity.
1362
1363 @type track: int
1364 @param track: track number to look for the event in. If not
1365 given, all tracks are searched.
1366
1367 """
1368 if track is None:
1369 tracks = self.tracklist.values()
1370 else:
1371 tracks = [self.tracklist[track]]
1372
1373 for trck in tracks:
1374 track_ids = [id(e) for e in trck]
1375 if id(ev) in track_ids:
1376 trck.pop(track_ids.index(id(ev)))
1377 self.__refresh()
1378 return
1379
1380 if track is None:
1381 track_mess = ""
1382 else:
1383 track_mess = ", track %d" % track
1384 raise ValueError, "remove_event: event %s not found in stream%s" % \
1385 (ev, track_mess)
1386
1388 """
1389 Has the same effect as calling L{remove_event_instance} on each members
1390 of C{evs}, but is a lot faster if removing many events in one go.
1391
1392 Note that this won't raise an exception if any of the events aren't
1393 found.
1394
1395 """
1396 remove_ids = [id(e) for e in evs]
1397
1398 for tracknum in self.tracklist.keys():
1399 self.tracklist[tracknum] = \
1400 [ev for ev in self.tracklist[tracknum] if id(ev) not in remove_ids]
1401 self.__refresh()
1402
1403 - def slice(self, start, end=None):
1406
1408 """
1409 Unimplemented. Will check for redundant messages and delete them,
1410 such as control changes that are followed by a "Reset Controllers"
1411 message before a note on.
1412
1413 """
1414 pass
1415
1417 """
1418 Takes care of writing MIDI data from an L{EventStream} to an output
1419 stream, such as a file.
1420
1421 """
1422 - def __init__(self, midistream, output):
1430
1431 - def write(cls, midistream, output):
1433 write = classmethod(write)
1434
1436
1437 packdata = pack(">LHHH", 6,
1438 self.midistream.format,
1439 self.midistream.trackcount,
1440 self.midistream.resolution)
1441 self.output.write('MThd%s' % packdata)
1442
1445
1447 buf = ''
1448 track = copy.copy(track)
1449 track.sort()
1450 last_tick = delta = 0
1451 smsg = 0
1452 chn = 0
1453 for event in track:
1454 running = (event.allow_running and (smsg == event.statusmsg) and (chn == event.channel))
1455 this_encoding=event.encode(last_tick=last_tick, running=running)
1456 buf += this_encoding
1457 last_tick = event.tick
1458
1459 if event.allow_running:
1460 smsg = event.statusmsg
1461 chn = event.channel
1462 else:
1463
1464
1465 smsg = 0
1466 chn = 0
1467 self.write_track_header(len(buf))
1468 self.output.write(buf)
1469
1471 """
1472 Reads MIDI data in from an input stream, probably a file, and
1473 produces an L{EventStream} to represent it internally.
1474
1475 """
1476 - def __init__(self, instream, outstream, force_resolution=None):
1477 self.eventfactory = None
1478 self.force_resolution = force_resolution
1479 self.parse(instream, outstream)
1480
1481 - def read(cls, instream, *args, **kwargs):
1482 if len(args) > 0:
1483 outstream = args[0]
1484 else:
1485 outstream = kwargs.pop('outstream', None)
1486 if not outstream:
1487 outstream = EventStream()
1488 cls(instream, outstream, *args, **kwargs)
1489 return outstream
1490 read = classmethod(read)
1491
1492 - def parse(self, instream, outstream):
1493 self.midistream = outstream
1494 if isinstance(instream, str):
1495 instream = open(instream)
1496 self.instream = instream
1497 if isinstance(instream, file):
1498 self.instream = StringIO(instream.read())
1499 self.cursor = 0
1500
1501 else:
1502
1503
1504 self.instream = instream
1505 self.parse_file_header()
1506 for track in range(self.tracks_to_read):
1507 trksz = self.parse_track_header()
1508 self.eventfactory = EventFactory()
1509 self.midistream.add_track()
1510 self.parse_track(trksz)
1511
1512 self.midistream._refresh_timemap()
1513
1534
1536
1537 magic = self.instream.read(4)
1538 if magic != 'MTrk':
1539 raise MidiReadError, "Bad track header in MIDI file: " + magic
1540
1541 trksz = unpack(">L", self.instream.read(4))[0]
1542 return trksz
1543
1545 track = iter(self.instream.read(trksz))
1546 while True:
1547 try:
1548 event = self.eventfactory.parse_midi_event(track)
1549
1550
1551
1552 self.midistream._add_event_without_timemap(event)
1553 except Warning, err:
1554 print "Warning: %s" % err
1555 except StopIteration:
1556 break
1557
1559 """
1560 Midi debugger. Checks through a midi event stream for things
1561 that might be wrong with it.
1562
1563 @todo: add more possible problems to the checks.
1564
1565 @type mid: L{EventStream}
1566 @param mid: midi stream to check
1567 @return: list of tuples, consisting of a string problems identifier,
1568 a descriptive message and a tuple of midi events that generated
1569 the problem.
1570
1571 """
1572 problems = []
1573 for event in mid.trackpool:
1574 if event.tick < 0:
1575
1576 problems.append(
1577 ("Negative time", "negative time value: %d" % event.tick, (event,)) )
1578 if event.msdelay < 0:
1579
1580 problems.append(
1581 ("Negative MS time", "negative millisecond time value: %s" % event.msdelay, (event,)) )
1582
1583 return problems
1584
1585 -def new_stream(tempo=120, resolution=480, format=1):
1595
1596 read_midifile = EventStreamReader.read
1597 """
1598 Reads in a MIDI file given by a file object or filename and returns
1599 an L{EventStream}.
1600 """
1601 write_midifile = EventStreamWriter.write
1602 """
1603 Writes an L{EventStream} out to a MIDI file.
1604 """
1607 """
1608 Usually raised on encountering invalid MIDI data while parsing.
1609 Some mildly bad things may be overlooked, but critical errors in
1610 the data will cause the reader to raise a MidiReadError.
1611
1612 """
1613 pass
1614
1617