sous forme de classe
This commit is contained in:
parent
c03110cfc1
commit
a4b1c6765a
117
midi2beep.py
117
midi2beep.py
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
###
|
###
|
||||||
#
|
#
|
||||||
# midi2beep.py
|
# midi4beep.py
|
||||||
# Author: Adrien MALINGREY <adrien@malingrey.fr>
|
# Author: Adrien MALINGREY <adrien@malingrey.fr>
|
||||||
#
|
#
|
||||||
# Play MIDI files with PC speaker using the beep command.
|
# Play MIDI files with PC speaker using the beep command.
|
||||||
#
|
#
|
||||||
# Usage: python3 midi2beep.py <midi file>
|
# Usage: python3 midi4beep.py <midi file> [channel]
|
||||||
#
|
#
|
||||||
# Dependencies:
|
# Dependencies:
|
||||||
# - Python 3
|
# - Python 3
|
||||||
@ -21,75 +21,64 @@ import subprocess
|
|||||||
import math
|
import math
|
||||||
import mido
|
import mido
|
||||||
|
|
||||||
|
|
||||||
|
class PCSpeaker(mido.ports.BaseOutput):
|
||||||
|
def __init__(self, channel=-1):
|
||||||
|
super().__init__(self)
|
||||||
|
self.channel = channel
|
||||||
|
self.note_on = 0
|
||||||
|
self.process = None
|
||||||
|
|
||||||
|
def _send(self, message):
|
||||||
|
if (message.type == "note_on" or message.type == "note_off") \
|
||||||
|
and (message.channel == self.channel or (self.channel == -1 and message.channel != 9)):
|
||||||
|
if message.type == "note_on" and message.velocity and message.note > self.note_on:
|
||||||
|
self.process = subprocess.Popen(
|
||||||
|
[
|
||||||
|
"beep",
|
||||||
|
"-f",
|
||||||
|
str(int(440 * math.pow(2, (message.note - 69) / 12))),
|
||||||
|
"-l100000",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.note_on = message.note
|
||||||
|
|
||||||
|
elif self.process and (message.type == "note_off" or (message.type == "note_on" and message.note == self.note_on)):
|
||||||
|
self.process.terminate()
|
||||||
|
self.process = None
|
||||||
|
self.note_on = 0
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
if self.process:
|
||||||
|
self.process.terminate()
|
||||||
|
self.process = None
|
||||||
|
self.note_on = 0
|
||||||
|
|
||||||
|
def panic(self):
|
||||||
|
if self.process:
|
||||||
|
self.process.kill()
|
||||||
|
self.process = None
|
||||||
|
self.note_on = 0
|
||||||
|
|
||||||
|
def _close(self):
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
print("Usage: python3 midi2beep.py <midi file> [channel]")
|
print("Usage: python3 midi4beep.py <midi file> [channel]")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
arpege = 0.015#ms
|
path = sys.argv[1]
|
||||||
|
|
||||||
FREQUENCIES = [
|
|
||||||
# C, C#, D, D#, E, F, F#, G, G#, A, A#, B
|
|
||||||
16.35, 17.32, 18.35, 19.45, 20.6, 21.83, 23.12, 24.5, 25.96, 27.5, 29.14, 30.87,
|
|
||||||
32.7, 34.65, 36.71, 38.89, 41.2, 43.65, 46.25, 49, 51.91, 55, 58.27, 61.74,
|
|
||||||
65.41, 69.3, 73.42, 77.78, 82.41, 87.31, 92.5, 98, 103.83, 110, 116.54, 123.47,
|
|
||||||
130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185, 196, 207.65, 220, 233.08, 246.94,
|
|
||||||
261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392, 415.3, 440, 466.16, 493.88,
|
|
||||||
523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, 880, 932.33, 987.77,
|
|
||||||
1046.5, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760, 1864.66, 1975.53,
|
|
||||||
2093, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520, 3729.31, 3951.07,
|
|
||||||
4186.01, 4434.92, 4698.64, 4978.03, 5274.04, 5587.65, 5919.91, 6271.93, 6644.88, 7040, 7458.62, 7902.13,
|
|
||||||
]
|
|
||||||
|
|
||||||
midi_file_path = sys.argv[1]
|
|
||||||
try:
|
try:
|
||||||
mid=mido.MidiFile(midi_file_path)
|
mid = mido.MidiFile(path)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
mido.read_syx_file(midi_file_path)
|
mido.read_syx_file(path)
|
||||||
|
|
||||||
if len(sys.argv) > 2:
|
if len(sys.argv) > 2:
|
||||||
channel = int(sys.argv[2])
|
channel = int(sys.argv[2])
|
||||||
else:
|
else:
|
||||||
channel = -1
|
channel = -1
|
||||||
|
|
||||||
time = 0
|
with PCSpeaker(channel) as speaker:
|
||||||
note_on = 0
|
for msg in mid.play():
|
||||||
start = 0
|
speaker.send(msg)
|
||||||
tempo = 500000
|
|
||||||
|
|
||||||
try:
|
|
||||||
for msg in mid:
|
|
||||||
time += msg.time
|
|
||||||
|
|
||||||
if msg.type == "track_name":
|
|
||||||
print(msg.name)
|
|
||||||
|
|
||||||
if msg.type == "set_tempo":
|
|
||||||
tempo = msg.tempo
|
|
||||||
|
|
||||||
if (msg.type == "note_on" or msg.type == "note_off") and (msg.channel == channel or (channel == -1 and msg.channel != 9)):
|
|
||||||
if msg.time:
|
|
||||||
lines = math.ceil(4e6 * (time - start) / tempo)
|
|
||||||
if note_on:
|
|
||||||
for _ in range(lines):
|
|
||||||
print(note_on * " " + "█")
|
|
||||||
subprocess.run(["beep", f"-f{FREQUENCIES[note_on]:.0f}", f"-l{1000*(time - start):.0f}"])
|
|
||||||
elif start:
|
|
||||||
for _ in range(lines):
|
|
||||||
print()
|
|
||||||
subprocess.run(["sleep", f"{0.8*(time - start)}"])
|
|
||||||
|
|
||||||
if msg.type == "note_on" and msg.velocity:
|
|
||||||
if msg.time or msg.note > note_on:
|
|
||||||
note_on = msg.note
|
|
||||||
else:
|
|
||||||
note_on = 0
|
|
||||||
|
|
||||||
start = time
|
|
||||||
|
|
||||||
lines = math.ceil(4e6 * (time - start) / tempo)
|
|
||||||
for _ in range(lines):
|
|
||||||
print(note_on * " " + "█")
|
|
||||||
subprocess.run(["beep", f"-f{FREQUENCIES[note_on]:.0f}", f"-l{1000*(time - start):.0f}"])
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
subprocess.run(["beep", "-f1", "-l1"])
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user