Ableton / LinkKit

iOS SDK for Ableton Link, a new technology that synchronizes musical beat, tempo, and phase across multiple applications running on one or more devices.
http://ableton.github.io/linkkit
Other
147 stars 10 forks source link

ABLLinkRequestBeatAtTime seemingly not working with ABLLinkCommitAppTimeline #39

Closed edsharp closed 6 years ago

edsharp commented 7 years ago

I'm converting my app from pre-2.x to use 2.1.1

My original working code was:

ABLLinkResetBeatTime(_ablLink, 0.0, AECurrentTimeInHostTicks());

However when I convert to the new format, I'm seeing something strange. From the main thread, the following code does not change the beat time:

  const ABLLinkTimelineRef timelineRef = ABLLinkCaptureAppTimeline(_ablLink);
  ABLLinkRequestBeatAtTime(timelineRef, 0.0, AECurrentTimeInHostTicks(), self.quantum);
  ABLLinkCommitAppTimeline(_ablLink, timelineRef);

but if I use:

  const ABLLinkTimelineRef timelineRef = ABLLinkCaptureAudioTimeline(_ablLink);
  ABLLinkRequestBeatAtTime(timelineRef, 0.0, AECurrentTimeInHostTicks(), self.quantum);
  ABLLinkCommitAudioTimeline(_ablLink, timelineRef);

it does work.

Of course, I'm not supposed to use the ABLLinkCaptureAudioTimeline in the main thread and I am certain I'm in the main thread.

Anyone seen anything similar?

fgo-ableton commented 7 years ago

I just did a test changing lines 160 and 207 of AudioEngine.m of the example App to use the App versions of capture... and commit... and could not see any issue.

Is it possible you are committing a timeline from another thread that overwrites your intended change? If you commit a change on the app thread it will not immediately propagate to the audio thread. So changing the timeline from multiple threads can lead to race conditions.

What is self.quantum set to? Maybe having it set to 0 will not give you the desired result. But if that is the same for both versions that is probably not the cause of the problem.

Let me know if that helps. If not, do you have more information that might help me to reproduce the problem?

edsharp commented 7 years ago

I found that I was not committing to the timeline from a different thread, but I was using ABLLinkCaptureAudioTimeline in a method that was sometimes called on the main thread and sometimes in my own thread.

My app is related to timing rather than producing audio. At first I used the audio thread, but eventually I I created a THREAD_TIME_CONSTRAINT_POLICY (real-time constraint) thread that's scheduled every 50ms to be independent of the audio thread buffer size.

I'm therefore sometimes calling link-related methods from the main thread and sometimes from my independent thread.

On the basis that the audio thread is realtime and so my independent thread, I guessed at generally using ABLLinkCaptureAudioTimeline in my thread and ABLLinkCaptureAppTimeline from the main thread. However because of the way I'd structured the app, some methods were written as plain C but could be called from either my thread or the main thread. In those cases I'd gone with ABLLinkCaptureAudioTimeline on the basis they're perhaps better behaved with regards to locks.

I'd love a clearer understanding of the difference between ABLLinkCaptureAudioTimeline and ABLLinkCaptureAppTimeline particularly when it comes to their use in a thread other than main or audio.

With a better understanding, I can rearchitect my app :)

Thanks for the speedy response.

edsharp commented 6 years ago

I have tracked down my problem and my mistake and it indeed was that I was sometimes using the wrong capture/commit from the wrong thread.