Play a sound every N milliseconds - java

I'm developing a metronome application. The user can select at runtime the bpm, and my app will play the "tick" sound accordingly. The "tick" is a single metronome "shot" (mp3). I tried implementing it using Handler and MediaPlayer, but the metronome is not precise at all.
So I thought about changing the whole approach: when the user choose a new bpm value, I synthesize a new sound by repeating the tick sound X times every N milliseconds, then looping over this runtime created sound.
Is this a valid alternative? How can it be implemented in Android?

The alternative of looping through a synthesized sound seems to be the best choice for now. There was a great session about audio on Google I/O 2013 called High Performance Audio that I would certainly advice watching for having a deeper understanding on how the system works and what problems the developers will face when dealing with the audio latency. At about the 17:00 of the video, there is graph that shows jitter versus callbacks. In the perfect world that does not exist (oh really?), the jitter would be zero for all the scheduled audio callbacks made. But that is not the case, for there are jitters as high as 35 milliseconds or even greater, for the data in the graph was made using an unspecified ICS device and there are certainly worse scenarios than that.
So, as a metronome is a precision tool and these jitters are not good at all, the scheduled playback approach should be left aside. I even made an reasonably realiable metronome work with a synthesized sound using AudioTrack.
Hope it helps ^^

You could try to use a TimerTask scheduled for fixed-rate execution on a Timer.
Timer and TimerTask are both part of the Android SDK (and Java SE). The executions do not delay because of execution time of the previous event.
Timer timer = new Timer("MetronomeTimer", true);
TimerTask tone = new TimerTask(){
#Override
public void run(){
//Play sound
}
};
timer.scheduleAtFixedRate(tone, 500, 500); //120 BPM. Executes every 500 ms.
You can then cancel the TimerTask when you need to change the BPM.
tone.cancel();
tone = new TimerTask(){...}
timer.scheduleAtFixedRate(tone, 1000, 1000); //60 BPM. Executes every 1000 ms.
Another possibility that may meet your requirements (from your comments) is spinning a thread and checking System.nanoTime() and sleeping in increments but spinning when you get close to wake up.
long delayNanos = 500000000;
long wakeup = System.nanoTime() + delayNanos; //Half second from right now
long now;
while(!done){
now = System.nanoTime();
//If we are less than 50 milliseconds from wake up. Spin away.
if(now <= wakeup - 50000000){
//Sleep in very small increments, so we don't spin unrestricted.
Thread.sleep(10);
}
if(now >= wakeup){
//Play sound
wakeup += delayNanos;
}
}

When this play sound is called
mSoundManager.playSound(1);
Android waits until that call is finished, then you call
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200);
however, if you reverse those calls, you may find that the timing is more accurate.
mHandler.postAtTime(this, SystemClock.uptimeMillis() + 200);
mSoundManager.playSound(1);
You can't count on your sound taking exactly the same amount of time to play, so telling the handler to post first is a bit better. Still not ideal, however.

Related

Java timer task runs slower than normal

Part of an application I'm writing uses a chronometer system. The timer should tick once every ms.
In my chronometer, I have these variables.
private static final int DELAY_IN_MILLISECONDS = 0;
private int intervalInMilliseconds = 1;
I start the timer like this:
timer = new Timer();
timer.schedule(new Task(), DELAY_IN_MILLISECONDS,
getIntervalInMilliseconds());
Yet, after a second he only reached about +- 100ms instead of 1000ms.
Though he used to work fine, untill I've added code to a different part of the game. I'm rather sure I've changed nothing on the timer but yet he became slower than normal (he used to work fine at first).
Is it possible that my timer runs slower due to the application requiring too much CPU time for other things? (it's a game I'm creating). If so, what would be the conventional way to solve this? Keeping in mind that it's more important the game runs smooth than the timer.
Thanks in advance!
EDIT: Is there a way to find out which part of your application is "bottlenecking" it, such as check where he uses most resources etc?
If long-term accuracy of scheduling is what you are after, then you should use the Timer#scheduleAtFixedRate method. If you continually reschedule the task with a delay, then the Timer instance cannot compensate for its past timing errors.
If short-term accuracy is also a concern, then you should switch to the Scheduled Executor Service, which uses a more accurate low-level technique to schedule the tasks.
I actually have a bit of a ad-hoc solution to the problem.
I stopped counting every ms, and just did the +=15ms to counter for the sleep();
The timer runs smooth now and after a minute I had less than 1second difference with the actual time it should have been.
Thanks everyone for your help, but any other (less ad-hoc) solutions are still very welcome!
EDIT: I just got this method due to Boris, so you can post your comment as an answer if you like :)

Make a simple timer in Java

I can't seem to figure out how to make a simple timer in java. All I need it to do is just display time, really. So just a start method, and it keeps counting up like 0:00, 0:01, 0:02, etc. I've seen some other similar forum posts on this, but all the code is kind of complicated for my level of understanding; I'm kind of new to java. But it shouldnt be that hard to make a timer that just performs such a basic function? If anyone could help it would be greatly appreciated :)
This is not difficult. However, I would caution you that I have seen some very confused answers on stack overflow, in some cases shockingly poor coding habits, so be very careful. First let me answer the question.
If seem that the biggest mistake that programmers make in implementing a timer, is thinking that they need something to keep track of the current time. That is, they write some sort of loop that increments a variable every second or some such silly thing. You do not need to write code to keep track of the time. The function System.currentTimeMillis() will do that for you, and it does it quite accurately.
Timer code will involve two aspects which many programmers mix up:
calculation of the time
refresh of the display
All you need to do to calculate the time to display, is to record the time that the timer started:
long startTime = System.currentTimeMillis();
Later, when you want to display the amount of time, you just subtract this from the current time.
long elapsedTime = System.currentTimeMillis() - startTime;
long elapsedSeconds = elapsedTime / 1000;
long secondsDisplay = elapsedSeconds % 60;
long elapsedMinutes = elapsedSeconds / 60;
//put here code to format and display the values
The biggest mistake that programmers make is to think they need a variable to hold the current time and then to write code to increment that variable every second, e.g. something called "elapsedSeconds" which they maintain. The problem is that you can schedule code to be called every second, but there is no guarantee of exactly when that code will be called. If the system is busy, that code might be called quite a bit later than the second. If the system is extremely busy (for example page fetching from a faulty disk) it could actually be several seconds late. Code that uses the Thread.sleep(1000) function to loop every second will find that the error builds up over time. If sleep returns 300ms late one time, that error is compounded into your calculation of what time it is. This is all completely unnecessary because the OS has a function to tell you the current time.
The above calculation will be accurate whether you run this code every second, 100 times a second, or once every 3.572 seconds. The point is that currentTimeMillis() is the accurate representation of the time regardless of when this code is called -- and that is an important consideration because thread and timer events are not guaranteed to be accurate at a specific time.
The second aspect of a timer is refresh of the display. This will depend upon the technology you are using to display with. In a GUI environment you need to schedule paint events. You would like these paint events to come right after the time that the display is expected to change. However, it is tricky. You can request a paint event, but there may be hundreds of other paint events queued up to be handled before yours.
One lazy way to do this is to schedule 10 paint events per second. Because the calculation of the time does not depend on the code being called at a particular point in time, and because it does not matter if you re-paint the screen with the same time, this approach more or less guarantees that the displayed time will show the right time within about 1/10 of a second. This seems a bit of a waste, because 9 times out of 10 you are painting what is already on the screen.
If you are writing a program with animation of some sort (like a game) which is refreshing the screen 30 times a second, then you need do nothing. Just incorporate the timer display call into your regular screen refresh.
If paint events are expensive, or if you are writing a program that does terminal-style output, you can optimize the scheduling of events by calculating the amount of time remaining until the display will change:
long elapsedTime = System.currentTimeMillis() - startTime;
long timeTillNextDisplayChange = 1000 - (elapsedTime % 1000);
The variable timeTillNextDisplayChange holds the number of milliseconds you need to wait until the seconds part of the timer will change. You can then schedule a paint event to occur at that time, possibly calling Thread.sleep(timeTillNextDisplayChange) and after the sleep do the output. If your code is running in a browser, you can use this technique to update the page DOM at the right time.
Note, that there is nothing in this calculation of the display refresh that effects the accuracy of the timer itself. The thread might return from sleep 10ms late, or even 500ms late, and the accuracy of the timer will not be effected. On every pass we calculate the time to wait from the currentTimeMillis, so being called late on one occasion will not cause later displays to be late.
That is the key to an accurate timer. Do not expect the OS to call your routine or send the paint event exactly when you ask it to. Usually, of course, with modern machines, the OS is remarkably responsive and accurate. This happens in test situations where you are not running much else, and the timer seems to work. But, in production, under rare stress situation, you do not want your timer "drifting" because the system is busy.
You can either use Timer class from java.util or another way, which is more complicated, is with Threads. Timer also has thread action, but it's pretty easy to understand to use it.
For creating a simple timer as you explained as per your need , it is very easy to write a code for that. I have written the below code for your reference. If you wish you can enhance it.
import java.util.concurrent.TimeUnit;
public class PerfectTimer {
public static void main(String[] args) throws InterruptedException
{
boolean x=true;
long displayMinutes=0;
long starttime=System.currentTimeMillis();
System.out.println("Timer:");
while(x)
{
TimeUnit.SECONDS.sleep(1);
long timepassed=System.currentTimeMillis()-starttime;
long secondspassed=timepassed/1000;
if(secondspassed==60)
{
secondspassed=0;
starttime=System.currentTimeMillis();
}
if((secondspassed%60)==0)
displayMinutes++;
System.out.println(displayMinutes+"::"+secondspassed);
}
}
}
if you want to update something in the main thread (like UI components)
better to use Handler
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override
public void run() {
//do something
}
}, 20);
20 - the delay In MS to do something.
and run it in a loop.
I have created a Timer that has everything you might need in it.
I even documented it!
And I also compiled it for faster usage.
Here's an example:
//...
//For demo only!
public static void main(String[]a){
Timer timer=new Timer();
timer.setWatcher(new Timer.TimerWatcher(){
public void hasStopped(boolean stopped){
System.out.print(stopped+" | ");
}
public void timeElapsed(long nano, long millis, long seconds){
System.out.print(nano+", ");
System.out.print(millis+", ");
System.out.print(seconds+" | ");
}
public void timeLeft(long timeLeft){
System.out.print(timeLeft+"\r");
}
});
//Block the thread for 5 seconds!
timer.stopAfter(5, Timer.seconds); //You can replace this with Integer.MAX_VALUE.
//So that our watcher won't go to waste.
System.out.println();
}
//...
This is not for promotion, made this to help people not waste their time in coding classes themselves!

Timer in android not correctly repeating on delay

I have this code called in a Service:
timer.scheduleAtFixedRate(new TimerTask(){
public void run() {
showNotification();
}
}, firstNotify, 86400000L);
It is my understanding that this should cause showNotification() to be called once per day at the same time each day, at the time specified in firstNotify (86400000 being the milliseconds in a day).
However, the notifies were happening approximately every 3 hours on my phone, and a little over 4 hours on my friend's phone. Is there any reason why these would be occurring faster than the specified 1-day period for repeating?
I know its not a direct answer to your question, but you should use AlarmManager in such cases as yours. See setRepeating function.
If your Service is not setup correctly and it is being shut down at some point, the Timer would be recreated and called again after a firstNotify delay. Does this sound possible? You might be better off using AlarmManager to create the timed event.

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 so 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.

Time-efficient Gameloop in J2ME

I've done a series of questions about J2ME Game developing, and in a recent one, Neil Coffey commented
As a side issue-- do you REALLY want
to do 100 ticks/second in a J2ME game?
As I think sb has mentioned, you
should really also sleep to the next
desired wake-up point, not a fixed
duration each time.
For some reason, that thing stuck in my mind and now I want the answers, what do I need to make my gameloop sleep to the desired wake-up point, I don't really know where is that point xD (theoretically speaking).
For the sake of feedback, this is a simplified version of my gameloop:
public void run() {
Graphics g = this.getGraphics();
while (running) {
long diff = System.currentTimeMillis() - lastLoop;
lastLoop = System.currentTimeMillis();
input();
this.level.doLogic();
render(g, diff);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
stop(e);
}
}
}
Thanks for your help!!
There is an excellent article on game loops here, if you haven't read it already.
From my experience writing J2ME games, you'll want to minimize how much you do anything in a game loop, as a poorly written game loop can quickly drain a phones puny battery. That is, if you're rendering ever 10 milliseconds, make sure to check to see if anything has changed, and if not, skip it.
If you decide that you want to render every 10 milliseconds, then you:
loop {
- record current time; render
- do input/logic
- check the current time, and calculate elapsed time
- if less than 10 ms has elapsed, calculate the remaining time (10 millis - elapsed time); sleep for this duration
}
I understand that there may be issues with timer resolution (for example, Thread.sleep(10) may not sleep for exactly 10 ms; and System.currentTimeMillis() may not return results with granularity down to 1 ms). This is platform dependent.

Categories

Resources