树莓派中Python Mido无法检测MIDI键盘输入问题求助
解决树莓派上MIDI输入无法触发GPIO控制的问题
核心问题定位
你的代码在树莓派上无法触发MIDI消息处理逻辑,大概率是因为mido.open_input()默认连接了Midi Through虚拟设备,而非实际的CASIO MIDI键盘,导致inport.iter_pending()读不到任何真实消息。另外,time.sleep(1)的阻塞式写法也会导致主循环响应异常。
具体修复步骤
1. 显式指定MIDI输入设备
先运行以下代码列出所有可用的MIDI输入设备:
import mido print(mido.get_input_names())
你会看到类似输出:
['Midi Through Port-0', 'CASIO USB-MIDI MIDI 1']
然后修改原代码中的inport = mido.open_input()为:
inport = mido.open_input("CASIO USB-MIDI MIDI 1") # 替换为你的设备名称
这样就能确保mido连接到真实的MIDI键盘。
2. 替换阻塞式的time.sleep(1)
原代码中的time.sleep(1)会完全阻塞主循环,导致在这1秒内无法读取新的MIDI消息,改用非阻塞的计时逻辑:
# 初始化计时变量 gpio_on_time = 0 gpio_active = False while not done: # 处理MIDI消息 for msg in inport.iter_pending(): print("收到消息:", msg) # 先打印所有消息,确认能正常接收 try: n = msg.note except AttributeError: continue if msg.type == 'note_on' and msg.velocity > 0 and msg.velocity != 64: GPIO.output(4, True) gpio_on_time = time.time() gpio_active = True elif msg.type == 'note_off' or (msg.type == 'note_on' and msg.velocity == 0): outport.send(mido.Message('note_off', note=n)) # 非阻塞判断是否需要关闭GPIO if gpio_active and time.time() - gpio_on_time >= 1: GPIO.output(4, False) gpio_active = False
3. 检查MIDI设备权限
确保运行脚本的用户有访问MIDI设备的权限,执行以下命令将用户加入audio组:
sudo usermod -a -G audio $USER
重启树莓派后生效。
4. 完善Pygame事件处理
原代码初始化了Pygame但未处理事件队列,可能导致主循环异常,添加事件处理逻辑:
while not done: # 处理Pygame退出事件 for event in pygame.event.get(): if event.type == pygame.QUIT: done = True # 后续的MIDI和GPIO处理逻辑...
完整修复后的代码
import pygame import mido import time import RPi.GPIO as GPIO pygame.init() GPIO.setmode(GPIO.BCM) GPIO.setup(4, GPIO.OUT) GPIO.output(4, False) # 列出并指定MIDI输入设备 input_devices = mido.get_input_names() print("可用MIDI输入设备:", input_devices) inport = mido.open_input("CASIO USB-MIDI MIDI 1") outport = mido.open_output() done = False gpio_on_time = 0 gpio_active = False print("START!") while not done: # 处理Pygame退出事件 for event in pygame.event.get(): if event.type == pygame.QUIT: done = True # 处理MIDI消息 for msg in inport.iter_pending(): print("收到MIDI消息:", msg) try: n = msg.note except AttributeError: continue if msg.type == 'note_on' and msg.velocity > 0 and msg.velocity != 64: print("触发GPIO,速度:", msg.velocity) GPIO.output(4, True) gpio_on_time = time.time() gpio_active = True elif msg.type == 'note_off' or (msg.type == 'note_on' and msg.velocity == 0): outport.send(mido.Message('note_off', note=n)) # 非阻塞关闭GPIO if gpio_active and time.time() - gpio_on_time >= 1: GPIO.output(4, False) gpio_active = False # 清理资源 GPIO.cleanup() pygame.quit()
内容的提问来源于stack exchange,提问作者Monty Swanson
相关产品推荐
相关产品推荐

