SourceDataLine (usb midi)键记录是慢的实时播放



嗨,我正在尝试在java中制作一个实时播放的synth。一个问题是延迟,通过几个建议,我能够得到可接受的延迟。然而,如果你在键盘上走得太快,它开始跳键或噼啪作响。我可以在技术上添加一点维持,至少可以部分缓解这个问题。

这里是源代码

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class SoundLine implements Runnable{
KeyStateInterface keyStateInterface;
OperatorStatesInterface operatorStatesInterface;
public SoundLine(KeyStateInterface arg,OperatorStatesInterface operatorStatesInterface){
keyStateInterface=arg;
this.operatorStatesInterface=operatorStatesInterface;
}
@Override
public void run() {
AudioFormat audioFormat = new AudioFormat(44100,8,1,true,false);
try {
SourceDataLine sourceDataLine = AudioSystem.getSourceDataLine(audioFormat);
sourceDataLine.open(audioFormat);
sourceDataLine.start();
SynthMain synthMain = new SynthMain();
int v = 0;
while (true) {
//int bytesAvailable = sourceDataLine.available();
//if (bytesAvailable > 0) {
int sampling = 256;
byte[] bytes = new byte[sampling];
for (int i = 0; i < sampling; i++) {
//bytes[i] = (byte) (Math.sin(angle) * 127f);
float t = (float) (synthMain.makeSound((double)v,44100,keyStateInterface,operatorStatesInterface)* 127f);
bytes[i] = (byte) (t);
v += 1;
}
if(keyStateInterface.getFlush()){
sourceDataLine.flush();
}
//for(int i = 0;i<100;i++)
sourceDataLine.write(bytes, 0, sampling);
//if(!keyStateInterface.isCacheKeysSame())sourceDataLine.flush();
//System.out.println(bytesWritten);
//} else {
//    Thread.sleep(1);
//}
//System.out.println(bytesAvailable);
//System.out.println();
//if((System.currentTimeMillis()-mil)%50==0)freq+=0.5;
}
}catch (Exception e){

}
import javax.sound.midi.*;
import java.util.List;
public class MIDIKeyboardHandler implements Runnable {
KeyStateInterface keyStateInterface;
public MIDIKeyboardHandler(KeyStateInterface arg) {
keyStateInterface = arg;
}
@Override
public void run() {
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(), keyStateInterface)
);
}
Transmitter trans = device.getTransmitter();
trans.setReceiver(new MidiInputReceiver(device.getDeviceInfo().toString(), keyStateInterface));
//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) {
}
}
}
public class MidiInputReceiver implements Receiver {
KeyStateInterface keyStateInterface;
public String name;
public MidiInputReceiver(String name, KeyStateInterface arg) {
this.name = name;
keyStateInterface = arg;
}
public void send(MidiMessage msg, long timeStamp) {
//System.out.println(msg.getStatus());
keyStateInterface.pushMidiKey(msg.getMessage()[0],msg.getMessage()[1],msg.getMessage()[2]);
System.out.println(msg.getMessage()[0]+","+msg.getMessage()[1]+","+msg.getMessage()[2]+" timestamp: "+timeStamp);
}
@Override
public void close() { }
}
}

如果需要,可以提供一些额外的代码

我明白了。这是因为跨线程消息传递。在一个线程中做所有的事情似乎可以解决这个问题。

最新更新