MCIでのMIDIファイル再生について

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
yu0627
記事: 154
登録日時: 2005年5月31日(火) 14:53

MCIでのMIDIファイル再生について

#1 投稿記事 by yu0627 »

 タイトルにもあるとおり、MCIでMIDIファイルを再生することについてですが、なぜか僕の環境ではラグが起きています。
ラグが起きている間はフリーズしたようになります。なぜこのようになるのでしょうか。お答えお願いいたします。

-----僕の環境-----
WinXP Home Edition SP2
ActiveBasic Ver 4.01.02
xsb007

MCIでのMIDIファイル再生について

#2 投稿記事 by xsb007 »

Windows2000/XPの仕様で、曲によっては10秒以上かかります。

コード: 全て選択

    'メッセージ通知のためのウィンドウを指定
    mop.dwCallback=hMainWnd

    'MPEGVideoデバイスを指定
    mop.lpstrDeviceType = "MPEGVideo"
	

    'MCIデバイスをオープン
    bErr=mciSendCommand(0,MCI_OPEN,MCI_OPEN_ELEMENT _
                        or MCI_OPEN_TYPE,mop)
    If bErr Then
       'だめなら、MCI_OPEN_TYPEを消して再挑戦
       bErr=mciSendCommand(0,MCI_OPEN,MCI_OPEN_ELEMENT ,mop)     
       If bErr Then
            MessageBox(hMainWnd, _
                "デバイスのオープンに失敗","error",MB_OK)
            Exit Sub
       End If
    End If
のように、MPEGVideoデバイスを指定してやれば、すぐに再生されます。
 Windows2000/XPであれば、MPEGVideoデバイスでMIDIを再生できますが、Windows95/98/Meの場合、MPEGVideoデバイスではMIDIなどを再生できない場合があります。その場合は普通に開きます。Windows95/98/Meなら普通に開いてもすぐ再生されるので、この方法はほぼ万能だと思います。
yu0627
記事: 154
登録日時: 2005年5月31日(火) 14:53

Re: MCIでのMIDIファイル再生について

#3 投稿記事 by yu0627 »

返信ありがとうございます。コードを元にアレンジしてみました。

コード: 全て選択


Function OpenMciDevice(FileName As BytePtr) As Long
	Dim bErr As DWord
	Dim buffer[255] As Byte				'MCIエラーを格納する変数

	'メッセージ通知のためのウィンドウを指定
    mop.dwCallback=hMainWnd

    'MPEGVideoデバイスを指定
    mop.lpstrDeviceType = "MPEGVideo"
	mop.lpstrElementName=FileName
    
    'MCIデバイスをオープン
    bErr=mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT or MCI_OPEN_TYPE, mop)
    If bErr Then
		'だめなら、MCI_OPEN_TYPEを消して再挑戦
		mop.lpstrElementName=FileName
        bErr=mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT ,mop)     
        If bErr Then
            MessageBox(hMainWnd, "デバイスのオープンに失敗", "error", MB_OK)
			OpenMciDevice=0
        	Exit Sub
        End If
    End If
	OpenMciDevice=1
End Function
これでMCIファイルの再生もスムーズになりました。しかし、逆にwavファイルなどの時間をリストビュー化すると前のよりも時間がかかってしまいます。
どうすればいいでしょうか。
NoWest
記事: 264
登録日時: 2005年5月31日(火) 10:52
お住まい: 高知
連絡する:

Re: MCIでのMIDIファイル再生について

#4 投稿記事 by NoWest »

コード: 全て選択


    'MPEGVideoデバイスを指定
    mop.lpstrDeviceType = "MPEGVideo"
    mop.lpstrElementName=FileName
mop.lpstrDeviceTypeは決め打ちするのではなく
再生しようとするメディアそれぞれにあったデバイスを選択すると
動作が速くなるでしょう。

そのためにはファイルの拡張子を調べて適切なデバイス名を
指定すればよいです。
(たぶんMCIに適切なデバイスを自動選択させているのが遅くなる原因だと思われます。)

代表的な拡張子とデバイスの対応
(この情報は[9X系ではwin.iniファイル][NT/XP系ではレジストリ]
[MEはwin.iniファイルとレジストリの両方]に入ってるみたいです。)

[mci extensions]
mid=Sequencer
rmi=Sequencer
wav=waveaudio
avi=AVIVideo
cda=CDAudio
midi=Sequencer
aif=MPEGVideo
aifc=MPEGVideo
aiff=MPEGVideo
asf=MPEGVideo2
asx=MPEGVideo2
au=MPEGVideo
snd=MPEGVideo
ivf=MPEGVideo2
m3u=MPEGVideo
mp3=MPEGVideo
mp2=MPEGVideo
mpa=MPEGVideo
mpe=MPEGVideo
mpeg=MPEGVideo
mpg=MPEGVideo
mpv2=MPEGVideo
mp2v=MPEGVideo
m1v=MPEGVideo
wax=MPEGVideo2
wvx=MPEGVideo2
wm=MPEGVideo2
wmx=MPEGVideo2
wma=MPEGVideo2
wmp=MPEGVideo2
wmv=MPEGVideo2
yu0627
記事: 154
登録日時: 2005年5月31日(火) 14:53

Re: MCIでのMIDIファイル再生について

#5 投稿記事 by yu0627 »

またお答えありがとうございます。また修正しました。

コード: 全て選択


Function OpenMciDevice(FileName As BytePtr) As Long
	Dim bErr As DWord
	Dim dwError As DWord
	Dim buffer[255] As Byte				'MCIエラーを格納する変数
	Dim OsVerInfo As OSVERSIONINFO		'OSのバージョンを格納する構造体

	'メッセージ通知のためのウィンドウを指定
    mop.dwCallback=hMainWnd
	'OsVerInfo.dwOSVersionInfoSizeのサイズを指定
	OsVerInfo.dwOSVersionInfoSize=Len(OsVerInfo)
	'OSのバージョンを取得
	GetVersionEx(OsVerInfo)

    'もしOSがWin2KかWinXPでファイルがMIDIならMPEGVideoデバイスを指定
	If OsVerInfo.dwPlatformId=VER_PLATFORM_WIN32_NT and OsVerInfo.dwMajorVersion=5 and OsVerInfo.dwMinorVersion=0 or OsVerInfo.dwMinorVersion=1 and Right$(FileName, 3)="mid" Then
		mop.lpstrDeviceType="Sequencer"
		mop.lpstrElementName="FileName"
		bErr=mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT or MCI_OPEN_TYPE, mop)
		If bErr Then
			mciGetErrorString(dwError, buffer, 255)
			MessageBox(hMainWnd, buffer, "デバイスのオープンに失敗 - error", MB_OK or MB_ICONERROR)
			OpenMciDevice=0
			Exit Sub
		End If
    Else
		mop.lpstrElementName="FileName"
		bErr=mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, mop)
		If bErr Then
			mciGetErrorString(dwError, buffer, 255)
			MessageBox(hMainWnd, buffer, "デバイスのオープンに失敗 - error", MB_OK or MB_ICONERROR)
			OpenMciDevice=0
			Exit Sub
		End If
	End If
	OpenMciDevice=1
End Function
以上のソースにしました。長ったらしいです^^;
しかし、なぜかMCIをオープンするときにエラーがでます。どこかいけないところでもあるでしょうか。
ゲスト

#6 投稿記事 by ゲスト »

 mop.lpstrElementName="FileName" でFileNameに 「""」がついているせいです。
 あと、mid=Sequencerとありますが、これはOSのデフォルト設定で、MCI_OPEN_TYPEを使わなかったときに使う既定のデバイス名です。Sequencerでは、ラグがある状況に戻ります。ちゃんと"MPEGVideo"を指定してください。
 また、OSの種類の判断についてですが、将来のバージョンのWindowsではMPEGVideoがサポートされない可能性があるし、2000/XPでも、MPEGVideoのサポート状況について、Microsoftから正式な資料はないので、従来どおり、bErrでの判定を推奨します。
NoWest@大学

#7 投稿記事 by NoWest@大学 »

>  あと、mid=Sequencerとありますが、これはOSのデフォルト設定で、MCI_OPEN_TYPEを使わなかったときに使う既定のデバイス名です。

”Sequencer”はMCI_OPEN_TYPEを”使ったとき”に指定する値です。
但し、XPでは”ゲスト”の方が仰るように遅くなるようです。
MPEGVideoを指定することで早くなる理由はXPでプログラミングを始めたばかりの私にはよく分かりませんが、

私としては標準で定義されるデバイス名を指定するか、
最初からデバイス名を省略することを推奨します。

>  また、OSの種類の判断についてですが、将来のバージョンのWindowsではMPEGVideoがサポートされない可能性があるし、2000/XPでも、MPEGVideoのサポート状況について、Microsoftから正式な資料はないので、従来どおり、bErrでの判定を推奨します。

確か、MCI_SYSINFOコマンドでデバイス対応状況を取得出来た筈です。
それについて場合分けをすればよいでしょう。



それにしてもMCIは奥が深いな。。。
NoWest
記事: 264
登録日時: 2005年5月31日(火) 10:52
お住まい: 高知
連絡する:

#8 投稿記事 by NoWest »

> 但し、XPでは”ゲスト”の方が仰るように遅くなるようです。

もしかしたら9XとかMEでもMPEGVideoで早くなるかもしれませんね。


> MPEGVideoを指定することで早くなる理由はXPでプログラミングを始めたばかりの私にはよく分かりませんが、

さっそく理由を調べてきました。

MPEGVideoのドライバがmidとwavの両方に対応していることが多いと
いうことらしいです。
このMPEGVideowoをwavやmidの再生に使用すると再生開始時間が早くなる
以外にも再生速度を変えることができたり、
ループ再生の速度が速くなったりという恩恵があるようです。
※MPEGVideoのドライバによるとmidに対応していない場合があるようです。
MPEGVideo2の方が確実性が高いらしいけど、こっちが搭載されているほうが確実性が低いような気がします。
yu0627
記事: 154
登録日時: 2005年5月31日(火) 14:53

ありがとうございます

#9 投稿記事 by yu0627 »

> また、OSの種類の判断についてですが、将来のバージョンのWindowsではMPEGVideoがサポートされない可能性があるし、2000/XPでも、MPEGVideoのサポート状況について、Microsoftから正式な資料はないので、従来どおり、bErrでの判定を推奨します。

次世代のWindowsはロングホーンということらしいですが、今のところかなり先のことなのですので、そのことについては考えていません。また、もしMPEGVideo=MPEG1ということなら、MPEG1のコーデックは全てのWindowsに搭載されているはずですので。


> 確か、MCI_SYSINFOコマンドでデバイス対応状況を取得出来た筈です。それについて場合分けをすればよいでしょう。

MCI_SYSINFOコマンドってどのように使うのでしょうか...。


とりやえず修正してみました。

コード: 全て選択


'MCIデバイスをオープンする為の自作関数。
Function OpenMciDevice(FileName As BytePtr) As Long
	Dim bErr As DWord
	Dim dwError As DWord
	Dim buffer[255] As Byte				'MCIエラーを格納する変数
	Dim OsVerInfo As OSVERSIONINFO		'OSのバージョンを格納する構造体

	'メッセージ通知のためのウィンドウを指定
    mop.dwCallback=hMainWnd
	'OsVerInfo.dwOSVersionInfoSizeのサイズを指定
	OsVerInfo.dwOSVersionInfoSize=Len(OsVerInfo)
	'OSのバージョンを取得
	GetVersionEx(OsVerInfo)

    'もしOSがWin2KかWinXPでファイルがMIDIならMPEGVideoデバイスを指定
	If OsVerInfo.dwPlatformId=VER_PLATFORM_WIN32_NT and Right$(FileName, 3)="mid" Then
		If OsVerInfo.dwMinorVersion=0 or OsVerInfo.dwMinorVersion=1 Then
			mop.lpstrDeviceType="MPEGVideo"
			mop.lpstrElementName=FileName
			bErr=mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT or MCI_OPEN_TYPE, mop)
			If bErr Then
				mciGetErrorString(dwError, buffer, 255)
				MessageBox(hMainWnd, buffer, "SameFolder MusicPlayer Error", MB_OK or MB_ICONERROR)
				OpenMciDevice=0
				CloseMciDevice()
				Exit Sub
			End If
		End If
    Else
		mop.lpstrElementName=FileName
		bErr=mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, mop)
		If bErr Then
			mciGetErrorString(dwError, buffer, 255)
			MessageBox(hMainWnd, buffer, "SameFolder MusicPlayer Error", MB_OK or MB_ICONERROR)
			OpenMciDevice=0
			CloseMciDevice()
			Exit Sub
		End If
	End If
	OpenMciDevice=1
End Function
以上です。
NoWest
記事: 264
登録日時: 2005年5月31日(火) 10:52
お住まい: 高知
連絡する:

Re: ありがとうございます

#10 投稿記事 by NoWest »

>
> MCI_SYSINFOコマンドってどのように使うのでしょうか...。
>

残念ながら私も分かりません。mciSendStringの方なら分かるんですが。。。

コード: 全て選択


#N88BASIC
#include <api_mmsysPro4.sbp>

Dim buf[255] As Char
Dim DeviceNum As Long

mciSendString("sysinfo all quantity",buf,256,NULL)
DeviceNum=Val(buf)

Dim cnt As Long
For cnt=1 To DeviceNum
	mciSendString("sysinfo all name "+Str$(cnt),buf,256,NULL)
	Print MakeStr(buf)
Next
yu0627
記事: 154
登録日時: 2005年5月31日(火) 14:53

解決

#11 投稿記事 by yu0627 »

返信が遅くなってすみません。Win2k&WinMeで動作確認できました。
ありがとうございました。
返信する