gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 06:35:14 24 4
gpt4 key购买 nike

我在高中的介绍类(class)中为我正在制作的游戏开设了这门音乐课。可以看到the source我从哪里得到代码的。

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

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

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;
}


}

最佳答案

我不确定您近距离听到的可怕声音,但我想我知道如何解决您提到的重叠问题。看起来您对 Sound API 的使用没有问题,但我怀疑您可能遇到了并发问题。我注意到你为你播放的每个声音开始了一个新线程。这是个好主意,但如果您不想让您的歌曲混音,则需要小心。我的理论是您的代码看起来像这样:

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 循环...

//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 是相当数量的音频数据,并且根据音频属性会持续一段时间。您真正想要做的是向线程发出退出信号(即将播放设置为 false),然后等待线程完成。我相信这会解决重叠问题,如果你没有正确地终止你的线程,这个问题也可能导致可怕的 Racket 退出。我谦虚地建议对您的音乐课进行以下更改(不保证正确性)...

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 .

关于java - 在 Java 中播放游戏音乐 - 如何停止数据流?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6259077/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com