fix const-cast
[ardour.git] / libs / backends / coreaudio / coremidi_io.cc
index 0cef589b89fe758ab86c43b0821dc1a22ccc3fd1..1d4f6fbf025e37163a71ec4fe72af2fe4aa25574 100644 (file)
 
 using namespace ARDOUR;
 
+#ifndef NDEBUG
+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);
 }
 
+#ifndef NDEBUG
+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 ", ((const uint8_t*)p->data)[bb]);
+       }
+       fprintf (stderr, "]\n");
+}
+
+static void dump_packet_list (const UInt32 numPackets, MIDIPacket const *p) {
+       for (UInt32 i = 0; i < numPackets; ++i) {
+               print_packet (p);
+               p = MIDIPacketNext (p);
+       }
+}
+#endif
+
 static void midiInputCallback(const MIDIPacketList *list, void *procRef, void *srcRef) {
        CoreMidiIo *self = static_cast<CoreMidiIo*> (procRef);
        if (!self || !self->enabled()) {
                // skip while freewheeling
+#ifndef NDEBUG
+               if (_debug_mode & 2) {
+                       fprintf (stderr, "Ignored Midi Packet while freewheeling:\n");
+                       dump_packet_list (list->numPackets, &list->packet[0]);
+               }
+#endif
                return;
        }
        RingBuffer<uint8_t> * rb  = static_cast<RingBuffer < uint8_t > *> (srcRef);
-       if (!rb) return;
+       if (!rb) {
+#ifndef NDEBUG
+               if (_debug_mode & 4) {
+                       fprintf (stderr, "Ignored Midi Packet - no ringbuffer:\n");
+                       dump_packet_list (list->numPackets, &list->packet[0]);
+               }
+#endif
+               return;
+       }
        MIDIPacket const *p = &list->packet[0];
        for (UInt32 i = 0; i < list->numPackets; ++i) {
                uint32_t len = ((p->length + 3)&~3) + sizeof(MIDITimeStamp) + sizeof(UInt16);
-               if (rb->write_space() < sizeof(uint32_t) + len) {
-                       fprintf(stderr, "CoreMIDI: dropped MIDI event\n");
-                       continue;
+#ifndef NDEBUG
+               if (_debug_mode & 1) {
+                       print_packet (p);
+               }
+#endif
+               if (rb->write_space() > sizeof(uint32_t) + len) {
+                       rb->write ((uint8_t*)&len, sizeof(uint32_t));
+                       rb->write ((uint8_t*)p, len);
+               }
+#ifndef NDEBUG
+               else {
+                       fprintf (stderr, "CoreMIDI: dropped MIDI event\n");
                }
-               rb->write ((uint8_t*)&len, sizeof(uint32_t));
-               rb->write ((uint8_t*)p, len);
+#endif
                p = MIDIPacketNext (p);
        }
 }
@@ -88,6 +151,11 @@ CoreMidiIo::CoreMidiIo()
        , _changed_arg (0)
 {
        pthread_mutex_init (&_discovery_lock, 0);
+
+#ifndef NDEBUG
+       const char *p = getenv ("COREMIDIDEBUG");
+       if (p && *p) _debug_mode = atoi (p);
+#endif
 }
 
 CoreMidiIo::~CoreMidiIo()
@@ -200,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