>> WINAPI入門トップに戻る
今回はMCIコマンドを使って音声ファイルを再生する方法を説明します。
MCIコマンドというものを用いると、waveファイルだけでなく、
MP3ファイルや動画ファイルの再生なども扱うことができます。
今回はwaveファイルとmp3ファイルを再生する方法について説明します。
まずMCIコマンドを送信するために、mciSendCommand関数を使います。
mmsystem.hをインクルードし、winmm.libをリンクする必要があります。
第一引数には再生対象のデバイス識別子を指定します。
第二引数には送信するコマンドを指定します。
以下のものがあります。
第三引数には、オプションのコマンドメッセージを指定します。
かなり数がおおいいので、MSDNを参照して下さい。
基本的には、アクションがあった時に親ウィンドウに通知メッセージを送る、MCI_NOTIFY,
デバイスオープン時に使うMCI_OPEN_TYPE,MCI_OPEN_TYPE_ID,MCI_OPEN_ELEMENTぐらいしか使いません。
第四引数にはパラメータをセットして、MCI_OPEN_PARMS構造体のポインタを指定します。
まず関数を実行する前に、
MCI_OPEN_PARMS構造体の値をセットする必要があります。
必要なのはlpstrDeviceTypeとlpstrElementNameだけです。
デバイスタイプには、以下のものを指定できます。
waveファイルを再生するには、MCI_DEVTYPE_WAVEFORM_AUDIOを指定します。
メンバの型自体は、LPSTR型なのでキャストします。
MCIではMP3ファイルも再生できます。
MP3ファイルの場合は定数がありませんが、「MPEGVideo」という文字列を直接指定することで、
再生できます。
定数を使わない場合のデバイス名の一覧は、レジストリの、
「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI Extensions」
の中に載っていますので、一度見てみるとよいかもしれません。
拡張子ごとのデバイス名が記載されています。
lpstrElementNameにはファイル名を書きます。
これで構造体のセットが終わったので、まずmciSendCommand関数でデバイスを開きます。
まず第一引数のデバイスIDですが最初はわからないのでNULLにします。
次に第二引数ですが、最初はまずデバイスをOPENする必要があるので、
[MCI_OPEN]を指定します。
第三引数はwaveファイルの場合は、
MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENTを指定し、
MP3ファイルの場合は、
MCI_OPEN_TYPE | MCI_OPEN_ELEMENT
を指定します。論理和演算で複数指定可能です。
WAVEみたいにあらかじめ定数が用意されているものはMCI_OPEN_TYPE_IDを指定する必要があるわけです。
第四引数は先程値をセットしたMCI_OPEN_PARMS構造体のポインタを指定します。
型自体は(DWORD_PTR)型なのでキャストして下さい。
成功すると0が返り、第四引数のポインタにデバイスの情報が格納されます。
これによってデバイスIDを取得できるわけです。
失敗すると0以外の値が返ります。
エラーが発生した場合は、mciGetErrorString関数で、
詳細なエラー情報を取得できます。
第一引数にはmciSendCommand関数の戻り値を指定します。
第二引数はエラー内容を格納するためのバッファのポインタ。
第三引数はそのサイズを指定します。
これで再生の準備が整ったので、後は再生するだけです。
今度はmciSendCommand関数の第二引数を、「MCI_PLAY」にします。
また第三引数にMCI_NOTIFYを指定すると、再生終了時に、
MM_MCINOTIFYというウィンドウメッセージを親ウィンドウに送信してくれます。
その際のWPARAMにはそのときの詳細なメッセージが格納されています。
MCI_NOTIFY_SUCCESSFULであれば正常に再生が終了したという意味です。
他にもいくつかありますが、特に使わないのでMSDNを参照して下さい。
LPARAMには再生が終了したデバイスのデバイスIDが入っています。
第四引数にはMCI_PLAY_PARMS型構造体のポインタを指定します。
第三引数にMCI_FROMやMCI_FROMを使った場合、dwFromメンバやdwToメンバに値を代入すると、
それぞれ、そこを開始位置として再生、そこを終了位置として再生することができます。
第一引数にはMCI_NOTIFYを第三引数で設定していた場合は、
親ウィンドウハンドルを代入しておくことで、
再生終了時にそのウィンドウハンドルにメッセージを飛ばすことができます。
最後にデバイスをクローズするために、mciSendCommand関数の、
第二引数をMCI_CLOSEに設定、第三、第四引数を0にしてデバイスをクローズします。
これが一連の流れです。
これらの関数を使ってWAVファイルとMP3ファイルを再生したコードのサンプルが以下になります。
プロジェクトファイルがあるフォルダに、
test.wav,test2.wav,test.mp3ファイルを置いて実行すると、
左クリック時にtest.wavファイルの再生、
右クリック時にtest2.wavファイルの再生、
キーボード押下時にtest.mp3ファイルが再生されます。
上記コードでは再生が終了した際に、
完了メッセージを出して、再生位置を最初に戻しています。
再生位置を変更する場合は、mciSendCommand関数の第二引数を、
「MCI_SEEK」に設定し、第三引数にその位置を指定します。
先頭に戻す場合はMCI_SEEK_TO_STARTを指定すればよいです。
他にも最初に説明したとおり、
MCI_STOPやMCI_PAUSEなどを使って停止や一時停止をすることもできます。
また音声ファイルだけでなく、デバイスタイプを動画再生用のデバイスに変更すれば、
動画の再生も可能です。
なお、この再生方法だと違うファイルの同時再生が可能です。
今回の説明は以上です。
次回は動画の再生(MCIウィンドウ)について説明します。
>> 【動画の再生(MCIウィンドウ)】に進む
>> WINAPI入門トップに戻る
MCIコマンドによる音声ファイル再生
MCIコマンドというものを用いると、waveファイルだけでなく、
MP3ファイルや動画ファイルの再生なども扱うことができます。
今回はwaveファイルとmp3ファイルを再生する方法について説明します。
まずMCIコマンドを送信するために、mciSendCommand関数を使います。
mmsystem.hをインクルードし、winmm.libをリンクする必要があります。
MCIERROR mciSendCommand(
MCIDEVICEID IDDevice, // デバイス識別子
UINT uMsg, // コマンドメッセージ
DWORD fdwCommand, // フラグ
DWORD dwParam // パラメータを保持している構造体
);
MCIDEVICEID IDDevice, // デバイス識別子
UINT uMsg, // コマンドメッセージ
DWORD fdwCommand, // フラグ
DWORD dwParam // パラメータを保持している構造体
);
第一引数には再生対象のデバイス識別子を指定します。
第二引数には送信するコマンドを指定します。
以下のものがあります。
MCI_OPEN デバイスをオープンします。 MCI_CLOSE デバイスをクローズします MCI_PLAY 再生します MCI_STOP 停止します MCI_PAUSE 一時停止します MCI_RESUME 一時停止解除します MCI_SET MCI_FORMAT_MILLISECONDSを指定し、時間のフォーマットを指定します。 MCI_SEEK MCI_SEEK_TO_STARTなどを指定し、シーク位置の調整をします。 MCI_STATUS MCI_STATUS_PARMS.dwItemにMCI_STATUS_LENGTHを指定し、再生時間取得 MCI_STATUS MCI_STATUS_PARMS.dwItemにMCI_STATUS_POSITIONを指定し、現在位置を取得 MCI_STATUS MCI_STATUS_PARMS.dwItemにMCI_STATUS_MODEを指定すると以下のものを返す。 MCI_MODE_PLAY : 再生中 MCI_MODE_STOP : 停止中 MCI_MODE_PAUSE : 一時停止中
第三引数には、オプションのコマンドメッセージを指定します。
かなり数がおおいいので、MSDNを参照して下さい。
基本的には、アクションがあった時に親ウィンドウに通知メッセージを送る、MCI_NOTIFY,
デバイスオープン時に使うMCI_OPEN_TYPE,MCI_OPEN_TYPE_ID,MCI_OPEN_ELEMENTぐらいしか使いません。
第四引数にはパラメータをセットして、MCI_OPEN_PARMS構造体のポインタを指定します。
まず関数を実行する前に、
MCI_OPEN_PARMS構造体の値をセットする必要があります。
typedef struct {
DWORD dwCallback;
MCIDEVICEID wDeviceID;
LPCSTR lpstrDeviceType;
LPCSTR lpstrElementName;
LPCSTR lpstrAlias;
} MCI_OPEN_PARMS;
DWORD dwCallback;
MCIDEVICEID wDeviceID;
LPCSTR lpstrDeviceType;
LPCSTR lpstrElementName;
LPCSTR lpstrAlias;
} MCI_OPEN_PARMS;
必要なのはlpstrDeviceTypeとlpstrElementNameだけです。
デバイスタイプには、以下のものを指定できます。
MCI_DEVTYPE_WAVEFORM_AUDIO ウェーブフォームオーディオ
MCI_DEVTYPE_CD_AUDIO CD オーディオ
MCI_DEVTYPE_DAT デジタルオーディオデバイス
MCI_DEVTYPE_DIGITAL_VIDEO 非 GDI ベースのウィンドウ内デジタルビデオ
MCI_DEVTYPE_OTHER 未定義
MCI_DEVTYPE_OVERLAY オーバーレイ
MCI_DEVTYPE_SCANNER イメージスキャナ
MCI_DEVTYPE_SEQUENCER MIDI シーケンサ
MCI_DEVTYPE_VCR ビデオカセットレコーダー、またはプレーヤー
MCI_DEVTYPE_VIDEODISC ビデオディスクプレーヤー
MCI_DEVTYPE_ANIMATION アニメーション
MCI_DEVTYPE_CD_AUDIO CD オーディオ
MCI_DEVTYPE_DAT デジタルオーディオデバイス
MCI_DEVTYPE_DIGITAL_VIDEO 非 GDI ベースのウィンドウ内デジタルビデオ
MCI_DEVTYPE_OTHER 未定義
MCI_DEVTYPE_OVERLAY オーバーレイ
MCI_DEVTYPE_SCANNER イメージスキャナ
MCI_DEVTYPE_SEQUENCER MIDI シーケンサ
MCI_DEVTYPE_VCR ビデオカセットレコーダー、またはプレーヤー
MCI_DEVTYPE_VIDEODISC ビデオディスクプレーヤー
MCI_DEVTYPE_ANIMATION アニメーション
waveファイルを再生するには、MCI_DEVTYPE_WAVEFORM_AUDIOを指定します。
メンバの型自体は、LPSTR型なのでキャストします。
MCIではMP3ファイルも再生できます。
MP3ファイルの場合は定数がありませんが、「MPEGVideo」という文字列を直接指定することで、
再生できます。
定数を使わない場合のデバイス名の一覧は、レジストリの、
「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI Extensions」
の中に載っていますので、一度見てみるとよいかもしれません。
拡張子ごとのデバイス名が記載されています。
lpstrElementNameにはファイル名を書きます。
これで構造体のセットが終わったので、まずmciSendCommand関数でデバイスを開きます。
まず第一引数のデバイスIDですが最初はわからないのでNULLにします。
次に第二引数ですが、最初はまずデバイスをOPENする必要があるので、
[MCI_OPEN]を指定します。
第三引数はwaveファイルの場合は、
MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENTを指定し、
MP3ファイルの場合は、
MCI_OPEN_TYPE | MCI_OPEN_ELEMENT
を指定します。論理和演算で複数指定可能です。
WAVEみたいにあらかじめ定数が用意されているものはMCI_OPEN_TYPE_IDを指定する必要があるわけです。
第四引数は先程値をセットしたMCI_OPEN_PARMS構造体のポインタを指定します。
型自体は(DWORD_PTR)型なのでキャストして下さい。
成功すると0が返り、第四引数のポインタにデバイスの情報が格納されます。
これによってデバイスIDを取得できるわけです。
失敗すると0以外の値が返ります。
エラーが発生した場合は、mciGetErrorString関数で、
詳細なエラー情報を取得できます。
BOOL mciGetErrorString(
DWORD fdwError, // エラーコード
LPTSTR lpszErrorText, // バッファへのポインタ
UINT cchErrorText // バッファのサイズ
);
DWORD fdwError, // エラーコード
LPTSTR lpszErrorText, // バッファへのポインタ
UINT cchErrorText // バッファのサイズ
);
第一引数にはmciSendCommand関数の戻り値を指定します。
第二引数はエラー内容を格納するためのバッファのポインタ。
第三引数はそのサイズを指定します。
これで再生の準備が整ったので、後は再生するだけです。
今度はmciSendCommand関数の第二引数を、「MCI_PLAY」にします。
また第三引数にMCI_NOTIFYを指定すると、再生終了時に、
MM_MCINOTIFYというウィンドウメッセージを親ウィンドウに送信してくれます。
その際のWPARAMにはそのときの詳細なメッセージが格納されています。
MCI_NOTIFY_SUCCESSFULであれば正常に再生が終了したという意味です。
他にもいくつかありますが、特に使わないのでMSDNを参照して下さい。
LPARAMには再生が終了したデバイスのデバイスIDが入っています。
第四引数にはMCI_PLAY_PARMS型構造体のポインタを指定します。
typedef struct {
DWORD_PTR dwCallback;
DWORD dwFrom;
DWORD dwTo;
} MCI_PLAY_PARMS;
DWORD_PTR dwCallback;
DWORD dwFrom;
DWORD dwTo;
} MCI_PLAY_PARMS;
第三引数にMCI_FROMやMCI_FROMを使った場合、dwFromメンバやdwToメンバに値を代入すると、
それぞれ、そこを開始位置として再生、そこを終了位置として再生することができます。
第一引数にはMCI_NOTIFYを第三引数で設定していた場合は、
親ウィンドウハンドルを代入しておくことで、
再生終了時にそのウィンドウハンドルにメッセージを飛ばすことができます。
最後にデバイスをクローズするために、mciSendCommand関数の、
第二引数をMCI_CLOSEに設定、第三、第四引数を0にしてデバイスをクローズします。
これが一連の流れです。
これらの関数を使ってWAVファイルとMP3ファイルを再生したコードのサンプルが以下になります。
#include <windows.h> #include <stdio.h> #include <string.h> #include <mmsystem.h> #pragma comment(lib,"winmm.lib") #define MSG(m) {\ MessageBoxA(NULL,m,NULL,MB_OK);} //ウィンドウハンドル HWND hwnd; //インスタンスハンドル HINSTANCE hinst; //ウィンドウ横幅 #define WIDTH 500 #define HEIGHT 300 LRESULT CALLBACK WinProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp) { static MCI_OPEN_PARMS open,open2,open3; static MCI_PLAY_PARMS play,play2,play3; int result; char buf[1000]; switch(msg){ case WM_DESTROY: mciSendCommand(open.wDeviceID,MCI_CLOSE,0,0); mciSendCommand(open2.wDeviceID,MCI_CLOSE,0,0); mciSendCommand(open3.wDeviceID,MCI_CLOSE,0,0); PostQuitMessage(0); return 0; case WM_CREATE: open.lpstrDeviceType=(LPSTR)MCI_DEVTYPE_WAVEFORM_AUDIO; open.lpstrElementName="test.wav"; open3.lpstrDeviceType=(LPSTR)MCI_DEVTYPE_WAVEFORM_AUDIO; open3.lpstrElementName="test2.wav"; result=mciSendCommand(0,MCI_OPEN,MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD_PTR)&open); result=mciSendCommand(0,MCI_OPEN,MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD_PTR)&open3); //エラーなら0以外が返る if(result){ //エラー取得 mciGetErrorString(result,buf,sizeof(buf)); MSG(buf); PostQuitMessage(0); return -1; } //mp3再生の場合 open2.lpstrDeviceType="MPEGVideo"; open2.lpstrElementName="test.mp3"; result=mciSendCommand(0,MCI_OPEN,MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD_PTR)&open2); //エラーなら0以外が返る if(result){ //エラー取得 mciGetErrorString(result,buf,sizeof(buf)); MSG(buf); PostQuitMessage(0); return -1; } play.dwCallback=(DWORD)hwnd; play2.dwCallback=(DWORD)hwnd; play3.dwCallback=(DWORD)hwnd; return 0; case WM_LBUTTONDOWN: mciSendCommand(open.wDeviceID,MCI_PLAY,MCI_NOTIFY,(DWORD_PTR)&play); return 0; case WM_KEYDOWN: mciSendCommand(open2.wDeviceID,MCI_PLAY,MCI_NOTIFY,(DWORD_PTR)&play2); return 0; case WM_RBUTTONDOWN: mciSendCommand(open3.wDeviceID,MCI_PLAY,MCI_NOTIFY,(DWORD_PTR)&play3); return 0; case MM_MCINOTIFY: if(lp==open.wDeviceID){ if(wp==MCI_NOTIFY_SUCCESSFUL){ MSG("再生完了"); //シークバーを先頭に戻す mciSendCommand(open.wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,0); } return 0; }else if(lp==open2.wDeviceID){ if(wp==MCI_NOTIFY_SUCCESSFUL){ MSG("再生完了"); //シークバーを先頭に戻す mciSendCommand(open2.wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,0); } return 0; }else if(lp==open3.wDeviceID){ if(wp==MCI_NOTIFY_SUCCESSFUL){ MSG("再生完了"); //シークバーを先頭に戻す mciSendCommand(open3.wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,0); } return 0; } } return DefWindowProc(hwnd,msg,wp,lp); } int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) { MSG msg; WNDCLASS wc; wc.style=CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc=WinProc; wc.cbClsExtra=wc.cbWndExtra=0; wc.hInstance=hInstance; wc.hCursor=wc.hIcon=NULL; wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); wc.lpszClassName="test"; wc.lpszMenuName=NULL; if(!RegisterClass(&wc)){ MSG("クラスの登録失敗"); return -1; } //インスタンスハンドル hinst=hInstance; hwnd=CreateWindowA("test","テストウィンドウ",WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 0,0,400,400,NULL,NULL,hInstance,NULL); if(hwnd==NULL){ MSG("ウィンドウ作成失敗"); return -1; } //エラーチェック用変数 int check; while(check=GetMessage(&msg,NULL,0,0)){ if(check==-1){ break; } DispatchMessage(&msg); } //クラス解放 UnregisterClass("test",hinst); return 0; }
プロジェクトファイルがあるフォルダに、
test.wav,test2.wav,test.mp3ファイルを置いて実行すると、
左クリック時にtest.wavファイルの再生、
右クリック時にtest2.wavファイルの再生、
キーボード押下時にtest.mp3ファイルが再生されます。
上記コードでは再生が終了した際に、
完了メッセージを出して、再生位置を最初に戻しています。
再生位置を変更する場合は、mciSendCommand関数の第二引数を、
「MCI_SEEK」に設定し、第三引数にその位置を指定します。
先頭に戻す場合はMCI_SEEK_TO_STARTを指定すればよいです。
他にも最初に説明したとおり、
MCI_STOPやMCI_PAUSEなどを使って停止や一時停止をすることもできます。
また音声ファイルだけでなく、デバイスタイプを動画再生用のデバイスに変更すれば、
動画の再生も可能です。
なお、この再生方法だと違うファイルの同時再生が可能です。
今回の説明は以上です。
次回は動画の再生(MCIウィンドウ)について説明します。
>> 【動画の再生(MCIウィンドウ)】に進む
>> WINAPI入門トップに戻る