1

Lazarus / FreePascal で OSX CoreMidi MidiCallback プロシージャを実装するのに苦労しています。

MIDIServices ユニットでは、コールバック ルーチンである MIDIReadProc が定義されています。

MIDIReadProc = procedure( (*const*) pktlist: MIDIPacketListPtr; readProcRefCon: UnivPtr; srcConnRefCon: UnivPtr );       

このルーチンは、MIDI イベントが受信されると、CoreMidi が所有する別の優先度の高いスレッドで呼び出されます。

受信した MIDI イベントを処理するためのコールバック プロシージャを定義しました。

Type procedure MyMidiCallback(pktList: MIDIPacketListPtr;readProcRefCon: UnivPtr; srcConnRefCon: UnivPtrMy);     

procedure TMainForm.MyMidiCallback(pktList: MIDIPacketListPtr;readProcRefCon: UnivPtr; srcConnRefCon: UnivPtr);
begin
  //  handle midi packets
end;     

midi コールバック フックは、次のコードの「MidiInputPortCreate」で定義されています。

procedure TMainForm.ReceiveMidiTestClick(Sender: TObject);
var
  NumOfSources, NumOfDestinations: ItemCount;
  x: byte;
  MIDIDestinationPointer, MidiSourcePointer: MIDIEndpointRef;
  EndPointName: CFStringRef;
  MidiClient: MidiClientRef;
  InputPort: MidiPortRef;
  MidiCallback: MidiReadProc;
begin
  NumOfDestinations := MIDIGetNumberOfDestinations;
  NumOfSources := MIDIGetNumberOfSources;
  Memo.Lines.Add('Number of Midi Sources: ' + IntToStr(NumOfSources));
  EndPointName := nil;
  MidiClient := nil;
  InputPort := nil;
  MidiCallback := @TMainform.MyMidiCallback;

  for x := 0 to NumOfDestinations -1 do  // show destinations
    begin
      MidiDestinationPointer := MidiGetDestination(x);
      MIDIObjectGetStringProperty(MidiDestinationPointer, kMIDIPropertyName, EndPointName);
      Memo.Lines.Add('Destination ' + IntToStr(x) + ': ' + CFStrToAnsiStr(EndPointName));
    end;

  for x := 0 to NumOfSources -1 do  // show sources
    begin
      MidiSourcePointer := MIDIGetSource(x);
      MIDIObjectGetStringProperty(MidiSourcePointer, kMIDIPropertyName, EndPointName);
      Memo.Lines.Add('Source ' + IntToStr(x) + ': ' + CFStrToAnsiStr(EndPointName));
    end;

  MidiClientCreate(CFSTRP('Midi Input Client'), nil, nil, MidiClient);
  MidiInputPortCreate(MidiClient, CFSTRP('Input'), MidiCallback, nil, InputPort);  //     MidiCallback
  MIDISourcePointer := MIDIGetSource(0);  // select source(0) = midi keyboard
  MidiPortConnectSource(InputPort, MIDISourcePointer, nil);
end;                       

コンパイルすると、次のエラー メッセージが生成されます。

mainunit.pas(480,19) Error: Incompatible types: got "<procedure variable type of procedure(MIDIPacketListPtr,Pointer,Pointer) of object;Register>" expected "<procedure variable type of procedure(MIDIPacketListPtr,Pointer,Pointer);MWPascal>"  

私は今ここで立ち往生しています。誰かが助けてくれることを願っています。

--------------------------------- 更新 #1 -------------- --------------------

上記のコードは確かに少し奇妙だったので、書き直しました。

procedure TMainForm.ReceiveMidiTestClick(Sender: TObject);
var
  MidiClient: MidiClientRef;
  InputPort: MidiPortRef;
  MidiCallback: MIDIReadProc;
begin
  MidiCallback := MyMidiCallback;
  MidiClientCreate(CFSTRP('Midi Input Client'), nil, nil, MidiClient);
  MidiInputPortCreate(MidiClient, CFSTRP('Input'), MidiCallback, nil, InputPort);
  MidiPortConnectSource(InputPort, MIDIGetSource(0), nil);
end;

procedure MyMidiCallback(pktList: MIDIPacketListPtr; readProcRefCon: UnivPtr;    srcConnRefCon: UnivPtr);
begin
//  handle midi packets
end;   

コードはエラーなしでコンパイルされるようになりましたが、MIDI キーボードのキーを押すとすぐに、次のエラー メッセージが表示されてアプリケーションがクラッシュします。

「エラー プロジェクト ... アドレス FFFFD96F で例外クラス '外部: Sigtrap' が発生しました」

(FFFFD96F は、おそらく MidiCallback ルーチンへのポインタです)。

基本的に、私が抱えている問題は、MidiInputPortCreate の MidiCallback ポインターが、midi イベントを処理する MyMidiCallback プロシージャを正しく指すようにする方法です。

ところで、Midi イベントの送信は正常に機能します。

4

1 に答える 1

1

エラーのエラー宣言を別の行に入れましょう。

mainunit.pas(480,19) エラー: 互換性のない型: 得た "

procedure(MIDIPacketListPtr,Pointer,Pointer) of object;Register>" expected "< procedure variable type of procedure(MIDIPacketListPtr,Pointer,Pointer);MWPascal>"

2 つの重要な違いに注意してください。

1) エラーの 2 つのプロシージャ宣言の "of object" の違いは、適切なプロシージャではなくメソッドを渡したということです。

2) それに加えて、呼び出し規約が一致していないようです。1 つは mwpascal です。1つは登録です。Register はほとんどのモードのデフォルトであるため、呼び出し規約修飾子は登録を意味しません。

あなたの質問の「コールバック」の部分は奇妙です。型をプロシージャとして定義しますが、メソッドを実装として提供しますか?

于 2013-09-25T18:44:24.450 に答える