Is there a good recipe to get decent, reliable digital sampled sound playback in Java?
My list of requests is pretty short:
- Load digitized samples in memory (for example, from resouces bundled in jar) from something like .wav files
- Play them in non-blocking manner
- When I play several samples simultaneously and they intersect in time, they should get properly mixed
It would be nice to have the following, but in fact I can live without it:
- Playing from .ogg or similar compressed format (without implementing a CPU-hungry decoder in Java, obviously)
- Playing back the same sample again while it is still playing should not stop previous playback of a given sample, but second copy should start and get properly mixed with the first one
I've tried the infamous Java Sound API, but found out that it is utterly unreliable and seem to be unable to satisfy even my minimal wish list. The problems I get:
On Linux with ALSA dmix (OpenJDK 6), having any other application using audio while initializing Java Sound API just makes all the sound from Java app disappear without any errors / warnings.
On Linux (OpenJDK 6), listing
MixerInfo
s and trying to get aClip
object using any of them throws the following exception when trying to load a wav file:java.lang.IllegalArgumentException: Line unsupported: interface Clip supporting format PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
Thus,
AudioSystem.getClip(anySortOfMixer)
doesn't seem to work at all. OnlyAudioSystem.getClip()
works.Loading files with different sample rate / bits / format using
Clip
fails withLineUnavailableException
. It seems that first invocation ofclip.open
sets up sound system to a particular sound options, following invocations to load a file with slightly different sample rate (for example, first one was 44100, second one is 48000)On Linux (OpenJDK 6) initializing several different
Clip
s and trying to play them makes only last loadedClip
audible - no errors/warnings are given, but only usingplay
on lastClip
loaded makes any sound at all - all others are silent:Clip loadSound(String name) { URL url = this.getClass().getResource("/" + name + ".wav"); Clip clip = AudioSystem.getClip(); AudioInputStream ais = AudioSystem.getAudioInputStream(url); clip.open(ais); return clip; } void playSound(Clip) { if (clip.isRunning()) clip.stop(); clip.setFramePosition(0); clip.start(); } ... Clip c1 = loadSound("foo"); Clip c2 = loadSound("bar"); ... playSound(c1); // silence ... playSound(c2); // audible
Everything's fine with this code on Windows - all Clips are audible, play and mix properly. Haven't tested it on Mac.
Supported file formats (analyzed with
AudioSystem.getAudioFileTypes
) returns wav / au / aif on both Linux/OpenJDK6 and Windows/Oracle JDK 7, so no oggs or even mp3s :(There seem to be no easy way to make two copies of the same
Clip
sound simultaneously without loading 2nd copy as a distinctClip
.
So, the question is - is there a good solution / workaround to remedy all this stuff and make it more reliable? Would switching to some other sound system (such as LWJGL OpenAL or paulscode.com sound system) help? Or is it possible to wrap Java Sound API in some safe-guards and it will work properly?
I've made a little application that tests all of the above, but it's a bit long, so I thought I'd publish it as a gist, but, unfortunately, GitHub is having some network issues right now. So, I guess, I will publish it a bit later.
mp3plugin.jar
of the JMF for MP3 support in Java Sound apps. I suggested JavaFX in the hope it uses some entirely alternate API to Java Sound (which, as you note, as less than entirely reliable). But speaking of Linux & sound, lack of sound support on Linux was the thing that caused Jamie Zawinski to toss Linux (for which he had written a lot of code) for Mac. ;) – Felishafelita