播放wav声音Java的最有效方式

时间:2014-08-24 17:47:13

标签: java audio

我正在开发一种鼓节拍器。所以我有.wav声音文件,我需要使用最小的计算机内存和CPU来播放它们,因为节拍器在准确的时间播放样本非常重要。目前我使用此链接中的代码 How to play .wav files with java

class MakeSound {

    private final int BUFFER_SIZE = 128000;
    private File soundFile;
    private AudioInputStream audioStream;
    private AudioFormat audioFormat;
    private SourceDataLine sourceLine;

    /**
     * @param filename the name of the file that is going to be played
     */
    public void playSound(String filename){

        String strFilename = filename;

        try {
            soundFile = new File(strFilename);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        try {
            audioStream = AudioSystem.getAudioInputStream(soundFile);
        } catch (Exception e){
            e.printStackTrace();
            System.exit(1);
        }

        audioFormat = audioStream.getFormat();

        DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
        try {
            sourceLine = (SourceDataLine) AudioSystem.getLine(info);
            sourceLine.open(audioFormat);
        } catch (LineUnavailableException e) {
            e.printStackTrace();
            System.exit(1);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

        sourceLine.start();

        int nBytesRead = 0;
        byte[] abData = new byte[BUFFER_SIZE];
        while (nBytesRead != -1) {
            try {
                nBytesRead = audioStream.read(abData, 0, abData.length);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (nBytesRead >= 0) {
                @SuppressWarnings("unused")
                int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
            }
        }

        sourceLine.drain();
        sourceLine.close();
    }
}

此代码有效,但在节拍器应用中使用它的速度太慢。那么这是播放wav声音文件的最快方式。请注意,有时我需要同时播放它们,所以声音应该作为一个单独的线程发挥我的想法。

由于

1 个答案:

答案 0 :(得分:1)

我假设你有一个看起来像这样的工作方法:

示例#1 :(不要这样做)

public void startMetronome(){
    boolean abort = false;
    String audoFileName = new String("myAudioFile);
    do{
        playSound(audoFileName );
    while(abort != false);    
}

或者你可能已经做了一些更好的实现:

exapmle#2 :(也不要这样做)

Runnable r = new Runnable(){
    boolean abort = false;
    String audoFileName = new String("myAudioFile);
    do{
        playSound(audoFileName );
        try{
            Thread.sleep(500);
        }catch (Exception e);
    while(abort != false);    
}
new Thread(r).start();

在任何情况下你都犯了一个大错:每次你发出声音时都会初始化声音,每次你一次又一次地加载文件。

但这是一个非常错误的方法,你必须加载一次文件,打开一次线并在线上重复播放声音!

(便宜)解决方案#3:

像这样调整你的playSoundmethode:

public void playSound(String filename){

    //same as above
    String strFilename = filename;
    soundFile = new File(strFilename); //i've shorened the catch/throws, to make it more readable 
    audioStream = AudioSystem.getAudioInputStream(soundFile);
    audioFormat = audioStream.getFormat();
    DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
    sourceLine = (SourceDataLine) AudioSystem.getLine(info);
    sourceLine.open(audioFormat);

    sourceLine.start();

    //right now, the line is set up and all data is availible
    boolean isRunning = true;

    while(isRunning){ //this is an endless loop!
        int nBytesRead = 0;
        byte[] abData = new byte[BUFFER_SIZE];
        while (nBytesRead != -1) {
        nBytesRead = audioStream.read(abData, 0, abData.length);

        //and your timing here
        try{
            Thread.sleep(500);
        }catch (Exception e);
    }

    sourceLine.drain();
    sourceLine.close();
}

最好的做法是在一个单独的线程中播放整个事情......(例如#2)