Reputation: 3835
The following is a link to the most likely explanation I've seen, but I still have questions.
I'll quote the code here:
public static synchronized void playSound(final String url) {
new Thread(new Runnable() {
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();
}
I've spent many hours now trying to play a simple sound effect. It's unbelievable how difficult it is. I hope that the above code can be made to work. Thanks for any help.
Chap
Upvotes: 1
Views: 9880
Reputation: 3835
Although I drew heavily from @Andrew's code, I did have to make some tweaks here and there. The following is a demo of my solution, complete except for a sample .wav file.
// Developed in Eclipse, YMMV regarding resource location.
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
class ClipPlayer {
public static void main(String[] args) {
// First, instantiate ourselves so we can call demoSam which
// needs to be able to do a wait().
ClipPlayer cp = new ClipPlayer();
// Now run the actual demo
cp.demoSam();
}
private void demoSam() {
/**
* Construct a Sam, capable of playing the "Chook.wav", a 0.1 sec sound.
* NOTE: it's very tricky debugging an incorrectly-located
* resource file, and I'm unable to give a general rule
* here. But in this example, Chook.wav is expected to be in the same
* directory as the .class file, and there is no surrounding
* package (i.e. we're taking the default package name). If you
* are using a package, you may have to write "myPackage/Chook.wav"
* instead.
*/
Sam sam;
try {
sam = new Sam("Chook.wav"); // or whatever, but it has to be .wav
}
catch (Exception e) {
say("Exception thrown by Sam: " + e.getMessage());
System.exit(1); // scoot
return; // get rid of warning about sam possib not init'd
}
int countDown = 20;
do {
say("Doing something requiring accompanying sound effect...");
try {
sam.playIt();
}
catch (Exception e) {
say("Caught exception from playIt: " + e.getMessage());
System.exit(1);
}
// Now wait a human-scale duration, like 1/8 second. In
// practice we may be processing, since the sound is playing
// asynchronously.
synchronized (this) {
try {
wait(125); // wait 1/8 sec
}
catch (Exception e2) {
say("huh?");
}
}
} while (--countDown > 0);
}
/**
* 'Sam' is a class that implements one method, playIt(), that simply
* plays the .wav file clip it was instantiated with. Just using an
* inner class here for simplicity of demo.
*/
final class Sam {
AudioInputStream ais;
Clip clip;
/**
* Constructor: prepare clip to be played. Do as much here as
* possible, to minimize the overhead of playing the clip,
* since I want to call the play() method 5-10 times a second.
*/
Sam(String clipName) throws Exception {
// Resource is in same directory as this source code.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url = classLoader.getResource(clipName);
ais = AudioSystem.getAudioInputStream(url);
clip = AudioSystem.getClip();
clip.open(ais);
}
/**
* playIt(): Start the clip playing once, asynchronously, and exit.
*/
public void playIt() throws Exception {
clip.setFramePosition(0); // Must always rewind!
clip.loop(0);
clip.start();
}
}
private static void say(String s) {
System.out.println(s);
}
}
Upvotes: 0
Reputation: 168825
Does this work in an application, as opposed to an Applet?
It works in either.
The method Main.class.getResourceAsStream() seems to require import com.sun.tools.apt.Main;
Where did you get that idea? I've made plenty of sound examples, and never heard of that class that you should not be using.
..but I cannot find documentation for that,..
No, the com.sun
classes are not only undocumented, but might change in the next micro-version.
..and I don't know what it does. For instance, is "/path/to/sounds/" absolute, or relative, and if the latter, relative to where?
It is relative to the root of the class-path.
..It's unbelievable how difficult it is.
Media handling in general, is tricky.
BTW - I'm not much impressed with the code on the linked thread. The Thread
wrapper is unnecessary, as mentioned in several of the comments, even for playing multiple Clip
instances simultaneously.
Instead see this code that I (wrote &) personally recommend.
Upvotes: 1
Reputation: 44808
I always loaded sounds like this:
Clip sound = (Clip) AudioSystem.getLine(new Line.Info(Clip.class));
sound.open(AudioSystem.getAudioInputStream(file));
but your method should also work.
Upvotes: 1