iossynchronizationmidiaudiokitaudiotoolbox

How to sync accurately enough two music sequences (Audiokit.AKAppleSequencer)?


I have 2 sequencers:

let sequencer1 = AKAppleSequencer(filename: "filename1")
let sequencer2 = AKAppleSequencer(filename: "filename2")

Both have the same bpm value.

When sequencer1 starts playing one midi track (playing it only once) I need that sequencer2 begin playing exactly after first sequencers finished. How can I achieve this ? Note that sequencer2 looped.

Currently I have this approach but it is not accurate enough:

let callbackInstrument = AKMIDICallbackInstrument(midiInputName: "callbackInstrument", callback: nil)
let callbackTrack = sequencer1.newTrack()!
callbackTrack.setMIDIOutput(callbackInstrument.midiIn)

let beatsCount = sequencer1.length.beats

callbackTrack.add(noteNumber: MIDINoteNumber(beatsCount),
    velocity: 1,
    position: AKDuration(beats: beatsCount),
    duration: AKDuration(beats: 0.1))

callbackInstrument.callback = { status, _, _ in
    guard AKMIDIStatusType.from(byte: status) == .noteOn else { return }
    DispatchQueue.main.async { self.sequencer2.play() }//not accurate
}

let sampler = AKMIDISampler(midiOutputName: nil)
sequencer1.tracks[0].setMIDIOutput(sampler.midiIn)

Appreciate any thoughts.


Solution

  • Apple's MusicSequence, upon which AKAppleSequencer is built, always flubs the timing for the first 100ms or so after it starts. It is a known issue in closed source code and won't ever be fixed. Here are two possible ways around it.

    1. Use the new AKSequencer. It might be accurate enough to make this work (but no guarantees). Here is an example of using AKSequencer with AKCallbackInstrument: https://stackoverflow.com/a/61545391/2717159

    2. Use a single AKAppleSequencer, but place your 'sequencer2' content after the 'sequencer1' content. You won't be able to loop it automatically, but you can repeatedly re-write it from your callback function (or pre-write it 300 times or something like that). In my experience, there is no problem writing MIDI to AKAppleSequencer while it is playing. The sample app https://github.com/AudioKit/MIDIFileEditAndSync has examples of time shifting MIDI note data, which could be used to accomplish this.