有效地解释串行数据

发布于 2024-12-19 23:22:05 字数 605 浏览 2 评论 0原文

我正在开发一个从外部 USB 设备读取 MIDI 数据的 C++ 项目。该程序应该根据 USB 设备上哪个推子/旋钮/按钮被移动/旋转/按下(例如音量 +- 或静音/取消静音通道)来调用某些功能。

我想出找出哪个推子/旋钮/按钮被更改的唯一方法是使用一个相当大的 switch 语句,该语句基本上检查每个传入的 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;  
    ...
    ...
    ...
}

没有更有效/更智能的方法来做到这一点吗?

I'm working on a c++ project that reads MIDI-data from an external USB-device. The program is supposed to call certain functions depending on which fader/knob/button on the USB-device is shiftet/rotated/pressed (such as vol +- or mute/unmute channel).

The only way I came up with finding out which fader/knob/button was changed was using a pretty big switch statement that basically checks every incoming midi event.

looks sort of like this :

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

Isn't there a more efficient/smart way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怪我鬧 2024-12-26 23:22:05

由于您的切换是在一个字节上完成的(因此只有 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),以便您的程序可以优雅地处理错误。

Since your switching is done on a byte (and thus just has 256 different values; I'm pretty sure MIDI files are based on 8-bit bytes), the best option is probably to use a simple array of function pointers:

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

This array just uses 1KB (32 bit platforms) or 2KB (64 bit platforms), gives guaranteed constant time lookup, has no hidden overhead, and possibly your compiler implements your big switch statement internally as lookup table anyway (so the only overhead you get is an extra function call).

Note that if there are invalid byte values, the array entry should point to an explicit error function (instead of a simple 0), so your program can handle the error gracefully.

空城缀染半城烟沙 2024-12-26 23:22:05

大多数编译器会将这样的大型开关编译成跳转表(或简单值的表查找),因此我建议您保留该开关。

如果情况之间的唯一区别是前缀字符串,我建议改为执行以下操作:

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;

Most compilers will compile a large switch like that into a jump table (or a table lookup for simple values), so I would suggest you keep the switch.

If the only difference between the cases is the prefix string, I would suggest doing something like this instead:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文