Hello,
I am quite new to audio programming with java and was recently trying to create a metronome in java and ran into problems with the sound playback from Clip having a lot of latency and being unreliable. It worked fine at about 100 bpm but once I started pushing 120 it started dropping beats. The program runs fine and in time without the audio playback and just a flashing dot, but as soon as I add the sound it starts slowing down. I just wanted to ask if anyone had any recommendations for either a way to reliably play a repeated sound within the standard java API or if there was another thing I should try using that would work better.
Thanks,
Thimbletack
Here is an interesting article that discusses some of the challenges of what you want to do, if you are doing it in pure Java.
http://quod.lib.umich.edu/cgi/p/pod/dod-idx?c=icmc;idno=bbp2372.2007.131
“Real-Time, Low Latency Audio Processing in Java”
NoiseFever’s “nordOsc” synth (a nearby thread) has very solid rhythm and gives a few hints about how he achieves it near the end of the thread. For myself, it was only when running a mixer I wrote in the background, continually, and feeding it sounds that I’ve been able to get decent timing. It is a fair bit of work to set something like this up, so if the goal is to just get it done, you might consider latching onto a library that can already do this.
By the way, are you loading the Clip once, then playing/replaying it (best practice) or loading it anew with each playback (common newbie error)? The former will perform better, but probably won’t eliminate all the timing problems. Even loading and playing from file (using SourceDataLine) starts the sound more reliably than a loading a playing a Clip, but resetting and restarting an existing Clip should be the best.
There is also the problem that Microsoft OS’s having a rather infrequent clock interrupt (once every 15 or 16 msec) which impacts the accuracy of sleep amounts and timers and game loops. Linux & Mac systems seem to have closer to 1msec accuracy. But even so, there are issues with code going in and out of RAM from bytecode, garbage collection and other JVM timing issues, as the article discusses.
Good luck! There will be others who will have libraries to recommend, I’m pretty sure.
Open a single audio channel, write raw audio into it. Write the metronome tick, silence, another metronome tick, silence, etc, etc.
It will have the accuracy of the sample-rate, so at 48kHz its accuracy will be about 0.0208 millis (!) - GC and swapping won’t be an issue either, if you make your native buffers big enough.
Thanks Riven! That boils things down to the essence. I was having trouble explaining to myself why I was getting better accuracy with my own code where I have mixer running and playing clips as a mixer track vs. playing the clips individually. In the first case raw audio (including silence when needed) is being written to a continually playing SourceDataLine.
Thanks for the help guys. I am indeed just calling on the file once then playing it over and over. I will look in to what you’ve mentioned and get back to you later.
Thanks again,
Thimbletack