Retain order of concurrent MIDI events
[ardour.git] / libs / backends / coreaudio / coremidi_io.cc
index a64fade8e33fcb6dbdebd6130312fbf7d9f8e057..1d4f6fbf025e37163a71ec4fe72af2fe4aa25574 100644 (file)
@@ -28,6 +28,26 @@ using namespace ARDOUR;
 static int _debug_mode = 0;
 #endif
 
+
+/** 
+ * MIDI Data flow
+ * 
+ * (A) INPUT (incoming from outside the application)
+ * 
+ *    - midiInputCallback (in its own thread, async WRT process callback):
+ *       takes OS X MIDIPacket, copies into lock-free ringbuffer
+ *
+ *    - processCallback (in its own thread):
+ *
+ *   (1) loop on all input ports:
+ *       1A) call recv_event() to read from ringbuffer into stack buffer, also assign-timestamp, 
+ *       1B) call parse_events() using stack buffer, when appropriate
+ *          pushes CoreMidiEvent into std::vector<CoreMidiEvent>
+ *
+ *   (2) in MidiPort::cycle_start() (also part of the process callback call tree), MidiPort::get_midi_buffer()
+ *       calls CoreAudioBackend::midi_event_get () returns a pointer to the  data of the specified CoreMidiEvent
+ */
+
 static void notifyProc (const MIDINotification *message, void *refCon) {
        CoreMidiIo *self = static_cast<CoreMidiIo*>(refCon);
        self->notify_proc(message);
@@ -37,7 +57,7 @@ static void notifyProc (const MIDINotification *message, void *refCon) {
 static void print_packet (const MIDIPacket *p) {
        fprintf (stderr, "CoreMIDI: Packet %d bytes [ ", p->length);
        for (int bb = 0; bb < p->length; ++bb) {
-               fprintf (stderr, "%02x ", ((uint8_t*)p->data)[bb]);
+               fprintf (stderr, "%02x ", ((const uint8_t*)p->data)[bb]);
        }
        fprintf (stderr, "]\n");
 }
@@ -248,13 +268,21 @@ CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uin
                if ((*it)->timeStamp < end) {
                        if ((*it)->timeStamp < start) {
                                uint64_t dt = AudioConvertHostTimeToNanos(start - (*it)->timeStamp);
-                               if (dt > 1e7) { // 10ms,
+                               if (dt > 1e7 && (*it)->timeStamp != 0) { // 10ms slack and a timestamp is given
 #ifndef NDEBUG
                                        printf("Dropped Stale Midi Event. dt:%.2fms\n", dt * 1e-6);
 #endif
                                        it = _input_queue[port].erase(it);
                                        continue;
                                } else {
+                                       /* events without a valid timestamp, or events that arrived
+                                        * less than 10ms in the past are allowed and
+                                        * queued at the beginning of the cycle:
+                                        * time (relative to cycle start) = 0
+                                        *
+                                        * The latter use needed for the "Avid Artist" Control Surface
+                                        * the OSX driver sends no timestamps.
+                                        */
 #if 0
                                        printf("Stale Midi Event. dt:%.2fms\n", dt * 1e-6);
 #endif