我正在开发一个从外部USB设备读取MIDI数据的c ++项目。该程序应该调用某些功能,具体取决于USB设备上的哪个推子/旋钮/按钮是shiftet / rotate / press(例如vol + - 或静音/取消静音通道)。
我想出找到哪个推子/旋钮/按钮被改变的唯一方法是使用一个非常大的开关语句,基本上检查每个传入的midi事件。
看起来像这样:
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;
...
...
...
}
有没有更有效/更聪明的方法来做到这一点?
答案 0 :(得分:2)
由于你的切换是在一个字节上完成的(因此只有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位平台),保证了恒定的时间查找,没有隐藏的开销,并且可能你的编译器在内部实现了你的big switch语句作为查询表(所以只有你得到的开销是一个额外的函数调用。)
请注意,如果字节值无效,则数组条目应指向显式错误函数(而不是简单的0),因此您的程序可以正常处理错误。
答案 1 :(得分:1)
大多数编译器会将这样的大型开关编译成跳转表(或者查找简单值的表),所以我建议你保留开关。
如果案例之间的唯一区别是前缀字符串,我建议改为做这样的事情:
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;