# sys.midiOut 库模块帮助文档

[使用编程记谱法合成音乐](https://www.aardio.com/zh-cn/docs/library-guide/std/sys/midiOut.html)

## sys 成员列表 <a id="sys" href="#sys">&#x23;</a>

### sys.midiOut() <a id="sys.midiOut" href="#sys.midiOut">&#x23;</a>
[返回对象:sysMidiOutObject](#sysMidiOutObject)

### sys.midiOut(deviceId,callback,flags) <a id="sys.midiOut" href="#sys.midiOut">&#x23;</a>
打开 MIDI 输出设备。  
所有参数都可以省略，一般不需要了解，用法细节请查看源码。  

可选用 @deviceId 指定设备 ID  
设备 ID 从 0 开始且小于 sys.midiOut.numDevice 函数返回值，  
省略则为默认值 -1，也就是 _MIDI_MAPPER

### sys.midiOut(sysMidiOutObject) <a id="sys.midiOut" href="#sys.midiOut">&#x23;</a>
参数指定其他 sys.midiOut 对象，  
返回复制的副本对象。  
副本对象可指定不同的 channel 属性，  
并可调用 changeInstrument 函数切换不同的乐器

## sys.midiOut 成员列表 <a id="sys.midiOut" href="#sys.midiOut">&#x23;</a>

MIDI 音乐输出设备

打开 MIDI 音乐输出设备。  
成功返回设备对象，失败返回 null，错误信息。  
返回的设备对象可传到其他线程，或复制多个副本对象，  
副本对象可指定不同的 channel 属性，  
并可调用 changeInstrument 函数切换不同的乐器，  
可实现多线程多乐器多通道合奏  

在同一进程中如果未关闭设备则不能重复打开，  
不同进程可以打开同一设备

### sys.midiOut.close() <a id="sys.midiOut.close" href="#sys.midiOut.close">&#x23;</a>
关闭 sys.midiOut.play 自动打开的设备。  
sys.midiOut.play 会重用自动打开的默认设备。  
如果已打开默认设备则不能再创建 sys.midiOut 对象打开同一设备，  
除非调用 sys.midiOut.close 关闭的开的设备。  
在线程退出时会自动调用 sys.midiOut.close 。

### sys.midiOut.eachDevice() <a id="sys.midiOut.eachDevice" href="#sys.midiOut.eachDevice">&#x23;</a>

```aardio
for deviceId,capabilities in sys.midiOut.eachDevice(){
	/*循环遍历所有 MIDI 输出设备，  
deviceId 为设备 ID,capabilities 为 MIDIOUTCAPS 结构体*/
}
```

### sys.midiOut.notes <a id="sys.midiOut.notes" href="#sys.midiOut.notes">&#x23;</a>
定义了全部音符的命名空间，  
键为 SPN 音名，值为音高（pitch）。  
音名中的 -1 省略，升号 ♯（Sharp） 用小写 s 替代。  
例如：C-1♯ 略写为 Cs  

可用 namespace sys.midiOut.notes { } 语句打开此命名空间使用音名  

此命名空间还包含所有音名的小写音名，  
小写音名为对应音高取负并减 1。  
正值作为音符参数传给 note 函数演奏该音符，  
负值作为音符参数传给 note 函数停止演奏对应音符  

此命名空间的下划线 _ 的值为 250，  
传入 note,xcal 等函数可延时 250 毫秒

### sys.midiOut.parseNotes <a id="sys.midiOut.parseNotes" href="#sys.midiOut.parseNotes">&#x23;</a>
解析字符串格式乐谱并返回 play 函数支持的音符数组，  
所有音符或指令使用逗号、竖线、换行之一分开，忽略空格与制表符。  
不符合格式要求的项一律作为字幕传给 log 函数输出

### sys.midiOut.parseNotes(notes,do,tempoMs) <a id="sys.midiOut.parseNotes" href="#sys.midiOut.parseNotes">&#x23;</a>
解析字符串格式乐谱并返回 play 函数支持的音符数组。  
参数 @notes 指定一个字符串，  
在字符串中所有音符或指令使用逗号、竖线、半角空格、制表符、换行之一分开，忽略多余空白字符。  
除了支持 sys.midiOut.notes 定义的全部音名，  
也可以使用简谱记号 1,2,3,4,5,6,7 表示音符，  
数字音符后加 N（小于 5 ）个单引号表示提高 N 个八度音，  
数字音符前加 N（小于 5 ）个单引号表示降低 N 个八度音。  
数字音符前再加 &num; 号表示升高半个音，0 为休止符。  
下划线则表示一个延时单位，其他数值也表示延时（毫秒），  
前面的音符（或下划线）与后面的下划线可以连起来写。  
双下划线 ‗ 表示 _ 的延时取半，多个 ‗ 不能连着写。  
支持函数语法，例如 "1,delay(120)"   

如果 @notes 为字符串，可选用 @do 参数指定 1 音的音高，默认为"C4"，  
可选用 @tempoMs 参数指定下划线表示的延时单位，默认 250 毫秒

### sys.midiOut.play <a id="sys.midiOut.play" href="#sys.midiOut.play">&#x23;</a>
使用默认音乐输出设备解析并播放所有音符与指令。  
可调用 sys.midiOut.close 关闭自动打开的设备。  
此方法内部会调用 sys.midiOut 对象的 playAsync 方法创建独立线程异步播放音乐，  
不会被界面线程的耗时代码阻塞播放过程。  
注意在播放完成前退出调用线程会自动关闭此函数打开的默认设备（停止播放）。  

如果要实现更精细地控制，请改用 sys.midiOut 打开设备而非直接使用此函数。

### sys.midiOut.play(notes,do,tempoMs) <a id="sys.midiOut.play" href="#sys.midiOut.play">&#x23;</a>
使用默认设备解析并播放所有音符（非阻塞异步播放）。  
如果参数 @note 是一个数组，则循环调用 sys.midiOut 对象的 xcall 方法解析并播放音符。  
如果参数 @notes 是一个字符串，  
则首先调用 sys.midiOut.parseNotes 解析为音符数组，  
字符串内所有音符或指令使用逗号、竖线、半角空格、制表符、换行之一分开，忽略多余的空白字符。  
除了支持 sys.midiOut.notes 定义的全部音名，  
也可以使用简谱记号 1,2,3,4,5,6,7 表示音符。  
数字音符后加 N（小于 5 ）个单引号表示提高 N 个八度音，  
数字音符前加 N（小于 5 ）个单引号表示降低 N 个八度音。  
数字音符前再加 &num; 号表示升高半个音，0 为休止符。  
下划线则表示一个延时单位，其他数值也表示延时（毫秒），  
前面的数字音符（或下划线）与后面的下划线可以连起来写。  
双下划线 ‗ 表示 _ 的延时取半，多个 ‗ 不能连着写。  
支持函数语法，例如 "1,delay(120)"   

如果 @notes 为字符串，可选用 @do 参数指定 1 音的音高，默认为"C4"，  
可选用 @tempoMs 参数指定下划线表示的延时单位，默认 250 毫秒

## sysMidiOutObject 成员列表 <a id="sysMidiOutObject" href="#sysMidiOutObject">&#x23;</a>

### sysMidiOutObject.afterTouch(pitch,pressure,channel) <a id="sysMidiOutObject.afterTouch" href="#sysMidiOutObject.afterTouch">&#x23;</a>
单个按键的触后效果，  
指击键后通过改变对键盘的压力来改变音色符。  
@pitch 用字符串指定数字音符或 SPN 音名，也可用 0~127 范围的值直接指定音高。  
@pressure 指定压力，可指定  0~127 范围的值。  
@channel 可用 0~16 范围的值指定通道，省略则默认为当前通道。  
注意指定 @channel 并不会修改当前通道

### sysMidiOutObject.autoNoteOff <a id="sysMidiOutObject.autoNoteOff" href="#sysMidiOutObject.autoNoteOff">&#x23;</a>
play、playSync、playAsync 是否根据音符后的首个延时自动发送 Note Off，默认为 true。  
默认将音符（或连续音符组成的和弦）后面的首个延时视为音符时值，并在延时结束时释放该组音符。  
直接调用 noteOn 不受此属性影响。需要自行使用负数音符或 noteOff 精确控制音符释放时，可设为 false

### sysMidiOutObject.cc(number,value,channel) <a id="sysMidiOutObject.cc" href="#sysMidiOutObject.cc">&#x23;</a>
发送 CC（Continuous controller） 消息  
@number 指定编号，@value 指定值，  
可选用 @channel 指定通道，省略则默认为当前通道。  
注意指定 @channel 并不会修改当前通道

### sysMidiOutObject.changeInstrument(instrument,channel) <a id="sysMidiOutObject.changeInstrument" href="#sysMidiOutObject.changeInstrument">&#x23;</a>
切换乐器,  
@instrument 指定乐器编号，可选编号为 0~127 范围的值。  
乐器编号就搜索 MIDI 资料。  
@channel 可用 0~16 范围的值指定通道，省略则默认为当前通道。  
注意指定 @channel 并不会修改当前通道

### sysMidiOutObject.channel <a id="sysMidiOutObject.channel" href="#sysMidiOutObject.channel">&#x23;</a>
默认通道，可指定 0~16 范围的值。  
如果将 sys.midiOut 传入不同的线程，  
或以 sys.midiOut 为构造参数复制对象，  
则可指定不同的 channel 属性，切换不同的乐器，  
实现多通道合奏

### sysMidiOutObject.channelPressure((pressure,channel) <a id="sysMidiOutObject.channelPressure(" href="#sysMidiOutObject.channelPressure(">&#x23;</a>
所有按键的触后通道压力。  
@pressure 指定压力，可指定  0~127 范围的值。  
可选用 @channel 指定通道，省略则默认为当前通道

### sysMidiOutObject.close() <a id="sysMidiOutObject.close" href="#sysMidiOutObject.close">&#x23;</a>
关闭所有线程的同一设备对象，  
不应关闭在其他线程已关闭的对象。  
对象回收时不会自动调用此函数。  

在同一进程中如果未关闭设备则不能重复打开，  
不同进程可以打开同一设备

### sysMidiOutObject.delay() <a id="sysMidiOutObject.delay" href="#sysMidiOutObject.delay">&#x23;</a>
延迟参数 @1 指定的毫秒数

### sysMidiOutObject.getVolume() <a id="sysMidiOutObject.getVolume" href="#sysMidiOutObject.getVolume">&#x23;</a>
获取音量，0xFFFF 为最大值，0 为静音

### sysMidiOutObject.log <a id="sysMidiOutObject.log" href="#sysMidiOutObject.log">&#x23;</a>
用于输出字幕，默认是一个空函数。  
可指定为其他可输出内容的函数。  
此函数仅接受一个要输出的字符串参数

### sysMidiOutObject.msg(msg,dw1,dw2) <a id="sysMidiOutObject.msg" href="#sysMidiOutObject.msg">&#x23;</a>
发送消息，  
@msg 指定消息 ID，其他参数为数值

### sysMidiOutObject.note <a id="sysMidiOutObject.note" href="#sysMidiOutObject.note">&#x23;</a>
演奏或停止演奏

### sysMidiOutObject.note(pitch,velocity,channel) <a id="sysMidiOutObject.note" href="#sysMidiOutObject.note">&#x23;</a>
演奏或停止演奏  
@pitch 如果指定 0~127 范围的值指定音高，则演奏指定音符。  
如果指定 -1~-128之间的值，则取正数并减一，然后停止演奏音高的音符。  
@velocity 指定按键速度（音量强度），可指定 0~127 范围的值。  
@channel 可用 0~16 范围的值指定通道，省略则默认为 0

### sysMidiOutObject.noteOff <a id="sysMidiOutObject.noteOff" href="#sysMidiOutObject.noteOff">&#x23;</a>
停止演奏音符

### sysMidiOutObject.noteOff(pitch,channel) <a id="sysMidiOutObject.noteOff" href="#sysMidiOutObject.noteOff">&#x23;</a>
停止演奏音符  
@pitch 可用 0~127 范围的值指定音高。  
@channel 可用 0~16 范围的值指定通道，省略则默认为当前通道

### sysMidiOutObject.noteOn <a id="sysMidiOutObject.noteOn" href="#sysMidiOutObject.noteOn">&#x23;</a>
演奏音符

### sysMidiOutObject.noteOn(pitch,velocity,channel) <a id="sysMidiOutObject.noteOn" href="#sysMidiOutObject.noteOn">&#x23;</a>
演奏音符。  
@pitch 可用 0~127 范围的值指定音高，相邻为半音，隔一为全音。  
@velocity 指定按键速度（音量强度），可指定 0~127 范围的值。  
@channel 可用 0~16 范围的值指定通道，省略则默认为当前通道

### sysMidiOutObject.pitchBend(value,channel) <a id="sysMidiOutObject.pitchBend" href="#sysMidiOutObject.pitchBend">&#x23;</a>
调整弯音轮  
@value 用一个小数指定音高弯曲比例。  
0 ~ 0.5 表示向下弯曲，0.5 ~ 1 表示向上弯曲

### sysMidiOutObject.pitchBend2(value,channel) <a id="sysMidiOutObject.pitchBend2" href="#sysMidiOutObject.pitchBend2">&#x23;</a>
调整弯音轮  
@value 用 14 位整数指定 0~16383 范围的音高弯曲值。  
0表示向下弯曲2个半音，16383表示向上弯曲2个半音

### sysMidiOutObject.play <a id="sysMidiOutObject.play" href="#sysMidiOutObject.play">&#x23;</a>
解析并播放所有音符与指令。  
在导入 win.ui 库的界面线程中此方法会立即返回并使用延时器异步启动播放，播放时仍然可以处理窗口消息（可能阻塞播放过程）。在未导入 win.ui 库的工作线程中此函数直接调用 playSync 函数。

### sysMidiOutObject.play(notes,do,tempoMs,startDelay) <a id="sysMidiOutObject.play" href="#sysMidiOutObject.play">&#x23;</a>
解析并播放所有音符。  
如果参数 @note 是一个数组，则循环调用 xcall 函数解析并播放音符。  
如果参数 @notes 是一个字符串，  
则首先调用 sys.midiOut.parseNotes 解析为音符数组，  
字符串内所有音符或指令使用逗号、竖线、半角空格、制表符、换行之一分开，忽略多余的空白字符。  
除了支持 sys.midiOut.notes 定义的全部音名，  
也可以使用简谱记号 1,2,3,4,5,6,7 表示音符。  
数字音符后加 N（小于 5 ）个单引号表示提高 N 个八度音，  
数字音符前加 N（小于 5 ）个单引号表示降低 N 个八度音。  
数字音符前再加 &num; 号表示升高半个音，0 为休止符。  
下划线则表示一个延时单位，其他数值也表示延时（毫秒），  
前面的数字音符（或下划线）与后面的下划线可以连起来写。  
双下划线 ‗ 表示 _ 的延时取半，多个 ‗ 不能连着写。  
支持函数语法，例如 "1,delay(120)"   

如果 @notes 为字符串，可选用 @do 参数指定 1 音的音高，默认为"C4"，  
可选用 @tempoMs 参数指定下划线表示的延时单位，默认 250 毫秒  
在界面线程中可选用 @startDelay 参数指定异步启动播放的延迟毫秒数

### sysMidiOutObject.playAsync <a id="sysMidiOutObject.playAsync" href="#sysMidiOutObject.playAsync">&#x23;</a>
解析并播放所有音符与指令。  
此方法会创建独立线程异步播放音乐，不会被界面线程的耗时代码阻塞播放过程。  
如果在较空闲的界面线程中播放短促的音乐，使用 playAsync 方法通常是不必要的。

### sysMidiOutObject.playAsync(notes,do,tempoMs) <a id="sysMidiOutObject.playAsync" href="#sysMidiOutObject.playAsync">&#x23;</a>
解析并播放所有音符。  
如果参数 @note 是一个数组，则循环调用 xcall 函数解析并播放音符。  
如果参数 @notes 是一个字符串，  
则首先调用 sys.midiOut.parseNotes 解析为音符数组，  
字符串内所有音符或指令使用逗号、竖线、半角空格、制表符、换行之一分开，忽略多余的空白字符。  
除了支持 sys.midiOut.notes 定义的全部音名，  
也可以使用简谱记号 1,2,3,4,5,6,7 表示音符。  
数字音符后加 N（小于 5 ）个单引号表示提高 N 个八度音，  
数字音符前加 N（小于 5 ）个单引号表示降低 N 个八度音。  
数字音符前再加 &num; 号表示升高半个音，0 为休止符。  
下划线则表示一个延时单位，其他数值也表示延时（毫秒），  
前面的数字音符（或下划线）与后面的下划线可以连起来写。  
双下划线 ‗ 表示 _ 的延时取半，多个 ‗ 不能连着写。  
支持函数语法，例如 "1,delay(120)"   

如果 @notes 为字符串，可选用 @do 参数指定 1 音的音高，默认为"C4"，  
可选用 @tempoMs 参数指定下划线表示的延时单位，默认 250 毫秒

### sysMidiOutObject.playSync <a id="sysMidiOutObject.playSync" href="#sysMidiOutObject.playSync">&#x23;</a>
解析并播放所有音符与指令。  
此方法在播放完成后才会返回，播放时仍然可以处理窗口消息（可能阻塞播放过程）。  
在界面线程中通常应当使用导步启动播放的 play 方法。

### sysMidiOutObject.playSync(notes,do,tempoMs) <a id="sysMidiOutObject.playSync" href="#sysMidiOutObject.playSync">&#x23;</a>
解析并播放所有音符。  
如果参数 @note 是一个数组，则循环调用 xcall 函数解析并播放音符。  
如果参数 @notes 是一个字符串，  
则首先调用 sys.midiOut.parseNotes 解析为音符数组，  
字符串内所有音符或指令使用逗号、竖线、半角空格、制表符、换行之一分开，忽略多余的空白字符。  
除了支持 sys.midiOut.notes 定义的全部音名，  
也可以使用简谱记号 1,2,3,4,5,6,7 表示音符。  
数字音符后加 N（小于 5 ）个单引号表示提高 N 个八度音，  
数字音符前加 N（小于 5 ）个单引号表示降低 N 个八度音。  
数字音符前再加 &num; 号表示升高半个音，0 为休止符。  
下划线则表示一个延时单位，其他数值也表示延时（毫秒），  
前面的数字音符（或下划线）与后面的下划线可以连起来写。  
双下划线 ‗ 表示 _ 的延时取半，多个 ‗ 不能连着写。  
支持函数语法，例如 "1,delay(120)"   

如果 @notes 为字符串，可选用 @do 参数指定 1 音的音高，默认为"C4"，  
可选用 @tempoMs 参数指定下划线表示的延时单位，默认 250 毫秒

### sysMidiOutObject.reset() <a id="sysMidiOutObject.reset" href="#sysMidiOutObject.reset">&#x23;</a>
关闭所有音符

### sysMidiOutObject.setVelocity() <a id="sysMidiOutObject.setVelocity" href="#sysMidiOutObject.setVelocity">&#x23;</a>
使用参数 @1 设置 xcall,play 函数默认按键速度（音量），  
参数可指定 0~127 范围的值

### sysMidiOutObject.setVolume() <a id="sysMidiOutObject.setVolume" href="#sysMidiOutObject.setVolume">&#x23;</a>
指定音量，0xFFFF 为最大值，0 为静音

### sysMidiOutObject.shortMsg <a id="sysMidiOutObject.shortMsg" href="#sysMidiOutObject.shortMsg">&#x23;</a>
发送短消息

### sysMidiOutObject.shortMsg(status,data1,data2) <a id="sysMidiOutObject.shortMsg" href="#sysMidiOutObject.shortMsg">&#x23;</a>
发送短消息。  
@status 指定数值，0xC0 为切换乐器，0x90 为发送音符。  
@data1,@data2 可选指定数值

### sysMidiOutObject.velocity <a id="sysMidiOutObject.velocity" href="#sysMidiOutObject.velocity">&#x23;</a>
xcall,play 函数默认按键速度（音量），  
参数可指定 0~127 范围的值

### sysMidiOutObject.xcall() <a id="sysMidiOutObject.xcall" href="#sysMidiOutObject.xcall">&#x23;</a>
如果参数指定一个数组，  
则数组的第 1 个元素指定要调用的成员函数名，  
其他元素为调用参数  

例如： {"pitchBend",0.3}  

如果参数指定一个大于 127 的数值，则延时指定的时间，  
如果为 0~127 间的数值则按下指定音符。  
如果为 -1 到 -128 的数值则消音指定的音符。  
按下音符与消音可以使用 sys.midiOut.notes 命名空间的音名表示。  
如果为字符串则调用 log 函数输出。  

指定上述参数函数返回 true，指定其他数值返回 null，  
参数为其他数据类型会报错。  

播放失败或 thread.delay 检测到消息泵终止返回 false 。

## sysMidiOutObject 事件列表 <a id="sysMidiOutObjectEvent" href="#sysMidiOutObjectEvent">&#x23;</a>

### sysMidiOutObject.onNote <a id="sysMidiOutObject.onNote" href="#sysMidiOutObject.onNote">&#x23;</a>

```aardio
sysMidiOutObject.onNote = function(pitch,velocity,channel){
	/*演奏指定音符时回调此函数，  
回调参数为 noteOn 函数的调用参数。  
这里最好不要阻塞线程，可用 thread.command 异步调用界面线程函数*/
}
```

