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 ", ((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);
}
}
, _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()
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
ss << "system:midi_capture_";
SInt32 id;
if (noErr == MIDIObjectGetIntegerProperty(_input_endpoints[port], kMIDIPropertyUniqueID, &id)) {
- ss << (int)id;
+ ss << (unsigned int)id;
} else {
ss << port;
}
ss << "system:midi_playback_";
SInt32 id;
if (noErr == MIDIObjectGetIntegerProperty(_output_endpoints[port], kMIDIPropertyUniqueID, &id)) {
- ss << (int)id;
+ ss << (unsigned int)id;
} else {
ss << port;
}