簡體   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