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

[复制链接]
查看2394 | 回复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_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音乐了。

本帖被以下淘专辑推荐:

选择去发光,而不是被照亮
回复

使用道具 举报

bzhou830 | 2024-1-16 17:31:51 | 显示全部楼层
代码在这里

AiPi-midi.zip

6.61 KB, 下载次数: 11

选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

1084504793 | 2024-1-16 17:37:52 | 显示全部楼层
回复

使用道具 举报

爱笑 | 2024-1-16 17:39:40 | 显示全部楼层
玛丽哥依旧高产!
用心做好保姆工作
回复 支持 反对

使用道具 举报

bzhou830 | 2024-1-16 17:55:31 | 显示全部楼层
爱笑 发表于 2024-1-16 17:39
玛丽哥依旧高产!

向园长学习
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

lazy | 2024-1-17 08:33:44 | 显示全部楼层
回复

使用道具 举报

bzhou830 | 2024-1-17 08:34:50 | 显示全部楼层
hdydy 发表于 2024-1-16 21:27
大佬是不是要把https://github.com/cherry-embedded/CherryUSB里的port挨个弄一遍

哈哈,挨个来
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

WT_0213 | 2024-1-17 08:36:15 | 显示全部楼层
回复

使用道具 举报

bzhou830 | 2024-1-17 08:51:17 | 显示全部楼层
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

WT_0213 | 2024-1-17 08:52:30 | 显示全部楼层
回复 支持 反对

使用道具 举报

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

本版积分规则