def test_meta_messages_with_length_0(): """sequence_number and midi_port with no data bytes should be accepted. In rare cases these messages have length 0 and thus no data bytes. (See issues 42 and 93.) It is unclear why these messages are missing their data. It could be cased by a bug in the software that created the files. So far this has been fixed by adding a test to each of these two meta message classes. If the problem appears with other message types it may be worth finding a more general solution. """ mid = read_file(HEADER_ONE_TRACK + """ 4d 54 72 6b # MTrk 00 00 00 17 00 ff 00 00 # sequence_number with no data bytes (should be 2). 00 ff 21 00 # midi_port with no data bytes (should be 1). 00 ff 00 02 00 01 # sequence_number with correct number of data bytes (2). 00 ff 21 01 01 # midi_port with correct number of data bytes (1). 00 ff 2f 00 """) assert mid.tracks[0] == [ MetaMessage('sequence_number', number=0), MetaMessage('midi_port', port=0), MetaMessage('sequence_number', number=1), MetaMessage('midi_port', port=1), MetaMessage('end_of_track'), ]
def test_track_name(): name1 = MetaMessage('track_name', name='name1') name2 = MetaMessage('track_name', name='name2') # The track should use the first name it finds. track = MidiTrack([name1, name2]) assert track.name == name1.name
def test_meta_messages(): # TODO: should this raise IOError? mid = read_file(HEADER_ONE_TRACK + """ 4d 54 72 6b # MTrk 00 00 00 0c # Chunk size 00 ff 03 04 54 65 73 74 # track_name name='Test' 00 ff 2f 00 # end_of_track """) track = mid.tracks[0] assert track[0] == MetaMessage('track_name', name='Test') assert track[1] == MetaMessage('end_of_track')
def merge_tracks(self, tracks, ticks_per_beat): """Returns a MidiTrack object with all messages from all tracks. The messages are returned in playback order with delta times as if they were all in one track. """ messages = [] for track in tracks: messages.extend(_to_abstime(track)) aux_msgs = list() print("Preload amt {} and common tone {}".format(self.preload_chord_amt, self.common_chord_tone_amt)) for msg in messages: if (self.preload_chord_amt > 0.0 or self.common_chord_tone_amt > 0.0) and msg.type == 'lyrics' and msg.time >= ticks_per_beat * self.preload_chord_amt: # push lyrics back a bit if self.common_chord_tone_amt > 0.0: m = MetaMessage(type='marker', time = msg.time - ticks_per_beat*self.common_chord_tone_amt, text=msg.text) aux_msgs.append(m) if self.preload_chord_amt > 0.0: msg.time -= ticks_per_beat * self.preload_chord_amt messages += aux_msgs messages.sort(key=lambda msg: msg.time) return MidiTrack(fix_end_of_track(_to_reltime(messages)))
def test_midifile_repr(): midifile = MidiFile(type=1, ticks_per_beat=123, tracks=[ MidiTrack([ Message('note_on', channel=1, note=2, time=3), Message('note_off', channel=1, note=2, time=3)]), MidiTrack([ MetaMessage('sequence_number', number=5), Message('note_on', channel=2, note=6, time=9), Message('note_off', channel=2, note=6, time=9)]), ]) midifile_eval = eval(repr(midifile)) for track, track_eval in zip(midifile.tracks, midifile_eval.tracks): for m1, m2 in zip(track, track_eval): assert m1 == m2
def test_copy_cant_override_type(): with pytest.raises(ValueError): MetaMessage('track_name').copy(type='end_of_track')
def test_copy_invalid_argument(): with pytest.raises(ValueError): MetaMessage('track_name').copy(a=1)
def test_meta_message_repr(): msg = MetaMessage('end_of_track', time=10) msg_eval = eval(repr(msg)) assert msg == msg_eval
def test_key_signature(self, input_bytes, expect_sig): msg = MetaMessage('key_signature') MetaSpec_key_signature().decode(msg, input_bytes) assert msg.key == expect_sig
def test_bad_key_sig_throws_key_signature_error(self, bad_key_sig): with pytest.raises(KeySignatureError): MetaSpec_key_signature().decode(MetaMessage('key_signature'), bad_key_sig)