CoreMIDI: rock solid midi sync

2020-07-27 06:06发布

问题:

I'm having troubles with midi synchronization. Following posts in the syntheticbits.com, I use a PGMidi class. Sync works, but is constantly shifting to 1-2 bpm.

Here is the code that I use:

- (void)sendMidiClockInMidiThread {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [lock lock];

    const int64_t kOneMillion = 1000 * 1000;
    const UInt8   tick[]      = { 0xF8 };

    // Calculate tick time
    // returns sample for sixteen note (5512 if current bpm is 120)
    SInt32 sixteen     = AGGetSamples_SixteensWithoutSwing(_grid, 1.0);
    UInt64 tickTime    = (sixteen / 6) * kOneMillion;
    int    tickLatency = 0;
    // Send ticks messages
    for (int i = 0; i < 6; ++i) {
         int beginTime = clock();
         hostTime      = hostTime + (tickTime - tickLatency);
         [self.midi sendBytes:tick size:sizeof(tick) atTime:hostTime];
         int endTime   = clock();
         tickLatency   = endTime - beginTime;
    }

    [lock unlock];
    [pool drain];
}

Please tell me how to get a clear synchronization.

回答1:

First: where is this message getting called from? What is your timer? You need to make sure you use a very accurate timer. You will essentially need something that is tighter than 10ms (20ms is the period of the MIDI clock pulse, at 24 pulses per quarter note, 120 quarter notes per minute).

This guy did a pretty decent write-up on synchronization primitives available on iOS / MacOS.

His worst case here (that involves spin-locking) is still off by almost 50ms in the worst case, and off by 14ms in the average case. This is absolutely terrible timing for MIDI. Your best bet is to start a CoreAudio thread (or a real-time thread using the info available here).