Hans Hans - 4 months ago 11x
iOS Question

Why does this code work on iOS 32 bit but not on 64 bit?

The code below receives MIDI data from a musical instrument connected to the iOS device. It works fine on a 32 bit iOS device. On 64 bit, the callback function is also called for every event, but the data received in 'pktlist' is invalid. What is wrong?

The data I receive in

is always the same on a 64 bit device, and it is clearly wrong as the length would normally never be 0:

pktlist^.numPackets = 1

The Callback function:

procedure MidiReadProc(pktlist: MIDIPacketListRef; refCon, connRefCon: Pointer); cdecl;
lPacket: MIDIPacket;
lPacketRef: MIDIPacketRef;
j: Integer;
lPtr: ^Byte;
lPacketRef := MIDIPacketRef(@(pktlist^.Packet[0]));
for j := 0 to pktlist^.numPackets-1 do
lPacket := lPacketRef^;
if (lPacket.length > 0) and (lPacket.data[0] <> $F0) then
//handle data here

//translation of the MIDIPacketNext Macro:
lPtr := @lPacketRef^.data[lPacketRef^.length];
lPacketRef := MIDIPacketRef((UInt64(lPtr) + 3) and (not 3));

In case it could be related to the header translation, here is the translation:

Extract from CoreMIDI.h:

typedef UInt64 MIDITimeStamp;

#pragma pack(push, 4)
struct MIDIPacket
MIDITimeStamp timeStamp;
UInt16 length;
Byte data[256];
typedef struct MIDIPacket MIDIPacket;

struct MIDIPacketList
UInt32 numPackets;
MIDIPacket packet[1];
typedef struct MIDIPacketList MIDIPacketList;
#pragma pack(pop)

typedef void
(*MIDIReadProc)(const MIDIPacketList *pktlist, void *readProcRefCon, void *srcConnRefCon);

// MIDIPacket must be 4-byte aligned
#define MIDIPacketNext(pkt) ((MIDIPacket *)(((uintptr_t)(&(pkt)->data[(pkt)->length]) + 3) & ~3))

Extract from CoreMIDI.pas (the translation of CoreMIDI.h is made by Pavel Jiri Strnad and is available here):

MIDITimeStamp = UInt64;

MIDIPacket = record
timeStamp: MIDITimeStamp;
length: UInt16;
data: array [0..255] of Byte;
MIDIPacketRef = ^MIDIPacket;

MIDIPacketList = record
numPackets: UInt32;
packet: array [0..0] of MIDIPacket;
MIDIPacketListRef = ^MIDIPacketList;

MIDIReadProc = procedure (pktlist: MIDIPacketListRef; readProcRefCon: pointer; srcConnRefCon: pointer); cdecl;


As suggested by David in the comments, here are field offsets of the records:


64 bit Align 8: numPackets=0 packet=8 <- this was the one causing problems
64 bit Align 1: numPackets=0 packet=4
32 bit Align 8: numPackets=0 packet=4
32 bit Align 1: numPackets=0 packet=4


64 bit Align 8: timeStamp=0 length=8 data=10
64 bit Align 1: timeStamp=0 length=8 data=10
32 bit Align 8: timeStamp=0 length=8 data=10
32 bit Align 1: timeStamp=0 length=8 data=10


As suggested in the comments, I looked further into the CoreMIDI.h header file. Though I have never worked with any C languages, I did spot this line: #pragma pack(push, 4) above the definition of MIDIPacket (I have now added it to extract in the question), which shows clearly what should be done.

Setting {$Align 1} for the whole file was not the correct solution. Instead only the two records (MIDIPacket and MIDIPacketList) should have 4 byte alignments instead of 8 byte alignment.