193

I want to be able to play sound files in my program. Where should I look?

pek
  • 17,847
  • 28
  • 86
  • 99
  • 1
    Take a look at this class: https://github.com/dberm22/DBoard/blob/master/src/com/dberm22/utils/MediaPlayer.java You can call it with (new Thread(new MediaPlayer(PATHTOFILE)).start(); – dberm22 Jan 20 '14 at 14:36

12 Answers12

147

I wrote the following code that works fine. But I think it only works with .wav format.

public static synchronized void playSound(final String url) {
  new Thread(new Runnable() {
  // The wrapper thread is unnecessary, unless it blocks on the
  // Clip finishing; see comments.
    public void run() {
      try {
        Clip clip = AudioSystem.getClip();
        AudioInputStream inputStream = AudioSystem.getAudioInputStream(
          Main.class.getResourceAsStream("/path/to/sounds/" + url));
        clip.open(inputStream);
        clip.start(); 
      } catch (Exception e) {
        System.err.println(e.getMessage());
      }
    }
  }).start();
}
Bilesh Ganguly
  • 3,792
  • 3
  • 36
  • 58
pek
  • 17,847
  • 28
  • 86
  • 99
  • 7
    To avoid Clip being shut down at random time, a LineListener is required. Have a look: http://stackoverflow.com/questions/577724/trouble-playing-wav-in-java/577926#577926 – yanchenko Feb 23 '09 at 15:40
  • 3
    +1 for a solution that uses the public API. Isn't creating a new thread unnecessary(redundant) though? – Jataro Jul 29 '09 at 09:09
  • 5
    Thanx.. Is it redundant? I made it into a new thread so I can play the sound again before the first clip ends. – pek Jul 29 '09 at 19:04
  • 4
    I know clip.start() spawns a new thread, so I'm pretty sure it is unnecessary. – Jataro Jul 29 '09 at 20:20
  • Appears you're using javax.sound.sampled.AudioSystem instead of sun.audio.* here (which is apparently better)? – rogerdpack Dec 23 '10 at 00:17
  • 50
    1) The `Thread` is unnecessary. 2) For a good example of using `Clip`, see the [JavaSound info. page](http://stackoverflow.com/tags/javasound/info). 3) If a method requires an `URL` (or `File`) give it a dang `URL` (or `File`) rather than accept a `String` that represents one. (Just a personal 'bee in my bonnet'.) 4) `e.printStackTrace();` provides more information with less typing than `System.err.println(e.getMessage());`. – Andrew Thompson Aug 18 '11 at 19:01
  • I tried to play a .wav and it gave NullPointerException. What type of files are supported by this command? – NoBugs Nov 19 '11 at 00:51
  • @NoBugs a NullPointerException can be thrown for 1000 reasons. Are you sure you load the .wav correctly? Are you sure it is in the right path? IIRC, the .wav file should be inside the compiled jar. Although I might be terribly wrong. – pek Nov 19 '11 at 01:15
  • 1
    @NoBugs did u find your soultion ? i also have same problem of NP ? so i need ur help if u solved it then plz let me know how u did it ? – Android Killer Jun 22 '12 at 14:45
  • The NullPointerException could be that you are not referencing the wav file correctly - e.g., use playSound("/bark.wav") not playSound("bark.wav") – ban-geoengineering Mar 05 '13 at 22:42
  • Replace the System.err.println(...) line with e.printStackTrace() for more information on the NullPointerException. – ban-geoengineering Mar 05 '13 at 22:43
  • 1
    I have my system all set up correctly, And the files in place. I get no errors. However, The sound doesn't play.. Do i need to initialize the sound system somewhere or something..? – Nathan F. Mar 17 '13 at 18:24
  • 1
    where to the Clip, AudioSystem, and AudioInputStream classes come from? – Snappawapa Apr 24 '14 at 23:44
  • 1
    Snappawapa: javax.sound.sampled – noisesmith May 08 '14 at 18:18
  • It looks like the `Clip` stays in memory and you create a new one with every call. So you would create a memory leak like that. – das Keks Mar 12 '15 at 23:45
  • To avoid clip.drain() bug as @yanchenko mentioned,here is a listener solution: http://stackoverflow.com/questions/34389991/drain-method-in-javas-clip-class/40429786#40429786 – Daniel Hári Nov 04 '16 at 18:46
  • Is this a robust solution if I am trying to play many sound files simultaneously (30+)? – JFreeman Jan 06 '19 at 00:53
  • Nobody is closing that `InputStream` – Hakanai Feb 17 '21 at 12:08
  • Or the `Clip`. Yep, those are closeable too! – Hakanai Feb 17 '21 at 12:14
20

A bad example:

import  sun.audio.*;    //import the sun.audio package
import  java.io.*;

//** add this into your application code as appropriate
// Open an input stream  to the audio file.
InputStream in = new FileInputStream(Filename);

// Create an AudioStream object from the input stream.
AudioStream as = new AudioStream(in);         

// Use the static class member "player" from class AudioPlayer to play
// clip.
AudioPlayer.player.start(as);            

// Similarly, to stop the audio.
AudioPlayer.player.stop(as); 
Greg Hurlman
  • 17,666
  • 6
  • 54
  • 86
14

I didn't want to have so many lines of code just to play a simple damn sound. This can work if you have the JavaFX package (already included in my jdk 8).

private static void playSound(String sound){
    // cl is the ClassLoader for the current class, ie. CurrentClass.class.getClassLoader();
    URL file = cl.getResource(sound);
    final Media media = new Media(file.toString());
    final MediaPlayer mediaPlayer = new MediaPlayer(media);
    mediaPlayer.play();
}

Notice : You need to initialize JavaFX. A quick way to do that, is to call the constructor of JFXPanel() once in your app :

static{
    JFXPanel fxPanel = new JFXPanel();
}
Community
  • 1
  • 1
Cyril Duchon-Doris
  • 12,964
  • 9
  • 77
  • 164
9

For whatever reason, the top answer by wchargin was giving me a null pointer error when I was calling this.getClass().getResourceAsStream().

What worked for me was the following:

void playSound(String soundFile) {
    File f = new File("./" + soundFile);
    AudioInputStream audioIn = AudioSystem.getAudioInputStream(f.toURI().toURL());  
    Clip clip = AudioSystem.getClip();
    clip.open(audioIn);
    clip.start();
}

And I would play the sound with:

 playSound("sounds/effects/sheep1.wav");

sounds/effects/sheep1.wav was located in the base directory of my project in Eclipse (so not inside the src folder).

Sebastian
  • 5,721
  • 3
  • 43
  • 69
Andrew Jenkins
  • 211
  • 3
  • 7
  • hello Anrew, your code worked for me, but i noticed that takes a little extra time in execution...about 1,5 sec. –  Dec 11 '16 at 11:32
  • 1
    `getResourceAsStream()` will return `null` if the resource is not found, or throw the exception if `name` is `null` - not a fault of top answer if the given path is not valid – user85421 Feb 22 '20 at 08:51
  • what if the audio is non - wav ? – gumuruh Jul 23 '22 at 00:02
  • Loading a file from the filesystem and loading a resource from the classpath is not equivalent, even if it seems so in your IDE. – Queeg Aug 13 '23 at 21:16
8

For playing sound in java, you can refer to the following code.

import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
import javax.swing.*;

// To play sound using Clip, the process need to be alive.
// Hence, we use a Swing application.
public class SoundClipTest extends JFrame {

   public SoundClipTest() {
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      this.setTitle("Test Sound Clip");
      this.setSize(300, 200);
      this.setVisible(true);

      try {
         // Open an audio input stream.
         URL url = this.getClass().getClassLoader().getResource("gameover.wav");
         AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
         // Get a sound clip resource.
         Clip clip = AudioSystem.getClip();
         // Open audio clip and load samples from the audio input stream.
         clip.open(audioIn);
         clip.start();
      } catch (UnsupportedAudioFileException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      } catch (LineUnavailableException e) {
         e.printStackTrace();
      }
   }

   public static void main(String[] args) {
      new SoundClipTest();
   }
}
Esterlinkof
  • 1,444
  • 3
  • 22
  • 27
Ishwor
  • 181
  • 2
  • 10
3

I created a game framework sometime ago to work on Android and Desktop, the desktop part that handle sound maybe can be used as inspiration to what you need.

https://github.com/hamilton-lima/jaga/blob/master/jaga%20desktop/src-desktop/com/athanazio/jaga/desktop/sound/Sound.java

Here is the code for reference.

package com.athanazio.jaga.desktop.sound;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class Sound {

    AudioInputStream in;

    AudioFormat decodedFormat;

    AudioInputStream din;

    AudioFormat baseFormat;

    SourceDataLine line;

    private boolean loop;

    private BufferedInputStream stream;

    // private ByteArrayInputStream stream;

    /**
     * recreate the stream
     * 
     */
    public void reset() {
        try {
            stream.reset();
            in = AudioSystem.getAudioInputStream(stream);
            din = AudioSystem.getAudioInputStream(decodedFormat, in);
            line = getLine(decodedFormat);

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

    public void close() {
        try {
            line.close();
            din.close();
            in.close();
        } catch (IOException e) {
        }
    }

    Sound(String filename, boolean loop) {
        this(filename);
        this.loop = loop;
    }

    Sound(String filename) {
        this.loop = false;
        try {
            InputStream raw = Object.class.getResourceAsStream(filename);
            stream = new BufferedInputStream(raw);

            // ByteArrayOutputStream out = new ByteArrayOutputStream();
            // byte[] buffer = new byte[1024];
            // int read = raw.read(buffer);
            // while( read > 0 ) {
            // out.write(buffer, 0, read);
            // read = raw.read(buffer);
            // }
            // stream = new ByteArrayInputStream(out.toByteArray());

            in = AudioSystem.getAudioInputStream(stream);
            din = null;

            if (in != null) {
                baseFormat = in.getFormat();

                decodedFormat = new AudioFormat(
                        AudioFormat.Encoding.PCM_SIGNED, baseFormat
                                .getSampleRate(), 16, baseFormat.getChannels(),
                        baseFormat.getChannels() * 2, baseFormat
                                .getSampleRate(), false);

                din = AudioSystem.getAudioInputStream(decodedFormat, in);
                line = getLine(decodedFormat);
            }
        } catch (UnsupportedAudioFileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    private SourceDataLine getLine(AudioFormat audioFormat)
            throws LineUnavailableException {
        SourceDataLine res = null;
        DataLine.Info info = new DataLine.Info(SourceDataLine.class,
                audioFormat);
        res = (SourceDataLine) AudioSystem.getLine(info);
        res.open(audioFormat);
        return res;
    }

    public void play() {

        try {
            boolean firstTime = true;
            while (firstTime || loop) {

                firstTime = false;
                byte[] data = new byte[4096];

                if (line != null) {

                    line.start();
                    int nBytesRead = 0;

                    while (nBytesRead != -1) {
                        nBytesRead = din.read(data, 0, data.length);
                        if (nBytesRead != -1)
                            line.write(data, 0, nBytesRead);
                    }

                    line.drain();
                    line.stop();
                    line.close();

                    reset();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
hamilton.lima
  • 1,902
  • 18
  • 29
  • This code may error on `stream.reset();` leading to `Resetting to invalid mark`. What do you propose to do to fix this? – driima Jan 10 '20 at 00:25
  • maybe recreate the stream, see https://stackoverflow.com/questions/18573767/exception-stating-resetting-to-invalid-mark-comes-while-marking-an-inputstre – hamilton.lima Jan 10 '20 at 12:45
  • 1
    I actually resolved this by using `raw.mark(raw.available()+1)` after initialising `raw` and then in the while loop, and then using `raw.reset()` instead of `stream.reset()`. My problem now is that when it comes around to reset, there's a gap between plays. I want to achieve a continuous loop like you get with `Clip`. I'm not using `Clip` because manipulating controls such as MASTER_GAIN has a noticeable delay of ~500ms. This should probably be its own question that I'll get around to asking later. – driima Jan 10 '20 at 13:47
  • 1
    Not a `do { ... } while`? – Andreas is moving to Codidact Jun 02 '20 at 14:52
3

It works for me. Simple variant

public void makeSound(){
    File lol = new File("somesound.wav");
    

    try{
        Clip clip = AudioSystem.getClip();
        clip.open(AudioSystem.getAudioInputStream(lol));
        clip.start();
    } catch (Exception e){
        e.printStackTrace();
    }
}
Arsen Tagaev
  • 411
  • 7
  • 13
2

There is an alternative to importing the sound files which works in both applets and applications: convert the audio files into .java files and simply use them in your code.

I have developed a tool which makes this process a lot easier. It simplifies the Java Sound API quite a bit.

http://stephengware.com/projects/soundtoclass/

Vogel612
  • 5,620
  • 5
  • 48
  • 73
Stephen Ware
  • 109
  • 1
  • 6
  • I used your system to create a class from a wav file, However, When i do my_wave.play(); it doesn't play the audio.. Is there an audio system i need to initialize or something?.. – Nathan F. Mar 17 '13 at 18:22
  • this would be really cool if it did actually work. When running play(), the get Audio Line fails (exception "java.lang.IllegalArgumentException: No line matching interface SourceDataLine supporting format PCM_UNSIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian is supported." is not thrown). Sad. – phil294 Dec 16 '14 at 02:29
2

I'm surprised nobody suggested using Applet. Use Applet. You'll have to supply the beep audio file as a wav file, but it works. I tried this on Ubuntu:

package javaapplication2;

import java.applet.Applet;
import java.applet.AudioClip;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;

public class JavaApplication2 {

    public static void main(String[] args) throws MalformedURLException {
        File file = new File("/path/to/your/sounds/beep3.wav");
        URL url = null;
        if (file.canRead()) {url = file.toURI().toURL();}
        System.out.println(url);
        AudioClip clip = Applet.newAudioClip(url);
        clip.play();
        System.out.println("should've played by now");
    }
}
//beep3.wav was available from: http://www.pacdv.com/sounds/interface_sound_effects/beep-3.wav
Nav
  • 19,885
  • 27
  • 92
  • 135
1
import java.net.URL;
import java.net.MalformedURLException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;
import java.io.File;
public class SoundClipTest{
    //plays the sound
    public static void playSound(final String path){
        try{
            final File audioFile=new File(path);
            AudioInputStream audioIn=AudioSystem.getAudioInputStream(audioFile);
            Clip clip=AudioSystem.getClip();
            clip.open(audioIn);
            clip.start();
            long duration=getDurationInSec(audioIn);
            //System.out.println(duration);
            //We need to delay it otherwise function will return
            //duration is in seconds we are converting it to milliseconds
            Thread.sleep(duration*1000);
        }catch(LineUnavailableException | UnsupportedAudioFileException | MalformedURLException | InterruptedException exception){
            exception.printStackTrace();
        }
        catch(IOException ioException){
            ioException.printStackTrace();
        }
    }
    //Gives duration in seconds for audio files
    public static long getDurationInSec(final AudioInputStream audioIn){
        final AudioFormat format=audioIn.getFormat();
        double frameRate=format.getFrameRate();
        return (long)(audioIn.getFrameLength()/frameRate);
    }
    ////////main//////
    public static void main(String $[]){
        //SoundClipTest test=new SoundClipTest();
        SoundClipTest.playSound("/home/dev/Downloads/mixkit-sad-game-over-trombone-471.wav");
    }
}
Udesh
  • 2,415
  • 2
  • 22
  • 32
0

This thread is rather old but I have determined an option that could prove useful.

Instead of using the Java AudioStream library you could use an external program like Windows Media Player or VLC and run it with a console command through Java.

String command = "\"C:/Program Files (x86)/Windows Media Player/wmplayer.exe\" \"C:/song.mp3\"";
try {
    Process p = Runtime.getRuntime().exec(command);
catch (IOException e) {
    e.printStackTrace();
}

This will also create a separate process that can be controlled it the program.

p.destroy();

Of course this will take longer to execute than using an internal library but there may be programs that can start up faster and possibly without a GUI given certain console commands.

If time is not of the essence then this is useful.

Galen Nare
  • 376
  • 2
  • 4
  • 18
  • 5
    Although I think this is an objectively bad solution (in terms of reliability, efficiency, and other such metrics), it is at least an interesting one I would not otherwise have thought of! – Max von Hippel Nov 29 '19 at 04:31
0

I faced many issues to play mp3 file format so converted it to .wav using some online converter

and then used below code (it was easier instead of mp3 supporting)

try
{
    Clip clip = AudioSystem.getClip();
    clip.open(AudioSystem.getAudioInputStream(GuiUtils.class.getResource("/sounds/success.wav")));
    clip.start();
}
catch (Exception e)
{
    LogUtils.logError(e);
}
Adir Dayan
  • 1,308
  • 13
  • 21