繁体   English   中英

从现场乐器读取 MIDI 输入流

[英]Read MIDI input stream from a live instrument

我正在尝试创建一种自动乐谱查看器,只是为了好玩,我最终会尝试将其与 raspberry pi 或其他东西集成到我的数码钢琴中,但这是另一回事了。 让我们专注于我当前的问题。

为了完成这项工作,我必须将来自我的钢琴的 MIDI 输入与代表我正在演奏的乐谱的 MIDI 文件进行比较。

因为我想实时比较两个 MIDI,所以我发现很难直接从我的钢琴上获得现场 MIDI。

我已经尝试读取 10 秒的 MIDI 并将所有内容写入文件并且它可以完美地工作,但是我找不到任何方法来在我的钢琴发送消息时接收某种回调。

这是我当前的测试代码(这很糟糕,我知道,但我现在正在测试)我基本上将 10 秒的 MIDI 从我的钢琴写入一个 .mid 文件,我也尝试使用 ControllerEventListener,但是它似乎不起作用。

import java.io.File;
import java.io.IOException;

import javax.sound.midi.ControllerEventListener;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiDevice.Info;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Receiver;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;
import javax.sound.midi.Transmitter;
import javax.swing.Timer;

public class Main {

    public static void main(String[] args) throws Exception {
        
        Info[] infos = MidiSystem.getMidiDeviceInfo();
        for(int i = 0; i < infos.length; i++) {
            System.out.println(infos[i].getName() + " - " + infos[i].getDescription());
        }
        
        MidiDevice inputDevice = MidiSystem.getMidiDevice(infos[1]);
        
        Sequencer sequencer = MidiSystem.getSequencer();
        Receiver receiver;
        Transmitter transmitter;
        
        inputDevice.open();
        sequencer.open();
        
        transmitter = inputDevice.getTransmitter();
        receiver = sequencer.getReceiver();
        transmitter.setReceiver(receiver);
        
        Sequence seq = new Sequence(Sequence.PPQ, 24);
        
        Track currentTrack = seq.createTrack();
        
        sequencer.setSequence(seq);
        sequencer.setTickPosition(0);
        
        sequencer.addControllerEventListener(new ControllerEventListener() {
            
            @Override
            public void controlChange(ShortMessage event) {
                System.out.println("listener works");
            }
        }, new int[] {127});
        
        sequencer.recordEnable(currentTrack, -1);
        
        sequencer.startRecording();
        
        new Timer(10000, e -> {
            
            Sequence tmp = sequencer.getSequence();
            sequencer.stopRecording();
            
            try {
                MidiSystem.write(tmp, 0, new File("midi.mid"));
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            System.exit(0);
        }).start();
        
    }

}

如您所见,我尝试向 Sequencer 添加一个 ControllerEventListener,但在录制时监听事件似乎不起作用:

sequencer.addControllerEventListener(new ControllerEventListener() {
    @Override
    public void controlChange(ShortMessage event) {
        System.out.println("listener works");
    }
}, new int[] {127});

无论我多么努力,但我找不到任何可以帮助我的东西......有什么方法可以接收现场 MIDI 乐器上的事件?

每当从我的钢琴发送消息时,我找不到任何方法来接收某种回调。

如果您希望在 Note ON MidiMessage 从您的钢琴到达时得到实时通知,请使用自定义接收器。

...
transmitter = inputDevice.getTransmitter();
receiver = new MyReceiver();
transmitter.setReceiver(receiver);
...


private class MyReceiver implements Receiver
{
    ...
    
    @Override
    public void send(MidiMessage mm, long timeStamp)
    {
        if (mm instanceof ShortMessage sm && sm.getCommand() == ShortMessage.NOTE_ON)
        {           
            // Do something with the NoteOn message, preferably in another thread
        } 
    }
}

如果您希望 Sequencer 并行记录 MidiMessages 以创建 Sequence,请从 inputDevice 获取第二个发送器并将其连接到 Sequencer 的接收器。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM