0

私は外部USBデバイスからMIDIデータを読み取るC++プロジェクトに取り組んでいます。プログラムは、USBデバイスのどのフェーダー/ノブ/ボタンがシフテット/回転/押されているかに応じて特定の関数を呼び出すことになっています(vol +-またはミュート/ミュート解除チャネルなど)。

どのフェーダー/ノブ/ボタンが変更されたかを知る唯一の方法は、基本的にすべての着信midiイベントをチェックするかなり大きなswitchステートメントを使用することでした。

このように見えます:

switch(MidiMessage.get2ndByte()){

    case 1 : cout << "Fader 1 Value : " << MidiMessage.get3rdByte() << endl;  
    case 2 : cout << "Fader 2 Value : " << MidiMessage.get3rdByte() << endl;  
    case 10 : cout << "Button 1 Value : << "MidiMessage.get3rdByte() << endl;  
    ...
    ...
    ...
}

これを行うためのより効率的でスマートな方法はありませんか?

4

2 に答える 2

2

切り替えは1バイトで行われるため(したがって、256の異なる値があります。MIDIファイルは8ビットバイトに基づいていると確信しています)、おそらく最良のオプションは、関数ポインターの単純な配列を使用することです。

typedef void (*MidiAction)(MidiMessageType& message);

action_fader_1(MidiMessageType& message)
{
  std::cout << "Fader 1 Value : " << message.get3rdByte() << std::endl;
}

action_fader_2(MidiMessageType& message)
{
  std::cout << "Fader 2 Value : " << message.get3rdByte() << std::endl;
}

...

MidiAction midi_actions[256] = {
   /*  0 */ action_whatever,
   /*  1 */ action_fader_1,
   /*  2 */ action_fader_2,
   ...
   /* 10 */ action_button_1,
   ...
};

...

// this goes where your switch statement was:
midi_actions[MidiAction.get2ndByte()](MidiAction);

この配列は1KB(32ビットプラットフォーム)または2KB(64ビットプラットフォーム)を使用し、一定時間のルックアップを保証し、隠れたオーバーヘッドはありません。コンパイラは、とにかくルックアップテーブルとして内部で大きなswitchステートメントを実装します(したがって、取得するオーバーヘッドは追加の関数呼び出しです)。

無効なバイト値がある場合、プログラムがエラーを適切に処理できるように、配列エントリは(単純な0ではなく)明示的なエラー関数を指す必要があることに注意してください。

于 2012-01-08T17:45:54.333 に答える
0

ほとんどのコンパイラは、そのような大きなスイッチをジャンプテーブル(または単純な値のテーブルルックアップ)にコンパイルするので、スイッチを保持することをお勧めします。

ケース間の唯一の違いがプレフィックス文字列である場合は、代わりに次のようなことをお勧めします。

const char *msg; // or std::string if you prefer

switch(MidiMessage.get2ndByte()){

    case 1 : msg = "Fader 1 Value : "; break;
    case 2 : msg = "Fader 2 Value : "; break;
    case 10: msg = "Button 1 Value : "; break;
    default: msg = "?"; break;
}

cout << msg << MidiMessage.get3rdByte() << endl;
于 2012-01-08T18:10:09.583 に答える