Hey all,
This isn't exactly a Link issue per se, but I know of no other place (besides the Audiobus developer forums) where there are experts on Core Audio that might be able to offer some insight into this issue. It also could potentially affect other developers integrating Link.
I have implemented Link into my iOS app, and all is working great. However last night I noticed a slight tempo drift on my iPhone compared to my iPad. Upon further testing I observed that at 100bpm (6615.0 frames per 16th note), over the course of 1 minute, the iPhone would fall behind Ableton Link by about 0.038 beats (ie. the first beatTime value was 1.000 and after a minute the beat time was about 99.962). Which is about 15-16% of a 16th note. This seems to drift at a reasonably linear rate and would result in a noticeable discrepancy between the beats after a few minutes when comparing to another app running Link on the iPhone, or against my own app running on the iPad at the same time. Indeed running the app (identical code base) on my iPad Air 1 (iOS 9.0) produced rock solid results with a beat discrepancy of 0.000001 for each beat. Where as both my iPhone 6 (iOS 8.4) and iPhone 5 (iOS 8.1) produced this tempo drift by the same degree.
I figure it must be Core Audio related if the same code was producing two different results, and noticed that on my iPad the difference in value between the inTimeStamp->mHostTime at each callback was 139320, where as on my two iPhones the mHostTime difference between each callback was 139264.
139320 - 139264 = 56 less mHostTime on iPhones, which is 56/139320 = 0.00040195 as a percent
44100 * 60 = 2,646,000 frames per minute
2,646,000 * 0.00040195 = 1063.5597 frames drift
As a percentage of a 16th note (6615 frames), this is 1063.5597 / 6615 = 16.078% - suspiciously close to the 15-16% of 1/16th drift I observed after 1 minute.
So I then added some code into the app that multiplied the frames per 16th beat by a ratio of (139320 / 139264).
eg:
Float64 newSamples = 44100.0 / ((newTempo * 4.0 )/60.0);
// ( = 6615, where newTempo is 100 )
newSamples = newSamples * (139320.0 / 139264.0);
This produces very consistent results with no tempo drift after many minutes!
beatTime = 217.999508 bpm = 99.959805 samplesPerBeat = 6617.659984 quantime = 4.000000
beatTime = 218.999527 bpm = 99.959805 samplesPerBeat = 6617.659984 quantime = 4.000000
beatTime = 219.999504 bpm = 99.959805 samplesPerBeat = 6617.659984 quantime = 4.000000
beatTime = 220.999520 bpm = 99.959805 samplesPerBeat = 6617.659984 quantime = 4.000000
However obviously I can't just apply this dodgy fix as I have no idea whats really causing it. Would a discrepancy in mHostTime actually cause this? (ie. does it mean the buffer is delivered to the speakers at an earlier time?). Is the cause iPhones vs iPad hardware or is it iOS 8 vs iOS 9? I would love to know what mHostTime results other people are getting on their devices (ie save the mHostTime between callbacks and each callback just do newHostTime - oldHostTime). Is no one else experiencing this issue? I have compared other Link enabled apps on my iPhone and they don't seem to suffer from any drift issues, however I am not sure whether or not this is because they are constantly recalibrating themselves based on Link's beat time, or whether they're just setting a new tempo once at the start and letting its do its thing until notified of any beat changes, as I am doing.
Anyway, sorry for the long explanation. Any insight anyone could provide would be greatly appreciated!
Cheers,
David
Edit: Just tested on my iPhone 4 / iOS 7.1.2, and although I can't run Link on it I'm getting a mHostTime difference of 139320 - like the iPad.