You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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...")

关键修正点

  1. 替换消息读取方式:用port.iter_pending()替代for msg in port:,前者只会读取当前已收到的消息,不会阻塞程序,让外层循环能正常执行,也能响应Ctrl+C中断。
  2. 增加速度判断:部分MIDI设备用note_on+0速度表示音符松开,加入msg.velocity > 0可以只捕获真正的音符按下事件,避免无效数据干扰。

内容的提问来源于stack exchange,提问作者vestieee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 02:19:51