玩游戏音乐在Java中 - 如何停止的数据流? [英] Playing game music in Java - How to stop the stream of data?

查看:198
本文介绍了玩游戏音乐在Java中 - 如何停止的数据流?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在高中的一场比赛,我做在介绍课程这个音乐课。你可以看到在那里我得到了code的。

我本来使用剪辑,却发现,有pretty小的缓冲区大小,并不能发挥悠长的歌很好(至少不是我们的在学校的Mac电脑)。新的code效果很好,从我的理解是越来越歌曲的豆腐块,打它们,然后获得更多的块。问题是,当音乐改变了歌曲有时会重叠,当我退出游戏,一个可怕的声音播放(至少在Mac上)可能造成的,因为被切断数据流游戏关闭之前。

反正是有比拖延程序,每次几秒钟就可以解决这个问题其他?
(注:我不想使用外部.jar的或库,我想保持它严格JRE)

 包mahaffeyfinalproject;进口的java.io.File;
进口javax.sound.sampled.AudioFormat中;
进口javax.sound.sampled.AudioInputStream中;
进口javax.sound.sampled.AudioSystem;
进口javax.sound.sampled.DataLine中;
进口javax.sound.sampled.SourceDataLine;
公共类音乐实现Runnable {//来源:http://www.ntu.edu.sg/home/ehchua/programming/java/J8c_PlayingSound.html
//注:我稍微修改了它私人字符串位置;
私人布尔播放;公共无效音乐(){}公共无效playMusic(字符串LOC){
    位置=禄;
    玩= TRUE;
    尝试{
        线程t =新主题(本);
        t.start();
    }赶上(例外五){
        通信System.err.println(无法启动线程的音乐);
    }
}公共无效的run(){
    SourceDataLine的soundLine = NULL;
    INT BUFFER_SIZE = 64 * 1024;    尝试{
        文件音效档=新的文件(位置);
        的AudioInputStream的AudioInputStream = AudioSystem.getAudioInputStream(音效档);
        AudioFormat的AudioFormat的= audioInputStream.getFormat();
        DataLine.Info信息=新DataLine.Info(SourceDataLine.class,AudioFormat的);
        soundLine =(SourceDataLine的)AudioSystem.getLine(信息);
        soundLine.open(AudioFormat的);
        soundLine.start();
        INT nBytesRead = 0;
        字节[] = sampledData新的字节[BUFFER_SIZE];        而(nBytesRead = -1&安培;!&安培;发挥== TRUE){
            nBytesRead = audioInputStream.read(sampledData,0,sampledData.length);
            如果(nBytesRead> = 0){
               soundLine.write(sampledData,0,nBytesRead);
            }
        }
    }赶上(例外五){
        通信System.err.println(无法启动音乐!);
    }    soundLine.drain();
    soundLine.close();}公共无效停止(){
    玩= FALSE;
}
}


解决方案

我不知道你越来越接近上可怕的声音,但我觉得我有如何解决你所提到的重叠问题的想法。它看起来像你的声音API的使用情况是好的,但我怀疑你可能有一个并发问题。我注意到,你开始为每个声音你玩一个新的线程。这是一个好主意,但是你必须要小心,如果你不想让你的歌曲混合。我的理论是,你的code看起来是这样的:

 音乐SONGA =新音乐();
音乐歌曲B =新音乐();//开始播放歌曲一
songA.playMusic(路径);//有些事情发生你的游戏...//一段时间以后,你想改变曲B
songA.stop();
songB.playMusic(另一条道路);

乍一看,这看起来不错,毕竟你是认真歌曲B开始之前停止SONGA,对不对?不幸的是,当涉及到并发几件事情是因为我们更喜欢他们是那么简单。让我们来看看你的code小一点,具体负责将数据输入的音频流...

,而循环

  //里面的run(),这是在年底有趣的位而(nBytesRead = -1&安培;!&安培;发挥== TRUE){
    //订阅的音频流,同时还有数据
}

停止()播放为false,导致while循环完成后退出,当前迭代。如果我没有记错的话,你的,而每次循环发送数据到64K音频流。 64K是音频数据的相当数量,并且根据音频属性会持续一段时间。你真正想要做的是信号线程退出(即一套打法为false),,然后等待线程完成的。我相信,这将解决重叠问题,如果你不杀你的线程正确这个问题也可能导致对退出的神可怕的球拍。我谦恭地提出了以下更改你的音乐类(不保证正确性)...

 公共类音乐实现Runnable {
    私人线程t; //使线程对象的类字段    //只是一切是因为它以前一样的...    公共无效停止(){
        玩= FALSE;
        尝试{
            t.join()
        }赶上(InterruptedException的E){
            //不要做任何事情,没关系
        }
   }
}

希望这会有所帮助,并为所有的爱是善良纯洁不要用我的code原样,就来到了我的头顶部约2分钟。我建议 Java教程系列的线程

I have this music class for a game I'm making in an Introduction Course in high school. You can see the source where I got the code from.

I originally was using a Clip, but found out that had pretty small buffer sizes, and couldn't play long songs well (at least not on our Macs at school). The new code works well, from what I understand it is getting "chunks" of the song, playing them, then getting more chunks. Problem is, when the music changes the songs will sometimes overlap, and when I exit the game, a terrible sound plays (at least on the Macs) probably caused because the stream of data is being cut before the game closes.

Is there anyway to fix this other than delaying the program a few seconds each time? (Note: I don't want to use external .jar's or libraries, I'd like to keep it to strictly the 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;
}


}

解决方案

I'm not sure about the horrible sound you are getting on close, but I think I have an idea of how to solve the overlap problem you mentioned. It looks like your usage of the Sound API is fine, but I suspect you may be having a concurrency issue. I noticed that you start off a new thread for each sound you play. This is a good idea, but you need to be careful if you don't want your songs to mix. My theory is that your code looks something like this:

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");

At first blush this looks fine, after all you were careful to stop songA before starting songB, right? Unfortunately, when it comes to concurrency few things are as simple as we might like them to be. Let's look at a small bit of your code, specifically the while loop responsible for feeding data into the audio stream...

//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() sets play to false, causing the while loop to exit, after finishing the current iteration. If I'm not mistaken, each iteration of your while loop is sending 64k of data into the audio stream. 64k is a fair amount of audio data, and depending on the audio properties will go on for some time. What you really want to do is signal the thread to quit (i.e. set play to false), and then wait for the thread to finish. I believe this will fix the overlap problem, and if you're not killing your threads properly this issue may also be causing the god-awful racket on quit. I humbly suggest the following change to your Music class (with no guarantee of correctness)...

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

Hope this helps, and for the love of all that is good and pure don't use my code as-is, it came off the top of my head in about 2 minutes. I recommend The Java Tutorials' series on threading.

这篇关于玩游戏音乐在Java中 - 如何停止的数据流?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆