Java 从 MIDI 键盘获取输入

2022-01-13 00:00:00 input keyboard midi java javasound

我已经用 java 设计了自己的合成器,现在我想将它与 MIDI 键盘连接.我下面的班级搜索所有具有发射器的 MIDI 设备.它成功地找到了我的 MIDI 键盘.我将自己的接收器添加到每个设备的每个发射器,以便它可以接收所有可能的信息.通过阅读所有帮助文档和 java 文档,我知道 Transmitter 将 MidiEvents 发送到 Receiver,然后使用 send 方法处理它们.所以我编写了自己的内部类来实现 Receiver 并使用 println 语句来检查 send 方法中是否检测到任何东西.然而,什么都没有被捡起.做这么简单的事情似乎没有什么帮助,我查看了每个帮助文件、javadoc 和论坛.我敢肯定,这一定是我错过了一些非常明显的事情.

I have designed my own synthesizer in java and I now want to connect it with a midi keyboard. My class below searches through all the midi devices that have transmitters. It successfully finds my midi keyboard. I add my own receivers to each transmitter for each device so that it should pick up everything possible. From reading all the help documents and java doc I know that a Transmitter sends MidiEvents to a Receiver which then handles them with the send method. So I wrote my own inner class implementing Receiver and just used a println statement to check if there was anything detected at all in the send method. However nothing is picked up at all. There seems to be very little help to do such a simple thing and I have looked at every help file, javadoc and forum. I'm sure it must be something really obvious I have somehow missed.

我的合成器不应该与界面合成器混淆,它不是一个 MIDI 乐器.它使用合成算法并具有播放方法.基本上我只需要让 MIDI 键盘发送一个关于事件的注释,该事件将调用播放方法.

My synthesizer should not be confused with the interface Synthesizer and it is not a midi instrument. It uses a synthesis algorithm and has a playback method. Basically I just need to get the midi keyboard sending a note on event which will invoke the playback method.

import javax.sound.midi.*;
import java.util.ArrayList;
import java.util.List;
import java.io.*;
public class MidiHandler
{
    //ArrayList of MidiDevices
    private ArrayList<MidiDevice> devices = new ArrayList<MidiDevice>();

    public MidiHandler()
    {
        MidiDevice device;
        MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
        for (int i = 0; i < infos.length; i++) {
            try {
                device = MidiSystem.getMidiDevice(infos[i]);
                //does the device have any transmitters?
                if (device.getTransmitters().size() > 0) {
                    //if it does, add it to the device list
                    System.out.println(infos[i] + ": " + device.getTransmitters().size());
                    devices.add(device);
                }
            } catch (MidiUnavailableException e) {}
        }
        //if any transmitting devices were found
        if(devices.size()>0) {
            //for each device
            for(int i = 0; i<devices.size(); i++) {
                try {
                    //get all transmitters
                    List<Transmitter> transmitters = devices.get(i).getTransmitters();
                    //and for each transmitter
                    for(int j = 0; j<transmitters.size();j++) {
                        //create a new receiver
                        transmitters.get(i).setReceiver(
                            //using my own MidiInputReceiver
                            new MidiInputReceiver(devices.get(i).getDeviceInfo().toString())
                        );
                    }
                    //open each device
                    devices.get(i).open();
                    //if code gets this far without throwing an exception
                    //print a success message
                    System.out.println(devices.get(i).getDeviceInfo()+" Was Opened");
                } catch (MidiUnavailableException e) {}
            }
        }
    }
    //tried to write my own class. I thought the send method handles an MidiEvents sent to it
    public class MidiInputReceiver implements Receiver {
        public String name;
        public MidiInputReceiver(String name) {
            this.name = name;
        }
        public void send(MidiMessage msg, long timeStamp) {
            System.out.println("midi received");
        }
        public void close() {}
    }
}

注意:我已经看过这个:Java MIDI - 从钢琴中获取数据?.

NOTE: I have already seen this: Java MIDI - getting data from piano?.

还有这个:http://www.jsresources.org/examples/MidiInDump.html

interface Sequencer 对于我想要的东西来说看起来也很复杂.

interface Sequencer looked way to complicated for what I want also.

推荐答案

我发现 MidiDevice getTransmitters() 似乎返回当前已经打开发射器的列表,而不是那些可用打开.我相信打开一个新发射器的方法是通过 getTransmitter() 方法.我已经修改了你的代码来做到这一点:

I've found that the MidiDevice getTransmitters() appears to return the list of currently already-open transmitters, not transmitters that are available to be opened. I believe the way to open a new transmitter is via the getTransmitter() method. I've modified your code to do this:

import javax.sound.midi.*;
import java.util.ArrayList;
import java.util.List;
import java.io.*;
    public class MidiHandler
{

    public MidiHandler()
    {
        MidiDevice device;
        MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
        for (int i = 0; i < infos.length; i++) {
            try {
            device = MidiSystem.getMidiDevice(infos[i]);
            //does the device have any transmitters?
            //if it does, add it to the device list
            System.out.println(infos[i]);

            //get all transmitters
            List<Transmitter> transmitters = device.getTransmitters();
            //and for each transmitter

            for(int j = 0; j<transmitters.size();j++) {
                //create a new receiver
                transmitters.get(j).setReceiver(
                        //using my own MidiInputReceiver
                        new MidiInputReceiver(device.getDeviceInfo().toString())
                );
            }

            Transmitter trans = device.getTransmitter();
            trans.setReceiver(new MidiInputReceiver(device.getDeviceInfo().toString()));

            //open each device
            device.open();
            //if code gets this far without throwing an exception
            //print a success message
            System.out.println(device.getDeviceInfo()+" Was Opened");


        } catch (MidiUnavailableException e) {}
    }


}
//tried to write my own class. I thought the send method handles an MidiEvents sent to it
public class MidiInputReceiver implements Receiver {
    public String name;
    public MidiInputReceiver(String name) {
        this.name = name;
    }
    public void send(MidiMessage msg, long timeStamp) {
        System.out.println("midi received");
    }
    public void close() {}
    }
}

在我的硬件上(我插入了一个简单的 USB MIDI 控制器),代码在创建 MidiHandler 实例后正确打印出midi received".

On my hardware (I have a simple USB MIDI controller plugged in), the code correctly prints out "midi received" after an instance of MidiHandler is created.

希望这会有所帮助!

相关文章