发帖
17 1 0

【外设移植】USB设备之USB midi+M61开发板

bzhou830
论坛元老

72

主题

1454

回帖

1万

积分

论坛元老

积分
12163
Ai-M61-Kit外设移植教程 3466 17 2024-1-16 17:27:27

本帖最后由 bzhou830 于 2024-1-16 17:33 编辑

本帖最后由 bzhou830 于 2024-1-16 17:30 编辑

本帖最后由 bzhou830 于 2024-1-16 17:29 编辑

前面已经实现了USB的键盘和鼠标,这次我们来做一个usb midi乐器。

在做之前我们首先要看看midi是个什么东西?

1. MIDI 简介

MIDI 协议即数字音乐接口(Musical Instrument Digital Interface),是电子乐器、合成器等演奏设备之间的一种即时通信协议,用于硬件之间的实时演奏数据传递。MIDI 协议诞生之初希望解决的事情是通过统一通信协议让不同乐器制造商的设备可以互相兼容,比如把 Roland 键盘接入 Yamaha 合成器。MIDI 协议的编码经过拓展后也可以作为一种记录音乐信息的文件格式,被称为“标准 MIDI 文件格式”。

2. midi描述符

和别的usb设备一样,midi设备也是需要设备描述符,AC接口描述符, midi streaming接口描述符。
https://www.usb.org/sites/default/files/USB%20MIDI%20v2[/url]_0.pdf 标准文档中可以找到对应描述符的说明。

首先是AC接口描述符:


1.png

midi streaming接口描述符:

2.png

按照文档的描述配置描述符如下:

const uint8_t midi_descriptor[] = {
    USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01),
    USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
    /* Standard AC Interface Descriptor */
    0x09,
    0x04,
    0x00,
    0x00,
    0x00,
    0x01,
    0x01,
    0x00,
    0x00,
    /* Class-specific AC Interface Descriptor */
    0x09,
    0x24,
    0x01,
    0x00,
    0x01,
    0x09,
    0x00,
    0x01,
    0x01,
    /* MIDIStreaming Interface Descriptors */
    0x09,
    0x04,
    0x01,
    0x00,
    0x02,
    0x01,
    0x03,
    0x00,
    0x00,
    /* Class-Specific MS Interface Header Descriptor */
    0x07,
    0x24,
    0x01,
    0x00,
    0x01,
    WBVAL(65),

    MIDI_JACK_DESCRIPTOR_INIT(0x01),
    /* OUT endpoint descriptor */
    0x09, 0x05, MIDI_OUT_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
    0x05, 0x25, 0x01, 0x01, 0x01,

    /* IN endpoint descriptor */
    0x09, 0x05, MIDI_IN_EP, 0x02, WBVAL(MIDI_EP_MPS), 0x00, 0x00, 0x00,
    0x05, 0x25, 0x01, 0x01, 0x03,

    /*
     * string0 descriptor
     */
    USB_LANGID_INIT(USBD_LANGID_STRING),
    /*
     * string1 descriptor
     */
    0x14,                       /* bLength */
    USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
    'C', 0x00,                  /* wcChar0 */
    'h', 0x00,                  /* wcChar1 */
    'e', 0x00,                  /* wcChar2 */
    'r', 0x00,                  /* wcChar3 */
    'r', 0x00,                  /* wcChar4 */
    'y', 0x00,                  /* wcChar5 */
    'U', 0x00,                  /* wcChar6 */
    'S', 0x00,                  /* wcChar7 */
    'B', 0x00,                  /* wcChar8 */
    /*
     * string2 descriptor
     */
    0x28,                       /* bLength */
    USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
    'C', 0x00,                  /* wcChar0 */
    'h', 0x00,                  /* wcChar1 */
    'e', 0x00,                  /* wcChar2 */
    'r', 0x00,                  /* wcChar3 */
    'r', 0x00,                  /* wcChar4 */
    'y', 0x00,                  /* wcChar5 */
    'U', 0x00,                  /* wcChar6 */
    'S', 0x00,                  /* wcChar7 */
    'B', 0x00,                  /* wcChar8 */
    ' ', 0x00,                  /* wcChar9 */
    'M', 0x00,                  /* wcChar10 */
    'I', 0x00,                  /* wcChar11 */
    'D', 0x00,                  /* wcChar12 */
    'I', 0x00,                  /* wcChar13 */
    ' ', 0x00,                  /* wcChar14 */
    'D', 0x00,                  /* wcChar15 */
    'E', 0x00,                  /* wcChar16 */
    'M', 0x00,                  /* wcChar17 */
    'O', 0x00,                  /* wcChar18 */
    /*
     * string3 descriptor
     */
    0x16,                       /* bLength */
    USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
    '2', 0x00,                  /* wcChar0 */
    '0', 0x00,                  /* wcChar1 */
    '2', 0x00,                  /* wcChar2 */
    '1', 0x00,                  /* wcChar3 */
    '0', 0x00,                  /* wcChar4 */
    '3', 0x00,                  /* wcChar5 */
    '1', 0x00,                  /* wcChar6 */
    '0', 0x00,                  /* wcChar7 */
    '0', 0x00,                  /* wcChar8 */
    '0', 0x00,                  /* wcChar9 */
    0x00
};

3. MIDI 消息

MIDI 最核心的功能是用于传输实时的音乐演奏信息,这些信息本质上是一条条包含了音高、力度、效果器参数等信息的指令,我们将这些指令称之为 MIDI 消息(MIDI message)。一条 MIDI 消息通常由数个字节组成,其中第一个字节被称为 STATUS byte,其后面有跟有数个 DATA bytes。STATUS byte 第七位为 1,而 DATA byte 第七位为 0。
每个键盘音符需要向主机发送一个4字节的消息。
第一个字节是 【状态码 + 通道编号】
第二个字节是音符,简谱上面的 1234567,唱出来就是 dol re mi fa sol la xi,用一个字节表示,从 0 - 127,共128 个音符。

3.png

不懂乐理的可以看看这段,这是从《圈圈教你玩USB》中截取出来的
4.png

第三个字节是音速,值也是从 0 到 127。这个音速其实你感觉不到什么,发送到声卡上的效果就是音量。值越小声音越小,如果是 0 就等于静音了,127 时声音最大。

4. 翻译乐谱

因为不懂五线谱,也不懂乐理,直接就找一个简谱来翻译成midi消息。


5.jpeg

为了简单,只翻译第一行。

static const uint8\_t s\_note\_sequence[] = {
69, 69, 64, 69, 72, 69, 64, 55,
69, 69, 64, 69, 72, 69, 64, 55,
69, 69, 64, 69, 72, 69, 64, 55,

5.开始实验

编译并烧录代码,安装happyeo软件。这个软件就是将接受到的midi消息通过电脑的声卡播放出来。


6.png

在happyeo中配置输入源为usb midi设备,就可以听到播放出来的midi音乐了。

──── 1人觉得很赞 ────

举报

2024-1-16 17:31:51
代码在这里

AiPi-midi.zip

6.61 KB, 下载次数: 11

2024-1-16 17:37:52
2024-1-16 17:39:40
玛丽哥依旧高产!
2024-1-16 17:55:31
爱笑 发表于 2024-1-16 17:39
玛丽哥依旧高产!

向园长学习
2024-1-17 08:33:44
2024-1-17 08:34:50
hdydy 发表于 2024-1-16 21:27
大佬是不是要把https://github.com/cherry-embedded/CherryUSB里的port挨个弄一遍

哈哈,挨个来
2024-1-17 08:36:15
2024-1-17 08:51:17
2024-1-17 08:52:30
您需要登录后才可以回帖 立即登录
高级模式
12下一页
统计信息
  • 会员数: 28274 个
  • 话题数: 40246 篇