Created
July 3, 2014 11:03
-
-
Save miettal/2c8c7630413959f477af to your computer and use it in GitHub Desktop.
midi_test2.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# coding:utf-8 | |
# | |
# midi_test.py | |
# | |
# Author: Hiromasa Ihara (miettal) | |
# URL: http://miettal.com | |
# License: MIT License | |
# Created: 2014-06-05 | |
import subprocess | |
import time | |
def midi_play(filename, callback) : | |
with open(filename) as f : | |
data = map(ord, f.read()) | |
header = data[:4+4+6] | |
format_ = (header[6]<<8)+header[7] | |
track_num = (header[8]<<8)+header[9] | |
resolution = (header[12]<<8)+header[13] | |
print """header: | |
format:{} | |
track_num:{} | |
resolution:{}""".format(format_, track_num, resolution) | |
i = 14 | |
tracks = [] | |
while i < len(data) : | |
track_len = (data[i+4]<<24)+(data[i+5]<<16)+(data[i+6]<<8)+data[i+7] | |
next_i = i+track_len+8 | |
tracks.append(data[i+8:next_i]) | |
i = next_i | |
for track in tracks : | |
i = 0 | |
while i < len(track) : | |
#parse deltatime | |
deltatime = 0 | |
while True : | |
data = track[i] | |
i += 1 | |
deltatime <<= 7 | |
deltatime += data&0x7f | |
if ((data>>7) & 1) == 0: break | |
print "deltatime:", | |
print deltatime | |
try : | |
duration_us = float(deltatime)/float(resolution)*float(tempo) | |
except NameError : | |
duration_us = 0.0 | |
if (track[i]&0xf0) == 0xf0 : | |
# meta event | |
if (track[i]&0x0f) == 0x0f : | |
i += 1 | |
event_type = track[i] | |
i += 1 | |
event_len = track[i] | |
i += 1 | |
event_data = track[i:i+event_len] | |
i += event_len | |
if event_type == 0x08 : | |
print "program name:", | |
print ''.join(map(chr, event_data)) | |
elif event_type == 0x03 : | |
print "seqence name:", | |
print ''.join(map(chr, event_data)) | |
elif event_type == 0x02 : | |
print "copyright:", | |
print ''.join(map(chr, event_data)) | |
elif event_type == 0x01 : | |
print "text:", | |
print ''.join(map(chr, event_data)) | |
elif event_type == 0x2f : | |
i += 1 | |
print "track end:" | |
elif event_type == 0x51 : | |
tempo = (event_data[0]<<16) + (event_data[1]<<8) + event_data[2] | |
print "tempo:{}".format(tempo) | |
elif event_type == 0x58 : | |
nn = event_data[0] | |
dd = event_data[1] | |
bb = event_data[2] | |
cc = event_data[3] | |
print "hyoshi:{}/{}".format(nn, 2**dd) | |
elif event_type == 0x59 : | |
sf = event_data[0] | |
mi = event_data[1] | |
print "tyogo:", sf, mi | |
elif event_type == 0x7f: | |
origin_event = event_data[1:] | |
print "origin event:", origin_event | |
else : | |
print "unknown meta event:", | |
print hex(event_type), | |
print event_data | |
# SysEx event | |
else : | |
sysex_type = track[i] | |
i += 1 | |
event_len = track[i] | |
i += 1 | |
event_data = track[i:i+event_len] | |
i += event_len | |
if sysex_type == 0xF0 : | |
print "F0 SysEx :", | |
print event_data | |
elif sysex_type == 0xF7 : | |
print "F7 SysEx :", | |
print event_data | |
else : | |
print "unknown SysEx event:", | |
print map(hex, track[i:i+8]) | |
# midi event | |
else : | |
if (track[i]&0x80) == 0x80 : | |
status_byte = track[i] | |
i += 1 | |
else : | |
pass | |
n = status_byte&0x0f | |
if (status_byte&0xf0) == 0x80 : | |
kk = track[i] | |
i += 1 | |
vv = track[i] | |
i += 1 | |
print """note off: | |
n:{} | |
kk:{} | |
vv:{}""".format(n,kk,vv) | |
freq = 440.0 * pow(2.0, (kk - 69.0) / 12.0) | |
callback(0, duration_us) | |
elif (status_byte&0xf0) == 0x90 : | |
kk = track[i] | |
i += 1 | |
vv = track[i] | |
i += 1 | |
print """note on: | |
n:{} | |
kk:{} | |
vv:{}""".format(n,kk,vv) | |
freq = 440.0 * pow(2.0, (kk - 69.0) / 12.0) | |
callback(freq, duration_us) | |
elif (status_byte&0xf0) == 0xa0 : | |
kk = track[i] | |
i += 1 | |
vv = track[i] | |
i += 1 | |
print """polifonic keep pressure: | |
n:{} | |
kk:{} | |
vv:{}""".format(n,kk,vv) | |
freq = 440.0 * pow(2.0, (kk - 69.0) / 12.0) | |
callback(0, tempo*(1/32.0)) | |
callback(freq, duration_us-tempo*(1/32.0)) | |
elif (status_byte&0xf0) == 0xb0 : | |
cc = track[i] | |
i += 1 | |
vv = track[i] | |
i += 1 | |
print """control change: | |
n:{} | |
cc:{} | |
vv:{}""".format(n,cc,vv) | |
try : | |
freq = 440.0 * pow(2.0, (kk - 69.0) / 12.0) | |
callback(freq, duration_us) | |
except NameError : | |
pass | |
elif (status_byte&0xf0) == 0xc0 : | |
pp = track[i] | |
i += 1 | |
print """program change: | |
n:{} | |
pp:{}""".format(n,pp) | |
elif (status_byte&0xf0) == 0xe0 : | |
mm = track[i] | |
i += 1 | |
ll = track[i] | |
i += 1 | |
print """pitch bend: | |
n:{} | |
mm:{} | |
ll:{}""".format(n,mm,ll) | |
else : | |
print "unknown midi event:", | |
print hex(status_byte), map(hex, track[i:i+8]) | |
if __name__ == '__main__': | |
def callback(freq, duration_us) : | |
if 0 < freq: | |
p = subprocess.Popen(["beep", "-l", str(duration_us/1000.0), "-f", str(freq)]) | |
p.wait() | |
else : | |
time.sleep(duration_us/1000.0/1000.0) | |
midi_play("./20111219165842b4a.mid", callback) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment