--- a/portmidi/pm_mac/pmmacosxcm.c
+++ b/portmidi/pm_mac/pmmacosxcm.c
@@ -26,9 +26,7 @@
 //#define CM_DEBUG 1
 
 #include "portmidi.h"
-#ifdef NEWBUFFER
 #include "pmutil.h"
-#endif
 #include "pminternal.h"
 #include "porttime.h"
 #include "pmmac.h"
@@ -40,17 +38,34 @@
 #include <CoreServices/CoreServices.h>
 #include <CoreMIDI/MIDIServices.h>
 #include <CoreAudio/HostTime.h>
+#include <unistd.h>
 
 #define PACKET_BUFFER_SIZE 1024
-
-/* this is very strange: if I put in a reasonable 
-   number here, e.g. 128, which would allow sysex data
-   to be sent 128 bytes at a time, then I lose sysex
-   data in my loopback test. With a buffer size of 4,
-   we put at most 4 bytes in a packet (but maybe many
-   packets in a packetList), and everything works fine.
+/* maximum overall data rate (OS X limit is 15000 bytes/second) */
+#define MAX_BYTES_PER_S 14000
+
+/* Apple reports that packets are dropped when the MIDI bytes/sec
+   exceeds 15000. This is computed by "tracking the number of MIDI 
+   bytes scheduled into 1-second buckets over the last six seconds
+   and averaging these counts." 
+
+   This is apparently based on timestamps, not on real time, so 
+   we have to avoid constructing packets that schedule high speed
+   output even if the actual writes are delayed (which was my first
+   solution).
+
+   The LIMIT_RATE symbol, if defined, enables code to modify 
+   timestamps as follows:
+     After each packet is formed, the next allowable timestamp is
+     computed as this_packet_time + this_packet_len * delay_per_byte
+
+     This is the minimum timestamp allowed in the next packet. 
+
+     Note that this distorts accurate timestamps somewhat.
  */
-#define SYSEX_BUFFER_SIZE 4
+#define LIMIT_RATE 1
+
+#define SYSEX_BUFFER_SIZE 128
 
 #define VERBOSE_ON 1
 #define VERBOSE if (VERBOSE_ON)
@@ -59,21 +74,29 @@
 #define MIDI_EOX        0xf7
 #define MIDI_STATUS_MASK 0x80
 
-static MIDIClientRef	client = NULL;	/* Client handle to the MIDI server */
-static MIDIPortRef	portIn = NULL;	/* Input port handle */
-static MIDIPortRef	portOut = NULL;	/* Output port handle */
+// "Ref"s are pointers on 32-bit machines and ints on 64 bit machines
+// NULL_REF is our representation of either 0 or NULL
+#ifdef __LP64__
+#define NULL_REF 0
+#else
+#define NULL_REF NULL
+#endif
+
+static MIDIClientRef	client = NULL_REF; 	/* Client handle to the MIDI server */
+static MIDIPortRef	portIn = NULL_REF;	/* Input port handle */
+static MIDIPortRef	portOut = NULL_REF;	/* Output port handle */
 
 extern pm_fns_node pm_macosx_in_dictionary;
 extern pm_fns_node pm_macosx_out_dictionary;
 
 typedef struct midi_macosxcm_struct {
-    unsigned long sync_time; /* when did we last determine delta? */
+    PmTimestamp sync_time; /* when did we last determine delta? */
     UInt64 delta;	/* difference between stream time and real time in ns */
-    UInt64 last_time;	/* last output time */
+    UInt64 last_time;	/* last output time in host units*/
     int first_message;  /* tells midi_write to sychronize timestamps */
     int sysex_mode;     /* middle of sending sysex */
-    unsigned long sysex_word; /* accumulate data when receiving sysex */
-    unsigned int sysex_byte_count; /* count how many received */
+    uint32_t sysex_word; /* accumulate data when receiving sysex */
+    uint32_t sysex_byte_count; /* count how many received */
     char error[PM_HOST_ERROR_MSG_LEN];
     char callback_error[PM_HOST_ERROR_MSG_LEN];
     Byte packetBuffer[PACKET_BUFFER_SIZE];
@@ -83,7 +106,12 @@
     MIDITimeStamp sysex_timestamp; /* timestamp to use with sysex data */
     /* allow for running status (is running status possible here? -rbd): -cpr */
     unsigned char last_command; 
-    long last_msg_length;
+    int32_t last_msg_length;
+    /* limit midi data rate (a CoreMidi requirement): */
+    UInt64 min_next_time; /* when can the next send take place? */
+    int byte_count; /* how many bytes in the next packet list? */
+    Float64 us_per_host_tick; /* host clock frequency, units of min_next_time */
+    UInt64 host_ticks_per_byte; /* host clock units per byte at maximum rate */
 } midi_macosxcm_node, *midi_macosxcm_type;
 
 /* private function declarations */
@@ -94,7 +122,7 @@
 
 
 static int
-midi_length(long msg)
+midi_length(int32_t msg)
 {
     int status, high, low;
     static int high_lengths[] = {
@@ -102,7 +130,7 @@
         3, 3, 3, 3, 2, 2, 3, 1          /* 0x80 through 0xf0 */
     };
     static int low_lengths[] = {
-        1, 1, 3, 2, 1, 1, 1, 1,         /* 0xf0 through 0xf8 */
+        1, 2, 3, 2, 1, 1, 1, 1,         /* 0xf0 through 0xf8 */
         1, 1, 1, 1, 1, 1, 1, 1          /* 0xf9 through 0xff */
     };
 
@@ -110,7 +138,7 @@
     high = status >> 4;
     low = status & 15;
 
-    return (high != 0xF0) ? high_lengths[high] : low_lengths[low];
+    return (high != 0xF) ? high_lengths[high] : low_lengths[low];
 }
 
 static PmTimestamp midi_synchronize(PmInternal *midi)
@@ -237,7 +265,7 @@
     PmEvent event;
     MIDIPacket *packet;
     unsigned int packetIndex;
-    unsigned long now;
+    uint32_t now;
     unsigned int status;
     
 #ifdef CM_DEBUG
@@ -262,9 +290,9 @@
                packet->length); */
     for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) {
         /* Set the timestamp and dispatch this message */
-        event.timestamp = 
+        event.timestamp = (PmTimestamp) /* explicit conversion */ (
                 (AudioConvertHostTimeToNanos(packet->timeStamp) - m->delta) / 
-                (UInt64) 1000000;
+                (UInt64) 1000000);
         status = packet->data[0];
         /* process packet as sysex data if it begins with MIDI_SYSEX, or
            MIDI_EOX or non-status byte with no running status */
@@ -305,9 +333,8 @@
         /* time_get does not take a parameter, so coerce */
         midi->time_proc = (PmTimeProcPtr) Pt_Time;
     }
-    
-    endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
-    if (endpoint == NULL) {
+    endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
+    if (endpoint == NULL_REF) {
         return pmInvalidDeviceId;
     }
 
@@ -335,7 +362,7 @@
         pm_hosterror = macHostError;
         sprintf(pm_hosterror_text, 
                 "Host error %ld: MIDIPortConnectSource() in midi_in_open()",
-                macHostError);
+                (long) macHostError);
         midi->descriptor = NULL;
         pm_free(m);
         return pmHostError;
@@ -355,8 +382,8 @@
     
     if (!m) return pmBadPtr;
 
-    endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
-    if (endpoint == NULL) {
+    endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
+    if (endpoint == NULL_REF) {
         pm_hosterror = pmBadPtr;
     }
     
@@ -366,7 +393,7 @@
         pm_hosterror = macHostError;
         sprintf(pm_hosterror_text, 
                 "Host error %ld: MIDIPortDisconnectSource() in midi_in_close()",
-                macHostError);
+                (long) macHostError);
         err = pmHostError;
     }
     
@@ -400,7 +427,11 @@
     m->packet = NULL;
     m->last_command = 0;
     m->last_msg_length = 0;
-
+    m->min_next_time = 0;
+    m->byte_count = 0;
+    m->us_per_host_tick = 1000000.0 / AudioGetHostClockFrequency();
+    m->host_ticks_per_byte = (UInt64) (1000000.0 / 
+                                       (m->us_per_host_tick * MAX_BYTES_PER_S));
     return pmNoError;
 }
 
@@ -420,7 +451,18 @@
 static PmError
 midi_abort(PmInternal *midi)
 {
-    return pmNoError;
+    PmError err = pmNoError;
+    OSStatus macHostError;
+    MIDIEndpointRef endpoint =
+            (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
+    macHostError = MIDIFlushOutput(endpoint);
+    if (macHostError != noErr) {
+        pm_hosterror = macHostError;
+        sprintf(pm_hosterror_text,
+                "Host error %ld: MIDIFlushOutput()", (long) macHostError);
+        err = pmHostError;
+    }
+    return err;
 }
 
 
@@ -430,13 +472,22 @@
     OSStatus macHostError;
     midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
     MIDIEndpointRef endpoint = 
-            (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
+            (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
     assert(m);
     assert(endpoint);
     if (m->packet != NULL) {
         /* out of space, send the buffer and start refilling it */
+        /* before we can send, maybe delay to limit data rate. OS X allows
+         * 15KB/s. */
+        UInt64 now = AudioGetCurrentHostTime();
+        if (now < m->min_next_time) {
+            usleep((useconds_t) 
+                   ((m->min_next_time - now) * m->us_per_host_tick));
+        }
         macHostError = MIDISend(portOut, endpoint, m->packetList);
         m->packet = NULL; /* indicate no data in packetList now */
+        m->min_next_time = now + m->byte_count * m->host_ticks_per_byte;
+        m->byte_count = 0;
         if (macHostError != noErr) goto send_packet_error;
     }
     return pmNoError;
@@ -445,7 +496,7 @@
     pm_hosterror = macHostError;
     sprintf(pm_hosterror_text, 
             "Host error %ld: MIDISend() in midi_write()",
-            macHostError);
+            (long) macHostError);
     return pmHostError;
 
 }
@@ -459,15 +510,21 @@
     midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
     assert(m);
     
-    /* printf("add %d to packet %lx len %d\n", message[0], m->packet, messageLength); */
+    /* printf("add %d to packet %p len %d\n", message[0], m->packet, messageLength); */
     m->packet = MIDIPacketListAdd(m->packetList, sizeof(m->packetBuffer), 
                                   m->packet, timestamp, messageLength, 
                                   message);
+    m->byte_count += messageLength;
     if (m->packet == NULL) {
         /* out of space, send the buffer and start refilling it */
         /* make midi->packet non-null to fool midi_write_flush into sending */
         m->packet = (MIDIPacket *) 4; 
-        if ((err = midi_write_flush(midi, timestamp)) != pmNoError) return err;
+        /* timestamp is 0 because midi_write_flush ignores timestamp since
+         * timestamps are already in packets. The timestamp parameter is here
+         * because other API's need it. midi_write_flush can be called 
+         * from system-independent code that must be cross-API.
+         */
+        if ((err = midi_write_flush(midi, 0)) != pmNoError) return err;
         m->packet = MIDIPacketListInit(m->packetList);
         assert(m->packet); /* if this fails, it's a programming error */
         m->packet = MIDIPacketListAdd(m->packetList, sizeof(m->packetBuffer),
@@ -482,8 +539,8 @@
 static PmError
 midi_write_short(PmInternal *midi, PmEvent *event)
 {
-    long when = event->timestamp;
-    long what = event->message;
+    PmTimestamp when = event->timestamp;
+    PmMessage what = event->message;
     MIDITimeStamp timestamp;
     UInt64 when_ns;
     midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
@@ -502,9 +559,6 @@
     /* if latency == 0, midi->now is not valid. We will just set it to zero */
     if (midi->latency == 0) when = 0;
     when_ns = ((UInt64) (when + midi->latency) * (UInt64) 1000000) + m->delta;
-    /* make sure we don't go backward in time */
-    if (when_ns < m->last_time) when_ns = m->last_time;
-    m->last_time = when_ns;
     timestamp = (MIDITimeStamp) AudioConvertNanosToHostTime(when_ns);
 
     message[0] = Pm_MessageStatus(what);
@@ -512,6 +566,15 @@
     message[2] = Pm_MessageData2(what);
     messageLength = midi_length(what);
         
+    /* make sure we go foreward in time */
+    if (timestamp < m->min_next_time) timestamp = m->min_next_time;
+
+    #ifdef LIMIT_RATE
+        if (timestamp < m->last_time)
+            timestamp = m->last_time;
+	m->last_time = timestamp + messageLength * m->host_ticks_per_byte;
+    #endif
+
     /* Add this message to the packet list */
     return send_packet(midi, message, messageLength, timestamp);
 }
@@ -549,16 +612,18 @@
     midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
     assert(m);
     
-    /* make sure we don't go backward in time */
-    if (m->sysex_timestamp < m->last_time) m->sysex_timestamp = m->last_time;
-    
-        /* if flush has been called in the meantime, packet list is NULL */
-    if (m->packet == NULL) {
-        m->packet = MIDIPacketListInit(m->packetList);
-        assert(m->packet);
-    }
-
-        /* now send what's in the buffer */
+    /* make sure we go foreward in time */
+    if (m->sysex_timestamp < m->min_next_time) 
+        m->sysex_timestamp = m->min_next_time;
+
+    #ifdef LIMIT_RATE
+        if (m->sysex_timestamp < m->last_time) 
+            m->sysex_timestamp = m->last_time;
+        m->last_time = m->sysex_timestamp + m->sysex_byte_count *
+                                            m->host_ticks_per_byte;
+    #endif
+    
+    /* now send what's in the buffer */
     err = send_packet(midi, m->sysex_buffer, m->sysex_byte_count,
                       m->sysex_timestamp);
     m->sysex_byte_count = 0;
@@ -656,9 +721,9 @@
     CFRelease(str);
   }
   
-  MIDIEntityRef entity = NULL;
+  MIDIEntityRef entity = NULL_REF;
   MIDIEndpointGetEntity(endpoint, &entity);
-  if (entity == NULL)
+  if (entity == NULL_REF)
     // probably virtual
     return result;
   
@@ -672,13 +737,17 @@
     }
   }
   // now consider the device's name
-  MIDIDeviceRef device = NULL;
+  MIDIDeviceRef device = NULL_REF;
   MIDIEntityGetDevice(entity, &device);
-  if (device == NULL)
+  if (device == NULL_REF)
     return result;
   
   str = NULL;
   MIDIObjectGetStringProperty(device, kMIDIPropertyName, &str);
+  if (CFStringGetLength(result) == 0) {
+      CFRelease(result);
+      return str;
+  }
   if (str != NULL) {
     // if an external device has only one entity, throw away
     // the endpoint name and just use the device name
@@ -686,6 +755,10 @@
       CFRelease(result);
       return str;
     } else {
+      if (CFStringGetLength(str) == 0) {
+        CFRelease(str);
+        return result;
+      }
       // does the entity name already start with the device name?
       // (some drivers do this though they shouldn't)
       // if so, do not prepend
@@ -703,6 +776,7 @@
   return result;
 }
 
+
 // Obtain the name of an endpoint, following connections.
 // The result should be released by the caller.
 static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint)
@@ -710,17 +784,17 @@
   CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
   CFStringRef str;
   OSStatus err;
-  int i;
+  long i;
   
   // Does the endpoint have connections?
   CFDataRef connections = NULL;
-  int nConnected = 0;
+  long nConnected = 0;
   bool anyStrings = false;
   err = MIDIObjectGetDataProperty(endpoint, kMIDIPropertyConnectionUniqueID, &connections);
   if (connections != NULL) {
     // It has connections, follow them
     // Concatenate the names of all connected devices
-    nConnected = CFDataGetLength(connections) / sizeof(MIDIUniqueID);
+    nConnected = CFDataGetLength(connections) / (int32_t) sizeof(MIDIUniqueID);
     if (nConnected) {
       const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
       for (i = 0; i < nConnected; ++i, ++pid) {
@@ -889,7 +963,7 @@
     /* Iterate over the MIDI input devices */
     for (i = 0; i < numInputs; i++) {
         endpoint = MIDIGetSource(i);
-        if (endpoint == NULL) {
+        if (endpoint == NULL_REF) {
             continue;
         }
 
@@ -899,13 +973,13 @@
         
         /* Register this device with PortMidi */
         pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint),
-                      TRUE, (void*)endpoint, &pm_macosx_in_dictionary);
+                      TRUE, (void *) (long) endpoint, &pm_macosx_in_dictionary);
     }
 
     /* Iterate over the MIDI output devices */
     for (i = 0; i < numOutputs; i++) {
         endpoint = MIDIGetDestination(i);
-        if (endpoint == NULL) {
+        if (endpoint == NULL_REF) {
             continue;
         }
 
@@ -915,20 +989,22 @@
 
         /* Register this device with PortMidi */
         pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint),
-                      FALSE, (void*)endpoint, &pm_macosx_out_dictionary);
+                      FALSE, (void *) (long) endpoint,
+                      &pm_macosx_out_dictionary);
     }
     return pmNoError;
     
 error_return:
     pm_hosterror = macHostError;
-    sprintf(pm_hosterror_text, "Host error %ld: %s\n", macHostError, error_text);
+    sprintf(pm_hosterror_text, "Host error %ld: %s\n", (long) macHostError, 
+            error_text);
     pm_macosxcm_term(); /* clear out any opened ports */
     return pmHostError;
 }
 
 void pm_macosxcm_term(void)
 {
-    if (client != NULL)	 MIDIClientDispose(client);
-    if (portIn != NULL)	 MIDIPortDispose(portIn);
-    if (portOut != NULL) MIDIPortDispose(portOut);
-}
+    if (client != NULL_REF) MIDIClientDispose(client);
+    if (portIn != NULL_REF) MIDIPortDispose(portIn);
+    if (portOut != NULL_REF) MIDIPortDispose(portOut);
+}