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

如何实时接收电子钢琴的Live MIDI输入事件?

问题分析

你添加的ControllerEventListener仅监听MIDI控制器变更事件(CC消息,比如编号127的控制器消息),但电子钢琴按键触发的是Note On/Note Off这类MIDI短消息,这是监听器未生效的核心原因。

有效解决方案

以下提供两种实时捕获MIDI乐器事件的可行方法:

方案1:直接监听MidiDevice输入(最直接的实时处理)

跳过Sequencer,直接给输入设备绑定自定义Receiver,可捕获所有从电子钢琴发来的MIDI消息,适合实时对比需求:

import java.io.File;
import java.io.IOException;
import javax.sound.midi.*;
import javax.swing.Timer;

public class Main {
    public static void main(String[] args) throws Exception {
        // 列出所有MIDI设备,确认目标输入设备索引
        Info[] infos = MidiSystem.getMidiDeviceInfo();
        for (int i = 0; i < infos.length; i++) {
            System.out.println(i + ": " + infos[i].getName() + " - " + infos[i].getDescription());
        }

        // 打开电子钢琴输入设备(根据实际列表调整索引)
        MidiDevice inputDevice = MidiSystem.getMidiDevice(infos[1]);
        inputDevice.open();

        // 自定义Receiver,实时处理所有MIDI消息
        Receiver customReceiver = new Receiver() {
            @Override
            public void send(MidiMessage message, long timeStamp) {
                if (message instanceof ShortMessage) {
                    ShortMessage sm = (ShortMessage) message;
                    switch (sm.getCommand()) {
                        case ShortMessage.NOTE_ON:
                            System.out.printf("按键按下: 通道%d, 音符%d, 力度%d%n",
                                    sm.getChannel(), sm.getData1(), sm.getData2());
                            // 在这里添加与乐谱MIDI文件的实时对比逻辑
                            break;
                        case ShortMessage.NOTE_OFF:
                            System.out.printf("按键松开: 通道%d, 音符%d%n",
                                    sm.getChannel(), sm.getData1());
                            break;
                        case ShortMessage.CONTROL_CHANGE:
                            System.out.printf("控制器变更: 通道%d, 编号%d, 值%d%n",
                                    sm.getChannel(), sm.getData1(), sm.getData2());
                            break;
                        // 可扩展处理其他MIDI消息类型
                    }
                }
            }

            @Override
            public void close() {}
        };

        // 将输入设备的Transmitter绑定到自定义Receiver
        Transmitter transmitter = inputDevice.getTransmitter();
        transmitter.setReceiver(customReceiver);

        // 保留原有录制功能(如果需要)
        Sequencer sequencer = MidiSystem.getSequencer();
        sequencer.open();
        Sequence seq = new Sequence(Sequence.PPQ, 24);
        Track track = seq.createTrack();
        sequencer.setSequence(seq);
        sequencer.recordEnable(track, -1);
        sequencer.startRecording();

        // 10秒后停止录制并清理资源
        new Timer(10000, e -> {
            sequencer.stopRecording();
            try {
                MidiSystem.write(sequencer.getSequence(), 0, new File("midi.mid"));
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            sequencer.close();
            inputDevice.close();
            System.exit(0);
        }).start();
    }
}

方案2:结合Sequencer的事件监听(适合需同步录制的场景)

如果必须通过Sequencer处理,可通过监听Track的事件或使用MetaEventListener,但需注意:Sequencer默认仅向ControllerEventListener传递CC消息,若要捕获Note事件,需额外处理:

// 在原有录制代码基础上,添加Track事件监听
Track currentTrack = seq.createTrack();
// 手动监听Track的新增事件(通过定时扫描或自定义Track实现)
new Timer(10, e -> {
    for (int i = currentTrack.size() - 1; i >= 0; i--) {
        MidiEvent event = currentTrack.get(i);
        MidiMessage msg = event.getMessage();
        if (msg instanceof ShortMessage) {
            ShortMessage sm = (ShortMessage) msg;
            // 处理Note On/Off等消息
            if (sm.getCommand() == ShortMessage.NOTE_ON) {
                System.out.println("录制到按键按下: " + sm.getData1());
            }
        }
    }
}).start();
注意事项
  • 确认infos[1]是正确的电子钢琴输入设备,可根据控制台打印的设备列表调整索引。
  • 树莓派运行时,需确保ALSA MIDI驱动正常,若遇设备识别问题,可添加系统属性配置:-Djavax.sound.midi.Receiver=com.sun.media.sound.MidiOutDeviceProvider。
  • 程序结束时务必关闭MidiDevice和Sequencer,避免资源泄漏。

内容的提问来源于stack exchange,提问作者Crih.exe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 19:55:22