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

如何在Java中读取MIDI设备数据并转换为音符信息

解析MIDI键盘的字节数组并转换为音符名称

一、这些字节数组是什么?

你收到的是MIDI协议消息的字节缓冲区,其中:

  • 前几个非零字节是实际的MIDI控制消息,后面的大量0是缓冲区的填充数据,无实际意义,可直接忽略。
  • MIDI消息由状态字节和数据字节组成:
    • 状态字节最高位为1(对应Java中byte类型的负数,因byte是有符号类型,范围-128~127),用来标识消息类型(比如Note On、Note Off、控制器消息等)。
    • 数据字节最高位为0(正数或0),是消息的具体参数(比如音符编号、按键力度)。
  • 举个例子:你数组里的-112(转成无符号int为0x90)是通道1的Note On消息,后面的47是音符编号,75是按键力度。

二、Java中转换为D4、C#5这类音符名称的方法

核心步骤

  1. 过滤缓冲区中的空字节(0),提取有效MIDI消息。
  2. 识别Note On/Off类型的消息(状态字节范围0x80~0x8F是Note Off,0x90~0x9F是Note On)。
  3. 将MIDI音符编号(0~127)映射为对应的音名+八度。

示例代码

修改你原有的onSend方法,加入解析逻辑:

import android.util.Log;

// 音名映射数组,对应MIDI编号0~11的音名
private static final String[] NOTE_NAMES = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};

@Override
public void onSend(byte[] bytes, int offset, int count, long timestamp) {
    // 遍历有效数据范围(offset到offset+count)
    for (int i = offset; i < offset + count; ) {
        int status = bytes[i] & 0xFF;
        // 跳过空字节
        if (status == 0) {
            i++;
            continue;
        }
        // 提取消息类型(高4位)
        int messageType = status & 0xF0;
        
        // 处理Note On和Note Off消息
        if (messageType == 0x80 || messageType == 0x90) {
            // 消息需要2个数据字节,检查是否有足够数据
            if (i + 2 >= offset + count) {
                break;
            }
            // 转换为无符号int,避免有符号byte的问题
            int noteNumber = bytes[i+1] & 0xFF;
            int velocity = bytes[i+2] & 0xFF;
            
            // 计算八度和音名
            int octave = (noteNumber / 12) - 1; // MIDI编号60对应C4,60/12=5,5-1=4
            int noteIndex = noteNumber % 12;
            String noteName = NOTE_NAMES[noteIndex] + octave;
            
            // 区分Note On/Off(Note On力度为0时视为Off)
            String action = (messageType == 0x90 && velocity > 0) ? "按下" : "松开";
            Log.d("MIDI音符", action + ": " + noteName + " | 力度: " + velocity);
            
            // 跳过当前3字节的消息
            i += 3;
        } else {
            // 其他类型消息(如控制器、程序变更),这里简单跳过1字节,可按需扩展
            i++;
        }
    }
}

关键说明

  • bytes[i] & 0xFF:将有符号byte转换为无符号int,正确表示MIDI协议中0~255的数值范围。
  • 八度计算:MIDI编号60是音乐中的中央C(C4),通过(noteNumber / 12) - 1对齐通用的音符命名规则。
  • Note On力度为0:部分MIDI设备会用力度0的Note On消息代替Note Off,代码中做了兼容处理。

内容的提问来源于stack exchange,提问作者M. Feyz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 07:27:04