#!/usr/bin/env python2 import sys import midi CLOCK = 1000000.0 mid = midi.read_midifile(sys.argv[1]) MIDIOFF = 24 print "// Music data" print print "const uint16_t note_wl[] __attribute__ ((section(\".text;\"))) = {" notes = range(0, 64) wls = [0] + [int(CLOCK / (2 ** ((n + MIDIOFF + 1 - 69) / 12.0) * 440)) for n in notes] print " " + ", ".join(["0x%04x" % wl for wl in wls]) print "};" print data = [] channel = [0, 0, 0] on = set() combined = [] i = 0 for track in mid: i += 1 if i == 10: continue t = 0 for ev in track: combined.append([t, ev]) t += ev.tick combined.sort(lambda a, b: cmp(a[0], b[0])) for i in range(0, len(combined)): if i < len(combined) - 1: combined[i][1].tick = combined[i+1][0] - combined[i][0] tempo = 120 for ev in combined: if ev[1].name == "Set Tempo": tempo = ev[1].bpm break tpb = (60.0 * 1000000.0 / float(tempo)) / mid.resolution tpb *= 0.8 print "const int32_t ticks_per_beat = %s;" % int(tpb); print buf = [] for mev in (x[1] for x in combined): if mev.tick: prevon = set(on) restart = set() for ev in buf: if ev.name in ["Note On", "Note Off"]: note = ev.data[0] - MIDIOFF if note <= 0 or note > 63: print "// RANGE" continue if ev.name == "Note On": on.add(note) restart.add(note) else: on.discard(note) tlist = list(on) tlist.sort() while len(tlist) > 3: del tlist[1] on = set(tlist) #print "// " + repr(tlist) add = list(on - prevon) for note in restart: for i in range(0, len(channel)): if channel[i] == note: # restart channel data.append((i + 1) << 6 | note) break for note in prevon - on: for i in range(0, len(channel)): if channel[i] == note: if len(add): print "// " + str(i) + " " + str(add[0]) channel[i] = add[0] data.append((i + 1) << 6 | add[0]) del add[0] else: channel[i] = 0 data.append((i + 1) << 6) break else: print "// WAT" for note in add: for i in range(0, len(channel)): if channel[i] == 0: channel[i] = note data.append((i + 1) << 6 | note) break else: print "// WAT" #print "// -> " + repr(channel) tick = mev.tick #print "// -- %s ticks" % tick while tick > 63: data.append(63) tick -= 63; if tick > 0: data.append(tick) buf = [mev] else: buf.append(mev) if len(data) > 7000: break print "const uint8_t music[] __attribute__ ((section(\".text;\"))) = {" print " " + ", ".join(["0x%02x" % d for d in data]) print "};" print "// " + str(len(data)) + " bytes"