http://blog.163.com/zom1995@126/blog/static/1680961322015723403380/
一、API声明
如果声明为Public则需要写到模块中,否则改为Private
Public Declare Function midiOutOpen Lib "winmm.dll" (lphMidiOut
As Long, _
ByVal
uDeviceID As Long, _
ByVal
dwCallback As Long, _
ByVal
dwInstance As Long, _
ByVal
dwFlags As Long) As Long
Public Declare Function midiOutClose Lib "winmm.dll" (ByVal
hMidiOut As Long) As Long
Public Declare Function midiOutShortMsg Lib "winmm.dll" (ByVal
hMidiOut As Long, ByVal dwMsg As Long) As Long
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As
Long)
这里面涉及到打开和关闭,分别是midiOutOpen和midiOutClose,必须先使用midiOutOpen然后才能调用midiOutShortMsg。调用后应立即调用midiOutClose关闭。否则,VB会重启。
Sleep的作用是控制时间。除外,还需要声明一个Long类型的变量作为midiOutOpen、midiOutClose、midiOutShortMsg函数的第一个参数。
二、实例
比如单击Command1发出一个长为1s,音量为80的C4音,则有如下代码:
Dim hMidiOut
Private Sub Command1_Click()
Dim Vol, Pitch, Channel As
Byte
midiOutOpen hMidiOut, -1,
0, 0, 0
midiOutShortMsg hMidiOut,
&HC0 + (0 * &H100) + 0
'参数:&HC0 + 音色表的值 * &H100 + 通道值
Pitch = 60
' C4,相邻的值是半音
Vol = 80
' 音量80
Channel =
0 '
通道0~15,值为9是Percussion专用的,在设置音色之前除了值为9,其他默认为钢琴
midiOutShortMsg hMidiOut,
&H90 + (Pitch * &H100) +
(Vol * &H10000) + Channel
Sleep 1000
'持续1s
midiOutClose hMidiOut
End Sub
如果放不出来声音,就想办法把midiOutOpen的返回值显示出来,值为0则正常。如果返回值是4,重启VB。
三、midiOutShortMsg的用法
1、换乐器:midiOutShortMsg hMidiOut,
&HC0 + (Patch * &H100) +
Channel
2、发送音符:midiOutShortMsg hMidiOut,
&H90 + (Pitch * &H100) +
(Volume * &H10000) + Channel
3、关闭音符:midiOutShortMsg hMidiOut,
&H80 + (Pitch * &H100) +
(Volume * &H10000) + Channel
hMidiOut指的是上面的Long类型变量;Patch是乐器,范围是0~127;Channel是通道,一个通道只能用一种乐器,一共16个通道;Pitch是音高,60是C4,61是C#4,相邻的是半音。
关闭音符也是很重要的,如果代码里面没有任何关闭音符的语句,那么就和加了延音踏板差不多。
四、连奏
声明一个Byte类型的一维数组,存放音高,然后用for循环依次发送。比如依次播放C4,D4,E4,F4,G4,A4,B4,C5。有如下代码:
Dim hMidi
Private Sub Command1_Click()
Dim i As Integer
Dim p(0 To 7) As
Integer
p(0) = 60
p(1) = 62
p(2) = 64
p(3) = 65
p(4) = 67
p(5) = 69
p(6) = 71
p(7) = 72
hMidi = 0
ret = midiOutOpen(hMidi,
-1, 0, 0, 0)
midiOutShortMsg hMidi,
(&HC0 + 0 * &H100) + 0
'发送改变乐器
patch =
60
vol = 80
channel = 0
For i = 0 To 7
midiOutShortMsg hMidi, &H90 + (p(i) *
&H100) + (vol * &H10000) + channel
'发送音符
Sleep 1000
midiOutShortMsg hMidi, &H80 + (p(i) *
&H100) + channel
Next
midiOutClose hMidi
End Sub
然后运行程序,单击Command1,就知道效果了
五、同时发送音符
如果是用数组,那就也可以用for循环,然后把Sleep放到Next的后面。或者,不用数组一行一行写。比如:
Private Sub Command2_Click()
ret = midiOutOpen(hMidi,
-1, 0, 0, 0)
midiOutShortMsg hMidi,
(&HC0 + 0 * &H100) + 0
vol = 80
channel = 0
midiOutShortMsg hMidi,
&H90 + (60 * &H100) + (vol * &H10000) + channel
midiOutShortMsg hMidi,
&H90 + (64 * &H100) + (vol * &H10000) + channel
Sleep 1000
midiOutClose hMidi
End Sub
七、琶音
假设两个或多个音符,在midiOutShortMsg之间使用Sleep语句,后面的数值不能太大也不能太小,比如:
Private Sub Command4_Click()
ret = midiOutOpen(hMidi, -1,
0, 0, 0)
midiOutShortMsg hMidi,
(&HC0 + 0 * &H100) + 0
vol = 80
channel = 0
midiOutShortMsg hMidi,
&H90 + (60 * &H100) + (vol * &H10000) + channel
Sleep 50
midiOutShortMsg hMidi,
&H90 + (64 * &H100) + (vol * &H10000) + channel
Sleep 50
midiOutShortMsg hMidi,
&H90 + (67 * &H100) + (vol * &H10000) + channel
Sleep 1000
midiOutClose hMidi
End Sub
八、非连奏
在中途关闭音符,比如:
Private Sub Command4_Click()
ret = midiOutOpen(hMidi, -1,
0, 0, 0)
midiOutShortMsg hMidi,
(&HC0 + 0 * &H100) + 0
vol = 80
channel = 0
midiOutShortMsg hMidi,
&H90 + (60 * &H100) + (vol * &H10000) + channel
Sleep 100
midiOutShortMsg hMidi,
&H80 + (60 * &H100) + (vol * &H10000) + channel
Sleep 1000
midiOutShortMsg hMidi,
&H90 + (67 * &H100) + (vol * &H10000) + channel
Sleep 1000
midiOutClose hMidi
End Sub
九、速度和时值
如果节拍是4/4,速度是120bpm,那么四分音符的时值是120/60=2s,也就是2000毫秒,而Sleep的参数就是用毫秒作为单位的。这样我们就能算出全音符,二分音符,八分音符等等的时值了。
加载中,请稍候......