USB MIDI 适配器
组件和用品
| | × | 1 | |
| | × | 1 | |
| | × | 1 | |
| | × | 1 | |
| | × | 3 | |
| | × | 1 | |
| | × | 1 | |
| | × | 1 | |
| | × | 1 | |
| | × | 2 | |
| | × | 1 | |
| | × | 1 | |
| | × | 1 | |
关于这个项目
我在网上搜索了如何使用 Arduino 构建 USB 到 MIDI 适配器,但不幸的是,我只找到了不太好的解决方案(糟糕的 MIDI 软件或硬件实现)。所以我决定自己构建并将结果放在 hackster.io 上。
我使用带有面包板的 Arduino Leonardo 来构建第一个原型。一切正常后,我使用 Arduino Micro 构建了一个焊接版本。两者都基于 ATmega32u4,它具有原生 USB,允许它作为 USB MIDI 接口呈现给您连接到的 PC。
MIDI 使用光耦合器和一些电阻器来创建完全隔离的电流回路。该电路非常标准,我使用了 6n137,因为它速度快且应用广泛。如电路图所示,只有MIDI OUT接口的2脚接地,这是MIDI的标准配置。
一些最终结果的照片:
图> 图> 图>
在软件方面,我决定使用出色的 Control Surface 库。与其他一些库或手动编码的实现不同,Control Surface 可以正确处理有点复杂的 MIDI 协议的所有不同方面。
Control Surface 还可以让您添加各种附加功能。例如,您可以添加一些连接到模拟/数字输入的电位器、踏板或按钮,以添加额外的 MIDI 控件。只需查看 Control Surface 网站了解更多信息,这真的很容易!
您还可以注册回调,以便您可以在从 MIDI 传递到 USB 或其他方向之前处理数据。就我而言,我用它来修复我的 Roland D50 合成器损坏的 MIDI 实现。每次按下最后一个键时,D50 都会发送“所有音符关闭”命令。现代实现,例如我使用的大多数 VST 乐器,将其解释为所有运行音符持续的立即硬截断。通过过滤“所有音符关闭”,D50 再次成为有用的主键盘。
我在使用 Control Surface 库时遇到的一个问题是它不能很好地处理大型 SysEx 包。这导致尝试使用 D50 编辑器/图书馆员时出错,因为它发送了相当大的 SysEx 包。我在源代码的注释标题中添加了有关如何解决此问题的说明。编写库的人表示,这个问题会在2.x版本出来后修复。
我包括了基本的 USB 到 MIDI 接口源代码和一个带有“所有音符关闭”过滤的版本。
当然,您也可以使用其他库或编写自己的 MIDI 实现,硬件应该可以与任何支持 USB MIDI 和串行 MIDI 的 MIDI 库一起使用。
故障排除提示:如果您似乎无法使用此接口与外部 MIDI 设备通信,那么您可能交换了引脚 4 和 5。有时连接器引脚图可能会令人困惑 因为它们并不总是清楚地表明您正在查看连接器的哪一侧。
我希望原理图和源代码对这里的任何人都有用。如果您喜欢这个项目,请给我一个赞,如果您有任何问题,请随时在下面发表评论。
代码
- 基本 MIDI 到 USB 接口的源代码
- 带有“所有音符关闭”过滤器的 MIDI 到 USB 适配器的源代码
基本MIDI到USB接口的源代码Arduino
/* * USB MIDI 适配器。 * * --- * * 要允许更大的 sysex 包,请按如下方式修改控制表面库: * * 在: * src\MIDI_Parsers\MIDI_MessageTypes.hpp * 更改: * uint8_t 长度; * to:* size_t 长度; * * 在:* src/Settings/Settings.hpp * 更改:* constexpr size_t SYSEX_BUFFER_SIZE =128; * to:* constexpr size_t SYSEX_BUFFER_SIZE =320; * * 这应该会在 Control Surface 2.x 发布时修复。 * * --- * * 要使用不同的 USB 设备名称,请使用管理员权限编辑 Arduino IDE 安装中的硬件/arduino/avr/boards.txt。 * 更改:* leonardo.build.usb_product="Arduino Leonardo" * 为: * leonardo.build.usb_product="..." * 在将项目上传到您的 Arduino 设备后将其更改回来。 */#include // 包含控制表面库USBMIDI_Interface midiusb;// 使用这个来将所有MIDI 数据转储到串行监视器// USBDebugMIDI_Interface midiusb;HardwareSerialMIDI_Interface midiser ={Serial1, MIDI_BAUD};// 创建MIDI 管道工厂,用于将 MIDI 接口相互连接并连接到 Control SurfaceMIDI_PipeFactory<5> 管道;// 添加额外控制器的示例:// CCPotentiometer pot ={ A0, MIDI_CC::Expression_Controller };// 电源引脚LED 已连接const int ledPin =10;// setup codevoid setup() { Serial.begin(115200); // 打开电源 LED pinMode(ledPin, OUTPUT);数字写入(ledPin,高); // 将 MIDI USB 转发到 MIDI 串行 midiusb>> 管道>> midiser; // 将 MIDI 串行转发到 MIDI USB midiser>> 管道>> midiusb; // 仅将控制表面消息发送到 MIDI USB Control_Surface>> 管道>> midiusb; // 将 MIDI USB 和串口连接到控制面 midiser>> 管道>> Control_Surface; midiusb>> 管道>> Control_Surface; // 初始化 Control Surface _after_ 连接接口 Control_Surface.begin();}// 主处理 loopvoid loop() { Control_Surface.loop();}
带有“所有音符关闭”过滤器的 MIDI 到 USB 适配器的源代码Arduino
/* * USB MIDI 适配器带有“所有音符关闭”过滤器。 * * --- * * 要允许更大的 sysex 包,请按如下方式修改控制表面库: * * 在: * src\MIDI_Parsers\MIDI_MessageTypes.hpp * 更改: * uint8_t 长度; * to:* size_t 长度; * * 在:* src/Settings/Settings.hpp * 更改:* constexpr size_t SYSEX_BUFFER_SIZE =128; * to:* constexpr size_t SYSEX_BUFFER_SIZE =320; * * 这应该会在 Control Surface 2.x 发布时修复。 * * --- * * 要使用不同的 USB 设备名称,请使用管理员权限编辑 Arduino IDE 安装中的硬件/arduino/avr/boards.txt。 * 更改:* leonardo.build.usb_product="Arduino Leonardo" * 为: * leonardo.build.usb_product="..." * 在将项目上传到您的 Arduino 设备后将其更改回来。 */#include // 包含控制表面库USBMIDI_Interface midiusb;// 使用这个来将所有MIDI 数据转储到串行监视器// USBDebugMIDI_Interface midiusb;HardwareSerialMIDI_Interface midiser ={Serial1, MIDI_BAUD};// 创建MIDI 管道工厂,用于将 MIDI 接口相互连接并连接到 Control SurfaceMIDI_PipeFactory<4> 管道;// 添加额外控制器的示例:// CCPotentiometer pot ={ A0, MIDI_CC::Expression_Controller };// 电源引脚LED is connectedconst int ledPin =10;// 打印传入消息的自定义 MIDI 回调。struct MyMIDI_Callbacks :MIDI_Callbacks { // 通道消息(音符、控制变化、弯音等)的回调。 void onChannelMessage(Parsing_MIDI_Interface &midi) override { ChannelMessage cm =midi.getChannelMessage(); if (cm.header ==0xb0 &&cm.data1 ==0x7b) { // 忽略“所有音符关闭”消息返回; } else if (cm.header ==0x90 &&cm.data2 ==0x00) { // 将速度为 0 的“note on”消息转换为“note off”消息 cm.header =0x80; midiusb.send(cm); } // 系统独占消息的回调 void onSysExMessage(Parsing_MIDI_Interface &midi) override { SysExMessage se =midi.getSysExMessage(); // 转发系统独占消息而无需更改 midiusb.send(se); } // 实时消息回调 void onRealTimeMessage(Parsing_MIDI_Interface &midi) override { RealTimeMessage rt =midi.getRealTimeMessage(); // 转发实时消息而无需更改 midiusb.send(rt); } } callbacks;// setup codevoid setup() { Serial.begin(115200); // 打开电源 LED pinMode(ledPin, OUTPUT);数字写入(ledPin,高); // 将 MIDI USB 转发到 MIDI 串行 midiusb>> 管道>> midiser; // 仅将控制表面消息发送到 MIDI USB Control_Surface>> 管道>> midiusb; // 将 MIDI USB 和串口连接到控制面 midiser>> 管道>> Control_Surface; midiusb>> 管道>> Control_Surface; // 初始化 Control Surface _after_ 连接接口 Control_Surface.begin(); // 设置回调方法 midiser.setCallbacks(callbacks);}// 主要处理 loopvoid loop() { Control_Surface.loop();}
示意图
只填写原理图标签 usb_midi_interface_twiE32gvR3.fzz