Can't get audio file to play - java

I can't seem to figure out why my audio file won't play. The audio file is a wav file and is just. The error i am getting is javax.sound.sampled.UnsupportedAudioFileException.
public class MusicProgress {
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame b = new JFrame();
FileDialog fd = new FileDialog(b, "Pick a file: ", FileDialog.LOAD);
fd.setVisible(true);
final File file = new File(fd.getDirectory() + fd.getFile());
//URI directory = new URI (fd.getDirectory() + fd.getFile());
try {
AudioInputStream inputStream = AudioSystem.getAudioInputStream(file);
AudioFormat audioFormat = inputStream.getFormat();
Clip clip = AudioSystem.getClip();
clip.open(inputStream);
clip.start();
} catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Java does not support all wav formats. The highest quality supported is a standard CD encoding format. With those files, you should be okay. That format has 16-bit encoding, 44100 fps, little endian, stereo. You should be able to inspect the properties of your wav file and learn if it matches or not.
It is getting more and more common for DAWs to produce wav files that have 24-bit or 32-bit encoding, or 48000fps or 92000fps.
It is possible to convert these to the "CD" encoding spec with a tool such as Audacity.

I dug up some old code of mine to play an audio file. This might work:
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.JOptionPane;
public class SoundPlayer {
Clip clip;
public SoundPlayer(String file){
//if(clip.isRunning()){clip.stop();}
try{
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(SoundPlayer.class.getResource(file));
clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start();
}catch(Exception err){err.printStackTrace(); JOptionPane.showMessageDialog(null, "SoundPlayer: "+err,null,0);}
}
}
And to play an audio clip:
new SoundPlayer(filepath);
The path should look somthing like this: "/game/resources/sound/Explosion.wav"
And as you stated, it must be a .wav file.

You have to use external libraries to play files like .mp3
Java support only .wav
but that's enough.All you need is an external algorithm to play other music formats.All the other format's came originally from .wav they pass into an algorithm and then boom they become .ogg,.mp3,.whatever
1.A very impressive library to use which support .mp3 JLayer.jar
You can import this jar into your project as an external library.
2.If you search more you will find JAudiotagger it's just amazing but difficult to use.
3.Also you can use Java Media FrameWork but whatever it doesnt support to much formats.
4.JavaZoom has also and other libraries to support .ogg,.speex,.flac,.mp3
Links to stackoverflow on How to play .wav files with java
And http://alvinalexander.com/java/java-audio-example-java-au-play-sound
Not sure if that still works with java 8
This:
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class AudioPlayerExample1 implements LineListener {
/**
* this flag indicates whether the playback completes or not.
*/
boolean playCompleted;
/**
* Play a given audio file.
* #param audioFilePath Path of the audio file.
*/
void play() {
File audioFile = new File("C:/Users/Alex.hp/Desktop/Musc/audio.wav");
try {
AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);
AudioFormat format = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip audioClip = (Clip) AudioSystem.getLine(info);
audioClip.addLineListener(this);
audioClip.open(audioStream);
audioClip.start();
while (!playCompleted) {
// wait for the playback completes
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
audioClip.close();
} catch (UnsupportedAudioFileException ex) {
System.out.println("The specified audio file is not supported.");
ex.printStackTrace();
} catch (LineUnavailableException ex) {
System.out.println("Audio line for playing back is unavailable.");
ex.printStackTrace();
} catch (IOException ex) {
System.out.println("Error playing the audio file.");
ex.printStackTrace();
}
}
/**
* Listens to the START and STOP events of the audio line.
*/
#Override
public void update(LineEvent event) {
LineEvent.Type type = event.getType();
if (type == LineEvent.Type.START) {
System.out.println("Playback started.");
} else if (type == LineEvent.Type.STOP) {
playCompleted = true;
System.out.println("Playback completed.");
}
}
public static void main(String[] args) {
AudioPlayerExample1 player = new AudioPlayerExample1();
player.play();
}
}

Related

I want to play multiple audio files at the same time using JavaSound but my threaded application skills are rusty [duplicate]

So my application should play the WAV file every time I click on the panel. But the problem right now is, it waits for the first one to finish before it plays the second one. I want to be able to have them play simultaneously.
The reason I put Thread.sleep(500) is because if I don't, then it won't play the sound at all :(
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class SoundEffectPlayer extends JFrame {
/*
* Jframe stuff
*/
public SoundEffectPlayer() {
this.setSize(400, 400);
this.setTitle("Mouse Clicker");
this.addMouseListener(new Clicker());
this.setVisible(true);
}
private class Clicker extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
try {
playSound(1);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
/*
* Directory of your sound files
* format is WAV
*/
private static final String DIRECTORY = "file:///C:/Users/Jessica/Desktop/audio/effects/sound 1.wav";
/*
* The volume for sound effects
*/
public static float soundEffectsVolume = 0.00f;
/*
* Loads the sound effect files from cache
* into the soundEffects array.
*/
public void playSound(int ID) throws InterruptedException {
try {
System.out.println("playing");
Clip clip;
URL url = new URL(DIRECTORY);
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.setFramePosition(0);
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(soundEffectsVolume);
clip.start();
System.out.println("played");
Thread.sleep(3000);
System.out.println("closing");
} catch (MalformedURLException e) {
System.out.println("Sound effect not found: "+ID);
e.printStackTrace();
return;
} catch (UnsupportedAudioFileException e) {
System.out.println("Unsupported format for sound: "+ID);
return;
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
}
public static void main(String[] args) throws InterruptedException {
new SoundEffectPlayer();
}
}
Update: Okay so I got them to play simeutaneously, but I want to make the the thread close when the Clip is done playing, instead of making the thread wait 500ms
How can I do that?
I have always run multiple sounds like this. I don't spawn a new thread as I guess javaSound already runs clips in an another threads. Main "game loop" may continue doing its own stuff. App may register listeners for callbacks or use getters to see what clips are doing.
Sometimes if we are to make multimedia or game application its easier to just use getters. Running gameloop 30-60fps gives enough granularity for most cases and we have a total control of what happens and when. This little testapp playbacks two wav files, first is run once, second is started after 3sec, second loops.
// java -cp ./classes SoundTest1 clip1=sound1.wav clip2=sound2.wav
import java.util.*;
import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
public class SoundTest1 {
public Clip play(String filename, boolean autostart, float gain) throws Exception {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(filename));
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.setFramePosition(0);
// values have min/max values, for now don't check for outOfBounds values
FloatControl gainControl = (FloatControl)clip.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(gain);
if(autostart) clip.start();
return clip;
}
public static void main(String[] args) throws Exception {
Map<String,String> params = parseParams(args);
SoundTest1 test1 = new SoundTest1();
Clip clip1 = test1.play(params.get("clip1"), true, -5.0f);
Clip clip2 = test1.play(params.get("clip2"), false, 5.0f);
final long duration=Long.MAX_VALUE;
final int interval=500;
float clip2IncGain=0.4f;
for(long ts=0; ts<duration; ts+=interval) {
System.out.println(String.format("clip1=%d/%d(%.2f), clip2=%d/%d(%.2f)"
,clip1.getFramePosition(), clip1.getFrameLength()
,((FloatControl)clip1.getControl(FloatControl.Type.MASTER_GAIN)).getValue()
,clip2.getFramePosition(), clip2.getFrameLength()
,((FloatControl)clip2.getControl(FloatControl.Type.MASTER_GAIN)).getValue()
));
if (ts>6000 && !clip2.isRunning()) {
clip2.setFramePosition(0);
clip2.start();
}
if (!clip1.isRunning()) {
clip1.close();
}
if(ts % 2000 == 0) {
// values have min/max values, for now don't check for outOfBounds values
FloatControl gainControl = (FloatControl)clip2.getControl(FloatControl.Type.MASTER_GAIN);
float oldVal=gainControl.getValue();
clip2IncGain = oldVal>=5.5 ? clip2IncGain*-1
: oldVal<=-5.5 ? clip2IncGain*-1
: clip2IncGain;
gainControl.setValue(oldVal+clip2IncGain);
}
Thread.sleep(interval);
}
}
private static Map<String,String> parseParams(String[] args) {
Map<String,String> params = new HashMap<String,String>();
for(String arg : args) {
int delim = arg.indexOf('=');
if (delim<0) params.put("", arg.trim());
else if (delim==0) params.put("", arg.substring(1).trim());
else params.put(arg.substring(0, delim).trim(), arg.substring(delim+1).trim() );
}
return params;
}
}
See JavaSound documentation for more information.
Try checking the source code of this open source soundboard program: DBoard.
You are specifically interested in using the MediaPlayer class. You can call it using
(new Thread(new MediaPlayer(PATHTOFILE)).start();

Java - Multi threading sound clips to play at same time

Problem; Only hearing one sound clip when executed. After one sound has played the other doesn't play & neither can play at the same time.
Result; To be able to play 2 sounds at the same time.
Code:
import java.io.*;
import javax.sound.sampled.*;
public class ThreadPlay extends Thread {
private String filename; // The name of the file to play
private boolean finished; // A flag showing that the thread has finished
private ThreadPlay(String fname) {
filename = fname;
finished = false;
}
public static void main(String[] args) {
ThreadPlay s1 = new ThreadPlay("soundClip1.wav");
ThreadPlay s2 = new ThreadPlay("soundClip2.wav");
s1.start();
s2.start();
while (!s1.finished || !s2.finished);
System.exit(0); // Java Sound bug fix...
}
public void run() {
try {
File file = new File(filename);
AudioInputStream stream = AudioSystem.getAudioInputStream(file);
AudioFormat format = stream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip clip = (Clip)AudioSystem.getLine(info);
clip.open(stream);
clip.start();
Thread.sleep(100);
while (clip.isRunning()) { Thread.sleep(100); }
clip.close();
}
catch (Exception e) { }
finished = true;
}
}
Audio Lines:
AudioSystem.getMixerInfo() results in:
[Ljavax.sound.sampled.Mixer$Info;#52cc8049
Array length: 7
Contents:
PulseAudio Mixer, version 0.02
default [default], version 4.4.0-66-generic
PCH [plughw:0,0], version 4.4.0-66-generic
PCH [plughw:0,1], version 4.4.0-66-generic
PCH [plughw:0,3], version 4.4.0-66-generic
PCH [plughw:0,7], version 4.4.0-66-generic
Port PCH [hw:0], version 4.4.0-66-generic
For each mixer, AudioSystem.getMixer(AudioSystem.getMixerInfo()[x])
Results:
org.classpath.icedtea.pulseaudio.PulseAudioMixer#685f4c2e
com.sun.media.sound.DirectAudioDevice#7a07c5b4
com.sun.media.sound.DirectAudioDevice#5ce65a89
com.sun.media.sound.DirectAudioDevice#1de0aca6
com.sun.media.sound.DirectAudioDevice#443b7951
com.sun.media.sound.DirectAudioDevice#45283ce2
com.sun.media.sound.PortMixer#4d76f3f8
Imports:
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
Run method:
public void run() {
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(this.getClass().getResource("NameOfFile.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioInputStream);
clip.start();
clip.loop(Clip.LOOP_CONTINUOUSLY); // There are several different amounts of time you can loop it, so you can change this if you want, or you can just use clip.stop() whenever you want.
} catch (Exception ex) {
ex.printStackTrace();
}
}
If you use this and piece of code over multiple threads, it should work. If I am correct in assuming that you are initiating this piece of code twice, once for each thread, then this should work. I hope that this helps.
Fixed:
public void run() {
try {
File file = new File(filename);
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
DataLine.Info info = new DataLine.Info(Clip.class, audioInputStream.getFormat());
Clip clip = (Clip)AudioSystem.getLine(info);
clip.open(audioInputStream);
clip.start();
clip.loop(Clip.LOOP_CONTINUOUSLY); // There are several different amounts of time you can loop it, so you can change this if you want, or you can just use clip.stop() whenever you want.
} catch (Exception ex) {
ex.printStackTrace();
}
finished = true;
}
Also, if you're running Ubuntu like myself you need to remove OpenJDK/OpenJRE and set SunJDK/SunJRE as Default.

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

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

Problem with Javas Audio Clips on frequent playback of beep sounds

I want to playback short beep sounds (WAV files) on success and error of a GUI triggered action.
I came across javax.sound.sampled.Clip, which seemed to work.
Here is the basic code I use:
clip.stop();
clip.setFramePosition(0);
clip.start();
This is executed after a button click triggers a database action. On success and error two different preloaded Clips are played.
But on the production machine (an old PC running Kubuntu 10.4) after some time (around 400+ executions or 2-4 hours) the clip refuses to play.
The stop method takes around 3 seconds to terminate and the following start action does not play any sound. Every following invocation of the code fails then without throwing exception or any other feedback.
The only thing, that fixes this, is restarting the whole application.
My questions are:
Is there any workaround for this? Does anyone else have the same problem? Or is there another framework I can use to play at least two different sounds (the Toolkit.beep() can only play one sound).
Don't be afraid to just recreate objects, the overhead is low. Instead of resetting the clips, try just creating new ones. You could cache the files, that would be a useful optimization. Reusing the clip objects is not.
Or you could try an alternative implementation [that is not restricted].
This is the top result in Google for 'java play wav files':
http://www.anyexample.com/programming/java/java_play_wav_sound_file.xml
It simplifies things down to a single call:
new AePlayWave("test.wav").start();
Just add this class to your codebase:
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
public class AePlayWave extends Thread {
private String filename;
private Position curPosition;
private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb
enum Position {
LEFT, RIGHT, NORMAL
};
public AePlayWave(String wavfile) {
filename = wavfile;
curPosition = Position.NORMAL;
}
public AePlayWave(String wavfile, Position p) {
filename = wavfile;
curPosition = p;
}
public void run() {
File soundFile = new File(filename);
if (!soundFile.exists()) {
System.err.println("Wave file not found: " + filename);
return;
}
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
if (auline.isControlSupported(FloatControl.Type.PAN)) {
FloatControl pan = (FloatControl) auline
.getControl(FloatControl.Type.PAN);
if (curPosition == Position.RIGHT)
pan.setValue(1.0f);
else if (curPosition == Position.LEFT)
pan.setValue(-1.0f);
}
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
auline.close();
}
}
}
So how i fixed it:
I basically followed the hint from Charles Goodwin, but i changed the AePlayWave class to implement runnable and use it with a thread pool (to avoid overhead from starting new Threads all the time). Also, i use URLs and not Files to use resources from within the packed JAR file. The AePlayWave Object is created when setup is done (the files are chosen) or settings change. There is an instance for every sound I want the application to play. The listener methods for the events then trigger the pool to run the specific AePlayWave instance for that events sound. The rest is basically the same.
There are only two inconvenient issues:
1.) on weak machines, the ending of a WAV is not always played. When sounds are very short (like 100ms beeps), this might lead to no sound being played at all! Thats why i added 500 ms of silence to the end of each sound i'd like to play. It's a workaround, but it helps and for now it seems to be the best and most stable approach.
2.) If more than one sound is played (because of very quick repetition) the sounds overlap and you hear a change in tune and volume. This is ok in my case but might be annoying for other uses.
It is already running on the productive system. If any errors are reported to me, i will edit this post to keep you up to date.
Now here is the (basically reduced) sourcecode:
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
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 AudibleListener implements SomeListener {
private Runnable successRunner;
private Runnable failRunner;
ExecutorService pool = Executors.newCachedThreadPool();
/**
* Call this after initialization and after every change in your config at runtime.
*/
public void reloadSettings() {
// put your configuration here
this.successRunner = new WavePlayer(this.getClass().getResource("success.wav"));
this.failRunner = new WavePlayer(this.getClass().getResource("fail.wav"));
}
/**
* Call this to savely shutdown the thread pool.
*/
public void shutdown() {
this.pool.shutdown();
}
/**
* Listener method called on success.
*/
public void eventSuccess() {
this.pool.execute(this.successRunner);
}
/**
* Listener method called on fail.
*/
public void eventFailed() {
this.pool.execute(this.failRunner);
}
private class WavePlayer implements Runnable {
private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb
private URL soundFile;
public WavePlayer(URL soundFile) {
this.soundFile = soundFile;
}
#Override
public void run() {
try {
// check if the URL is still accessible!
this.soundFile.openConnection().connect();
this.soundFile.openStream().close();
} catch (Exception e) {
return;
}
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem
.getAudioInputStream(this.soundFile);
} catch (UnsupportedAudioFileException e) {
return;
} catch (IOException e) {
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (LineUnavailableException e) {
return;
} catch (Exception e) {
return;
}
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[this.EXTERNAL_BUFFER_SIZE];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream
.read(abData, 0, abData.length);
if (nBytesRead >= 0) {
auline.write(abData, 0, nBytesRead);
}
}
} catch (IOException e) {
return;
} finally {
auline.drain();
auline.close();
}
}
}
}
Cheers and thanks so far for all the help!
P.
Update:
This is now running for the last 72 hours without any errors! Looks like we made it!

How can I play sound in Java?

I want to be able to play sound files in my program. Where should I look?
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();
}
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);
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();
}
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).
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();
}
}
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();
}
}
}
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();
}
}
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/
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
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");
}
}
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.
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);
}

Categories

Resources