
Windows API の MCI コマンド(MCI は Media Control Interface の略)を使って音声を鳴らす方法について確認します。
小さいファイルを単純に再生したいだけであれば、PlaySound 関数の方が簡単な場合もあります。
MCI コマンドを使った場合は、音の波形を直接編集してエフェクトをかける、というようなことはできませんが、 音の再生を一時停止したり巻き戻したり、という制御が簡単にできるのがメリットです。
wave 形式だけでなく、mp3 など、Windows OS 上で再生できる形式であれば再生できます。
MCI コマンドを使って音の再生を制御するには、 コマンドメッセージ(Command-Message)を送信して制御する方法と、コマンド文字列(Command-String)を使って命令する方法があります。
まずはコマンドメッセージを送信することのできる、mciSendCommand 関数を使った、 1つの音声ファイル「sarasara.wav」を再生、停止、巻き戻し、一時停止などができる シンプルな音楽プレイヤを作ってみます。
#include <stdio.h>
#include <windows.h>
#pragma comment(lib,"winmm")
int main () {
MCI_OPEN_PARMS mParam;
char inputKey;
mParam.lpstrDeviceType = L"WaveAudio";
mParam.lpstrElementName = L"sarasara.wav";
mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)&mParam);
printf("はーぴー:音を流すので指示をだしてね♪\n");
BOOL isLoopFlag = TRUE;
while(isLoopFlag) {
printf("\n");
printf(" [e]nd : 終了 [p]lay : 再生 [s]top : 停止\n");
printf(" [b]ack:巻き戻す [w]ait : 一時停止 [g]o : 停止解除\n");
printf("入力:");
inputKey = getchar();
switch (inputKey) {
case 'p': // play:再生
mciSendCommand(mParam.wDeviceID, MCI_PLAY, 0, 0);
printf("はーぴー:再生しますね!\n");
break;
case 's': // stop:停止
mciSendCommand(mParam.wDeviceID, MCI_STOP, 0, 0);
printf("はーぴー:停止しますね!\n");
break;
case 'w': // wait:一時停止
mciSendCommand(mParam.wDeviceID, MCI_PAUSE, 0, 0);
printf("はーぴー:一時停止しますね!\n");
break;
case 'g': // go:一時停止解除
mciSendCommand(mParam.wDeviceID, MCI_RESUME, 0, 0);
printf("はーぴー:一時停止を解除しますね!\n");
break;
case 'b': // back:巻き戻し
mciSendCommand(mParam.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0);
printf("はーぴー:巻き戻ししますね!\n");
break;
case 'e': // end:再生を終了する
mciSendCommand(mParam.wDeviceID, MCI_CLOSE, 0, 0);
printf("はーぴー:終わりますね!\n");
isLoopFlag = FALSE;
break;
}
while (getchar() != '\n');
}
}
実行すると、下のように「sarasara.wav」を再生したり 一時停止したりをキーボードから制御できる超簡易ミュージックプレイヤーとして動きます。
それでは、MCI コマンドメッセージを送信するために必要となる MCI_OPEN_PARMS 構造体と mciSendCommand 関数について確認していきます。
MCI_OPEN_PARAMS 構造体は、再生したい音声ファイルの名前や種類を指定するときに使用します。
構造体は下のようなメンバを持っています。
typedef struct tagMCI_OPEN_PARMSW {
DWORD_PTR dwCallback; // コールバックウィンドウのハンドル
MCIDEVICEID wDeviceID; // デバイスのID
LPCTSTR lpstrDeviceType; // デバイスの形式
LPCTSTR lpstrElementName; // ファイル名
LPCTSTR lpstrAlias;
} MCI_OPEN_PARMS;
今回のプログラムでは、下のように2つのメンバのみ設定しています。
mParam.lpstrDeviceType = L"WaveAudio";
mParam.lpstrElementName = L"sarasara.wav";
Wave 形式の音声ファイル「sarasara.wav」を開いて欲しい、というパラメータを作成しています。
続いて mciSendCommand 関数の使い方を確認していきます。
mciSendCommand 関数は下のように定義されています。
MCIERROR mciSendCommand(
MCIDEVICEID IDDevice, // 命令を送る先の MCI デバイス番号
UINT uMsg, // 命令の種類(メッセージ)
DWORD_PTR fdwCommand, // 命令のフラグ
DWORD_PTR dwParam // 命令のパラメータ構造体
);
コードを追って確認していきます。
MCI コマンドで音声ファイルを再生するには、まず音を再生するのに使うデバイスと 再生するファイルを指定します。
9 行目の mciSendCommand 関数で、MCIデバイスを開いています。 また、直前に作成した MCI_OPEN_PARMS 構造体を渡して、 指定した音声ファイルを開いています。
int main () {
MCI_OPEN_PARMS mParam;
char inputKey;
mParam.lpstrDeviceType = L"WaveAudio";
mParam.lpstrElementName = L"sarasara.wav";
mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)&mParam);
MCIコマンドが成功すると、渡した MCI_OPEN_PARMS 構造体の変数 mParam.wDeviceID に、 再生に使用する機器のID(MCI デバイスID)がセットされます。
再生する機器が一つついている、よくあるパソコンの構成でしたら、1 がセットされるかと思います。
以降、入力されるキーボードの文字によって、開いた音声ファイルの制御を mciSendCommand を使って行っています。
下のように音声ファイルを制御できます。
mciSendCommand(mParam.wDeviceID, MCI_PLAY, 0, 0); // 再生
mciSendCommand(mParam.wDeviceID, MCI_STOP, 0, 0); // 停止
mciSendCommand(mParam.wDeviceID, MCI_PAUSE, 0, 0); // 一時停止
mciSendCommand(mParam.wDeviceID, MCI_RESUME, 0, 0); // 一時停止の解除
mciSendCommand(mParam.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0); // 再生位置を最初に戻す
mciSendCommand(mParam.wDeviceID, MCI_CLOSE, 0, 0); // MCIデバイス使用を終了
命令一つで簡単に制御できてとても便利です!
mciSendCommand 関数の戻り値に MCIERROR が得られます。 この MCIERROR の数値を確認することで、MCI命令が成功したか、失敗したかを確認できます。
MCIERROR が 0 なら、ちゃんと mciSendCommand 実行に成功しています。
エラーの種類は様々なものがありますが、例えば、”指定したファイルが存在しない” というエラーであれば、 MCIERR_FILE_NOT_FOUND という定数と比較することでチェックできます。
#include <stdio.h>
#include <windows.h>
#pragma comment(lib,"winmm")
int main () {
MCI_OPEN_PARMS mParam;
mParam.lpstrDeviceType = L"WaveAudio";
mParam.lpstrElementName = L"notfound.wav"; // 存在しないファイル
MCIERROR e = mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)&mParam);
if ( e == 0 ) {
printf("はーぴー:音声ファイルを開くことが出来ましたー♪");
} else if ( e == MCIERR_FILE_NOT_FOUND ) {
printf("はーぴー:音声ファイルが開けませんでしたー!");
} else {
printf("はーぴー:なんかダメでした。エラーコードは %lu です!", e);
}
}
こんな感じで、音声ファイルがちゃんと開けたかどうかのエラーチェックが出来ます。
ここまではコマンドメッセージ(mciSendCommand関数)を使って音声ファイルを制御してきました。
続いて、コマンド文字列を使って MCI の制御を行うプログラムを確認してみます。
コマンド文字列を使うには mciSendString 関数を使います。関数は下のように定義されています。
MCIERROR mciSendString(
LPCTSTR lpszCommand, // MCIコマンド文字列
LPTSTR lpszReturnString, // コマンドの結果を受け取る文字列へのポインタ
UINT cchReturn, // lpszReturnString のサイズ
HANDLE hwndCallback // コールバックウィンドウのハンドル
);
この関数を使用した、超簡単な音楽再生プレイヤープログラムは下のようになります。
#include <stdio.h>
#include <windows.h>
#pragma comment(lib,"winmm")
int main() {
char inputKey;
mciSendString(TEXT("open happy.mp3 type Mpegvideo alias happy"), NULL, 0, 0);
printf("はーぴー:音を流すので指示をだしてね♪\n");
BOOL isLoopFlag = TRUE;
while (isLoopFlag) {
printf("\n");
printf(" [e]nd : 終了 [p]lay : 再生 [s]top : 停止\n");
printf(" [b]ack:巻き戻す [w]ait : 一時停止 [g]o : 停止解除\n");
printf("入力:");
inputKey = getchar();
switch (inputKey) {
case 'p': // play:再生
mciSendString(TEXT("play happy"), NULL, 0, 0);
printf("はーぴー:再生しますね!\n");
break;
case 's': // stop:停止
mciSendString(TEXT("stop happy"), NULL, 0, 0);
printf("はーぴー:停止しますね!\n");
break;
case 'w': // wait:一時停止
mciSendString(TEXT("pause happy"), NULL, 0, 0);
printf("はーぴー:一時停止しますね!\n");
break;
case 'g': // go:一時停止解除
mciSendString(TEXT("resume happy"), NULL, 0, 0);
printf("はーぴー:一時停止を解除しますね!\n");
break;
case 'b': // back:巻き戻し
mciSendString(TEXT("seek happy to 00 : 00 : 00"), NULL, 0, 0);
printf("はーぴー:巻き戻ししますね!\n");
break;
case 'e': // end:再生を終了する
mciSendString(TEXT("close happy"), NULL, 0, 0);
printf("はーぴー:終わりますね!\n");
isLoopFlag = FALSE;
break;
}
while (getchar() != '\n');
}
}
実行すると、先ほどのプログラム同様、再生や巻き戻しなどをキーボードから入力して 音楽ファイルの再生を制御できます。
mciSendString にコマンドを渡して、再生や停止などを制御しています。 コマンドの文字列は TEXT("文字列") の形でTEXTマクロを使って適切な型に変換してから渡しています。
MCIコマンドの種類は沢山ありますが、音声再生でつかう代表的なものを下に一覧にしておきます。
MCIコマンド | 用途 | 使い方の例 |
---|---|---|
open | MCIデバイスを開き音声ファイルを読み込む。 音声ファイル種類は type xxx で指定する。 alias xxx で開いたMCIに別名を割り当てできる。 |
open happy.mp3 type Mpegvideo alias happy |
close | MCIデバイスの使用を終了する | close happy |
play | 音声を再生する | play happy |
stop | 音声を停止する | stop happy |
pause | 音声を一時停止する | pause happy |
resume | 音声の一時停止を解除 | resume happy |
seek | 再生位置を指定 | seek happy to 00 : 00 : 00 |
setaudio | 設定変更 音量調整(0~1000) |
setaudio happy volume to 500 |
MCIコマンドで音声ファイルを再生する時は、 再生に必要となる部分のデータを徐々に読み込んで再生していきますので、 メモリの使用量は少なくて済みます。大きなバックミュージックなどを再生する時などに使いやすいです。
MCI コマンドや PlaySound 関数を使う以外にも、音声ファイルを再生する方法は沢山あります。 他にどんな方法があるのかを補足しておきます。
MCI コマンドは Windows 3.1 から導入された仕組みで、非常に古くからある機能です。 Windows Vista 以降からはより音声データや動画の再生二特化した Media Foundation 、略して MF という機能が使用できます。
Media Foundation は Windows SDK と呼ばれる、開発者向けのライブラリをインストールすると利用できます。 今回は Media Foundation については割愛します。
Windows に標準でインストールされている Windows Media Player も Media Foundation を使用しています。
音声にフィルタやエフェクトを付けたり、立体音響の計算ができるなど、非常に高機能です。
Windows API には音声ファイルをもっと詳細に制御するための Windows Multimedia と呼ばれる 動画や音楽を制御する原始的な API(関数)が用意されています。
これらは mmeapi.h というヘッダをインクルードすることで使用できます。
WaveOutXxx / WaveInXxx などの関数群があり、音声データを生成したりエフェクトをかけたりすることが可能です。
DirectX とは Microsoft 社が公開している、ゲームなどでよく使われる音声や動画、3Dデータ処理などを高速に処理できる 機能群です。
Windows10 であれば、DirectX の中には音声を再生することに特化している、DirectX Audio2 という機能があり、 DirectX Audio2 を使用することで、 MIDI や音声を制御する機能が用意されています。 具体的には XBox 360 などのゲーム機内部で使用されています。
DirectX Audio2(細かくはバージョン 2.9)では、先ほど挙げた Media Foundation 機能を使って制御することが推奨されています。
コメント、ありがとうございます。
ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。
Twitter:@NodachiSoft_jpお名前:以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください
お名前: