#!/usr/bin/python3 import sys, os, mido DEFAULT_ENV = { "sampling": 16000, "signed": True, "verbose": False, "bits": 16, "msbfirst": True, "tempo": 130 } FP = sys.stdout class SoundEncoder: def __init__(self, env=DEFAULT_ENV, fp=sys.stdout, fp_log=sys.stderr): self.env = env self.fp = fp if fp.mode == "wb" else os.fdopen(fp.fileno(), 'wb') self.fp_log = fp_log def write_sample(self, amplitude): smax = 2**(self.env["bits"]-self.env["signed"])-1 if self.env["signed"]: v = int(amplitude*smax) w = v s = v < 0 v = abs(v) if s: v = smax-v v |= (s<<(self.env["bits"]-1)) else: v = int((amplitude*smax+smax)/2) w = v if self.env["msbfirst"]: i = 0 while i < self.env["bits"]: if self.fp.write(bytes([(v>>i)&255])) > 1: self.fp_log.write(str(v)) b = bin((v>>i)&255)[2:] if self.env["verbose"]: self.fp_log.write("0"*(8-len(b))+b) i += 8 else: i = self.env["bits"] while i > 0: i -= 8 self.fp.write(bytes([(v>>i)&255])) b = bin((v>>i)&255)[2:] if self.env["verbose"]: self.fp_log.write("0"*(8-len(b))+b) if self.env["verbose"]: self.fp_log.write(" "+"0"*(self.env["bits"]-len(bin(v))+2)+bin(v)[2:]+" "+str(v)+" "+str(w)+"\n") class Event: def __init__(self, type): self.type = type class Wait(Event): def __init__(self, value): Event.__init__(self, Wait) self.value = value def dict(self): return { "type": "wait", "number": self.value, } class End(Event): def __init__(self): Event.__init__(self, End) def dict(self): return { "type": "end" } class Note(Event): def __init__(self, number, velocity, channel=0, track=0): Event.__init__(self, Note) self.number = number self.velocity = velocity self.channel = channel self.track = track def dict(self): return { "type": "note", "number": self.number, "velocity": self.velocity, "channel": self.channel } def midi(): return from_midi3(sys.argv[1]) def from_midi(filename, env=DEFAULT_ENV): result = [] t = 0 tempo = env["tempo"] mid = mido.MidiFile(filename) for i, track in enumerate(mid.tracks): for msg in track: if msg.type == "set_tempo": tempo = 6e7/msg.tempo elif msg.type == "note_on": if msg.time != 0: result.append(Wait(msg.time/tempo/4)) result.append(Note(msg.note-50, msg.velocity/100, msg.channel)) elif msg.type == "end_of_track": result.append(Wait(msg.time/tempo/4)) result.append(End()) return result def from_midi2(filename, env=DEFAULT_ENV): mid = mido.MidiFile(filename) result = [] tracks = [0 for i in mid.tracks] tempos = [env["tempo"] for i in mid.tracks] wait = [None for i in mid.tracks] end = [True for i in mid.tracks] t = 0 loop = True while loop: loop = False for i, track in enumerate(mid.tracks): if end[i]: loop = True continue if wait[i] == None: wait[i] = track[tracks[i]].time/tempos[i]/4 #result.append(Wait(track[tracks[i]].time/tempo/4)) if wait[i] <= 0: msg = track[tracks[i]] if t > 0: result.append(Wait(t)) t = 0 if msg.type == "set_tempo": tempos[i] = 6e7/msg.tempo elif msg.type == "note_on": result.append(Note(msg.note-50, msg.velocity/100, msg.channel, i)) elif msg.type == "end_of_track": result.append(End()) end[i] = False tracks[i] += 1 if len(track) > tracks[i]: wait[i] = track[tracks[i]].time/tempos[i]/4 else: wait[i] -= 1 print(t) t += 1 print(result) exit() return result def from_midi3(filename, env=DEFAULT_ENV): mid = mido.MidiFile(filename) result = [] tracks = [0 for i in mid.tracks] tempo = [env["tempo"] for i in mid.tracks] wait = [None for i in mid.tracks] end = [False for i in mid.tracks] t = 0 loop = True while loop: loop = False # Find the first events first = [] firstt = None for i, track in enumerate(mid.tracks): if end[i]: continue if wait[i] == None: wait[i] = track[tracks[i]].time/tempo[i]/4 if firstt == None or wait[i] < firstt: firstt = wait[i] first = [i] elif wait[i] == firstt: first.append(i) if firstt > 0: result.append(Wait(firstt)) # Play the first events for i, track in enumerate(mid.tracks): if end[i]: continue loop = True msg = track[tracks[i]] if i in first: # Play event if msg.type == "set_tempo": tempo[i] = 6e7/msg.tempo elif msg.type == "note_on": result.append(Note(msg.note-50, msg.velocity/100, msg.channel, i)) elif msg.type == "end_of_track": result.append(End()) end[i] = True # Find next event tracks[i] += 1 wait[i] = None else: wait[i] -= firstt if not (False in end): loop = False ### """loop = False for i, track in enumerate(mid.tracks): if end[i]: loop = True continue if wait[i] == None: wait[i] = track[tracks[i]].time/tempo[i]/4 #result.append(Wait(track[tracks[i]].time/tempo/4)) if wait[i] <= 0: msg = track[tracks[i]] if t > 0: result.append(Wait(t)) t = 0 if msg.type == "set_tempo": tempo[i] = 6e7/msg.tempo elif msg.type == "note_on": result.append(Note(msg.note-50, msg.velocity/100, msg.channel, i)) elif msg.type == "end_of_track": result.append(End()) end[i] = False tracks[i] += 1 if len(track) > tracks[i]: wait[i] = track[tracks[i]].time/tempo[i]/4 else: wait[i] -= 1 print(t) t += 1""" return result