首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SourceDataLine延迟到实时播放(synth)

SourceDataLine延迟到实时播放(synth)
EN

Stack Overflow用户
提问于 2021-08-16 11:12:21
回答 1查看 127关注 0票数 0

我试着做一个合成器,它可以工作,我可以和他们一起演奏音乐。然而,我做的第一个合成器有延迟,你不能播放快速歌曲。因此,我再次尝试使用sourceDataline.flush()方法来加快速度。嗯,它有点修正了,但是拖延太久了。我也试过降低采样率,但延迟太大了。

编辑:原来你可以评论这行keyStateInterface.setFlush(false);,它改善了延迟,但是你仍然不能播放快歌

以下是代码:

代码语言:javascript
复制
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;
    public SoundLine(KeyStateInterface arg){
        keyStateInterface=arg;
    }

    @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/(64);
                    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)* 127f);
                        bytes[i] = (byte) (t);
                        v += 1;
                    }
                    if(keyStateInterface.getFlush()){
                        sourceDataLine.flush();
                    }
                    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){


        }
    }
}
代码语言:javascript
复制
public class SynthMain {
    double[] noteFrequency = {
            466.1637615181,
            493.8833012561,
            523.2511306012,
            554.3652619537,
            587.3295358348,
            622.2539674442,
            659.2551138257,
            698.4564628660,
            739.9888454233,
            783.9908719635,
            830.6093951599,
            880.0000000000,
            932.3275230362,
            987.7666025122,
            1046.5022612024,
            1108.7305239075,
            1174.6590716696,
            1244.5079348883,
            1318.5102276515,
            1396.9129257320,
            1479.9776908465,
            1567.9817439270,
            1661.2187903198,
            1760.0000000000,
            1864.6550460724,
            1975.5332050245,
            2093.0045224048,
            2217.4610478150,
            2349.3181433393,
            2489.0158697766,
            2637.0204553030,
            2793.8258514640,
            2959.9553816931,
            3135.9634878540,
            3322.4375806396,
            3520.0000000000,
            3729.3100921447,
    };
    boolean[] keys = new boolean[noteFrequency.length];
    public double makeSound(double dTime,double SampleRate,KeyStateInterface keyStateInterface){
        if(keyStateInterface.getSizeOfMidiKey()>0){
            keyStateInterface.setFlush(true);
            for(int i=0;i<keyStateInterface.getSizeOfMidiKey();i++) {
                KeyRequest keyRequest = keyStateInterface.popMidiKey();
                if(keyRequest.getCommand()==-112){
                    if(keyRequest.getVelocity()>0)keys[keyRequest.getArg1()] = true;
                    if(keyRequest.getVelocity()<1)keys[keyRequest.getArg1()] = false;
                    System.out.println(keyRequest.getVelocity());
                }
            }
        }else{
            keyStateInterface.setFlush(false);
        }
        //System.out.println("makeSound");
        double a = 0.0;
        for(int i=0;i<keys.length;i++){
            if(keys[i]){
                a+=Oscillate(dTime,noteFrequency[i],(int)SampleRate);
            }
        }
        return a*0.4;
    }
    public double Oscillate(double dTime,double dFreq,int sampleRate){
        double period = (double)sampleRate / dFreq;
        return Math.sin(2.0 * Math.PI * (int)dTime / period);
    }
}
代码语言:javascript
复制
import java.util.ArrayList;
import java.util.Stack;

public class KeyState implements KeyStateInterface{
    boolean isFlush;
    ArrayList<KeyRequest> keyRequest = new ArrayList<KeyRequest>();
    ArrayList<KeyRequest> midiKeyRequest = new ArrayList<KeyRequest>();

    @Override
    public void pushKey(int keyCode, boolean press) {
        keyRequest.add(new KeyRequest(KeyRequest.KEY,keyCode,press));
    }

    @Override
    public void pushMidiKey(int command, int arg1, int velocity) {
        midiKeyRequest.add(new KeyRequest(KeyRequest.MIDI_KEY,command,arg1,velocity));
    }

    @Override
    public KeyRequest popKey() {
        KeyRequest t = keyRequest.get(keyRequest.size());
        return t;
    }

    @Override
    public KeyRequest popMidiKey() {
        KeyRequest t = midiKeyRequest.get(keyRequest.size());
        midiKeyRequest.remove(keyRequest.size());
        return t;
    }

    @Override
    public int getSizeOfKey() {
        return keyRequest.size();
    }

    @Override
    public int getSizeOfMidiKey() {
        return midiKeyRequest.size();
    }

    @Override
    public boolean getFlush() {
        boolean v = isFlush;
        isFlush = false;
        return v;
    }

    @Override
    public void setFlush(boolean arg) {
        isFlush=arg;
    }
}
EN

回答 1

Stack Overflow用户

发布于 2021-08-16 21:27:35

我还没有深入了解您的代码,但是下面的信息可能会很有用。

SourceDataLine.write()方法在内部使用阻塞队列。它只有在处理数据时才能取得进展。因此,在填充和发送bytes之前,不需要测试可用容量。

我会给予SDL线程10的优先级,因为它的大部分时间都是在阻塞状态下度过的。

而且,我会让这条线路开着运行。我首先从Praxis Live的Neil那里得到了这个建议。不断地重建它是有代价的。在我看来,你正在为每4个字节的音频数据创建一个新的SDL。那将是非常低效的。我怀疑,在256到8K的范围内,在一条开放的线路上运送货物是一个更好的选择,但我没有确凿的事实来支持这一观点。Neil写过所有传输数组都是相同大小的(例如,由synth生成的数据数组与SDL写的大小相同)。

我用java做了一个实时搜索,其中的延迟包括读取鼠标单击和位置的任务,然后将其发送到生成音频数据的synth。我不会把我的延迟归结为允许“在口袋里”开始和停止笔记的精确性,但它仍然很好。我怀疑在我的一端可能会有进一步的优化。

我认为尼尔(前面提到)取得了较好的结果。早在2011年,他就谈到了在5毫秒或更短的时间内实现延迟。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68801835

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档