Using javax.sound.sampled.Clip to play, loop, and stop multiple sounds in a game. Unexpected Errors
Asked Answered
M

2

7

I'm trying to play two wav sounds at once during a game (Background Music and an effect). I first constructed this chunk of code using another audio handler in java which would handle the playing, stopping, and looping of the sound. This construct would play the background music or effect but only one at a time. I looked around the internet and was told to use javax.sound.sampled.Clip to handle the sounds so reused the same construct(play, stop, loop) but switched it to use javax.sound.sampled.Clip. Now I'm completely lost. From what I have read so far I've done everything correct and get no errors in the eclipse editor, but when I run it I get one of two errors. In eclipse (running on Linux) a LineUnavailableException is thrown. In eclipse (running on windows 7) I get a java.lang.NullPointerException in the loop() section of this code. If you could show me what I'm doing wrong or point me to some relevant documentation I'd appreciate it. I'm assuming its something with my code that handles Exceptions but I'm not sure. If you see any other hideous code missteps please let me know I'm striving the be the best programmer I can and really appreciate constructive criticism. Thank you for your time.

    import java.io.File;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import javax.sound.sampled.AudioInputStream;
    import javax.sound.sampled.AudioSystem;
    import javax.sound.sampled.Clip;
    import javax.sound.sampled.LineUnavailableException;
    import javax.sound.sampled.UnsupportedAudioFileException;

    /**
     * Handles play, pause, and looping of sounds for the game.
     * @author Tyler Thomas
     *
     */
    public class Sound {
        private Clip myClip;
        public Sound(String fileName) {
                try {
                    File file = new File(fileName);
                    if (file.exists()) {
                        Clip myClip = AudioSystem.getClip();
                        AudioInputStream ais = AudioSystem.getAudioInputStream(file.toURI().toURL());
                        myClip.open(ais);
                    }
                    else {
                        throw new RuntimeException("Sound: file not found: " + fileName);
                    }
                }
                catch (MalformedURLException e) {
                    throw new RuntimeException("Sound: Malformed URL: " + e);
                }
                catch (UnsupportedAudioFileException e) {
                    throw new RuntimeException("Sound: Unsupported Audio File: " + e);
                }
                catch (IOException e) {
                    throw new RuntimeException("Sound: Input/Output Error: " + e);
                }
                catch (LineUnavailableException e) {
                    throw new RuntimeException("Sound: Line Unavailable: " + e);
                }
        }
        public void play(){
            myClip.setFramePosition(0);  // Must always rewind!
            myClip.loop(0);
            myClip.start();
        }
        public void loop(){
            myClip.loop(Clip.LOOP_CONTINUOUSLY);
        }
        public void stop(){
            myClip.stop();
        }
    }
Makassar answered 12/8, 2012 at 1:23 Comment(0)
M
17

I was able to get the code working and now have a better understanding of Clips. The page that helped me the most was http://www3.ntu.edu.sg/home/ehchua/programming/java/J8c_PlayingSound.html it breaks everything down and helped me see where I made mistakes. Here is my final working code. As before if you see any horrible errors or over sights in logic or style let me know.

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

/**
 * Handles playing, stoping, and looping of sounds for the game.
 * @author Tyler Thomas
 *
 */
public class Sound {
    private Clip clip;
    public Sound(String fileName) {
        // specify the sound to play
        // (assuming the sound can be played by the audio system)
        // from a wave File
        try {
            File file = new File(fileName);
            if (file.exists()) {
                AudioInputStream sound = AudioSystem.getAudioInputStream(file);
             // load the sound into memory (a Clip)
                clip = AudioSystem.getClip();
                clip.open(sound);
            }
            else {
                throw new RuntimeException("Sound: file not found: " + fileName);
            }
        }
        catch (MalformedURLException e) {
            e.printStackTrace();
            throw new RuntimeException("Sound: Malformed URL: " + e);
        }
        catch (UnsupportedAudioFileException e) {
            e.printStackTrace();
            throw new RuntimeException("Sound: Unsupported Audio File: " + e);
        }
        catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("Sound: Input/Output Error: " + e);
        }
        catch (LineUnavailableException e) {
            e.printStackTrace();
            throw new RuntimeException("Sound: Line Unavailable Exception Error: " + e);
        }

    // play, stop, loop the sound clip
    }
    public void play(){
        clip.setFramePosition(0);  // Must always rewind!
        clip.start();
    }
    public void loop(){
        clip.loop(Clip.LOOP_CONTINUOUSLY);
    }
    public void stop(){
            clip.stop();
        }
    }
Makassar answered 16/8, 2012 at 3:28 Comment(1)
Could you explain a little more about that link in case it goes down?Cottonmouth
I
3

I found a useful technique to stop sound. You can copy these two classes down and test it out for yourself. Nevertheless, the clip.stop() method is more of a pause method. It stops the sound from playing, yes, but it does not clear the sound from the line. As a result, the sound is still queued to play and no new sound can be played. So using the clip.close() method will clear out this queued data and allow a new sound to be played or another action to take place. Also note in the following code a sound file was placed in the project folder called "predator.wav" this sound can be any type of sound you want to use instead of the sound I chose, but be sure it is a .wav format and the sound must be in the top-most tier of the project folder.

/*
 * File: KeyMap.java
 * Author: Andrew Peturis Chaselyn Langley; UAB EE Students
 * Assignment:  SoundBox - EE333 Fall 2015
 * Vers: 1.0.0 10/20/2015 agp - initial coding
 *
 * Credits: Dr. Green, UAB EE Engineering Professor
 */

import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

public class KeyMap {

    private char keyCode;
    private String song;
    private Clip clip;

    // Don't allow default constructor
    private KeyMap() {
    }

    public KeyMap(char keyCode, String song) throws LineUnavailableException {
        this.keyCode = keyCode;
        this.song = song;

        // Create an audiostream from the inputstream
        clip = AudioSystem.getClip();
    }

    public boolean match(char key) {
        return key == keyCode;
    }

    // Play a sound using javax.sound and Clip interface
    public String play() {
        try {
            // Open a sound file stored in the project folder
            clip.open(AudioSystem.getAudioInputStream(new File(song + ".wav")));

            // Play the audio clip with the audioplayer class
            clip.start();

            // Create a sleep time of 2 seconds to prevent any action from occuring for the first
            // 2 seconds of the sound playing
            Thread.sleep(2000);

        } catch (LineUnavailableException | UnsupportedAudioFileException | IOException | InterruptedException e) {
            System.out.println("Things did not go well");
            System.exit(-1);
        }
        return song;
    }

    // Stop a sound from playing and clear out the line to play another sound if need be.
    public void stop() {
        // clip.stop() will only pause the sound and still leave the sound in the line
        // waiting to be continued. It does not actually clear the line so a new action could be performed.
        clip.stop();

        // clip.close(); will clear out the line and allow a new sound to play. clip.flush() was not 
        // used because it can only flush out a line of data already performed.
        clip.close();
    }
}

/*
 * File: SoundBox.java
 * Author: Andrew Peturis, Chaselyn Langley; UAB EE Students
 * Assignment:  GUI SoundBox - EE333 Fall 2015
 * Vers: 1.0.0 09/08/2015 agp - initial coding
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
import javax.sound.sampled.LineUnavailableException;

/**
 *
 * @author Andrew Peturis, Chaselyn Langley
 *
 */
public class SoundBox {

    static Scanner scanner = new Scanner(System.in);   //Scanner object to read user input
    InputStream input;

    /**
     * @param args the command line arguments
     * @throws java.io.IOException
     */
    public static void main(String[] args) throws IOException, LineUnavailableException {

        String line;
        Character firstChar;
        String predator = "predator";
        String explosion = "explosion";

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        KeyMap[] keyedSongs = {
            new KeyMap('a', predator),};

        while (true) {
            line = br.readLine();
            firstChar = line.charAt(0);

            for (int i = 0; i < keyedSongs.length; i++) {
                if (keyedSongs[i].match(firstChar)) {

                    // Notice now by running the code, after the first second of sleep time the sound can
                    // and another sound can be played in its place
                    keyedSongs[i].stop();
                    System.out.println("Played the sound: " + keyedSongs[i].play());
                    break;
                }
            }

            if (firstChar == 'q') {
                break;
            }
        }
    }
}
Insurgency answered 9/12, 2015 at 17:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.