246 lines
5.4 KiB
Python
246 lines
5.4 KiB
Python
#!/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
|