Ableton / link

Ableton Link
Other
1.09k stars 149 forks source link

Drift on some iOS devices #110

Open lijon opened 2 years ago

lijon commented 2 years ago

For some reason, the beat time from Link on iOS (based on hostTime) deviates more from an ideal sample precise time on some devices and some sample rates. Some jitter is expected, but on those devices and sample rate combinations it's drifting over time. In other words, the effective tempo is constantly too low or high (don't remember which) compared to a mathemtically correct tempo. I doubt there is anything to do about this, since the problem is present already in the CoreAudio system layer. (Drift and not only jitter between mHostTime and mSampleTime). But maybe Link could find some workaround to detect and compensate for this? What about mRateScalar?

Example devices that shows this behaviour: 2017 iPad Pro 10.5, iPad Air 4th gen.

fgo-ableton commented 2 years ago

Yes, sample time and host time drift. They are really different clocks based on different quartzes. And there is really not much one can do about this. AFAICT this is the case for all iOS devices, event though it is more noticeable on some. And it becomes somehow obvious when thinking about a USB audio device connected to host.

The Link API is based on host time. In fact Link has no idea about the sample time or any other audio properties of the system. As the individual host times (and sample times) of the peers in a Link session also unavoidably drift, eventually any peer has to be able to deal with the clock drift when being part of a Link session. At this point trying to compensate for this using something like mRateScalar won't help as it is local to one peer.

If it is possible in your setup I would probably recommend to generally base the (beat) clock on host time. This is not only easier with Link but also with i.e. Core MIDI as the timing information there is also in host time. On the other hand, if there are benefits in running on sample time (i.e. not having to warp audio / sample accurate reproducibility) in case Link is not enabled it might make sense to implement two different clock modes.

lijon commented 2 years ago

Yes, I understand that host time and sample time does drift when compared to each other. The thing is that it drifts much more on some devices. On most devices I tested, there is no noticeable drift at all, only jitter. What I wonder is if it on these devices also host time drifts more compared to another device host time. I suspect it does but haven't measured it. Is there a way with Link to log the amount of time adjustments being done to keep peers in sync? If so one could then see if this amount increases more when certain peers joins the session.

Yes, personally (in AUM) I've based my clock on host time converted to beat time via the Link API all the time, regardless if Link is enabled or not. In the next update, it will instead use a sample perfect clock when Link is disabled.

fgo-ableton commented 2 years ago

Unfortunately there is no easy way to log this. Yes, I remember that on some iOS devices the drift is barely noticeable. When it comes to Laptops and other OSes the amount of drift increases a lot compared to iOS. So the amount of drift should not increase based on the number of peers in a session but rather on the kind of peers.

Anyways, using host time when Link is involved and sample time otherwise makes sense to me. (That is also the way we do it in Live).

lijon commented 2 years ago

I guess one way is to log the predicted beat time for each buffer cycle vs the beat time returned from Link, that will show any jitter and I assume also occasional larger jumps due to Link doing adjustments to keep peers in sync? If so one should be able to see if there are larger amounts of such adjustments or not.

fgo-ableton commented 2 years ago

I guess I don't really understand what you're trying to achieve. You could surely use this information to determine how much the peer is drifting from the session. However, this won't allow you to determine which peer causes the drift.

Side note: After starting the session the clock will initially be based on the local clock of peer that first enabled Link. So peers joining later will align to it.

lijon commented 2 years ago

Right. My initial question was simply if this drift between host time and sample time on some devices could be improved. And if mRateScalar might be useful for that purpose. Interestingly, on my device that does drift, I tried this:

clock->_beatTimeAtEndOfBuffer /= timestamp->mRateScalar; and it reduced the drift to jitter only! However, this was not a generic solution and perhaps it was even just a coincidence, because it lead to runaway beat clock for some beta testers. Also I never tried it while synced to other Link peers.

But my conclusion was that maybe mRateScalar can be useful to reduce drift on some devices, if used correctly (which I apparently did not).

fgo-ableton commented 2 years ago

I see. When not being connected to other peers mRateScalar does exactly what you want. So instead of basing your app on the sample clock when not using Link, you could also use the host clock and compensate for drift using mRateScalar. However, that won't help when being connected to other peers. I can't think of any reasonably simple way to provide a factor similar to mRateScalar that can compensate the clock drift for peers on the network. The straight forward way to do this is to compare a locally predicted beat time with the Link beat time. If the locally predicted beat time is calculated from the sample clock, it should be the same as mRateScalar in case Link is not connected to other peers.