'Java MIDI: Connecting MIDI Keyboard to Default Synthesizer
I gotta a MIDI Keyboard. All I want is an example of how I can setup the default software synthesizer to play sounds as I play the Keyboard.
package cleffsgame;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
public class CheckDevices {
public static void main(String[] args) {
MidiDevice device;
// display each device's properties
for (MidiDevice.Info info: MidiSystem.getMidiDeviceInfo()) {
try {
device = MidiSystem.getMidiDevice(info);
System.out.println("\nDevice: ");
System.out.println("Name: " + device.getDeviceInfo().getName());
System.out.println("Vendor: " + device.getDeviceInfo().getVendor());
System.out.println("Version: " + device.getDeviceInfo().getVersion());
System.out.println("Description: " + device.getDeviceInfo().getDescription());
System.out.println("Transmitters: " + device.getMaxTransmitters());
System.out.println("Receivers: " + device.getMaxReceivers());
} catch (MidiUnavailableException ex) {
Logger.getLogger(CheckDevices.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
By running the code above, I get the following output:
run:
Device: Name: Gervill Vendor: OpenJDK Version: 1.0 Description: Software MIDI Synthesizer Transmitters: 0 Receivers: -1
Device: Name: Oxygen 49 Vendor: M-Audio Version: Unknown version Description: Oxygen 49 Transmitters: -1 Receivers: 0
Device: Name: Oxygen 49 Vendor: M-Audio Version: Unknown version Description: Oxygen 49 Transmitters: 0 Receivers: -1
Device: Name: Real Time Sequencer Vendor: Oracle Corporation Version: Version 1.0 Description: Software sequencer Transmitters: -1 Receivers: -1 BUILD SUCCESSFUL (total time: 2 seconds)
But when I run the code below, no sound is played when I hit the keys.
package cleffsgame;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Transmitter;
/**
*
* @author umberto
*/
public class Test {
public static void main(String[] args) {
MidiDevice inputDevice = null, synthDevice = null;
Transmitter transmitter = null;
Synthesizer synthesizer = null;
Receiver receiver = null;
try {
inputDevice = MidiSystem.getMidiDevice(MidiSystem.getMidiDeviceInfo()[1]);
synthDevice = MidiSystem.getMidiDevice(MidiSystem.getMidiDeviceInfo()[0]);
} catch (MidiUnavailableException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
// goodDevice must be Oxygen 49 transmitter (MIDI Input)
if (inputDevice != null && synthDevice != null) {
try {
transmitter = inputDevice.getTransmitter();
System.out.println("Transmitter: " + inputDevice.getDeviceInfo());
System.out.println(String.format("T/R: %s/%s", inputDevice.getMaxTransmitters(), inputDevice.getMaxReceivers()));
receiver = synthDevice.getReceiver();
System.out.println("Receiver: " + synthDevice.getDeviceInfo());
System.out.println(String.format("T/R: %s/%s", synthDevice.getMaxTransmitters(), synthDevice.getMaxReceivers()));
transmitter.setReceiver(receiver);
System.out.println("GoodDevice is open... check sound\n");
inputDevice.open();
synthDevice.open();
} catch (Exception ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
It seems there is more to do than connecting a Synthesizer.receiver to a InputDevice.transmitter as I got from the docs https://docs.oracle.com/javase/tutorial/sound/MIDI-synth.html.
Solution 1:[1]
This works for me
transmitter.setReceiver(new Receiver() {
@Override
public void send(MidiMessage message, long timeStamp) {
receiver.send(message, -1);
}
@Override
public void close() {
receiver.close();
}
});
Solution 2:[2]
It might be a good idea to open the devices before acquiring their transmitter/receiver.
But the actual problem is that this program exits immediately, so the devices aren't open for a useful amount of time.
Solution 3:[3]
Recently tried to do the same thing. Java tutorials and Stackoverflow answers weren't working. The problem was that, I was passing the keyboard's Note On timestamp
to the internal synth. The fix was to pass -1
as the timestamp instead.
This example uses Kotlin to call the Java MIDI APIs.
JDK 17, MacOS 11.3, Kotlin 1.6
import javax.sound.midi.*
class ReceiverAdapter (val targetReceiver: Receiver) : Receiver {
override fun send(midiMsg: MidiMessage, timeStamp: Long) {
targetReceiver.send(midiMsg, -1); // only works for me when i pass -1 as timestamp instead of original value from keyboard
}
override fun close() { }
}
class MidiKeyboardInternalSynthExample {
companion object {
fun doIt(keyboardDeviceName: String){
// connect external keyboard to internal synth
val midiTransmitter = find1stMidiTransmitterWithName(keyboardDeviceName)
if(midiTransmitter != null) {
val synth = MidiSystem.getSynthesizer()!!
val midiReceiver = ReceiverAdapter(synth.receiver)
midiTransmitter.transmitter.receiver = midiReceiver
synth.open()
midiTransmitter.open()
}
else {
println("Didn't find MIDI transmitter named '$keyboardDeviceName'.")
}
}
fun find1stMidiTransmitterWithName(deviceName: String): MidiDevice? =
MidiSystem.getMidiDeviceInfo()
?.filter { info -> info.name == deviceName }
?.map { info -> MidiSystem.getMidiDevice(info) }
?.filter { device -> device.maxTransmitters == -1 }
?.first()
}
}
fun main(args: Array<String>) {
MidiKeyboardInternalSynthExample.doIt("LPK25")
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | jizhihaoSAMA |
Solution 2 | CL. |
Solution 3 |