【VB.NET】 MCIで音楽再生
 VB.NETで音楽を再生するプログラムを記述する場合、以下の幾つかの方法で実現させることができる。

 ・PlaySound
 ・SoundPlayer(*)
 ・My.Computer.Audio(*)
 ・Windows Media Player
 ・MCI
 ・DirectX
 ・WaveOut

 自分の中での簡単な順番のイメージで並べてみた。因みに*付きは.NET Framework 2.0以降ということでVB.NET(2002)しか知らない私には縁がないため良くわからない。あとこれ以外にも幾つか方法はあると思う。そんな中で、そこそこ手軽にいろいろと音楽再生を実現させようとすると、MCIが落とし所なのかな。しかし、MCIでいろいろとやってみたいと思っても、なかなかVB.NETで実用的に転用できるコードがなかった。C++だったりVB6だったり、何かが惜しい。ということで、試行錯誤してVB.NETで扱いやすいように作ってみた。

 今回はmciSendStringを使用した場合。Unicode云々は良くわからないけど、一応日本語のファイルもそこそこ動作しています。Windowsのコーデックが対応していればMP3とかWMVとかも平気みたい。例によってこんな苦労もあったので、一応4Gまでのファイルは再生できると思います(シークはできないけど)。



Public Class MMCI
#Region " 変数と初期値 "
Private WaveFileName As String = ""
Private DeviceName As String = "x1"
Private FileLength As Long

Public Sub New()
WaveFileName = ""
DeviceName = "x1"
FileLength = 0
End Sub
#End Region

#Region " プロパティ・ファイル名の設定とステータスの取得 "
Public Property DevName() As String
Get
Return DeviceName
End Get
Set(ByVal Value As String)
DeviceName = Value
End Set
End Property

Public Property FileName() As String
Get
Return WaveFileName
End Get
Set(ByVal Value As String)
WaveFileName = Value
End Set
End Property

Public ReadOnly Property Status() As PlayerState
Get
Dim retStr As String
mciCmd("status " & DeviceName & " mode", retStr)
Select Case retStr.ToLower
Case "playing"
Return PlayerState.Playing
Case "stopped"
Return PlayerState.Stopped
Case "paused"
Return PlayerState.Paused
Case "not ready"
Return PlayerState.notready
Case "open"
Return PlayerState.open
Case "parked"
Return PlayerState.parked
Case "recording"
Return PlayerState.recording
Case "seeking"
Return PlayerState.seeking
End Select
End Get
End Property

Public Property Length() As Long
Get
Return FileLength
End Get
Set(ByVal Value As Long)
FileLength = Value
End Set
End Property
#End Region

#Region " MCI関数用定義 "
'文字列長の指定
Const l_command As Integer = 512
Const l_error As Integer = 256
Dim command As String = Space(l_command)
Dim errmes As String = Space(l_error)

'mciSendString
Public Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" _
(ByVal lpstrCommand As String, _
ByVal lpstrReturnString As String, _
ByVal uReturnLength As UInt32, _
ByVal hwndCallback As Integer) As Integer

'mciGetErrorString
Public Declare Function mciGetErrorString Lib "winmm.dll" _
Alias "mciGetErrorStringA" _
(ByVal dwError As Integer, _
ByVal lpstrBuffer As String, _
ByVal uLength As UInt32) As Long
#End Region

#Region " mciCmd(mcicommandstring,*returnstring) "
Public Function mciCmd(ByVal mcicommand As String, _
ByRef retStr As String) As Integer

Dim ret As Integer

If mcicommand <> "" Then
ret = mciSendString(mcicommand, command, _
UInt32.Parse(l_command), Nothing)
If ret <> 0 Then
If mciGetErrorString(ret, errmes, UInt32.Parse(l_error)) = 0 Then
retStr = "Error (文字列の取得に失敗しました)"
Else
retStr = Mid(errmes, 1, InStr(errmes, Chr(0)))
End If
mciCmd = ret
Else
retStr = Mid(command, 1, InStr(command, Chr(0)))
mciCmd = 0
End If
Else
retStr = "Error (コマンド文字列が指定されていません)"
mciCmd = -1
End If
End Function
#End Region

#Region " コマンド群 "
'ファイルオープン
Public Function Open () As Integer
Dim retStr As String
Dim l As Long
If WaveFileName Is Nothing OrElse WaveFileName = "" Then Return -2
If mciCmd("open " & Chr(34) & WaveFileName & Chr(34) & _
" alias " & DeviceName, retStr) = -1 Then
Return -1
Else
'ファイルが開いたらタイムフォーマットをミリ秒に
mciCmd("set " & DeviceName & " time format msf", retStr)
l = GetLength()
'取得した値がマイナスの場合は先にセットされている値を表示する
If l > 0 Then
FileLength = l
End If
End If
Return 0
End Function

'音楽再生開始
Public Function Play(Optional ByVal pos As Long = 0) As Integer
Dim retStr As String
Return mciCmd("play " & DeviceName & " from " & CStr(pos), retStr)
End Function

'長さ取得
Public Function GetLength() As Long
Dim retStr As String
mciCmd("status " & DeviceName & " length", retStr)
If Not IsNumeric(retStr) Then retStr = "0"
If Long.Parse(retStr) < 0 Then
Return ((Long.Parse(retStr) And &H7FFF) + 2 ^ 15)
Else
Return Long.Parse(retStr)
End If
End Function
Public Function GetLengthTimeString() As String
Dim retStr As String
mciCmd("status " & DeviceName & " length", retStr)
If Not IsNumeric(retStr) Then retStr = "0"
If Long.Parse(retStr) < 0 Then
Return cnvHMS((Long.Parse(retStr) And &H7FFF) + 2 ^ 15)
Else
Return cnvHMS(Long.Parse(retStr))
End If
End Function

'現在位置取得
Public Function GetPosition() As Long
Dim retStr As String
mciCmd("status " & DeviceName & " position", retStr)
If Not IsNumeric(retStr) Then retStr = "0"
If Long.Parse(retStr) < 0 Then
Return ((Long.Parse(retStr) And &H7FFF) + 2 ^ 15)
Else
Return Long.Parse(retStr)
End If
End Function
Public Function GetPositionTimeString() As String
Dim retStr As String
mciCmd("status " & DeviceName & " position", retStr)
If Not IsNumeric(retStr) Then retStr = "0"
If Long.Parse(retStr) < 0 Then
Return cnvHMS((Long.Parse(retStr) And &H7FFF) + 2 ^ 15)
Else
Return cnvHMS(Long.Parse(retStr))
End If
End Function

'音楽再生一時停止
Public Sub Pause()
Dim retStr As String
mciCmd("pause " & DeviceName, retStr)
End Sub

'音楽再生再開
Public Sub ResumePlayer()
Dim retStr As String
mciCmd("resume " & DeviceName, retStr)
End Sub

'音楽再生停止
Public Sub StopPlayer()
Dim retStr As String
mciCmd("stop " & DeviceName, retStr)
End Sub

'ファイルクローズ
Public Sub Close()
Dim retStr As String
mciCmd("close " & DeviceName, retStr)
End Sub

'任意のコマンド→返り値:文字列
Public Function Cmd(ByVal str As String) As String
Dim retStr As String
mciCmd(str, retStr)
Return retStr
End Function
#End Region

#Region " 秒数→時分秒に変換 "
'秒数→時分秒に変換
Public Function cnvHMS(ByVal milliseconds As Long) As String
Dim hour, minute, second, millisecond As Integer
hour = milliseconds \ 3600000
minute = (milliseconds - hour * 3600000) \ 60000
second = (milliseconds - hour * 3600000 - minute * 60000) \ 1000
millisecond = (milliseconds Mod 1000) \ 100
cnvHMS = Format(hour, "00") & ":" & Format(minute, "00") & ":" & _
Format(second, "00") & "." & Format(millisecond, "0")
End Function
#End Region

#Region " 再生状態 "
Public Enum PlayerState
Playing
Stopped
Paused
notready
open
parked
recording
seeking
End Enum
#End Region

End Class


使い方
Dim mc as New MMCI()

mc.Filename="c:\wavedir\sound.wav"
mc.Open ()
mc.Play()


再生終了の検知はしていないので、Timerコントロールと組み合わせて作る必要がある。私は常時再生時間を表示させながら使っているためこれでも不自由しないので気にしない。因みに自動で終了検知したい場合はMM_MCINOTIFYメッセージを受け取る必要があるので、呼出元のWndProcをオーバーライドしたりと結構大変だからここでは省略。

    Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick

t_nowpos.Text = mc.GetPositionTimeString()
If mc.GetPosition() >= mc.GetLength() Then mc.StopPlayer()
End Sub


因みに幾つできるかはわからないけど、このコントロールを配列で宣言して複数の音声を同時に鳴らすことも可能っぽい。その場合は各配列のDevNameを改めて書いてあげる必要がある。

Dim mc(1) as MMCI
Dim i as Integer

For i=0 to mc.Length-1
mc(i) = New MMCI()
mc(i).DevName = "x" & Trim(CInt(i))
Next i


ファイル名称
MMCI.FileName = FullPath

ファイルを開く
MMCI.Open ()

音楽の再生(Positionを指定→指定場所(ミリ秒)から再生)
MMCI.Play([position])

素材時間の取得
MMCI.GetLength()
素材時間を文字列で取得
MMCI.GetLengthTimeString()

現在位置の取得
MMCI.GetPosition()
現在位置を文字列で取得
MMCI.GetPosition()

音楽の一時停止
MMCI.Pause()

一時停止からの復帰
MMCI.ResumePlayer()

音楽再生の停止
MMCI.StopPlayer()

ファイルを閉じる
MMCI.Close()

任意のコマンドを送信
MMCI.Cmd(commandstring)

状態の確認
MMCI.Status()

素材長
MMCI.Length

デバイス名
MMCI.DevName
[PR]
by hidemite | 2009-02-23 10:58 | PC
<< 【覚書】 IEのQuickTi... 【職業】 不況の荒波の中で >>