-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplay_midi.py
More file actions
81 lines (72 loc) · 2.53 KB
/
play_midi.py
File metadata and controls
81 lines (72 loc) · 2.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
'''
Uses mido to play a midi file.
'''
from __future__ import annotations
import typing as tp
import time
import mido
from .myfile import sysArgvOrInput
from .interactive import inputChin
def any2zero(x: int): # an example channel remap
return 0
def identity(x: int):
return x
def askOutput():
outputs = mido.get_output_names() # type: ignore
for i, name in enumerate(outputs):
print(i, name, sep = '\t')
selected = outputs[int(inputChin('> ', '0'))]
print(f'{selected = }')
return selected
def main(
filename: str | None = None,
midi_output_name: str | None = None,
channel_remap: tp.Callable[[int], int | None] = identity,
velocity_remap: tp.Callable[[int], int] = identity,
discard_meta: bool = True,
verbose: bool = True,
):
'''
`channel_remap`: return None to discard message.
`velocity_remap`: must return 0 if input is 0.
'''
filename = filename or sysArgvOrInput()
midi_output_name = midi_output_name or askOutput()
with mido.open_output(midi_output_name) as port: # type: ignore
manualPanic(port)
down_keys = set()
with mido.MidiFile(filename) as mid:
if verbose:
print('playing...')
try:
for msg in mid.play(meta_messages = not discard_meta):
if verbose:
print(msg)
try:
msg.velocity = round(velocity_remap(msg.velocity))
new_channel = channel_remap(msg.channel)
if new_channel is None:
continue
msg.channel = new_channel
except AttributeError:
pass # allow control_change
port.send(msg)
if msg.type == 'note_on' and msg.velocity != 0:
down_keys.add(msg.note)
elif msg.type == 'note_off' or (msg.type == 'note_on' and msg.velocity == 0):
down_keys.discard(msg.note)
except KeyboardInterrupt:
if verbose:
print('Stop. ')
finally:
port.panic()
manualPanic(port)
if verbose:
print('ok')
def manualPanic(outPort: mido.ports.BaseOutput):
# in case the MIDI device did not implement panic
for note in range(128):
outPort.send(mido.Message('note_off', note=note))
time.sleep(0.01)
if __name__ == '__main__':
main()