MIDI码深度解析
MIDI 协议即数字音乐接口(Musical Instrument Digital Interface),是电子乐器、合成器等演奏设备之间的一种即时通信协议,用于硬件之间的实时演奏数据传递。如果理解还不够深刻,官方如下解释:
常用midi硬件接口如5芯插头串口midi和USB midi设备(usb midi任意一种usb口都行,只要usb枚举成midi设备即可),硬件midi串口接口如下:
好了,有了midi硬件,硬件中通信的数据,有个标准,我们叫做midi码,本章将重点介绍midi码如何组成的,解析思路,usb midi 和串口midi之间的封包差异。
相关链接:
MIDIOX
Bus Hound
USB MIDI Devices 1.0 | USB-IF
MIDI 1.0
1.midi码的基本格式
midi码分为状态码和数据码,状态码在字节最高位写1,数据码在字节最高位写0。状态码可以看出当前midi事件的具体用途,数据码当然是具体内容参数了。
如下格式,就是一个标准midi码
2.midi状态码分类
我们已经知道midi状态码字节最高位写1,那么如何区分是什么类型状态码呢?在【4:6】位用于区分状态码具体内容,注意midi 系统码,0xfn具体的内容功能众多,需要根据不同类型帧分析
//midi码事件类型
#define MIDI_STATUS_NOTE_OFF 0x80
#define MIDI_STATUS_NOTE_ON 0x90
#define MIDI_STATUS_AFTERTOUCH 0xA0
#define MIDI_STATUS_CONTROL_CHANGE 0xB0
#define MIDI_STATUS_PROGRAM_CHANGE 0xC0
#define MIDI_STATUS_CHANNEL_PRESSURE 0xD0
#define MIDI_STATUS_PITCH_WHEEL 0xE0
//#define MIDI_STATUS_SYSTEM 0xF0//系统码具体类型
/*消息类型为系统消息时,低四位的数据定义*/
#define MIDI_SYSEX_Start 0xF0 //系统独有的格式
#define MIDI_SYSEX_End 0xF7#define MIDI_SYS_MTC_Quarter_Frame_Message 0xF1 //2
#define MIDI_SYS_Song_Position_Pointer 0xF2 //3
#define MIDI_SYS_Song_Select 0xF3 //2
#define MIDI_SYS_Tune_Request 0xF6 //1
#define MIDI_SYS_Clock 0xF8 //1
#define MIDI_SYS_Tick 0xF9 //1
#define MIDI_SYS_Start 0xFA //1
#define MIDI_SYS_Stop 0xFC //1
#define MIDI_SYS_Continue 0xFB //1
#define MIDI_SYS_ActiveSense 0xFE //1
#define MIDI_SYS_Reset 0xFF //1
3.midi 通道区分
除去系统码,midi通道在低四位中有效【0:3】
16个通道就像16个人!对各个通道的操作就是对各个人的操作,你叫他们干嘛就干嘛,你可以叫某个人唱歌、闭嘴、以钢琴的音色唱歌,以吉他的音色唱歌、声音多大、在别人唱了多久开始唱。在同一时间里可以有多个人发声,系统将同一时间所有人的声音合成一个声音再发出去。
4.midi状态码具体功能(系统码下一章介绍)
顾名思义,就是让某个音符发音,数据参数1:为值键,或者说是音符,就简单理解成触发某个音源发声;数据参数2:力度,或者说是音量大小。注:力度参数为0时,可当作关音码使用
00165716 KEY 2 90 30 14 1 C 3 Note On
0016578C KEY 2 80 30 40 1 C 3 Note Off
00165B07 KEY 2 90 30 08 1 C 3 Note On
00165B7E KEY 2 80 30 40 1 C 3 Note Off
00165F08 KEY 2 90 30 00 1 C 3 Note Off
00165F7B KEY 2 80 30 40 1 C 3 Note Off
关掉某个音符,可直接理解成让某个音源停止发声。
注意:开音码和关音码需要成对出现,不能有丢包现象
触后音:Key Aftertouch,这个用在钢琴的特殊技法中,大概就是在某个音反复按压过程的一种技巧。数据参数1:值键;数据参数2:力度。具体解释如下官方文档:
控制改变:Control Change,所以也被叫做CC码。数据参数1:控制ID;数据参数2:控制参数。CC码用处十分广泛,可以自定义,用于某些特殊功能,比如控制某个音色效果参数,音量,开关等等。
00187E4F KEY 2 B0 40 00 1 --- CC: Pedal (Sustain)
00187EE3 KEY 2 B0 40 7F 1 --- CC: Pedal (Sustain)
CC码在midi标准中实际是指定了某些具体ID是用来干什么的,但是随着乐曲效果器发展,后面很多ID都被厂商自定义使用了,如下标准ID指定:
乐器改变:Program Change 也叫做PC码。数据参数1:改变乐器ID。通常电子乐器中可用于音源改变(如,让电子钢琴发吉他贝斯音色等等),在效果器中可以用于预设切换功能。
00177A4D KEY 2 C0 00 -- 1 --- PC: Acc. Grand Piano
通道压力:Channel Aftertouch Pressure ,从文章中了解,这玩意儿跟0xAn功能有点类似,处理多个Key的时候可能会调用这个。笔者看到文档有说数据两个字节的,也有说一个字节的,因为常规使用没有遇到过,大家遇到可以回复下(笔者这里比较坚持是一个字节的说法,感觉两个字节的那个Note已经没有啥意义了)
弯音轮:pitch wheel ,特殊技法,会发出特殊音色。数据参数两个字节,14bit有效,所以有效参数在0~0x3FFF
001DA6DD MOX 2 E0 00 44 1 --- Pitch Bend
5.midi 系统码具体功能
-
System Exclusive (0xF0 0xF7)
系统独占码,0xF0开始,0xF7截至,0xF0后第一个字节可以表示制造商ID(也有其他功能),早期MIDI有这么定义
文档有备注的厂商入下:
Sequential Circuits 1 Big Briar 2 Octave / Plateau 3 Moog 4 Passport Designs 5 Lexicon 6 Kurzweil 7 Fender 8 Gulbransen 9 Delta Labs 0x0A Sound Comp. 0x0B General Electro 0x0C Techmar 0x0D Matthews Research 0x0E Oberheim 0x10 PAIA 0x11 Simmons 0x12 DigiDesign 0x13 Fairlight 0x14 Peavey 0x1B JL Cooper 0x15 Lowery 0x16 Lin 0x17 Emu 0x18 Bon Tempi 0x20 S.I.E.L. 0x21 SyntheAxe 0x23 Hohner 0x24 Crumar 0x25 Solton 0x26 Jellinghaus Ms 0x27 CTS 0x28 PPG 0x29 Elka 0x2F Cheetah 0x36 Waldorf 0x3E Kawai 0x40 Roland 0x41 Korg 0x42 Yamaha 0x43 Casio 0x44 Akai 0x45
系统独占码还有如下Master Volume功能(其实用CC码自定义也可以):
0xF0 SysEx 0x7F Realtime 0x7F The SysEx channel. Could be from 0x00 to 0x7F.Here we set it to "disregard channel". 0x04 Sub-ID -- Device Control 0x01 Sub-ID2 -- Master Volume 0xLL Bits 0 to 6 of a 14-bit volume 0xMM Bits 7 to 13 of a 14-bit volume 0xF7 End of SysEx
除此之外还有很多很多,具体查阅文档了解
-
MTC Quarter Frame Message (0xF1)
0013E3B1 MOX 2 F1 30 -- -- --- MTC Quarter Frame
00122F9F MOX 2 F2 00 00 -- --- Song Position Ptr
需要 start stop continue 配合使用
这里放到一起说,因为midi的时钟同步需要这几个midi共同实现:
TIMESTAMP IN PORT STATUS DATA1 DATA2 CHAN NOTE EVENT 00002689 MOX 2 FB -- -- -- --- Continue 0000268B MOX 2 F8 -- -- -- --- Timing Clock 000026A4 MOX 2 F8 -- -- -- --- Timing Clock 000026BD MOX 2 F8 -- -- -- --- Timing Clock 000026D6 MOX 2 F8 -- -- -- --- Timing Clock 000026EF MOX 2 F8 -- -- -- --- Timing Clock 00002707 MOX 2 F8 -- -- -- --- Timing Clock 00002720 MOX 2 F8 -- -- -- --- Timing Clock 0000273A MOX 2 F8 -- -- -- --- Timing Clock 00002753 MOX 2 F8 -- -- -- --- Timing Clock 0000276D MOX 2 F8 -- -- -- --- Timing Clock 00002784 MOX 2 F8 -- -- -- --- Timing Clock 0000279E MOX 2 F8 -- -- -- --- Timing Clock 000027B7 MOX 2 F8 -- -- -- --- Timing Clock 000027D0 MOX 2 F8 -- -- -- --- Timing Clock 000027E9 MOX 2 F8 -- -- -- --- Timing Clock 00002801 MOX 2 F8 -- -- -- --- Timing Clock 0000281B MOX 2 F8 -- -- -- --- Timing Clock 00002834 MOX 2 F8 -- -- -- --- Timing Clock 0000284C MOX 2 F8 -- -- -- --- Timing Clock 00002866 MOX 2 F8 -- -- -- --- Timing Clock 0000287E MOX 2 F8 -- -- -- --- Timing Clock 00002898 MOX 2 F8 -- -- -- --- Timing Clock 000028B1 MOX 2 F8 -- -- -- --- Timing Clock 000028BE MOX 2 FC -- -- -- --- Stop
6.midi 码的简发模式
大概意思就是,如果midi在第一次发送了某个事件类型,那么接下来如果重复发送,可以将事件类型省略(这里吐槽一下,当年因为走马观花没把文档读完,封装代码的时候没有考虑简写模式,导致跟某些乐器不兼容情况)。如下,省略开音码方法:
注:关于为什么要简写,应该是但当年midi设备波特率为:31250原因,带宽过小,某些设备需要发送的midi事件过多造成的
7.usb midi中封包要求(参考文档,midi10,usb官网可以下载)
usb midi是块传输设备,但在midi限制下,强制每帧格式为:4Byte,具体如下:
这里我们可以知道,midi数据大小可以通过cin码来确定:
举例如下封包:
这里我们通过midiox 和 bus hound软件,看看midi码是如何呈现的:
8.usb midi 描述符详细内容 ctrl+midi
//midi ctrl 18
0x09, 0x04, 0x03, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, //ctrl
0x09, 0x24, 0x01, 0x00, 0x01, 0x09, 0x00, 0x01, 0x01, //midi
0x09, 0x04, 0x04, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00,
0x07, 0x24, 0x01, 0x00, 0x01, 0x41, 0x00,
0x06, 0x24, 0x02, 0x01, 0x01, 0x00,
0x06, 0x24, 0x02, 0x02, 0x02, 0x0C,
0x09, 0x24, 0x03, 0x01, 0x03, 0x01, 0x02, 0x01, 0x00,
0x09, 0x24, 0x03, 0x02, 0x04, 0x01, 0x01, 0x01, 0x0B,
0x09, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
0x05, 0x25, 0x01, 0x01, 0x01,
0x09, 0x05, 0x84, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
0x05, 0x25, 0x01, 0x01, 0x03,
相关文章:

MIDI码深度解析
MIDI 协议即数字音乐接口(Musical Instrument Digital Interface),是电子乐器、合成器等演奏设备之间的一种即时通信协议,用于硬件之间的实时演奏数据传递。如果理解还不够深刻,官方如下解释: 常用midi硬件…...

小红书如何做混部?
作者:宋泽辉(小红书)、张佐玮(阿里云) 编者按: Koordinator 是一个开源项目,是基于阿里巴巴内部多年容器调度、混部实践经验孵化诞生,是行业首个生产可用、面向大规模场景的开源混…...

[PHP]严格类型
PHP: 类型声明 - Manual...

作为程序员,你必须学会Maven
资源领取在末尾. Maven 是一款旨在简化 Java 开发流程的管理工具,它的主要功能包括: 1. 项目管理:Maven 提供了一种项目对象模型(Project Object Model, POM),用于管理项目的构建、报告和文档。它允许开发者通过少量代码…...
UDF学习(三)数据访问宏
数据访问宏一 网格节点相关宏** NODE_X (v) 节点v的x方向的坐标 (Node *v) NODE_Y (v) 节点v的y方向的坐标 (Node *v) NODE_Z (v) 节点v的z方向的坐标 (Node *v) F_NODE (f,t,n) 获取节点 (face_t f, Thread *t, int n 节点索引号) F_NNODES(f,t) 获取面上的节点数量 (…...

Web3技术革新:重新定义在线体验
互联网的不断演进塑造了我们的数字生活,而Web3技术的涌现正带来一场前所未有的变革。本文将深入探讨Web3技术的创新,以及它如何重新定义和提升我们的在线体验。 Web3技术的基本概念 Web3是互联网的第三个时代,它将去中心化、区块链、智能合约…...
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
目录 一、前端Vue发送JSON数据二、后端Spring Boot接收JSON数据三、常见错误和问题四、总结 在现代Web开发中,前后端分离已成为一种趋势,Vue和Spring Boot也成为了其中最流行的前后端框架。在Vue前端向Spring Boot后端发送数据时,常常需要将数…...

nvm 工具使用介绍
目录 1.背景2.nvm介绍3.下载和安装4.配置环境变量5.配置淘宝镜像5.1 方式一:直接执行命令5.2 方式二:修改配置文件6.常用命令7.总结下载地址: https://github.com/coreybutler/nvm-windows/releases1.背景 在工作中,我们可能需要同时进行2个或者多个前端项目的开发,每个项…...

Shell 入门_1
Shell概述 本次课程主要包含内容: Shell脚本入门Shell变量Shell内置命令Shell运算符与执行运算命令流程控制语句Shell函数Shell重定向Shell好用的工具, cut sed awk sort大厂常见企业面试题 Shell脚本入门 疑问 linux系统是如何操作计算机硬件CPU,内存,磁盘,显示器等? 答…...

力扣hot100 柱状图中最大的矩形 单调栈
Problem: 84. 柱状图中最大的矩形 文章目录 思路复杂度Code 思路 👨🏫 参考地址 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) Code class Solution {public static int largestRectangleArea(int[] height){Stack&l…...

018 用户交互Scanner
什么是Scanner对象 next()方法 // 声明输入对象 Scanner scanner new Scanner(System.in);System.out.println("next()方法接收:"); if (scanner.hasNext()) {// 输入 Hello worldString str1 scanner.next();// 输出 HelloSystem.out.println(str1); }…...
华为HCIE课堂笔记第十七章 广域网互联技术
第十七章 广域网互联技术 17.1 GRE VPN GRE VPN用于分支与分支通过私网地址互联,通过在私网报文上添加一个GRE的头部,以及添加一层外层的IP头部,通过外层头部中的目IP地址使得报文到达隧道对端接口,并解封装得到原始的私网报文…...
代码随想录算法训练营第17天(二叉树5)| 找树左下角的值二叉树的路径总和从中序与后序遍历序列构造二叉树从前序与中序遍历序列构造二叉树
513.找树左下角的值 leetcode题目地址 题目链接/文章讲解/视频讲解 如果使用递归法,如何判断是最后一行: 其实就是深度最大的叶子节点一定是最后一行。 //迭代法 class Solution { public:int findBottomLeftValue(TreeNode* root) {queue<TreeNod…...

代码随想录 Leetcode106. 从中序与后序遍历序列构造二叉树
题目: 代码(首刷看解析 2024年1月30日): class Solution { public:TreeNode* recursion(vector<int>& inorder, vector<int>& postorder, int longthOfLeft, int longthOfRight) {if (postorder.size() 0) …...
Log4j Log4j2
前言 今天抽时间来把这个日志框架学学,毕竟经常用,虽然不用自己写,但是书到用时方恨少,技多不压身。而且最近我的 GUI 软件中有一个关于日志问题的希望学完能够感觉解决掉。 Log4j & Log4j2 Log4j2 是 Log4j 的升级版&#x…...

C语言——如何进行文件操作
大家好,我是残念,希望在你看完之后,能对你有所帮助,有什么不足请指正!共同学习交流 本文由:残念ing原创CSDN首发,如需要转载请通知 个人主页:残念ing-CSDN博客,欢迎各位→…...
python中for循环的几个现象
1. 运行如下代码 l [{}, {}, {}] for k in l:k[1] 1 print(l) 输出为 [{1: 1}, {1: 1}, {1: 1}]2. 运行如下代码 l [{}, {}, {}] for k in l:k {1:1} print(l) 输出为 [{}, {}, {}] 3. 运行如下代码 l [1,2,3] for k in l:k k * 2 print(l)输出为 [1, 2, 3…...

openssl3.2 - 测试程序的学习 - 准备openssl测试专用工程的模板
文章目录 openssl3.2 - 测试程序的学习 - 准备openssl测试专用工程的模板概述笔记工程中需要的openssl的库实现补充 - 最终的模板工程END openssl3.2 - 测试程序的学习 - 准备openssl测试专用工程的模板 概述 openssl3.2 - 测试程序的学习 整了几个test.c, 每开一个新的测试工…...

Delphi.cz采访Embarcadero捷克共和国办事处经理:理查德·库巴特 - 第一部分
Embarcadero捷克办事处主任理查德库巴特(Richard Kubt,55 岁)接受了我的采访。 Radek Červinka (RČ):库巴特先生您好,感谢您抽出时间访问 delphi.cz。 一开始:我在某处听说您是一名程序员,从…...

AI投资或成科技裁员罪魁祸首
最近的科技裁员让许多人对这个行业的稳定性产生了疑问。然而,仔细观察发现,这些裁员并不是经济困境的迹象,而是科技公司为了重新调整优先事项并投资未来而进行的战略举措。科技行业正投入数十亿美元用于人工智能(AI)&a…...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...