4917浏览
查看: 4917|回复: 7

[入门] DFRobot Leonardo & Xbee R3 实现MIDI播放

[复制链接]
MIDI(Musical Instrument Digital Interface)乐器数字接口 ,是20 世纪80 年代初为解决电声乐器之间的通信问题而提出的。MIDI是编曲界最广泛的音乐标准格式,可称为“计算机能理解的乐谱”。它用音符的数字控制信号来记录音乐。一首完整的MIDI音乐只有几十KB大,而能包含数十条音乐轨道。几乎所有的现代音乐都是用MIDI加上音色库来制作合成的。MIDI传输的不是声音信号, 而是音符、控制参数等指令,它指示MIDI 设备要做什么,怎么做, 如演奏哪个音符、多大音量等。它们被统一表示成MIDI消息(MIDIMessage)
这次的目标是使用 DFRobot DFRobot Leonardo & Xbee R3板子来实现发送 MIDI消息,然后通过电脑上的软件进行播放。这个板子的核心是Atmel 32U4 单片机,内部支持 USB Device,因此可以用来将自身模拟为一个USBMIDI设备(你可以想象为一个自动演奏的钢琴键盘)。
首先介绍一下歌曲的获得。经过研究,可以在网上找到MIDI文件,然后使用MIDI编辑软件打开之。这里我使用的是 MCH MixPad。通常MIDI会有多个音轨,比如伴奏等等。这时候需要找到主要的音轨,可以通过下图指示出来的位置选择对不同的音轨静音然后预览。下面的MIDI文件中第一个(最上面)的音轨是主旋律,里面包含我们需要的数据。
DFRobot Leonardo & Xbee R3 实现MIDI播放图3
接下来我们需要将这个音轨提取出来。我这里使用一个MIDICSV的小工具。这个工具有两个软件,一个是将MIDI转为CSV 的,另外一个是相反的,将CSV中的数据生成为 MIDI
DFRobot Leonardo & Xbee R3 实现MIDI播放图1
使用非常简单,输入 MID文件名然后再给出生成的名称,然后就得到了数据:
DFRobot Leonardo & Xbee R3 实现MIDI播放图2
前面提到了,MIDI文件中有多个音轨,生成的 CSV文件中,会以Start_track字符串作为标志开启数据记录。比如:下面  Title_t Track 1 开始的数据就是我们需要的。
DFRobot Leonardo & Xbee R3 实现MIDI播放图4
简单看一下数据:
DFRobot Leonardo & Xbee R3 实现MIDI播放图5
第一列是数据的类型号,比如2开始的都是前面提到的Track1 数据。接下来是这个事件发生的时间。然后Note_on_c是表示一个消息,后面是它的参数,第一个参数是 Channel 号;然后是Note(可以理解为钢琴的按键编号,一般 60 对应的C4);最后是按键力度,0表示按键抬起。整理上面的数据然后我们就有一个 .h 文件:
DFRobot Leonardo & Xbee R3 实现MIDI播放图6
接下来是软件的设计,代码很简单,开始之后不断检查时间标志,如果当前取得的时间大于Current指向的时间那就发送后面的 midi 消息。
  1. #include "MIDIUSB.h"
  2. #include "chysx.h"
  3. uint32_t start;
  4. uint16_t current = 0;
  5. // First parameter is the event type (0x09 = note on, 0x08 = note off).
  6. // Second parameter is note-on/note-off, combined with the channel.
  7. // Channel can be anything between 0-15. Typically reported to the user as 1-16.
  8. // Third parameter is the note number (48 = middle C).
  9. // Fourth parameter is the velocity (64 = normal, 127 = fastest).
  10. void noteOn(byte channel, byte pitch, byte velocity) {
  11.   midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
  12.   MidiUSB.sendMIDI(noteOn);
  13. }
  14. void setup() {
  15.   Serial.begin(115200);
  16.      start = millis();
  17. }
  18. // First parameter is the event type (0x0B = control change).
  19. // Second parameter is the event type, combined with the channel.
  20. // Third parameter is the control number number (0-119).
  21. // Fourth parameter is the control value (0-127).
  22. void controlChange(byte channel, byte control, byte value) {
  23.   midiEventPacket_t event = {0x0B, 0xB0 | channel, control, value};
  24.   MidiUSB.sendMIDI(event);
  25. }
  26. void loop() {
  27.   
  28.   if (millis() - start > music[current].time*3) {
  29.     Serial.println(current);
  30.     noteOn(0, music[current].ctrlnum, music[current].value);
  31.     MidiUSB.flush();
  32.     noteOn(0, music[current + 1].ctrlnum, music[current + 1].value);
  33.     MidiUSB.flush();
  34.     if (current == 302) {
  35.       current = 0;
  36.       start = millis();
  37.     } else {
  38.       current += 2;
  39.     }
  40.   }
  41. }
复制代码

其中的判断语句  if (millis() - start >music[current].time*3)  可以用来调整播放速度,如果想慢一点就增加乘以的数值,反之就是加速。
本文最关键的部分在于如何获得歌谱,这样的方法比自己对照乐谱敲出来省事得多,另外还可以用播放软件来确认结果是否正确。

参考:


zoologist  高级技匠
 楼主|

发表于 2022-2-16 09:28:15

本文提到的 MIDI 文件下载

MIDICSV 工具

完整的源代码下载附件WideSea.zip

测试的视频
回复

使用道具 举报

赤星三春牛!  初级技神

发表于 2022-2-16 18:58:04

哇!!!!!!!!!
回复

使用道具 举报

赤星三春牛!  初级技神

发表于 2022-2-16 18:59:24

大神厉害了!
回复

使用道具 举报

赤星三春牛!  初级技神

发表于 2022-2-16 20:26:55

值得学习!
回复

使用道具 举报

赤星三春牛!  初级技神

发表于 2022-2-16 20:28:15

呵呵呵呵
回复

使用道具 举报

赤星三春牛!  初级技神

发表于 2022-2-16 20:29:37

6666666666
回复

使用道具 举报

赤星三春牛!  初级技神

发表于 2022-2-16 20:31:10

MIDI播放                        
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail