I want to run a timer that says play a sound sample every 600 milliseconds. The accuracy is really important, as when played against a backing metronome track, any slight slip in time you can hear easily. I've tried this: Code (csharp): float timeLastBeat; Update(){ if(time.timeSinceLevelLoad - timeLastBeat >= 0.6f){ MasterAudio.play() timeLastBeat = time.timeSinceLevelLoad; } i've also tried using Stopwatch Code (csharp): usingSystem.Diagnostics; float timeLastBeat; Start(){ timer = newStopwatch(); timer.start(); } Update(){ if(timer.ElapsedMilliseconds - timeLastBeat >= 600.0f){ MasterAudio.play() timeLastBeat = timer.ElapsedMilliseconds; } both create slight variations in gaps between beats, 600ms, 612ms, 650ms etc. I'm guessing this is an Update speed/frequency issue and even a coroutine would be the same. I found this http://docs.unity3d.com/ScriptReference/AudioSettings-dspTime.html but I don't want to generate a sound from script, I want to play one using MasterAudio. I can't put a MasterAudio call inside OnAudioFilterRead. Any thoughts? Thanks
The Update loop is only called once a frame, and there's really no way around that. Even if there was, anything that is built on Unity's own audio components will almost certainly not have any timing better than a per-frame level. I see two options: A) If a ~15 ms variance is acceptable, focus on performance; if you can maintain a constant 60fps your timing will be within 16 ms. The toughest thing here would be eliminating all garbage collection, because a "bump" in a frame where the GC runs is what will really kill you. B) Go outside of Unity, both for the timing and the audio playback. It may be possible to get Mono to trigger some timed events that aren't dependent on Unity's Update cycle, but audio is a whole other can of worms. You'd probably have to write a native plugin.
You can use dspTime outside of OnAudioFilterRead() - it's just used in that example to create procedural sounds. However, as StarManta stated, Update() is called every frame, meaning that there is no guarantee that using .dspTime will land you right on the 600ms mark - in fact, that will never happen. You can't use a separate thread to do the timing either, as you need to call the Unity functions on its main thread. You can use Unity's PlayScheduled() to to what you require - there is a nice post on that topic here.
Huh, I did not realize that PlayScheduled exists. That's exactly what's needed for this. Good to know!
Thanks! Tom Betts on Twitter also recommended the same blog post mentioned above https://twitter.com/TomNullpointer/status/651150130528194560 https://twitter.com/TomNullpointer/status/651148867052810241 I've implemented the code from Christian Floisand, there is still a very slight delay, but at least the delay is consistent not like the Update method I was trying. See the attached image of the audio waveform, you can see the click track and the sample I'm trying to play on beat. I wonder if thats because the object you are notifying is still running this inside Update() : Code (csharp): if ((beatObserver.beatMask & BeatType.OnBeat) == BeatType.OnBeat) { } Thanks