def testTuningProgram(self): #import pdb; pdb.set_trace() program = 10 channel = 0 MyMIDI = MIDIFile(1) MyMIDI.changeTuningProgram(0, 0, 0, program) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].type, 'ControllerEvent') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(2), 0x65) # Controller Number self.assertEqual(data.unpack_into_byte(3), 0x0) # Controller Value self.assertEqual(data.unpack_into_byte(4), 0x00) # time self.assertEqual(data.unpack_into_byte(5), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(6), 0x64) # Controller Number self.assertEqual(data.unpack_into_byte(7), 0x03) # Controller Value self.assertEqual(data.unpack_into_byte(8), 0x00) # time self.assertEqual(data.unpack_into_byte(9), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(10), 0x06) # Bank MSB self.assertEqual(data.unpack_into_byte(11), 0x00) # Value self.assertEqual(data.unpack_into_byte(12), 0x00) # time self.assertEqual(data.unpack_into_byte(13), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(14), 0x26) # Bank LSB self.assertEqual(data.unpack_into_byte(15), program) # Bank value (bank number)
def testPitchWheel(self): val = 1000 MyMIDI = MIDIFile(1) MyMIDI.addPitchWheelEvent(0, 0, 0, val) MyMIDI.close() MSB = (val + 8192) >> 7 LSB = (val + 8192) & 0x7F data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 224) # Code self.assertEqual(data.unpack_into_byte(2), LSB) self.assertEqual(data.unpack_into_byte(3), MSB) val = -1000 MyMIDI = MIDIFile(1) MyMIDI.addPitchWheelEvent(0, 0, 0, val) MyMIDI.close() MSB = (val + 8192) >> 7 LSB = (val + 8192) & 0x7F data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 224) # Code self.assertEqual(data.unpack_into_byte(2), LSB) self.assertEqual(data.unpack_into_byte(3), MSB)
def testTuningBank(self): bank = 1 channel = 0 MyMIDI = MIDIFile(1) MyMIDI.changeTuningBank(0, 0, 0, bank) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'ControllerEvent') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(2), 0x65) # Controller Number self.assertEqual(data.unpack_into_byte(3), 0x0) # Controller Value self.assertEqual(data.unpack_into_byte(4), 0x00) # time self.assertEqual(data.unpack_into_byte(5), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(6), 0x64) # Controller Number self.assertEqual(data.unpack_into_byte(7), 0x4) # Controller Value self.assertEqual(data.unpack_into_byte(8), 0x00) # time self.assertEqual(data.unpack_into_byte(9), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(10), 0x06) # Bank MSB self.assertEqual(data.unpack_into_byte(11), 0x00) # Value self.assertEqual(data.unpack_into_byte(12), 0x00) # time self.assertEqual(data.unpack_into_byte(13), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(14), 0x26) # Bank LSB self.assertEqual(data.unpack_into_byte(15), bank) # Bank value (bank number)
def testText(self): #import pdb; pdb.set_trace() text = "2016(C) MCW" MyMIDI = MIDIFile(1) MyMIDI.addText(0, 0, text) MyMIDI.close() payload_encoded = text.encode("ISO-8859-1") payloadLength = len(payload_encoded) payloadLengthVar = writeVarLength(payloadLength) data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].type, 'Text') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xff) # Code self.assertEqual(data.unpack_into_byte(2), 0x01) # Subcode index = 3 for i in range(len(payloadLengthVar)): self.assertEqual(data.unpack_into_byte(index), payloadLengthVar[i]) index = index + 1 for i in range(len(payload_encoded)): if sys.version_info < (3, ): test_char = ord(payload_encoded[i]) else: test_char = payload_encoded[i] self.assertEqual(data.unpack_into_byte(index), test_char) index = index + 1
def testTuning(self): MyMIDI = MIDIFile(1) MyMIDI.changeNoteTuning(0, [(1, 440), (2, 880)]) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].type, 'UniversalSysEx') self.assertEqual(data.unpack_into_byte(0), 0x00) self.assertEqual(data.unpack_into_byte(1), 0xf0) self.assertEqual(data.unpack_into_byte(2), 15) self.assertEqual(data.unpack_into_byte(3), 0x7F) self.assertEqual(data.unpack_into_byte(4), 0x7F) self.assertEqual(data.unpack_into_byte(5), 0x08) self.assertEqual(data.unpack_into_byte(6), 0x02) self.assertEqual(data.unpack_into_byte(7), 0x00) self.assertEqual(data.unpack_into_byte(8), 0x2) self.assertEqual(data.unpack_into_byte(9), 0x1) self.assertEqual(data.unpack_into_byte(10), 69) self.assertEqual(data.unpack_into_byte(11), 0) self.assertEqual(data.unpack_into_byte(12), 0) self.assertEqual(data.unpack_into_byte(13), 0x2) self.assertEqual(data.unpack_into_byte(14), 81) self.assertEqual(data.unpack_into_byte(15), 0) self.assertEqual(data.unpack_into_byte(16), 0) self.assertEqual(data.unpack_into_byte(17), 0xf7)
def testTempo(self): #import pdb; pdb.set_trace() tempo = 60 MyMIDI = MIDIFile(1, file_format=2) MyMIDI.addTempo(0, 0, tempo) MyMIDI.close() data = Decoder(MyMIDI.tracks[0].MIDIdata) self.assertEqual(MyMIDI.tracks[0].MIDIEventList[0].type, 'Tempo') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xff) # Code self.assertEqual(data.unpack_into_byte(2), 0x51) self.assertEqual(data.unpack_into_byte(3), 0x03) self.assertEqual(data[4:7], struct.pack('>L', int(60000000 / tempo))[1:4]) # Also check the format 1 file tempo = 60 MyMIDI = MIDIFile(2, file_format=1) MyMIDI.addTempo(1, 0, tempo) MyMIDI.close() data = Decoder(MyMIDI.tracks[0].MIDIdata) self.assertEqual(MyMIDI.tracks[0].MIDIEventList[0].type, 'Tempo') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xff) # Code self.assertEqual(data.unpack_into_byte(2), 0x51) self.assertEqual(data.unpack_into_byte(3), 0x03) self.assertEqual(data[4:7], struct.pack('>L', int(60000000 / tempo))[1:4])
def testAdujustOrigin(self): track = 0 channel = 0 pitch = 69 time = 1 duration = 0.1 volume = 64 MyMIDI = MIDIFile(1) MyMIDI.addNote(track, channel, pitch, time, duration, volume) time = 1.1 MyMIDI.addNote(track, channel, pitch, time, duration, volume) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(data.unpack_into_byte(0), 0x00) # first time self.assertEqual(data.unpack_into_byte(8), 0x00) # seconds time MyMIDI = MIDIFile(1, adjust_origin=False) time = 0.1 MyMIDI.addNote(track, channel, pitch, time, duration, volume) time = 0.2 MyMIDI.addNote(track, channel, pitch, time, duration, volume) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(data.unpack_into_byte(0), TICKSPERBEAT / 10) # first time, should be an integer < 127 self.assertEqual(data.unpack_into_byte(8), 0x00) # first time
def testCopyright(self): notice = "2016(C) MCW" MyMIDI = MIDIFile(1) MyMIDI.addCopyright(0, 0, notice) MyMIDI.close() payload_encoded = notice.encode("ISO-8859-1") payloadLength = len(payload_encoded) payloadLengthVar = writeVarLength(payloadLength) data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'Copyright') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xff) # Code self.assertEqual(data.unpack_into_byte(2), 0x02) # Subcode index = 3 for i in range(len(payloadLengthVar)): self.assertEqual(data.unpack_into_byte(index), payloadLengthVar[i]) index = index + 1 for i in range(len(payload_encoded)): if sys.version_info < (3,): test_char = ord(payload_encoded[i]) else: test_char = payload_encoded[i] self.assertEqual(data.unpack_into_byte(index), test_char) index = index + 1
def testNRPNCallWithTimeOrder(self): #import pdb; pdb.set_trace() track = 0 time = 0 channel = 0 controller_msb = 1 controller_lsb = 2 data_msb = 3 data_lsb = 4 MyMIDI = MIDIFile(1) MyMIDI.makeNRPNCall(track, channel, time, controller_msb, controller_lsb, data_msb, data_lsb, time_order=True) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'ControllerEvent') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(2), 99) # Controller Number self.assertEqual(data.unpack_into_byte(3), controller_msb) # Controller Value self.assertEqual(data.unpack_into_byte(4), 0x01) # time self.assertEqual(data.unpack_into_byte(5), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(6), 98) # Controller Number self.assertEqual(data.unpack_into_byte(7), controller_lsb) # Controller Value self.assertEqual(data.unpack_into_byte(8), 0x01) # time self.assertEqual(data.unpack_into_byte(9), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(10), 0x06) # Bank MSB self.assertEqual(data.unpack_into_byte(11), data_msb) # Value self.assertEqual(data.unpack_into_byte(12), 0x01) # time self.assertEqual(data.unpack_into_byte(13), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(14), 0x26) # Bank LSB self.assertEqual(data.unpack_into_byte(15), data_lsb) # Bank value (bank number)
def testNonRealTimeUniversalSysEx(self): code = 1 subcode = 2 payload_number = 42 payload = struct.pack('>B', payload_number) MyMIDI = MIDIFile(1, adjust_origin=False) # Just for fun we'll use a multi-byte time time = 1 time_bytes = writeVarLength(time * MyMIDI.ticks_per_quarternote) MyMIDI.addUniversalSysEx(0, time, code, subcode, payload, realTime=False) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'UniversalSysEx') self.assertEqual(data.unpack_into_byte(0), time_bytes[0]) # Time self.assertEqual(data.unpack_into_byte(1), time_bytes[1]) # Time self.assertEqual(data.unpack_into_byte(2), 0xf0) # UniversalSysEx == 0xF0 self.assertEqual(data.unpack_into_byte(3), 5 + len(payload)) # Payload length = 5+actual pyayload self.assertEqual(data.unpack_into_byte(4), 0x7E) # 0x7E == non-realtime self.assertEqual(data.unpack_into_byte(5), 0x7F) # Sysex channel (always 0x7F) self.assertEqual(data.unpack_into_byte(6), code) self.assertEqual(data.unpack_into_byte(7), subcode) self.assertEqual(data.unpack_into_byte(8), payload_number) # Data self.assertEqual(data.unpack_into_byte(9), 0xf7) # End of message
def testTimeSignature(self): time = 0 track = 0 numerator = 4 denominator = 2 clocks_per_tick = 24 MyMIDI = MIDIFile(1, file_format=2) MyMIDI.addTimeSignature(track, time, numerator, denominator, clocks_per_tick) MyMIDI.close() data = Decoder(MyMIDI.tracks[0].MIDIdata) self.assertEqual(MyMIDI.tracks[0].MIDIEventList[0].type, 'TimeSignature') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xFF) # Code self.assertEqual(data.unpack_into_byte(2), 0x58) # subcode self.assertEqual(data.unpack_into_byte(3), 0x04) # Data length self.assertEqual(data.unpack_into_byte(4), numerator) self.assertEqual(data.unpack_into_byte(5), denominator) self.assertEqual(data.unpack_into_byte(6), clocks_per_tick) # Data length self.assertEqual(data.unpack_into_byte(7), 0x08) # 32nd notes per quarter note # We also want to check with a format 1 file, make sure it ends up in # the tempo track time = 0 track = 1 numerator = 4 denominator = 2 clocks_per_tick = 24 MyMIDI = MIDIFile(2, file_format=1) MyMIDI.addTimeSignature(track, time, numerator, denominator, clocks_per_tick) MyMIDI.close() data = Decoder(MyMIDI.tracks[0].MIDIdata) self.assertEqual(MyMIDI.tracks[0].MIDIEventList[0].type, 'TimeSignature') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xFF) # Code self.assertEqual(data.unpack_into_byte(2), 0x58) # subcode self.assertEqual(data.unpack_into_byte(3), 0x04) # Data length self.assertEqual(data.unpack_into_byte(4), numerator) self.assertEqual(data.unpack_into_byte(5), denominator) self.assertEqual(data.unpack_into_byte(6), clocks_per_tick) # Data length self.assertEqual(data.unpack_into_byte(7), 0x08) # 32nd notes per quarter note
def testSysEx(self): MyMIDI = MIDIFile(1) MyMIDI.addSysEx(0, 0, 0, struct.pack(">B", 0x01)) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, "SysEx") self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[0])[0], 0x00) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[1])[0], 0xF0) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[2])[0], 3) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[3])[0], 0x00) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[4])[0], 0x01) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[5])[0], 0xF7)
def testSysEx(self): MyMIDI = MIDIFile(1) MyMIDI.addSysEx(0,0, 0, struct.pack('>B', 0x01)) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, 'SysEx') self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[0])[0], 0x00) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[1])[0], 0xf0) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[2])[0], 3) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[3])[0], 0x00) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[4])[0], 0x01) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[5])[0], 0xf7)
def testLongTrackName(self): track_name = 'long track name ' * 8 MyMIDI = MIDIFile(1) MyMIDI.addTrackName(0, 0, track_name) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'TrackName') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xFF) # Code self.assertEqual(data.unpack_into_byte(2), 0x03) # subcodes
def testDeinterleaveNotes(self): MyMIDI = MIDIFile(1) MyMIDI.addNote(0, 0, 100, 0, 2, 100) MyMIDI.addNote(0, 0, 100, 1, 2, 100) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, "NoteOn") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].time, 0) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].type, "NoteOff") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].time, 128) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[2].type, "NoteOn") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[2].time, 0) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[3].type, "NoteOff") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[3].time, 256)
def testDeinterleaveNotes(self): MyMIDI = MIDIFile(1) MyMIDI.addNote(0, 0, 100, 0, 2, 100) MyMIDI.addNote(0, 0, 100, 1, 2, 100) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, 'NoteOn') self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].time, 0) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].type, 'NoteOff') self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].time, 960) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[2].type, 'NoteOn') self.assertEquals(MyMIDI.tracks[0].MIDIEventList[2].time, 0) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[3].type, 'NoteOff') self.assertEquals(MyMIDI.tracks[0].MIDIEventList[3].time, 1920)
def testTrackName(self): #import pdb; pdb.set_trace() track_name = "track" MyMIDI = MIDIFile(1) MyMIDI.addTrackName(0, 0, track_name) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].type, 'TrackName') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xFF) # Code self.assertEqual(data.unpack_into_byte(2), 0x03) # subcodes
def testUniversalSysEx(self): MyMIDI = MIDIFile(1) MyMIDI.addUniversalSysEx(0,0, 1, 2, struct.pack('>B', 0x01)) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, 'UniversalSysEx') self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[0])[0], 0x00) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[1])[0], 0xf0) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[2])[0], 6) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[3])[0], 0x7E) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[4])[0], 0x7F) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[5])[0], 0x01) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[6])[0], 0x02) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[7])[0], 0x01) self.assertEquals(struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[8])[0], 0xf7)
def testTuningProgramWithTimeOrder(self): program = 10 MyMIDI = MIDIFile(1) MyMIDI.changeTuningProgram(0, 0, 0, program, time_order=True) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'ControllerEvent') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(4), 0x01) # time self.assertEqual(data.unpack_into_byte(8), 0x01) # time self.assertEqual(data.unpack_into_byte(12), 0x01) # time
def testUniversalSysEx(self): MyMIDI = MIDIFile(1) MyMIDI.addUniversalSysEx(0, 0, 1, 2, struct.pack(">B", 0x01)) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, "UniversalSysEx") self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[0])[0], 0x00) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[1])[0], 0xF0) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[2])[0], 6) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[3])[0], 0x7E) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[4])[0], 0x7F) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[5])[0], 0x01) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[6])[0], 0x02) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[7])[0], 0x01) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[8])[0], 0xF7)
def testSysEx(self): MyMIDI = MIDIFile(1) MyMIDI.addSysEx(0, 0, 0, struct.pack('>B', 0x01)) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'SysEx') self.assertEqual(data.unpack_into_byte(0), 0x00) self.assertEqual(data.unpack_into_byte(1), 0xf0) self.assertEqual(data.unpack_into_byte(2), 3) self.assertEqual(data.unpack_into_byte(3), 0x00) self.assertEqual(data.unpack_into_byte(4), 0x01) self.assertEqual(data.unpack_into_byte(5), 0xf7)
def testTuningBankWithTimeOrder(self): #import pdb; pdb.set_trace() bank = 1 MyMIDI = MIDIFile(1) MyMIDI.changeTuningBank(0, 0, 0, bank, time_order=True) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'ControllerEvent') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(4), 0x01) # time self.assertEqual(data.unpack_into_byte(8), 0x01) # time self.assertEqual(data.unpack_into_byte(12), 0x01) # time
def testUnknownEventType(self): track = 0 channel = 0 pitch = 69 time = 0 duration = 1.0 volume = 64 bad_type = "bad" MyMIDI = MIDIFile(1) MyMIDI.addNote(track, channel, pitch, time, duration, volume) MyMIDI.tracks[1].eventList[0].type = bad_type with self.assertRaises(Exception) as context: MyMIDI.close() self.assertTrue(('Error in MIDITrack: Unknown event type %s' % bad_type) in str(context.exception))
def testProgramChange(self): #import pdb; pdb.set_trace() program = 10 channel = 0 MyMIDI = MIDIFile(1) MyMIDI.addProgramChange(0, channel, 0, program) MyMIDI.close() data = Decoder(MyMIDI.tracks[0].MIDIdata) self.assertEqual(MyMIDI.tracks[0].MIDIEventList[0].type, 'ProgramChange') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xC << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(2), program)
def testMultiClose(self): track = 0 channel = 0 pitch = 69 time = 0 duration = 1.0 volume = 64 MyMIDI = MIDIFile(1) MyMIDI.addNote(track, channel, pitch, time, duration, volume) MyMIDI.close() data_length_1 = len(MyMIDI.tracks[0].MIDIdata) MyMIDI.close() data_length_2 = len(MyMIDI.tracks[0].MIDIdata) self.assertEqual(data_length_1, data_length_2) MyMIDI.tracks[0].closeTrack() data_length_3 = len(MyMIDI.tracks[0].MIDIdata) self.assertEqual(data_length_1, data_length_3)
def testProgramChange(self): program = 10 channel = 0 tracknum = 0 realtracknum = tracknum time = 0.0 MyMIDI = MIDIFile(1) if MyMIDI.header.numeric_format == 1: realtracknum = tracknum + 1 MyMIDI.addProgramChange(tracknum, channel, time, program) MyMIDI.close() data = Decoder(MyMIDI.tracks[realtracknum].MIDIdata) self.assertEqual(MyMIDI.tracks[realtracknum].MIDIEventList[0].evtname, 'ProgramChange') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xC << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(2), program)
def testChannelPressure(self): pressure = 10 channel = 0 time = 0.0 tracknum = 0 realtracknum = tracknum MyMIDI = MIDIFile(1) if MyMIDI.header.numeric_format == 1: realtracknum = tracknum + 1 MyMIDI.addChannelPressure(tracknum, channel, time, pressure) MyMIDI.close() data = Decoder(MyMIDI.tracks[realtracknum].MIDIdata) self.assertEqual(MyMIDI.tracks[realtracknum].MIDIEventList[0].evtname, 'ChannelPressure') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xD0 | channel) # Code self.assertEqual(data.unpack_into_byte(2), pressure)
def testAddControllerEvent(self): track = 0 time = 0 channel = 3 controller_number = 1 parameter = 2 MyMIDI = MIDIFile(1) MyMIDI.addControllerEvent(track, channel, time, controller_number, parameter) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'ControllerEvent') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xB << 4 | channel) # Code self.assertEqual(data.unpack_into_byte(2), controller_number) # Controller Number self.assertEqual(data.unpack_into_byte(3), parameter) # Controller Value
def testTuning(self): MyMIDI = MIDIFile(1) MyMIDI.changeNoteTuning(0, [(1, 440), (2, 880)]) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, 'UniversalSysEx') self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[0])[0], 0x00) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[1])[0], 0xf0) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[2])[0], 15) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[3])[0], 0x7E) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[4])[0], 0x7F) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[5])[0], 0x08) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[6])[0], 0x02) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[7])[0], 0x00) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[8])[0], 0x2) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[9])[0], 0x1) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[10])[0], 69) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[11])[0], 0) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[12])[0], 0) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[13])[0], 0x2) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[14])[0], 81) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[15])[0], 0) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[16])[0], 0) self.assertEquals( struct.unpack('>B', MyMIDI.tracks[0].MIDIdata[17])[0], 0xf7)
def testKeySignature(self): time = 0 track = 0 accidentals = 3 accidental_type = MINOR mode = MAJOR MyMIDI = MIDIFile(1) MyMIDI.addKeySignature(track, time, accidentals, accidental_type, mode) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'KeySignature') self.assertEqual(data.unpack_into_byte(0), 0x00) # time self.assertEqual(data.unpack_into_byte(1), 0xFF) # Code self.assertEqual(data.unpack_into_byte(2), 0x59) # subcode self.assertEqual(data.unpack_into_byte(3), 0x02) # Event subtype self.assertEqual(data.unpack_into_byte(4), accidentals * accidental_type) self.assertEqual(data.unpack_into_byte(5), mode)
def testDeinterleaveNotes(self): MyMIDI = MIDIFile(1, adjust_origin=False) track = 0 channel = 0 pitch = 100 time1 = 0 time2 = 1 duration = 2 volume = 100 MyMIDI.addNote(track, channel, pitch, time1, duration, volume) # on at 0 off at 2 MyMIDI.addNote(track, channel, pitch, time2, duration, volume+1) # on at 1 off at 3 MyMIDI.close() # ticks have already been converted to delta ticks self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'NoteOn') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].tick, MyMIDI.time_to_ticks(time1)) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].evtname, 'NoteOff') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].tick, MyMIDI.time_to_ticks(time2)) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[2].evtname, 'NoteOn') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[2].tick, MyMIDI.time_to_ticks(time2 - time2)) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[3].evtname, 'NoteOff') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[3].tick, MyMIDI.time_to_ticks(time2 - time2 + duration))
def testTimeShift(self): # With one track MyMIDI = MIDIFile(1) MyMIDI.addNote(0, 0, 100, 5, 1, 100) MyMIDI.close() self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].type, 'NoteOn') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].time, 0) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].type, 'NoteOff') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].time, TICKSPERBEAT) # With two tracks MyMIDI = MIDIFile(2) MyMIDI.addNote(0, 0, 100, 5, 1, 100) MyMIDI.addNote(1, 0, 100, 6, 1, 100) MyMIDI.close() self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].type, 'NoteOn') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].time, 0) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].type, 'NoteOff') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].time, TICKSPERBEAT) self.assertEqual(MyMIDI.tracks[2].MIDIEventList[0].type, 'NoteOn') self.assertEqual(MyMIDI.tracks[2].MIDIEventList[0].time, TICKSPERBEAT) self.assertEqual(MyMIDI.tracks[2].MIDIEventList[1].type, 'NoteOff') self.assertEqual(MyMIDI.tracks[2].MIDIEventList[1].time, TICKSPERBEAT) # Negative Time MyMIDI = MIDIFile(1) MyMIDI.addNote(0, 0, 100, -5, 1, 100) MyMIDI.close() self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].type, 'NoteOn') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].time, 0) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].type, 'NoteOff') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].time, TICKSPERBEAT) # Negative time, two tracks MyMIDI = MIDIFile(2) MyMIDI.addNote(0, 0, 100, -1, 1, 100) MyMIDI.addNote(1, 0, 100, 0, 1, 100) MyMIDI.close() self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].type, 'NoteOn') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].time, 0) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].type, 'NoteOff') self.assertEqual(MyMIDI.tracks[1].MIDIEventList[1].time, TICKSPERBEAT) self.assertEqual(MyMIDI.tracks[2].MIDIEventList[0].type, 'NoteOn') self.assertEqual(MyMIDI.tracks[2].MIDIEventList[0].time, TICKSPERBEAT) self.assertEqual(MyMIDI.tracks[2].MIDIEventList[1].type, 'NoteOff') self.assertEqual(MyMIDI.tracks[2].MIDIEventList[1].time, TICKSPERBEAT)
def testTimeShift(self): # With one track MyMIDI = MIDIFile(1) MyMIDI.addNote(0, 0, 100, 5, 1, 100) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, "NoteOn") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].time, 0) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].type, "NoteOff") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].time, 128) # With two tracks MyMIDI = MIDIFile(2) MyMIDI.addNote(0, 0, 100, 5, 1, 100) MyMIDI.addNote(1, 0, 100, 6, 1, 100) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, "NoteOn") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].time, 0) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].type, "NoteOff") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].time, 128) self.assertEquals(MyMIDI.tracks[1].MIDIEventList[0].type, "NoteOn") self.assertEquals(MyMIDI.tracks[1].MIDIEventList[0].time, 128) self.assertEquals(MyMIDI.tracks[1].MIDIEventList[1].type, "NoteOff") self.assertEquals(MyMIDI.tracks[1].MIDIEventList[1].time, 128) # Negative Time MyMIDI = MIDIFile(1) MyMIDI.addNote(0, 0, 100, -5, 1, 100) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, "NoteOn") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].time, 0) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].type, "NoteOff") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].time, 128) # Negative time, two tracks MyMIDI = MIDIFile(2) MyMIDI.addNote(0, 0, 100, -1, 1, 100) MyMIDI.addNote(1, 0, 100, 0, 1, 100) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, "NoteOn") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].time, 0) self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].type, "NoteOff") self.assertEquals(MyMIDI.tracks[0].MIDIEventList[1].time, 128) self.assertEquals(MyMIDI.tracks[1].MIDIEventList[0].type, "NoteOn") self.assertEquals(MyMIDI.tracks[1].MIDIEventList[0].time, 128) self.assertEquals(MyMIDI.tracks[1].MIDIEventList[1].type, "NoteOff") self.assertEquals(MyMIDI.tracks[1].MIDIEventList[1].time, 128)
def testTuning(self): MyMIDI = MIDIFile(1) MyMIDI.changeNoteTuning(0, [(1, 440), (2, 880)]) MyMIDI.close() self.assertEquals(MyMIDI.tracks[0].MIDIEventList[0].type, "UniversalSysEx") self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[0])[0], 0x00) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[1])[0], 0xF0) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[2])[0], 15) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[3])[0], 0x7E) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[4])[0], 0x7F) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[5])[0], 0x08) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[6])[0], 0x02) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[7])[0], 0x00) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[8])[0], 0x2) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[9])[0], 0x1) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[10])[0], 69) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[11])[0], 0) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[12])[0], 0) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[13])[0], 0x2) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[14])[0], 81) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[15])[0], 0) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[16])[0], 0) self.assertEquals(struct.unpack(">B", MyMIDI.tracks[0].MIDIdata[17])[0], 0xF7)
def testRealTimeUniversalSysEx(self): code = 1 subcode = 2 payload_number = 47 payload = struct.pack('>B', payload_number) MyMIDI = MIDIFile(1) MyMIDI.addUniversalSysEx(0, 0, code, subcode, payload, realTime=True) MyMIDI.close() data = Decoder(MyMIDI.tracks[1].MIDIdata) self.assertEqual(MyMIDI.tracks[1].MIDIEventList[0].evtname, 'UniversalSysEx') self.assertEqual(data.unpack_into_byte(0), 0x00) self.assertEqual(data.unpack_into_byte(1), 0xf0) self.assertEqual(data.unpack_into_byte(2), 5 + len(payload)) self.assertEqual(data.unpack_into_byte(3), 0x7F) # 0x7F == real-time self.assertEqual(data.unpack_into_byte(4), 0x7F) self.assertEqual(data.unpack_into_byte(5), code) self.assertEqual(data.unpack_into_byte(6), subcode) self.assertEqual(data.unpack_into_byte(7), payload_number) self.assertEqual(data.unpack_into_byte(8), 0xf7)
class MidiManager(object): MidiPortName = "MIDIphon" def __init__(self, midiPhonConfig): super(MidiManager, self).__init__() self.midiPhonConfig = midiPhonConfig self.midiChannels = {} self.oldPlayers = {} self.availableChannels = range(1, self.midiPhonConfig.NumMidiChannels + 1) self.mout = rtmidi.RtMidiOut() # self.min = rtmidi.RtMidiIn() # self.min.openVirtualPort(MidiManager.MidiPortName) # self.mout.openVirtualPort(MidiManager.MidiPortName) self.midiPort = -1 for i in xrange(0, self.mout.getPortCount()): name = self.mout.getPortName(i) print ("Port {0} is named {1}".format(i, name)) if name == ("IAC Driver " + MidiManager.MidiPortName): self.midiPort = i break if self.midiPort == -1: raise Exception("You need to have a virtual midi port named 'MIDIphon'") self.mout.openPort(self.midiPort) self.startedPlaying = False self.initialTime = time.clock() # for i in range(0, self.mout.getPortCount()): # if self.mout.getPortName(i) == MidiManager.MidiPortName: # self.midiPort = i # break # if self.midiPort == -1: # raise Exception('Epic failure of finding midi channel I just opened.') self.twilio_client = TwilioRestClient( account=self.midiPhonConfig.TwilioAppSid, token=self.midiPhonConfig.TwilioApiToken ) def releaseMidi(self): self.mout.closePort() def uploadMidiFile(self, filename): print "Uploading midi file" ftp = ftplib.FTP("midiphon.bartnett.com", "midiphon_uploader", "grantophone") mf = open(filename) ftp.storbinary("STOR midiphon.bartnett.com/" + filename, mf) mf.close() print "Done storing midi file" if self.midiPhonConfig.BitlyApiToken: link = self.getBitlyLink("http://midiphon.bartnett.com/" + str(filename)) print "GOT LINK: " + link self.sendBitlyLink(link) print "SMS Sent!" else: print "Not Bit.ly api token specified, not sending out the link to midi file." def getBitlyLink(self, url): print "Opening bitly connection" connect = Connection("midiphon", self.midiPhonConfig.BitlyApiToken) print "Shortening URL" short = connect.shorten(url) print "Done shortening URL" return short["url"] def sendBitlyLink(self, link): for p in self.oldPlayers: self.twilio_client.sms.messages.create( to=p, from_="13866434928", body=("Listen to your performance at " + link) ) self.oldPlayers.clear() self.startedPlaying = False def setNumMidiChannels(numChannels): if not self.startedPlaying: if numChannels <= 16: self.availableChannels = range(1, numChannels + 1) else: print "Error: limit is 16 channels" return False else: print "Error, can't change number of midi channels in the middle of a session." def addPlayer(self, phone): if not self.startedPlaying: self.startedPlaying = True self.midiFile = MIDIFile(self.midiPhonConfig.NumMidiChannels) for i in range(0, self.midiPhonConfig.NumMidiChannels): self.midiFile.addTrackName(i, 0, str(i)) self.midiFile.addTempo(i, 0, 60) if self.midiChannels.has_key(phone): return True channelCount = len(self.availableChannels) if channelCount > 0: self.midiChannels[phone] = PhoneMusician( phone, self.availableChannels.pop(random.randint(1, channelCount) - 1) ) print "Adding player#" + phone return True return False def removePlayer(self, phone): if self.midiChannels.has_key(phone): player = self.midiChannels.pop(phone) channelNumber = player.midiChannel print "Removing player {0} with midi channel {1}".format(phone, channelNumber) self.availableChannels.append(channelNumber) self.oldPlayers[phone] = player if len(self.midiChannels) < 1: fn = str(uuid.uuid1()) + ".mid" f = open(fn, "wb") self.midiFile.writeFile(f) f.close() self.midiFile.close() self.uploadMidiFile(fn) def playNote(self, phone, digit): if self.midiChannels.has_key(phone): player = self.midiChannels[phone] msg = player.getNoteOnMessage(digit) if msg: noteLength = 1.5 elapsedTime = (time.clock() - self.initialTime) * 60.0 try: self.midiFile.addNote( player.getMidiChannel() - 1, player.getMidiChannel() - 1, msg.getNoteNumber(), elapsedTime, noteLength, 127, ) print "Sending midi message: channel={0} note={1} vel={2}".format( msg.getChannel(), msg.getNoteNumber(), msg.getVelocity() ) self.mout.sendMessage(msg) t = threading.Timer(noteLength, self.stopNote, [phone, digit]) t.start() except IndexError: print "Error adding midi note" print "PlayerInfo: MidiChannel: {0} MidiNote: {1}".format( player.getMidiChannel(), msg.getNoteNumber() ) return False return True def stopNote(self, phone, digit): if self.midiChannels.has_key(phone): player = self.midiChannels[phone] elif self.oldPlayers.has_key(phone): player = self.oldPlayers[phone] else: player = None if player: msg = player.getNoteOffMessage(digit) if msg: print "Sending midi message: channel={0} note={1}".format(msg.getChannel(), msg.getNoteNumber()) self.mout.sendMessage(msg)