Mido库无法读取MIDI键盘输入及退出异常问题求助
问题:Mido读取MIDI键盘输入无响应且无法正常退出
我尝试用Python的Mido库编写代码,对比.mid文件的MIDI数据和MIDI键盘实时演奏数据,生成错误演奏的音符列表。打印.mid文件的音符音高没问题,但读取键盘输入时遇到问题。
附上的读取键盘输入代码,输入MIDI端口名称后完全没反应——演奏音符不会打印内容,按Ctrl+C也不会换行显示‘Exiting’。作为编程新手,想知道问题出在哪?
def collect_note_events(port): note_events = [] for msg in port: if msg.type == 'note_on': note_events.append([msg.note]) return note_events print("Available MIDI ports: ") for i, port_name in enumerate(mido.get_input_names()): print(f"{i}: {port_name}") selected_port = input("Enter the name of the MIDI port to use: ") with mido.open_input(selected_port) as port: print("Listening for MIDI input. Press Ctrl+C to exit.") try: while True: note_events = collect_note_events(port) if note_events: print(note_events) time.sleep(0.1) except KeyboardInterrupt: print("\nExiting...")
问题原因分析
- 函数阻塞导致程序卡死:
collect_note_events里的for msg in port:是一个无限阻塞循环,它会一直等待MIDI消息,不会主动返回。外层的while True完全没机会执行后续逻辑,哪怕演奏音符,程序也会卡在这个函数里,永远不会输出内容。 - 中断信号无法被捕获:因为程序卡在
for msg in port:的阻塞循环中,这个循环内部没有处理中断的逻辑,导致Ctrl+C的信号无法被外层的try-except捕获,所以不会触发退出提示。
修正后的代码
import mido import time def collect_note_events(port): note_events = [] # 使用iter_pending()读取当前已到达的消息,不会阻塞程序 for msg in port.iter_pending(): # 增加velocity判断,避免把note_off(部分设备用note_on+0速度表示)误判为按下事件 if msg.type == 'note_on' and msg.velocity > 0: note_events.append(msg.note) return note_events print("Available MIDI ports: ") for i, port_name in enumerate(mido.get_input_names()): print(f"{i}: {port_name}") selected_port = input("Enter the name of the MIDI port to use: ") with mido.open_input(selected_port) as port: print("Listening for MIDI input. Press Ctrl+C to exit.") try: while True: note_events = collect_note_events(port) if note_events: print(note_events) time.sleep(0.1) except KeyboardInterrupt: print("\nExiting...")
关键修正点
- 替换消息读取方式:用
port.iter_pending()替代for msg in port:,前者只会读取当前已收到的消息,不会阻塞程序,让外层循环能正常执行,也能响应Ctrl+C中断。 - 增加速度判断:部分MIDI设备用
note_on+0速度表示音符松开,加入msg.velocity > 0可以只捕获真正的音符按下事件,避免无效数据干扰。
内容的提问来源于stack exchange,提问作者vestieee
相关产品推荐
相关产品推荐

