开发者

Using multiple timers in a Java application with animation

I'm writing a Java Application that will side scroll sheet music across the screen and then when it crosses a middle line, it will play the note(s).

It will have a variable speed based on the beats per minute.

Every quarter of a beat I need to have a "tick" function that will get the next note (if any) and start its animation. To calculate this tick I have a function 60000ms/bpm/4. This will be separate from the animation timer, because the repaint should probably be called at some constant rate.

So I'm thinking I need Util Timer for the "ticks" and a swing timer for the JPanel and drawing in the paintComponent() method.

My question is: What would be the best practice for accomplishing this? I've done a fair amount of Java programming, but no Swing or animations s开发者_如何学Goo I would like to learn the best way to do this.

Thanks

Nate


There is no reason to use Timer or TimerTask to solve this problem.

In this case, you have a series of notes, and when you start playing, you can calculate ahead of time, the exact time that each and every note should play. I am assuming that you already have some sort of loop that is updating the display at a steady rate. (e.g. 30 refreshes per second, or something like that). Given such a loop, all you need is an event oriented class that can tell you whether it is time to play a note.

long noteTime[] = new long[numberOfNotes];
long startTime = System.currentTimeMillis();

Declare the above array. Then walk through all the notes in the song, and calculate the time that each note is expected to play. Say you have qurter notes, the first note will play at startTime, the second one beat after startTime, the third two beats after start time, etc. This is where you calculate the time for a beat and use it. Just calculate the actual time values for each note to play.

Then, in the middle of your event loop that is refreshing the display, include the following code:

int nextNote = 0;
while (event_loop_condition) {
    .
    .
    .
    if (System.currentTimeMillis()>noteTime[nextNote]) {
       playNote(nextNote++);
    }
    .
    .
    .
}

The point is that you already have an event loop, all you need to know is whether it it time yet to play the note, and this will do that for you.

On the other hand, if you are not handling the refresh, and you really do want to do this on a thread, the follow method can be called on a thread, and it will play all the notes at the correct times:

playAllNotes() {
    for (int i=0; i<numberOfNotes; i++) {
        Thread.sleep(noteTime[i]-System.currentTimeMillis());
        playNote(i);
    }
}

The sleep statement will delay until the time that the note should be played, and will play it at that time. Then it will sleep until the time for the next note to be played.

The important thing to notice about both methods, is that any delay in playing a note is NOT compounded for the next note. Say some system utility kicks in and delays one note by 50ms. The next note will not be delayed by this, because you calculated all the times for all the notes to be played up front. Given that threads are competing for CPU time, you will have thread/process contention, and there will be small variances in the time that notes are played, but they will never compound!

A lot of programmers inappropriately use timers (See discussion of Timers) on my website if you want to know more.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜