1
2
3 from MidiOutStream import MidiOutStream
4 from RawOutstreamFile import RawOutstreamFile
5
6 from constants import *
7 from DataTypeConverters import fromBytes, writeVar
8
10
11
12 """
13 MidiOutFile is an eventhandler that subclasses MidiOutStream.
14 """
15
16
21
22
25
26
28 """
29 Writes the slice of an event to the current track. Correctly
30 inserting a varlen timestamp too.
31 """
32 trk = self._current_track_buffer
33 trk.writeVarLen(self.rel_time())
34 trk.writeSlice(slc)
35
36
37
38
39
40
41 - def note_on(self, channel=0, note=0x40, velocity=0x40):
42
43 """
44 channel: 0-15
45 note, velocity: 0-127
46 """
47 slc = fromBytes([NOTE_ON + channel, note, velocity])
48 self.event_slice(slc)
49
50
51 - def note_off(self, channel=0, note=0x40, velocity=0x40):
52
53 """
54 channel: 0-15
55 note, velocity: 0-127
56 """
57 slc = fromBytes([NOTE_OFF + channel, note, velocity])
58 self.event_slice(slc)
59
60
61 - def aftertouch(self, channel=0, note=0x40, velocity=0x40):
69
70
79
80
81
82
91
92
101
102
104
105 """
106 channel: 0-15
107 value: 0-16383
108 """
109 msb = (value>>7) & 0xFF
110 lsb = value & 0xFF
111 slc = fromBytes([PITCH_BEND + channel, msb, lsb])
112 self.event_slice(slc)
113
114
115
116
117
118
119
120
121
122
123
124
132
133
134
135
136
138 """
139 msg_type: 0-7
140 values: 0-15
141 """
142 value = (msg_type<<4) + values
143 self.event_slice(fromBytes([MIDI_TIME_CODE, value]))
144
145
154
155
162
163
170
171
172
173
174
176
177 """
178 format: type of midi file in [0,1,2]
179 nTracks: number of tracks. 1 track for type 0 file
180 division: timing division ie. 96 ppq.
181
182 """
183 raw = self.raw_out
184 raw.writeSlice('MThd')
185 bew = raw.writeBew
186 bew(6, 4)
187 bew(format, 2)
188 bew(nTracks, 2)
189 bew(division, 2)
190
191
193
194 """
195 End of file. No more events to be processed.
196 """
197
198 self.write()
199
200
201
202
203
204
210
211
217
218
220 """
221 n_track: number of track
222 """
223 self._current_track_buffer = RawOutstreamFile()
224 self.reset_time()
225 self._current_track += 1
226
227
241
242
243
250
251
252 - def text(self, text):
253 """
254 Text event
255 text: string
256 """
257 self.meta_slice(TEXT, text)
258
259
267
268
275
276
283
284
291
292
299
300
307
308
310
311 """
312 channel: midi channel for subsequent data
313 (deprecated in the spec)
314 """
315 self.meta_slice(MIDI_CH_PREFIX, chr(channel))
316
317
324
325
327
328 """
329 value: 0-2097151
330 tempo in us/quarternote
331 (to calculate value from bpm: int(60,000,000.00 / BPM))
332 """
333 hb, mb, lb = (value>>16 & 0xff), (value>>8 & 0xff), (value & 0xff)
334 self.meta_slice(TEMPO, fromBytes([hb, mb, lb]))
335
336
337 - def smtp_offset(self, hour, minute, second, frame, framePart):
338
339 """
340 hour,
341 minute,
342 second: 3 bytes specifying the hour (0-23), minutes (0-59) and
343 seconds (0-59), respectively. The hour should be
344 encoded with the SMPTE format, just as it is in MIDI
345 Time Code.
346 frame: A byte specifying the number of frames per second (one
347 of : 24, 25, 29, 30).
348 framePart: A byte specifying the number of fractional frames,
349 in 100ths of a frame (even in SMPTE-based tracks
350 using a different frame subdivision, defined in the
351 MThd chunk).
352 """
353 self.meta_slice(SMTP_OFFSET, fromBytes([hour, minute, second, frame, framePart]))
354
355
356
358
359 """
360 nn: Numerator of the signature as notated on sheet music
361 dd: Denominator of the signature as notated on sheet music
362 The denominator is a negative power of 2: 2 = quarter
363 note, 3 = eighth, etc.
364 cc: The number of MIDI clocks in a metronome click
365 bb: The number of notated 32nd notes in a MIDI quarter note
366 (24 MIDI clocks)
367 """
368 self.meta_slice(TIME_SIGNATURE, fromBytes([nn, dd, cc, bb]))
369
370
371
372
374
375 """
376 sf: is a byte specifying the number of flats (-ve) or sharps
377 (+ve) that identifies the key signature (-7 = 7 flats, -1
378 = 1 flat, 0 = key of C, 1 = 1 sharp, etc).
379 mi: is a byte specifying a major (0) or minor (1) key.
380 """
381 self.meta_slice(KEY_SIGNATURE, fromBytes([sf, mi]))
382
383
384
386
387 """
388 data: The data as byte values
389 """
390 self.meta_slice(SEQUENCER_SPECIFIC, data)
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410 if __name__ == '__main__':
411
412 out_file = 'test/midifiles/midiout.mid'
413 midi = MidiOutFile(out_file)
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429 midi.header(0, 1, 480)
430
431 midi.start_of_track()
432 midi.sequence_name('Type 0')
433 midi.tempo(750000)
434 midi.time_signature(4, 2, 24, 8)
435 ch = 0
436 for i in range(127):
437 midi.note_on(ch, i, 0x64)
438 midi.update_time(96)
439 midi.note_off(ch, i, 0x40)
440 midi.update_time(0)
441
442 midi.update_time(0)
443 midi.end_of_track()
444
445 midi.eof()
446
447
448 midi.write()
449