MCIコマンドによる音楽ファイル再生

概要:MCIコマンドによる再生とよく使う操作

MCI は WAVE 以外の形式である MIDI や MP3 はもちろん、動画形式も扱う事ができます。

様々な形式に対応していて、機能性が高いという事で、
マルチメディア操作に一番よく使われています。

MCIには「MCIウィンドウ、MCI文字列、MCIコマンド」という複数の操作方法が提供されていますが、
一番直接的で、一番よく使われるのはMCIコマンドです。
従って、ここではMCIコマンドについてのみ解説します。

PlaySound 関数とは違い、MCIコマンドは色々と面倒です。
ここでは、動画については扱わず、
また、よく使う操作だけに絞って解説します。

■MCIコマンド

MCIコマンドによる指示は全て mciSendCommand 関数で行います。
統一されているので簡単に思えるかもしれませんが、
それぞれの操作に専用の構造体が定義されていて、設定が面倒です……。

MCIERROR mciSendCommand(
  MCIDEVICEID IDDevice,  // デバイス識別子
  UINT uMsg,          // コマンドメッセージ
  DWORD fdwCommand,   // フラグ
  DWORD dwParam      // パラメータを保持している構造体
);


winmm.lib をリンクする必要があります。

IDDevice には操作したいデバイスの識別子を指定します。MCI_OPEN の時は NULL を指定します。
uMsg には希望の操作を表す定数を指定します。
fdwCommand にはそれぞれの操作に対応した追加情報を指定します。
dwParam にはそれぞれの操作に対応した構造体を指定します。

fdwCommand と dwParam は追加情報です。

uMsg に指定するコマンドメッセージでよく使うのはこれくらいでしょう。

MCI_PLAY …… 再生
MCI_STOP
 …… 停止
MCI_SEEK
 …… 再生開始場所の移動
MCI_PAUSE
 …… 一時停止
MCI_RESUME
 …… 一時停止解除

ここで注意しなければならないのは、MCI_STOP です。
MCI_STOP の意味はデバイスによって異なります。
つまり、再生を停止して先頭に巻き戻してくれるかもしれませんし、
停止するだけかもしれないのです。
再生は現在の位置から行われるので、停止後は次の再生の為に先頭に巻き戻す必要があります。
同じく、MCI_PAUSE についてもデバイス依存です。

また、一時停止は MCI_PLAY でも解除できるかもしれません。

それぞれの操作では必要に応じて、fdwCommand と dwParam を設定します。
難しいのは構造体の設定なので、少しずつ解説していきます。

■MCIデバイスを開く

とりあえずMCIデバイスをオープンしなければ始まりません。
MCIデバイスをオープンするには MCI_OPEN コマンドを使います。
MCI_OPEN では構造体の設定は避けられません。
MCI_OPEN_PARMS という専用の構造体を使います。

typedef struct {
  DWORD_PTR dwCallback;
  MCIDEVICEID wDeviceID;
  LPCSTR lpstrDeviceType;
  LPCSTR lpstrElementName;
  LPCSTR lpstrAlias;
} MCI_OPEN_PARMS;


dwCallBack はコールバックウィンドウのハンドルです。
wDeviceID はデバイス識別子です。
lpstrDeviceType はデバイス形式です。
lpstrElementName はファイル名です。
lpstrAlias はデバイスの別名です。使いません。

この中で最低限設定しなければならないのは、lpstrDeviceType と lpstrElementName です。

lpstrDeviceType に設定できる値はレジストリの
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MCI Extensions
に一覧があります。
私の環境では以下のようになっていました。

他にも、定数を使う方法があります。

コールバックについては次節で解説します。

構造体を設定したら、構造体のどのメンバを設定したかを
mciSendCommand 関数の fdwCommand 引数にフラグで指定します。
フラグで指定したメンバしか参照しないので、フラグを指定しなければ構造体は必要ありません。

MCI_OPEN_TYPE …… MCI_OPEN_PARMS の lpstrDeviceType に形式を表す文字列か定数が設定されている
MCI_OPEN_TYPE_ID
 …… MCI_OPEN_PARMS の lpstrDeviceType は定数である
MCI_OPEN_ELEMENT
 …… MCI_OPEN_PARMS の lpstrElementName にファイル名が設定されている

lpstrDeviceType に定数を設定した場合は、
MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID と指定しなければならない事に注意して下さい。
定数にはない形式もありますし、フラグが一つ多くなるので、文字列で指定した方が良いでしょう。

MCI_OPEN に関係したフラグは他にも大量に定義されていますが、あまり使わないのでここでは取り上げません。
更に、それぞれの操作についても大量のフラグが定義されています。

それでは、WAVEファイルをオープンするプログラムを組んでみましょう。

// winmm.lib をリンクする
#pragma comment(lib,"winmm")

static MCI_OPEN_PARMS mop;

mop.lpstrDeviceType="WaveAudio";
mop.lpstrElementName="Windows XP Startup.wav";
mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,(DWORD)&mop);

MCI_OPEN が成功すると、
MCI_OPEN_PARMS 構造体の wDeviceID メンバにデバイス識別子が設定されます。

以降の操作はこのデバイス識別子を対象にして行います。
従って、MCI_OPEN_PARMS 構造体型の変数は静的である必要があります。

■再生&MCIデバイスを閉じる

再生は MCI_PLAY コマンドで行います。
普通に再生するだけなら構造体を設定する必要はないので、フラグも指定しません。

mciSendCommand(mop.wDeviceID,MCI_PLAY,0,0);

操作対象として MCI_OPEN で取得したデバイス識別子を指定している事に注目して下さい。

クローズは MCI_CLOSE コマンドで行います。
こちらも特別な操作は必要ないので、フラグと構造体は設定しません。

そもそも MCI_CLOSE には専用の構造体が無く、必要ならば全コマンド共通の構造体を使います。
それぞれの構造体については次節でもう少し詳しく解説します。

mciSendCommand(mop.wDeviceID,MCI_CLOSE,0,0);

★☆ ソースファイル表示 ☆★

難しいのは星の数ほどある設定項目の意味を理解する事で、プログラム自体は簡単ですね。
MIDI や MP3 , WMA 等も再生させてみて下さい。

■よく使うコマンド

先程のプログラムは「オープン→再生→クローズ」という最低限の操作しかしていませんでしたが、
停止後の巻き戻しは欠かせませんし、一時停止もよく使うでしょう。

以下のプログラムでは、よく使う操作を実装しています。
本来は一緒に実行すべき操作も個別に割り当てているので、手動で動作を確認してみましょう。

case WM_KEYDOWN:
    switch(wParam){
        case 'A':    //再生
            mciSendCommand(mop.wDeviceID,MCI_PLAY,0,0);
            return 0;
        case 'S':    //停止
            mciSendCommand(mop.wDeviceID,MCI_STOP,0,0);
            return 0;
        case 'D':    //巻き戻し
            mciSendCommand(mop.wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,0);
            return 0;
        case 'F':    //一時停止
            mciSendCommand(mop.wDeviceID,MCI_PAUSE,0,0);
            return 0;
        case 'G':    //一時停止解除
            mciSendCommand(mop.wDeviceID,MCI_RESUME,0,0);
            return 0;
        }
    return 0;

停止の動作が不定なので、本来、停止と巻き戻しはセットで実行するべきです。

mciSendCommand(mop.wDeviceID,MCI_STOP,0,0);
mciSendCommand(mop.wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,0);


また、一時停止は MCI_PLAY でも解除できるかもしれません。

MCI_SEEK のフラグ MCI_SEEK_TO_START は先頭にシークする事を意味しています。
MCI_SEEK_TO_END を指定すれば最後にシークします。
任意の位置にシークする事もできますが、それは次節で解説します。

★☆ ソースファイル表示 ☆★

■MCIの欠点

MCI はメモリにあるWAVE等を操作する事ができません。
リソースからの操作もできません。
ファイルだけです。
従って、リソースデータを操作するには、一時ファイルに書き出す必要があります。

また、オープンしたスレッド以外からは操作できません。
他のスレッドから操作したい場合は、オープンしたスレッドに独自メッセージを投げて、
そちらで操作してもらいます。
特にこちらは見落としやすいので注意して下さい。


戻る / ホーム