Reading data from the MIDI keyboard at iOS (and probably also at the Mac)

I’m just implementing support for the MIDI keyboard under iOS – mean you can connect MIDI keyboards (I’m using MIDITECH GARAGEKEY Mini) connected via the Apple iPad Camera Connection Kit.

The keyboard works perfect, you just plug it into the iPhone or iPad and it works. As the keyboard doesn’t have any additional led diode it has really low power consumption.

From the free software I found only GarageBand from Apple to be working with the keys.

At my application the keyboards can be easily implemented via the CoreMIDI (here is link to download my implementation for Delphi).

Garagekey mini

 

The code to read is very simple (it’s based on this code).

var
 aresult:OSStatus;
 inputMIDIClient:MIDIClientRef;
 inputSrc,source:MIDIEndpointRef;
 inputPort:MIDIPortRef;
 lastError:string;
 i,ci:Integer;

begin
 aresult:= MIDIClientCreate(CFSTR('MIDI client'), nil, nil, inputMIDIClient);
//note the use of "self" to send the reference to this document object
 aresult:= MIDIDestinationCreate(inputMIDIClient, CFSTR('Virtual port'), MyMIDIReadProcInput, nil, inputSrc);

 //and again here
 aresult:= MIDIInputPortCreate(inputMIDIClient, CFSTR('Input'), MyMIDIReadProcInput, nil, inputPort);
 if aresult<>0 then
  lastError:=lastError+'Cant create Input '+IntToStr(aresult);
i := MIDIGetNumberOfSources();
if (inputPort<>nil) and (i>0) then
 for ci := 0 to i-1 do
 begin
  source:= MIDIGetSource(ci);
  if (source<>nil) then
  begin
   // inputPort
   aresult:=MIDIPortConnectSource(inputPort, source, nil);
   if aresult<>0 then
    lastError:=lastError+'Cant link the device '+IntToStr(aresult);
  end;
 end;
end;

 

Then the keys are read at function MyMIDIReadProcInput.

procedure MyMIDIReadProcInput(pktlist: MIDIPacketListRef;
 readProcRefCon: pointer;
 srcConnRefCon: pointer); cdecl;
var
 packet:MIDIPacketRef;
 ci,c2:integer;
 note:integer;
 midiStatus,midiCommand:Byte;
begin
 packet:=@pktList.packet;
  for ci := 0 to pktlist.numPackets-1 do
 begin
  c2:=0;
   while c2<packet.length-2 do
  begin
   midiStatus:= packet.data[c2];
   midiCommand:= midiStatus shr 4;
   note:= packet.data[c2+1] and $7F;
     if (midiCommand = $09) then
   begin
    //Key DOWN
   end
     else if (midiCommand = $08) then
   begin
    // Key UP
     end;
   c2:=c2+3;
  end;
{$IF defined(CPUARM) or defined(CPUARM64)}
 packet:=@packet.data[packet.length];
 packet:=pointer((UIntPtr(packet)+3) and not 3);
{$ELSE}
 packet:=@packet.data[packet.length];
{$ENDIF}
 end;
end;

 

Please note the while cycle when reading data from packet.data. This is something I has figured out my self and the other resources have here a mistake.

The data.length is usually 3 bytes. But if you manage to press more than one key at the moment (it’s more hard than it’s sounds) you will not get more messages or more MIDIPackets. You will get more data at the packet.data and the packet.length will be multiplied by 3.

Also note that the function MyMIDIReadProcInput is called at separated thread. So for example you can’t write data to a string that is readed by other part of the application – the application will then freeze.

Leave a Reply

Your email address will not be published. Required fields are marked *