replace "None" with DeviceNone in ALSA/Coreaudio
[ardour.git] / libs / backends / coreaudio / coremidi_io.cc
index 87f88a3a029a05938550e31c322a1ae32c11dc4b..a64fade8e33fcb6dbdebd6130312fbf7d9f8e057 100644 (file)
  */
 
 #include <sstream>
-#include "coremidi_io.h"
 #include <CoreAudio/HostTime.h>
 
+#include "coremidi_io.h"
+#include "coreaudio_backend.h"
+
+using namespace ARDOUR;
+
+#ifndef NDEBUG
+static int _debug_mode = 0;
+#endif
+
 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;
-       for (UInt32 i = 0; i < list->numPackets; i++) {
-               const MIDIPacket *packet = &list->packet[i];
-               if (rb->write_space() < sizeof(MIDIPacket)) {
-                       fprintf(stderr, "CoreMIDI: dropped MIDI event\n");
-                       continue;
+       if (!rb) {
+#ifndef NDEBUG
+               if (_debug_mode & 4) {
+                       fprintf (stderr, "Ignored Midi Packet - no ringbuffer:\n");
+                       dump_packet_list (list->numPackets, &list->packet[0]);
                }
-               rb->write((uint8_t*)packet, sizeof(MIDIPacket));
+#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);
+#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");
+               }
+#endif
+               p = MIDIPacketNext (p);
        }
 }
 
-static std::string getDisplayName(MIDIObjectRef object)
+static std::string getPropertyString (MIDIObjectRef object, CFStringRef key)
 {
-       CFStringRef name = nil;
+       CFStringRef name = NULL;
        std::string rv = "";
-       if (noErr == MIDIObjectGetStringProperty(object, kMIDIPropertyDisplayName, &name)) {
+       if (noErr == MIDIObjectGetStringProperty(object, key, &name)) {
                const CFIndex size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(name), kCFStringEncodingUTF8);
                char *tmp = (char*) malloc(size);
                if (CFStringGetCString(name, tmp, size, kCFStringEncodingUTF8)) {
@@ -59,6 +109,10 @@ static std::string getDisplayName(MIDIObjectRef object)
        return rv;
 }
 
+static std::string getDisplayName (MIDIObjectRef object) {
+       return getPropertyString(object, kMIDIPropertyDisplayName);
+}
+
 CoreMidiIo::CoreMidiIo()
        : _midi_client (0)
        , _input_endpoints (0)
@@ -77,6 +131,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()
@@ -169,10 +228,16 @@ CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uin
        }
        assert(port < _n_midi_in);
 
-       while (_rb[port]->read_space() >= sizeof(MIDIPacket)) {
+       const size_t minsize = 1 + sizeof(uint32_t) + sizeof(MIDITimeStamp) + sizeof(UInt16);
+
+       while (_rb[port]->read_space() > minsize) {
                MIDIPacket packet;
-               size_t rv = _rb[port]->read((uint8_t*)&packet, sizeof(MIDIPacket));
-               assert(rv == sizeof(MIDIPacket));
+               size_t rv;
+               uint32_t s = 0;
+               rv = _rb[port]->read((uint8_t*)&s, sizeof(uint32_t));
+               assert(rv == sizeof(uint32_t));
+               rv = _rb[port]->read((uint8_t*)&packet, s);
+               assert(rv == s);
                _input_queue[port].push_back(boost::shared_ptr<CoreMIDIPacket>(new _CoreMIDIPacket (&packet)));
        }
 
@@ -183,10 +248,16 @@ 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);
-                               //printf("Stale Midi Event dt:%.2fms\n", dt * 1e-6);
-                               if (dt > 1e-4) { // 100ms, maybe too large
+                               if (dt > 1e7) { // 10ms,
+#ifndef NDEBUG
+                                       printf("Dropped Stale Midi Event. dt:%.2fms\n", dt * 1e-6);
+#endif
                                        it = _input_queue[port].erase(it);
                                        continue;
+                               } else {
+#if 0
+                                       printf("Stale Midi Event. dt:%.2fms\n", dt * 1e-6);
+#endif
                                }
                                time = 0;
                        } else {
@@ -205,6 +276,40 @@ CoreMidiIo::recv_event (uint32_t port, double cycle_time_us, uint64_t &time, uin
        return 0;
 }
 
+int
+CoreMidiIo::send_events (uint32_t port, double timescale, const void *b)
+{
+       if (!_active || _time_at_cycle_start == 0) {
+               return 0;
+       }
+
+       assert(port < _n_midi_out);
+       const UInt64 ts = AudioConvertHostTimeToNanos(_time_at_cycle_start);
+
+       const CoreMidiBuffer *src = static_cast<CoreMidiBuffer const *>(b);
+
+       int32_t bytes[8192]; // int for alignment
+       MIDIPacketList *mpl = (MIDIPacketList*)bytes;
+       MIDIPacket *cur = MIDIPacketListInit(mpl);
+
+       for (CoreMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) {
+               assert((*mit)->size() < 256);
+               cur = MIDIPacketListAdd(mpl, sizeof(bytes), cur,
+                               AudioConvertNanosToHostTime(ts + (*mit)->timestamp() / timescale),
+                               (*mit)->size(), (*mit)->data());
+               if (!cur) {
+#ifndef DEBUG
+                       printf("CoreMidi: Packet list overflow, dropped events\n");
+#endif
+                       break;
+               }
+       }
+       if (mpl->numPackets > 0) {
+               MIDISend(_output_ports[port], _output_endpoints[port], mpl);
+       }
+       return 0;
+}
+
 int
 CoreMidiIo::send_event (uint32_t port, double reltime_us, const uint8_t *d, const size_t s)
 {
@@ -231,28 +336,44 @@ CoreMidiIo::send_event (uint32_t port, double reltime_us, const uint8_t *d, cons
        return 0;
 }
 
+
 std::string
-CoreMidiIo::port_name (uint32_t port, bool input)
+CoreMidiIo::port_id (uint32_t port, bool input)
 {
        std::stringstream ss;
-       std::string pn;
-       // XXX including the number will not yield persistent port-names
-       // when disconnecting devices in the middle.
        if (input) {
-               ss << "system:midi_capture_" << port;
+               ss << "system:midi_capture_";
+               SInt32 id;
+               if (noErr == MIDIObjectGetIntegerProperty(_input_endpoints[port], kMIDIPropertyUniqueID, &id)) {
+                       ss << (unsigned int)id;
+               } else {
+                       ss << port;
+               }
+       } else {
+               ss << "system:midi_playback_";
+               SInt32 id;
+               if (noErr == MIDIObjectGetIntegerProperty(_output_endpoints[port], kMIDIPropertyUniqueID, &id)) {
+                       ss << (unsigned int)id;
+               } else {
+                       ss << port;
+               }
+       }
+       return ss.str();
+}
+
+std::string
+CoreMidiIo::port_name (uint32_t port, bool input)
+{
+       if (input) {
                if (port < _n_midi_in) {
-                       pn = getDisplayName(_input_endpoints[port]);
+                       return getDisplayName(_input_endpoints[port]);
                }
        } else {
-               ss << "system:midi_playback_" << port;
                if (port < _n_midi_out) {
-                       pn = getDisplayName(_output_endpoints[port]);
+                       return getDisplayName(_output_endpoints[port]);
                }
        }
-       if (!pn.empty()) {
-               ss << " - " << pn;
-       }
-       return ss.str();
+       return "";
 }
 
 void
@@ -324,7 +445,7 @@ CoreMidiIo::discover()
                        fprintf(stderr, "Cannot create Midi Output\n");
                        continue;
                }
-               _rb[_n_midi_in] = new RingBuffer<uint8_t>(1024 * sizeof(MIDIPacket));
+               _rb[_n_midi_in] = new RingBuffer<uint8_t>(32768);
                _input_queue[_n_midi_in] = CoreMIDIQueue();
                MIDIPortConnectSource(_input_ports[_n_midi_in], src, (void*) _rb[_n_midi_in]);
                CFRelease(port_name);