开发者

How to play audio in Java Application

I'm making a java application and I need to play audio. I'm playing mainly small sound files of my cannon firing (its a cannon shooting game) and the projectiles exploding, though I plan on having looping background music. I have found two different methods to accomplish this, but both don't work how I want.

The first method is literally a method:

        public void playSoundFile(File file) {//http://java.ittoolbox.com/groups/technical-functional/java-l/sound-in-an-application-90681

        try {
//get an AudioInputStream
            AudioInputStream ais = AudioSystem.getAudioInputStream(file);
//get the AudioFormat for the AudioInputStream
            AudioFormat audioformat = ais.getFormat();
            System.out.println("Format: " + audioformat.toString());
            System.out.println("Encoding: " + audioformat.getEncoding());
            System.out.println("SampleRate:" + audioformat.getSampleRate());
            System.out.println("SampleSizeInBits: " + audioformat.getSampleSizeInBits());
            System.out.println("Channels: " + audioformat.getChannels());
            System.out.println("FrameSize: " + audioformat.getFrameSize());
            System.out.println("FrameRate: " + audioformat.getFrameRate());
            System.out.println("BigEndian: " + audioformat.isBigEndian());
//ULAW format to PCM format conversion
            if ((audioformat.getEncoding() == AudioFormat.Encoding.ULAW)
                    || (audioformat.getEncoding() == AudioFormat.Encoding.ALAW)) {
                AudioFormat newformat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                        audioformat.getSampleRate(),
                        audioformat.getSampleSizeInBits() * 2,
                        audioformat.getChannels(),
                        audioformat.getFrameSize() * 2,
                        audioformat.getFrameRate(), true);
                ais = AudioSystem.getAudioInputStream(newformat, ais);
                audioformat = newformat;
            }

//checking for a supported output line
            DataLine.Info datalineinfo = new DataLine.Info(SourceDataLine.class, audioformat);
            if (!AudioSystem.isLineSupported(datalineinfo)) {
                //System.out.println("Line matching " + datalineinfo + " is not supported.");
            } else {
                //System.out.println("Line matching " + datalineinfo + " is supported.");
//opening the sound output line
                SourceData开发者_JS百科Line sourcedataline = (SourceDataLine) AudioSystem.getLine(datalineinfo);
                sourcedataline.open(audioformat);
                sourcedataline.start();
//Copy data from the input stream to the output data line
                int framesizeinbytes = audioformat.getFrameSize();
                int bufferlengthinframes = sourcedataline.getBufferSize() / 8;
                int bufferlengthinbytes = bufferlengthinframes * framesizeinbytes;
                byte[] sounddata = new byte[bufferlengthinbytes];
                int numberofbytesread = 0;
                while ((numberofbytesread = ais.read(sounddata)) != -1) {
                    int numberofbytesremaining = numberofbytesread;
                    sourcedataline.write(sounddata, 0, numberofbytesread);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

The problem with this is that my entire program stops until the sound file is finished, or at least nearly finished.

The second method is this:

    File file = new File("Launch1.wav");
    AudioClip clip;
    try {
        clip = JApplet.newAudioClip(file.toURL());
        clip.play();
    } catch (Exception e) {
        e.getMessage();
    }

The problem I have here is that every time the sound file ends early or doesn't play at all depending on where I place the code.

Is their any way to play sound without the above mentioned problems? Am I doing something wrong? Any help is greatly appreciated.


For the first method you have to create another thread for audio.

For example like this:

new Thread(
            new Runnable() {
                public void run() {
                    try {
                        // PLAY AUDIO CODE
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();

Of course you have to make sure that previous sound isn't still playing.


I guess you should run your playSound method in a background thread as mentioned in the doc here

"you'll probably want to invoke this playback loop in a separate thread from the rest of the application program, so that your program doesn't appear to freeze when playing a long sound"

Maybe by doing something like

// shared executor
ExecutorService soundExecutor = ...; //Executors.newSingleThreadExecutor();
...
final File soundFile = ...;
soundExecutor.submit(new Runnable(){
   public void run(){
        SoundUtils.playSoundFile(soundFile);
   }
});


The problem with this is that my entire program stops until the sound file is finished, or at least nearly finished.

This screams a threading issue. Have you tried playing the sound in a background thread? By the way, is this a Swing program? If so, use a SwingWorker to play the sound. There are many reasons for this, but one primary reason is that it's easy to track the state of the thread via the PropertyChangeListener support built in to SwingWorker.


You should create a thread that handles the audio playback. But make sure that it is able to mix in sounds, so two shots that happen after each other can get their sounds played at the correct time, without waiting for the prior sound to finish. There should be Frameworks out there that do the mixing for you.

A good starting point is: http://www.oracle.com/technetwork/java/javase/tech/index-jsp-140239.html

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜