I am using the mp3plugin.jar library and my music works great. The only problem is that when my program starts the JFrame doesn't show. Before I added the music, it worked perfectly. This is my code for the music:
package com.org.pong;
import javax.sound.sampled.*;
import javax.sound.*;
import java.io.*;
import java.net.URL;
public class Music {
Music(String url) {
int total, totalToRead, numBytesRead, numBytesToRead;
byte[] buffer;
boolean stopped;
AudioFormat wav;
TargetDataLine line;
SourceDataLine lineIn;
DataLine.Info info;
File file;
FileInputStream fis;
// AudioFormat(float sampleRate, int sampleSizeInBits,
// int channels, boolean signed, boolean bigEndian)
wav = new AudioFormat(44100, 16, 2, true, false);
info = new DataLine.Info(SourceDataLine.class, wav);
buffer = new byte[1024 * 333];
numBytesToRead = 1024 * 333;
total = 0;
stopped = false;
if (!AudioSystem.isLineSupported(info)) {
System.out.print("no support for " + wav.toString());
}
try {
// Obtain and open the line.
lineIn = (SourceDataLine) AudioSystem.getLine(info);
lineIn.open(wav);
lineIn.start();
fis = new FileInputStream(file = new File(url));
totalToRead = fis.available();
while (total < totalToRead && !stopped) {
numBytesRead = fis.read(buffer, 0, numBytesToRead);
if (numBytesRead == -1)
break;
total += numBytesRead;
lineIn.write(buffer, 0, numBytesRead);
}
} catch (LineUnavailableException ex) {
ex.printStackTrace();
} catch (FileNotFoundException nofile) {
nofile.printStackTrace();
} catch (IOException io) {
io.printStackTrace();
}
}
}
This suggest that you are blocking the Event Dispatching Thread. This will prevent any UI elements from being updated until you stop blocking.
Having only looked at you code, I would suggest that your culprit is here...
while (total < totalToRead && !stopped) {
numBytesRead = fis.read(buffer, 0, numBytesToRead);
if (numBytesRead == -1)
break;
total += numBytesRead;
lineIn.write(buffer, 0, numBytesRead);
}
Try creating a background thread in which you either run the Music class in OR run the loop within it's own background thread.
Take a look at Concurrency in Swing for more details
Updated with working example
This is a rather crude example. Normally I would have a single Thread which would be responsible for playing the music, but which could be interrupted and made to play another song, but this is just a proof of concept.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestMusic {
public static void main(String[] args) {
new TestMusic();
}
public TestMusic() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
Music.play("/play/some/music/white/boy");
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JLabel("Look Ma, no hands"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class Music {
public static void play(final String url) {
new Thread(new Runnable() {
#Override
public void run() {
new Music(url);
}
}).start();
}
private int total, totalToRead, numBytesRead, numBytesToRead;
private byte[] buffer;
private boolean stopped;
private AudioFormat wav;
private TargetDataLine line;
private SourceDataLine lineIn;
private DataLine.Info info;
private File file;
private FileInputStream fis;
public Music(String url) {
// AudioFormat(float sampleRate, int sampleSizeInBits,
// int channels, boolean signed, boolean bigEndian)
wav = new AudioFormat(44100, 16, 2, true, false);
info = new DataLine.Info(SourceDataLine.class, wav);
buffer = new byte[1024 * 333];
numBytesToRead = 1024 * 333;
total = 0;
stopped = false;
if (!AudioSystem.isLineSupported(info)) {
System.out.print("no support for " + wav.toString());
}
try {
// Obtain and open the line.
lineIn = (SourceDataLine) AudioSystem.getLine(info);
lineIn.open(wav);
lineIn.start();
fis = new FileInputStream(file = new File(url));
totalToRead = fis.available();
while (total < totalToRead && !stopped) {
numBytesRead = fis.read(buffer, 0, numBytesToRead);
if (numBytesRead == -1) {
break;
}
total += numBytesRead;
lineIn.write(buffer, 0, numBytesRead);
}
} catch (LineUnavailableException ex) {
ex.printStackTrace();
} catch (FileNotFoundException nofile) {
nofile.printStackTrace();
} catch (IOException io) {
io.printStackTrace();
}
}
}
}
This is a classic example of blocking the Swing event dispatch thread with a long-running bit of code. This will cause the GUI to freeze since the thread isn't available to paint components or interact with the user. The solution: use a background thread for the music so you don't block the GUI's event thread.
Related
I am making a skype like program. I have a "VoiceChat" class to handle the voice chat connections. I have a "ClientAudio" class to handle the client audio output. I also have a "ClientAudioRec" to handle receiving audio from the server and playing it. In the "ClientAudio" class I store the audio data in a buffer until it is full to try and reduce lag. Then I send it to the server. If I have two people in the call it lags unless the buffer is at 1000. When I add another person to the call it lags so much that you can't understand anyone. But I don't want to extend the buffer every time someone else joins because 1000 is already like a two-second delay. If anyone knows how to reduce the lag or make it almost instant that would really help. thank you in advance!!!
VoiceChat (Server Side)
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class VoiceChat extends Thread {
private Socket s;
private ObjectOutputStream out;
private ObjectInputStream in;
private Thread acceptThread;
private int VoicePort;
private int num;
public VoiceChat(Socket sVoice, int VoicePort, Thread acceptThread) {
s = sVoice;
this.VoicePort = VoicePort;
this.acceptThread = acceptThread;
num = chat.threads.indexOf(this.acceptThread)+1;
try {
out = new ObjectOutputStream(s.getOutputStream());
in = new ObjectInputStream(s.getInputStream());
if(VoicePort <= 65511) {
chat.users1_Voice.add(out);
}else {
chat.users2.add(out);
}
} catch (IOException e) {
System.out.println("ERROR2");
e.printStackTrace();
}
}
public void run() {
int bytesRead = 0;
byte[] inBytes = new byte[100];
while(bytesRead != -1) {
try {
bytesRead = in.read(inBytes, 0, inBytes.length);
}catch (IOException e) {
System.out.println("ERROR2");
if(VoicePort <= 65511) {
chat.users1_Voice.remove(out);
}else {
chat.users2.remove(out);
}
}
if(bytesRead > 0) {
System.out.println(chat.users1_Voice);
send(inBytes, bytesRead, out);
System.out.println("SENDING DATA");
}
}
}
public void send(byte[] soundData, int bytesRead, ObjectOutputStream out) {
if(VoicePort <= 65511) {
for(ObjectOutputStream o : chat.users1_Voice) {
try {
if(o != out) {
o.write(soundData, 0, bytesRead);
o.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}else {
for(ObjectOutputStream o : chat.users2) {
try {
if(o != out) {
o.write(soundData, 0, bytesRead);
o.flush();
}
} catch (IOException e) {
}
}
}
}
}
ClientAudio
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
public class ClientAudio implements Runnable {
private ObjectOutputStream out = null;
private AudioFormat af;
private TargetDataLine microphone;
ClientAudio(AudioFormat af) {
this.af = af;
}
public void run() {
try {
client.voiceSocket = new Socket("***IP***", client.VoicePort);
Thread car = new Thread(new ClientAudioRec(af));
car.start();
out = new ObjectOutputStream(client.voiceSocket.getOutputStream());
DataLine.Info info = new DataLine.Info(TargetDataLine.class, af);
microphone = (TargetDataLine)AudioSystem.getLine(info);
microphone.open(af);
microphone.start();
int bytesRead = 0;
int offset = 0;
byte[] soundData = new byte[1000];
while(bytesRead != -1 && client.callRunning == true) {
bytesRead = microphone.read(soundData, 0, soundData.length);
if(bytesRead >= 0) {
offset += bytesRead;
if(offset == soundData.length) {
out.write(soundData, 0, bytesRead);
offset = 0;
}
}
}
microphone.close();
try {
client.voiceSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
System.out.println("Client Audio Stopped Because Client Disconnected From Call");
} catch (IOException | LineUnavailableException e) {
microphone.close();
try {
client.voiceSocket.close();
} catch (IOException e1) {
System.out.println("Plug Microphone In...");
}
System.out.println("Client Audio Stopped...");
}
}
}
ClientAudioRec
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class ClientAudioRec implements Runnable {
private SourceDataLine inSpeaker = null;
private AudioFormat audioformat;
private ObjectInputStream in;
ClientAudioRec(AudioFormat af) {
audioformat = af;
try {
in = new ObjectInputStream(client.voiceSocket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioformat);
try {
inSpeaker = (SourceDataLine)AudioSystem.getLine(info);
inSpeaker.open(audioformat);
} catch (LineUnavailableException e1) {
System.out.println("ERROR");
e1.printStackTrace();
}
int bytesRead = 0;
byte[] inSound = new byte[100000];
inSpeaker.start();
while(bytesRead != -1 && client.callRunning == true) {
try{bytesRead = in.read(inSound, 0, inSound.length);} catch (Exception e){
inSpeaker.close();
System.out.println("Speaker Closed");
}
if(bytesRead >= 0) {
inSpeaker.write(inSound, 0, bytesRead);
}
}
inSpeaker.close();
System.out.println("Speaker Closed Because Client Disconneted From Call");
}
}
I have been trying to write a basic 'Jeopardy' game in java, and right now I'm trying to add sound to play when the player get's an answer right or wrong. I have tried to add the sound (placing the sound file in the bin folder and using the code below), but when I try to play the file there is no sound. There is no null pointer exception.
public class Overview{
static AudioClip right, wrong;
//start the game
public static void guiApp(){
right = Applet.newAudioClip(Jeopardy.class.getResource("correct.wav"));
wrong = Applet.newAudioClip(Jeopardy.class.getResource("wrong.wav"));
right.play();
intro = new Intro();
intro.start();
}
public static void main (String[ ] args)
{
javax.swing.SwingUtilities.invokeLater (new Runnable ( )
{
public void run ( )
{
guiApp();
}
}
);
}
}
The following is essentially what is happening in the method called:
public class Intro{
public Intro(){
}
public void start(){
JFrame frame = new JFrame();
frame.setSize(100, 100);
frame.setVisible(true);
}
}
This is something that i use to play sound.
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.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class SoundPlayer extends Thread
{
private static final int BUFFER_SIZE = 128000;
private static File soundFile;
private static AudioInputStream audioStream;
private static AudioFormat audioFormat;
private static SourceDataLine sourceLine;
private String file;
public static String turn = "data/bell.wav"; //bell sound for black jack when it is your turn (played once each turn)
/**
* Plays the sound of the sent file name
* #param file Audio File's path
*/
public SoundPlayer(String file)
{
super("SoundPlayer");
this.file = file;
start();
}
public void run()
{
String strFilename = file;
try {
soundFile = new File(strFilename);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try {
audioStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e){
e.printStackTrace();
System.exit(1);
}
audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
#SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
this.stop();
}
public static void main(String[] args)
{
}
}
I have a game that I want to play audio in. What I want to be able to do is that I should be able to declare a ClipPlayer object with the arguments of a path name. Then the constructor should be able to load the sound and then I can just make a call with that object so it won't lag. This is the code that I am using currently for 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 ClipPlayer {
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) {
}
}
ClipPlayer(String filename, boolean loop) {
this(filename);
this.loop = loop;
}
ClipPlayer(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();
}
}
}
Declare, load and cache the sounds as class attributes. Then when it is time to hear them, play them in a Clip.
I am creating a metronome program and the for loop is executing +1 times than it should.
public class Tempo {
String file;
int bpm;
public Tempo(int bpm, String file){
this.bpm=bpm;
this.file=file;
}
public void tempoPlay () throws InterruptedException{
new Play(file).start();
Thread.sleep(60000/bpm);
}
public static void main(String[] args) throws InterruptedException {
Tempo t = new Tempo(120, "C:\\Users\\Korisnik\\Desktop\\dome3.wav");
for(int i=0;i<20;i++){
t.tempoPlay();
}
}
}
The first beat is rapidly followed by the second one but later as it goes it is sounding compliant. I've counted it plays 21 beats but it should play 20.
Here's the Play class:
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;
class Play extends Thread {
private String filename;
private Position curPosition;
private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb
enum Position {
LEFT, RIGHT, NORMAL
};
public Play(String wavfile) {
filename = wavfile;
curPosition = Position.NORMAL;
}
public Play(String wavfile, Position p) {
filename = wavfile;
curPosition = p;
}
#Override
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();
}
}
}
Shot in the dark: It might be worthwhile to read the file into memory completely for testing purposes. A guess as to what might be happening is that the I/O from reading the file is interfering with the timing of the playback.
You might be able to get away with this to test.
Tempo t = new Tempo(120, "C:\\Users\\Korisnik\\Desktop\\dome3.wav");
t.tempoPlay() // ignore this
Thread.sleep(10);
for(int i=0;i<20;i++){
t.tempoPlay();
}
Or better yet, have Tempo cache the read in before playing the sound.
I am trying to play a *.wav file with Java. I want it to do the following:
When a button is pressed, play a short beep sound.
I have googled it, but most of the code wasn't working. Can someone give me a simple code snippet to play a .wav file?
Finally I managed to do the following and it works fine
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.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class MakeSound {
private final int BUFFER_SIZE = 128000;
private File soundFile;
private AudioInputStream audioStream;
private AudioFormat audioFormat;
private SourceDataLine sourceLine;
/**
* #param filename the name of the file that is going to be played
*/
public void playSound(String filename){
String strFilename = filename;
try {
soundFile = new File(strFilename);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try {
audioStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e){
e.printStackTrace();
System.exit(1);
}
audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
#SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
}
}
Here is the most elegant form I could come up without using sun.*:
import java.io.*;
import javax.sound.sampled.*;
try {
File yourFile;
AudioInputStream stream;
AudioFormat format;
DataLine.Info info;
Clip clip;
stream = AudioSystem.getAudioInputStream(yourFile);
format = stream.getFormat();
info = new DataLine.Info(Clip.class, format);
clip = (Clip) AudioSystem.getLine(info);
clip.open(stream);
clip.start();
}
catch (Exception e) {
//whatevers
}
Shortest form (without having to install random libraries) ?
public static void play(String filename)
{
try
{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File(filename)));
clip.start();
}
catch (Exception exc)
{
exc.printStackTrace(System.out);
}
}
The only problem is there is no good way to make this method blocking to close and dispose the data after *.wav finishes.
clip.drain() says it's blocking but it's not. The clip isn't running RIGHT AFTER start().
The only working but UGLY way I found is:
// ...
clip.start();
while (!clip.isRunning())
Thread.sleep(10);
while (clip.isRunning())
Thread.sleep(10);
clip.close();
You can use an event listener to close the clip after it is played
import java.io.File;
import javax.sound.sampled.*;
public void play(File file)
{
try
{
final Clip clip = (Clip)AudioSystem.getLine(new Line.Info(Clip.class));
clip.addLineListener(new LineListener()
{
#Override
public void update(LineEvent event)
{
if (event.getType() == LineEvent.Type.STOP)
clip.close();
}
});
clip.open(AudioSystem.getAudioInputStream(file));
clip.start();
}
catch (Exception exc)
{
exc.printStackTrace(System.out);
}
}
The snippet here works fine, tested with windows sound:
public static void main(String[] args) {
AePlayWave aw = new AePlayWave( "C:\\WINDOWS\\Media\\tada.wav" );
aw.start();
}
A class that will play a WAV file, blocking until the sound has finished playing:
class Sound implements Playable {
private final Path wavPath;
private final CyclicBarrier barrier = new CyclicBarrier(2);
Sound(final Path wavPath) {
this.wavPath = wavPath;
}
#Override
public void play() throws LineUnavailableException, IOException, UnsupportedAudioFileException {
try (final AudioInputStream audioIn = AudioSystem.getAudioInputStream(wavPath.toFile());
final Clip clip = AudioSystem.getClip()) {
listenForEndOf(clip);
clip.open(audioIn);
clip.start();
waitForSoundEnd();
}
}
private void listenForEndOf(final Clip clip) {
clip.addLineListener(event -> {
if (event.getType() == LineEvent.Type.STOP) waitOnBarrier();
});
}
private void waitOnBarrier() {
try {
barrier.await();
} catch (final InterruptedException ignored) {
} catch (final BrokenBarrierException e) {
throw new RuntimeException(e);
}
}
private void waitForSoundEnd() {
waitOnBarrier();
}
}
Another way of doing it with AudioInputStream:
import java.io.File;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
public class CoreJavaSound extends Object implements LineListener {
File soundFile;
JDialog playingDialog;
Clip clip;
public static void main(String[] args) throws Exception {
CoreJavaSound s = new CoreJavaSound();
}
public CoreJavaSound() throws Exception {
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(null);
soundFile = chooser.getSelectedFile();
System.out.println("Playing " + soundFile.getName());
Line.Info linfo = new Line.Info(Clip.class);
Line line = AudioSystem.getLine(linfo);
clip = (Clip) line;
clip.addLineListener(this);
AudioInputStream ais = AudioSystem.getAudioInputStream(soundFile);
clip.open(ais);
clip.start();
}
public void update(LineEvent le) {
LineEvent.Type type = le.getType();
if (type == LineEvent.Type.OPEN) {
System.out.println("OPEN");
} else if (type == LineEvent.Type.CLOSE) {
System.out.println("CLOSE");
System.exit(0);
} else if (type == LineEvent.Type.START) {
System.out.println("START");
playingDialog.setVisible(true);
} else if (type == LineEvent.Type.STOP) {
System.out.println("STOP");
playingDialog.setVisible(false);
clip.close();
}
}
}
A solution without java reflection DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat)
Java reflection decrease performance.
to run: java playsound absoluteFilePathTo/file.wav
import javax.sound.sampled.*;
import java.io.*;
public class playsound {
public static void main (String args[]) throws Exception {
playSound (args[0]);
}
public static void playSound () throws Exception {
AudioInputStream
audioStream = AudioSystem.getAudioInputStream(new File (filename));
int BUFFER_SIZE = 128000;
AudioFormat audioFormat = null;
SourceDataLine sourceLine = null;
audioFormat = audioStream.getFormat();
sourceLine = AudioSystem.getSourceDataLine(audioFormat);
sourceLine.open(audioFormat);
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead =
audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
}
}
You can use AudioStream this way as well:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
public class AudioWizz extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L; //you like your cereal and the program likes their "serial"
static AudioWizz a;
static JButton playBuddon;
static JFrame frame;
public static void main(String arguments[]){
frame= new JFrame("AudioWizz");
frame.setSize(300,300);
frame.setVisible(true);
a= new AudioWizz();
playBuddon= new JButton("PUSH ME");
playBuddon.setBounds(10,10,80,30);
playBuddon.addActionListener(a);
frame.add(playBuddon);
frame.add(a);
}
public void actionPerformed(ActionEvent e){ //an eventListener
if (e.getSource() == playBuddon) {
try {
InputStream in = new FileInputStream("*.wav");
AudioStream sound = new AudioStream(in);
AudioPlayer.player.start(sound);
} catch(FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
I took #greenLizard's code and made it more robust.
I closed the AudioInputStream.
I used a BufferedInputStream. The AudioSystem getAudioInputStream was throwing an occasional IOException because the getAutoInputSytream method couldn't back up the input stream and start over.
Hopefully, there are no more exceptions to be found.
Here's the modified code. The ErrorDisplayDialog shows an exception as a JDialog in a Java Swing application. Just replace with e.printStackTrace();.
private void playWavFile(String fileName) {
InputStream inputStream = getClass().getResourceAsStream(fileName);
BufferedInputStream bufferedInputStream = new BufferedInputStream(
inputStream);
AudioInputStream audioStream = null;
AudioFormat audioFormat = null;
try {
audioStream = AudioSystem.getAudioInputStream(bufferedInputStream);
audioFormat = audioStream.getFormat();
} catch (UnsupportedAudioFileException e) {
new ErrorDisplayDialog(view.getFrame(),
"UnsupportedAudioFileException", e);
return;
} catch (IOException e) {
new ErrorDisplayDialog(view.getFrame(), "IOException", e);
return;
}
DataLine.Info info = new DataLine.Info(SourceDataLine.class,
audioFormat);
SourceDataLine sourceLine;
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
new ErrorDisplayDialog(view.getFrame(), "LineUnavailableException",
e);
return;
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[128000];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
new ErrorDisplayDialog(view.getFrame(), "IOException", e);
return;
}
if (nBytesRead >= 0) {
sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
try {
audioStream.close();
} catch (IOException e) {
new ErrorDisplayDialog(view.getFrame(), "IOException", e);
}
}