эффективно интерпретировать последовательные данные - PullRequest
0 голосов
/ 07 декабря 2011

Я работаю над проектом c ++, который читает MIDI-данные с внешнего USB-устройства.Программа должна вызывать определенные функции в зависимости от того, какая фейдерная / ручка / кнопка на USB-устройстве сдвинута / повернута / нажата (например, vol + - или отключить / включить звук канала).

Единственный способ, которым явыяснил, какие фейдеры / регуляторы / кнопки были изменены, использовал довольно большой оператор 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;  
    ...
    ...
    ...
}

Нет ли более эффективного / умного способа сделать это?

Ответы [ 2 ]

2 голосов
/ 08 января 2012

Поскольку переключение выполняется для байта (и, следовательно, оно имеет 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);

Этот массив просто использует 1 КБ (32-разрядные платформы) или 2 КБ (64-разрядные платформы), обеспечивает гарантированный поиск в постоянном времени, не имеет скрытых накладных расходов, и, возможно, ваш компилятор реализует ваш большой оператор switch внутри как таблицу поиска в любом случае (так накладные расходы, которые вы получаете, это дополнительный вызов функции).

Обратите внимание, что при наличии недопустимых байтовых значений запись массива должна указывать на явную функцию ошибки (вместо простого 0), чтобы ваша программа могла корректно обработать ошибку.

1 голос
/ 08 января 2012

Большинство компиляторов скомпилируют такой большой переключатель в таблицу переходов (или таблицу для поиска простых значений), поэтому я бы посоветовал вам сохранить переключатель.

Если единственное различие между падежами - этопрефикс строки, я бы предложил сделать что-то вроде этого:

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;
...