Making a *very* accurate iOS metronome for has been discussed under two different approaches:
1) using The Amazing Audio Engine (TAAE) approach, as presented in the ABetterMetronome example and
2) using Pure Data (PD) and libPD for iOS as presented in the linked video.
The aforementioned approaches are completely accurate, but in both examples there some things that makes them difficult to be extended to a not-only-metronome kind of app:
1) The TAAE approach is based on synthesising the metronome’s “click” sound sample-by-sample. The ABetterMetronome tutorial does not show how and if we could use other means to produce the metronome “click” sound, or play any other instrument note or sound.
2) In the PD approach, time scheduling is performed “inside” the PD patch. It seems that all the music-side reasoning has to be performed inside the PD patch, while it seems more reasonable to do the musical reasoning part of code in Objective-C or Swift instead.
Therefore, both examples discuss simple cases to make an accurate metronome. However, there is no discussion on how to harness the immense timing accuracy that they both have to iOS programming with more sophisticated musical reasoning. For instance, if you are making an app that decides in real-time about which notes to be played at certain (accurate) time intervals both aforementioned examples make it seem hard – while all the info is in there and it is completely easy!
The attached file is again a simple metronome that combines the TAAE and the PD approaches. However, in this example the programmer can decide on the Objective-C side of the code which notes to be played on the PD side. Hence the block frame counter approach of the TAAE example is combined with the facilities that PD offers, allowing accuracy and creativity to music-based app development.
Bonus: In the attached example, there is also a not-so-pretty but functional screen that updates the current beat of the metronome. It might seem trivial but it is not – when you need to update UI elements inside a AEBlockChannel it has to go through an NSOperationQueue block… Check it out!