0

嗨,我正在尝试制作一个在 java 中实时播放的合成器。一个问题是延迟,通过一些建议,我能够达到可接受的延迟。但是,如果您在键盘上快速操作,它会开始跳过键或噼啪作响。我可以在技术上添加一些延音,至少可以部分缓解这个问题。

这是源代码

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() { }
    }
}

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

4

1 回答 1

0

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

于 2021-08-30T09:50:05.710 回答