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

如何解析MIDI键盘输出的音符值以执行对应命令?

如何解析MIDI键盘输出的音符值以执行对应命令?

看起来你遇到的核心问题是MIDI数据流的实时处理和消息过滤,我来帮你梳理下解决方案:

首先得明确你看到的那些十六进制行对应的MIDI消息类型:

  • 以E0开头的是控制消息(比如弯音轮、表情踏板这类),不是我们需要的音符触发事件
  • 以90开头的是Note On消息(按键按下时发送),这正是你要捕捉来执行命令的目标
  • 以80开头的是Note Off消息(按键松开时发送),如果不需要处理松开动作可以暂时忽略

你之前用head -n NUM截取固定行数的方式行不通,原因很简单:MIDI消息是异步流数据,只有按键时才会输出,而且消息顺序完全随机(可能先出控制消息,再出音符消息),固定行数会导致要么等待很久,要么拿到的是无关消息,还会打乱顺序。

正确的实时处理方案

我们需要逐行读取amidi的输出,只过滤出Note On消息,这样每按下一个键就能立刻触发对应命令,不会出现顺序混乱的问题。

这里给你一个修改后的完整脚本:

#!/bin/bash
set -x

MIDI_DEVICE="hw:1,0,0"  # 记得替换成你的实际MIDI设备ID

# 实时读取MIDI输出,逐行处理每一条消息
amidi -p "$MIDI_DEVICE" -d | while read -r line; do
    # 只处理按键按下的Note On消息(以90开头)
    if [[ "$line" == 90* ]]; then
        # 如果你需要精准匹配完整的Note On消息(包含力度)
        full_note="$line"
        echo "检测到按键消息: $full_note"
        
        case "$full_note" in
            "904E63")
                xdotool key ctrl+alt+t  # 打开终端
                ;;
            # 可以添加更多完整消息对应的操作
            "904F60")
                xdotool key ctrl+w  # 关闭当前窗口
                ;;
        esac

        # 如果你想忽略力度,只按音符编号匹配(更灵活)
        # note_num=${line:2:2}  # 提取消息的第3-4位(十六进制音符编号)
        # case "$note_num" in
        #     "4E")
        #         xdotool key ctrl+alt+t
        #         ;;
        # esac
    fi

    # 如果需要处理按键松开事件,可以添加下面的判断
    # elif [[ "$line" == 80* ]]; then
    #     echo "按键松开: $line"
    #     # 这里可以添加松开时的操作
    # fi
done

关键细节解释

  1. 实时流处理:用amidi ... | while read -r line代替一次性截取,amidi的输出会实时传给循环,每收到一条消息就处理一条,不需要等待固定行数。
  2. 消息过滤:通过[[ "$line" == 90* ]]筛选出Note On消息,直接跳过无关的控制消息和松开消息。
  3. 两种匹配方式:
    • 匹配完整消息:适合需要区分不同力度的场景(比如轻按和重按执行不同命令)
    • 匹配音符编号:提取line的第3到第4位(${line:2:2}),忽略最后两位的力度值,同一个音符不管力度大小都会触发命令,更通用。

调试小技巧

先单独运行amidi -p "hw:1,0,0" -d,然后按你想映射的键盘按键,记录下对应的90开头的消息,再把这些消息添加到脚本的case分支里就可以了。

备注:内容来源于stack exchange,提问作者j0h

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 08:34:34