The question is answered
Precise metronome problem
Hi guys, i have been having a problem for a while now. I have made a simple android beat machine that plays audioclips on specific intervals. I can not get the intervals to be precise and consistent. I tried this: http://cubeslam.net/2013/12/19/unity-metronome-like-a-pro/ and also this: http://nodgez.net/?p=153
Using coroutines or fixedupdate while calculating time between beats prooves to be inacurate as soon as anything else happens in the scene, as well as if left running for more than a few seconds. I found a unity metronome here: http://docs.unity3d.com/ScriptReference/AudioSettings-dspTime.html , that uses AudioSettings.dspTime, which seems to work, but i can not make it trigger audioclips.
current best version of the metronome, which tends to slow down or make errors often.
IEnumerator PlaySounds()
{
isPlaying = true;
while (isPlaying)
{
if (interval <= 0)
{
myAudio.PlayOneShot(myAudioClip, 1f);
interval = (60f / BPM);
interval -= Time.deltaTime;
}
else {
interval -= Time.deltaTime;
}
yield return null;
}
}
Can anybody suggest a better approach or even has a method of using the unity metronome, linked above, to time my sounds? Running Unity version 5.3.2f1 on Windows 10.
Thanks alot for your help!
I would use the system clock. It can be used on PC by using the System
Library:
int timer = 0;
if(System.DateTime.Now.Second == timer+1)
{
Tick();
}
timer = System.DateTime.Now.Second;
void Tick();
{
//Do whatever.
}
This seems to be a very precise ti$$anonymous$$g mechanism that does not rely on fps (as far as I know and experimented with it, I don't claim it to be a fact).
I'm not sure if it works the same way on an Android device, but I don't see why it shouldn't work, but then again I'm no expert on Android hardware.
Everything that involves Time.deltaTime is directly FPS based and should be avoided for normal or precise ti$$anonymous$$g operations.
Hope this helps, I once was looking for a precise timer and it seemed to be the most precise due to the fact it has millisecond accuracy.
I might add that this timer is ticking every second and you would have to adapt it to your desired bpm.
Thank you! I want a really precise ti$$anonymous$$g machine and this works exact for hours because it is actually a clock :D
Answer by troien · Mar 22, 2016 at 07:43 PM
The last link (Unity docs one) doesn't work for me...
As for how to make your current code better. Sinse you want to play audio on the tick, threads are not really an option as they can't call Uniy code... So ye, I believe coroutines or update are indeed your best option. However they will obviously not work very well when you do a lot of other things in the scene that affect your fps in a negative way. As they al run on the same thread and your metronome simply has to wait untill the rest of your code (Update etc. of other gameobjects), Unity overhead and perhaps rendering(not sure) is finished. If it is supposed to tick while it is waiting, then this one tick will be delayed. So the more other things you are doing, the higher the chance is that your metronome will be late.
You might however get an improvement by changing your code slightly to this:
IEnumerator PlaySounds()
{
isPlaying = true;
while (isPlaying)
{
if (interval <= 0)
{
myAudio.PlayOneShot(myAudioClip, 1f);
interval += (60f / BPM);
}
interval -= Time.deltaTime;
yield return null;
}
}
By adding (60 / BPM) to the interval instead of setting the interval to it, you should get a more steady beat, as now when one beat is a millisec to late, this will be compensated at the next beat.
Also, reading the docs, this might be a way better answer. See AudioSource.PlayScheduled
agree, PlayScheduled seems like the way to go. Update() may be called irregularly, but inside Update() you can look at AudioSettings.dspTime to calculate what time it is "now" and schedule a handful of sound-plays for the future. you'll need to be careful w/ your book-keeping not to schedule the same one twice, and i'm not sure how to cancel scheduled sounds.
Thanks @troien, I will try PlayScheduled and report ASAP. I have no idea, why i didn't discover that sooner.
As for the threads and Unity code: i just found this dude who managed to do something with AudioSettings.dspTime here: https://github.com/Nidre/Unity-Audio-Sequencer
I will still try playscheduled first, since it sounds simpler.
AudioSource.PlayScheduled did the trick. Thank you very very much!
Follow this Question
Related Questions
Audio not playing when destroying a GameObject. 1 Answer
Audio is way too soft on mobile but alright in Unity Editor! 0 Answers
Audio Cutting Out Unexplainably 1 Answer
How to make audio play at once. 1 Answer
Cracking at end of audio? 0 Answers