Reputation: 5406
Let's say I have a number of sounds (imagine piano/guitar notes).
I want to play each sound after a given interval, for example 200 miliseconds.
But I want to let the previous sound "ring out".
Although the approach below works ok for longer delays (700-1000 ms) it's not too precise.
For short delays, sometimes the sounds "bunch up" and play in rapid succession.
What I tried (sort of pseudo code):
for (Clip clip: clipList){
clip.start();
Thread.sleep(500);
}
My guess this has something to do with thread scheduling by JVM/OS...
Any ideas?
EDIT:
As advised in the comments I tried with a timer too:
final Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
try{
Clip clip = clipList.remove();
clip.start();
}catch (NoSuchElementException e) {
timer.cancel();
}
}
};
timer.schedule(timerTask, 0, delay);
I still get the same behaviour when I have 7-8 sounds and 500 ms delay.
Upvotes: 1
Views: 1031
Reputation: 7910
Having the notes "ring out" is a great thing, and something that has driven my researches and trials with Java Sound as well. I'm not sure I can help specifically, but I can share an experience or two.
I made a clip player that allows one to retrigger the clip before it has finished playing (allowing the first to play out while another is started), and at different sample rates. This is done by giving the clip multiple cursors, and having them increment through the internally-stored sample data independently. (The playbacks that are at higher or lower speeds use linear interpolation to derive audio values when the cursor lands in between two samples.) The output is funneled into a single SourceDataLine.
Curiously, when this clip player is invoked multiple times, as a stand-alone program, there is a bunching up that occurs that is similar to what you describe. However, I also wrote an audio mixer that is capable of playing back both a number of these clips AND a sourceDataLine .wav file AND some live FM synth sounds, mixing them all into a SINGLE SourceDataLine output, and the timing on this is pretty darn good!
It really baffles me, as the clip part (and the triggers to the clips) are virtually the same code. One key difference might be that the AudioMixer I wrote is set to run continuously, so some of possible timing problems might be coming from when code is run from bytecode versus from memory. The HotSpot compiler will run code a few times as bytecode before committing to placing it in memory where it will run more quickly, and this would account for some timing problems.
I found a good article on timing issues you might want to check out: http://quod.lib.umich.edu/cgi/p/pod/dod-idx?c=icmc;idno=bbp2372.2007.131
Basically, java doesn't offer "real time" guarantees, and this is the big challenge to achieving low latency performance. Sources of variance include: the issue of when HotSpot or whatever decides to run from bytecode or from memory, garbage collection, vm thread switching.
Having clips that "play out" would be a key component to doing branching music, allowing one to zig instead of zag at a moment in a game, for example, and the music or sfx would remain "seamless." That is part of what I'm envisioning. Of course, it would also be nice if there was a DAW where one could take a track and designate it be saved as multiple audio tiles (that overlap/playout), rather than making one export each tile individually. But that is getting ahead of the game...Was this a general direction you are also thinking about? Or do you have another application in mind? (Just curious.)
Upvotes: 1