首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Java中播放游戏音乐-如何停止数据流?

在Java中播放游戏音乐-如何停止数据流?
EN

Stack Overflow用户
提问于 2011-06-07 07:15:36
回答 1查看 5.7K关注 0票数 2

我在高中的一门入门课上做了一个游戏,上了这个音乐课。你可以看到我从哪里得到代码的the source

我最初使用的是Clip,但后来发现它的缓冲区非常小,而且不能很好地播放长歌(至少不能在学校的Mac上播放)。新的代码运行良好,据我所知,它是获得歌曲的“块”,播放它们,然后获得更多的块。问题是,当音乐改变时,歌曲有时会重叠,当我退出游戏时,播放糟糕的声音(至少在Mac上)可能是因为数据流在游戏结束前被切断。

除了每次延迟程序几秒钟之外,还有什么办法可以解决这个问题吗?(注意:我不想使用外部的.jar或库,我想将其严格限制在JRE中)

代码语言:javascript
运行
复制
package mahaffeyfinalproject;

import java.io.File;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;


public class Music implements Runnable{

//SOURCE: http://www.ntu.edu.sg/home/ehchua/programming/java/J8c_PlayingSound.html
//Note: I've modified it slightly

private String location;
private boolean play;

public void Music(){

}

public void playMusic(String loc) {
    location = loc;
    play = true;
    try{
        Thread t = new Thread(this);
        t.start();
    }catch(Exception e){
        System.err.println("Could not start music thread");
    }
}

public void run(){
    SourceDataLine soundLine = null;
    int BUFFER_SIZE = 64*1024;

    try {
        File soundFile = new File(location);
        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile);
        AudioFormat audioFormat = audioInputStream.getFormat();
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
        soundLine = (SourceDataLine) AudioSystem.getLine(info);
        soundLine.open(audioFormat);
        soundLine.start();
        int nBytesRead = 0;
        byte[] sampledData = new byte[BUFFER_SIZE];

        while (nBytesRead != -1 && play == true) {
            nBytesRead = audioInputStream.read(sampledData, 0, sampledData.length);
            if (nBytesRead >= 0) {
               soundLine.write(sampledData, 0, nBytesRead);
            }
        }
    } catch (Exception e) {
        System.err.println("Could not start music!");
    }

    soundLine.drain();
    soundLine.close();

}

public void stop(){
    play = false;
}


}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-06-07 11:46:21

我不确定你正在接近的可怕的声音,但我想我知道如何解决你提到的重叠问题。看起来您对Sound API的使用很好,但我怀疑您可能有并发问题。我注意到你播放的每一个声音都会有一个新的线程。这是个好主意,但是如果你不想把你的歌曲混在一起,那就得小心了。我的理论是你的代码应该是这样的:

代码语言:javascript
运行
复制
Music songA = new Music();
Music songB = new Music();

//Start playing song A
songA.playMusic("path");

//Some stuff happens with your game...

//Some time later you want to change to song B
songA.stop();
songB.playMusic("other path");

乍一看,这看起来很好,毕竟您在启动songB之前小心地停止了songA,对吧?不幸的是,当涉及到并发性时,很少有事情像我们希望的那样简单。让我们看一小段代码,特别是负责向音频流提供数据的while循环……

代码语言:javascript
运行
复制
//Inside run(), this is the interesting bit at the end

while(nBytesRead != -1 && play == true){
    //Feed the audio stream while there is still data 
}

stop()play设置为false,导致while循环退出,并在完成当前迭代后返回。如果我没记错的话,您的while循环的每次迭代都会向音频流发送64k的数据。64k是一个相当大的音频数据量,根据音频属性的不同还会持续一段时间。你真正想做的是通知线程退出(即设置play为false),然后等待线程结束。我相信这将解决重叠的问题,如果你没有正确地杀死你的线程,这个问题也可能导致退出时可怕的球拍。我谦虚地建议对您的音乐类进行以下更改(不保证正确性)……

代码语言:javascript
运行
复制
public class Music implements Runnable{
    private Thread t;    //Make the thread object a class field

    //Just about everything is the same as it was before...

    public void stop(){
        play = false;
        try{
            t.join()
        }catch(InterruptedException e){
            //Don't do anything, it doesn't matter
        }
   }
}

希望这对我有所帮助,出于对所有好的和纯粹的东西的喜爱,请不要使用我的代码,它在大约2分钟内就从我的脑海中消失了。我推荐The Java Tutorials' series on threading

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

https://stackoverflow.com/questions/6259077

复制
相关文章

相似问题

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