【问题标题】:The Most efficient way of playing wav sound Java播放wav声音Java的最有效方式
【发布时间】:2014-10-17 22:23:48
【问题描述】:

我正在开发鼓节拍器。所以我有 .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声音文件的最快方式。请考虑到有时我需要同时播放它们,所以我认为声音应该作为单独的线程播放。

谢谢

【问题讨论】:

  • 你可以尝试在codereview.stackexchange.com添加这个问题!
  • 是的,代码审查可以对这段代码说很多话。比如你滥用实例变量,就好像它们是局部变量一样。
  • 根据我的经验,任何依赖 Thread.sleep 的解决方案都不适合任何音频播放解决方案,例如麦克风,因为计时器分辨率差。最好的解决方案是不断地流式传输音频,为计算出的样本数写入零,然后写出波形。
  • 使用 Java Timer 和线程可以得到相同的结果吗?

标签: java audio


【解决方案1】:

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

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

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

或者也许你已经做了一些更好的实现,比如:

示例#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:

像这样调整你的 playSound 方法:

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)

【讨论】:

  • 但不是每次都初始化声音变量吗?我的意思是 playSound() 方法
  • 它将留在循环中:while(true){ ...} 循环将永远不会中止...
  • 问题是每次播放不同的声音文件不一样。首先,您有编辑器,您可以在其中告诉程序应该播放哪种鼓声,并设置持续时间
  • 我的回答不完整——您必须根据自己的需要进行调整...这只是为了让您的声音播放得更好...
  • 让我知道这篇文章是否对您有帮助 - 我很乐意提供更多帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-21
  • 2013-04-25
相关资源
最近更新 更多