MCIによるWAVファイルの再生


MCI(メディア コントロール インターフェイス)を使用することで WAV ファイルや MIDI ファイル等を再生することができます。
mciSendCommand 関数で再生〜停止するには、MCI_OPEN、MCI_PLAY、MCI_STOP、MCI_CLOSE の順でメッセージを送ります。
Windows Media Player のバージョンによりMP3ファイルなども再生できます。

再生〜停止までの mciSendCommand のメッセージ

メッセージ 機能
MCI_OPEN デバイスまたはファイルを初期化します。
MCI_PLAY 出力データの送信を開始するようにデバイスに指示します。
MCI_STOP すべての再生または記録シーケンスを停止し、すべての再生バッファをアンロードし、ビデオイメージの表示を停止します。
MCI_CLOSE デバイスやファイルへのアクセスを解放します。


Sample code
#include <windows.h>
#include <tchar.h>
#include <mmsystem.h>

#pragma comment(lib, "winmm.lib")

#define IDM_OPEN  100
#define IDM_CLOSE 101
#define IDM_EXIT  102

#define AllocMemory(s) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, s)
#define FreeMemory(p)  HeapFree(GetProcessHeap(), 0, p)

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void ShowMciErrorMessage(HWND hwnd, MCIERROR mciError);

HINSTANCE hInst;
LPCTSTR lpszAppName   = TEXT("MyApp");
LPCTSTR lpszAppTitle  = TEXT("MyApp");

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    MSG        msg = {0};
    HWND       hWnd;
    WNDCLASSEX wc = {0};
    
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    UNREFERENCED_PARAMETER(nCmdShow);
    
    //メインウィンドウクラス登録
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = lpszAppName;
    wc.hIconSm       = NULL;
    if(RegisterClassEx(&wc) == 0) {
        return 0;
    }
    
    hInst = hInstance;
    
    //メニュー作成
    HMENU hMenu = CreateMenu();
    HMENU hPopMenu = CreatePopupMenu();
    AppendMenu(hPopMenu, MF_STRING, IDM_OPEN, TEXT("&Open"));
    AppendMenu(hPopMenu, MF_STRING, IDM_CLOSE, TEXT("&Close"));
    AppendMenu(hPopMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hPopMenu, MF_STRING, IDM_EXIT, TEXT("&Exit"));
    AppendMenu(hMenu, MF_POPUP | MF_STRING, reinterpret_cast<UINT_PTR>(hPopMenu), TEXT("&File"));
    
    //メインウインドウ作成
    hWnd = CreateWindow(lpszAppName, lpszAppTitle, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, hMenu, hInstance, NULL
    );
    if(hWnd == NULL) {
        return 0;
    }
    
    ShowWindow(hWnd, SW_SHOWDEFAULT);
    UpdateWindow(hWnd);
    
    //メイン メッセージ ループ
    while(GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg); 
        DispatchMessage(&msg);
    }
    return static_cast<int>(msg.wParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static MCIDEVICEID mciDeviceID = 0;
    static MCI_PLAY_PARMS mciPlayParms = {0};
    static OPENFILENAME ofn = {0};
    
    switch(uMsg) {
        case WM_COMMAND:
            switch(LOWORD(wParam)) {
                case IDM_OPEN: //WAVファイル再生
                    {
                        //WAVファイルを選択
                        if(!GetOpenFileName(&ofn)) {
                            break;
                        }
                        
                        //MCIデバイスのオープン
                        SendMessage(hWnd, WM_COMMAND, IDM_CLOSE, 0);
                        MCI_OPEN_PARMS mciOpenParms = {0};
                        DWORD fdwCommand = MCI_WAIT | MCI_OPEN_ALIAS | MCI_OPEN_ELEMENT;
                        MCIERROR mciError = 0;
                        TCHAR szAlias[MAX_PATH * sizeof(WCHAR) / sizeof(TCHAR) + 10];
                        
                        mciOpenParms.lpstrElementName = ofn.lpstrFile;
                        mciOpenParms.lpstrAlias = szAlias;
                        int i = 0;
                        wsprintf(szAlias, TEXT("%s_%x"), ofn.lpstrFile, i++);
                        mciError = mciSendCommand(0, MCI_OPEN, fdwCommand, reinterpret_cast<DWORD_PTR>(&mciOpenParms));
                        while(mciError == MCIERR_DUPLICATE_ALIAS) {
                            wsprintf(szAlias, TEXT("%s_%x"), ofn.lpstrFile, i++);
                            mciError = mciSendCommand(0, MCI_OPEN, fdwCommand, reinterpret_cast<DWORD_PTR>(&mciOpenParms));
                        }
                        if(mciError > 0) { //エラー
                            ShowMciErrorMessage(hWnd, mciError);
                            break;
                        }
                        mciDeviceID = mciOpenParms.wDeviceID;
                        //再生
                        mciPlayParms.dwCallback = reinterpret_cast<DWORD_PTR>(hWnd);
                        mciPlayParms.dwFrom = 0;
                        mciError = mciSendCommand(mciDeviceID, MCI_PLAY, MCI_FROM | MCI_NOTIFY, reinterpret_cast<DWORD_PTR>(&mciPlayParms));
                        if(mciError > 0) { //エラー
                            ShowMciErrorMessage(hWnd, mciError);
                            break;
                        }
                    }
                    break;
                case IDM_CLOSE: //停止
                    {
                        if(mciDeviceID > 0) {
                            //停止
                            mciSendCommand(mciDeviceID, MCI_STOP, MCI_WAIT, 0);
                            //MCIデバイスのクローズ
                            mciSendCommand(mciDeviceID, MCI_CLOSE, MCI_WAIT, 0);
                            mciDeviceID = 0;
                            ZeroMemory(&mciPlayParms, sizeof(MCI_PLAY_PARMS));
                        }
                    }
                    break;
                case IDM_EXIT: //終了
                    SendMessage(hWnd, WM_CLOSE, 0, 0);
                    break;
            }
            break;
        case MM_MCINOTIFY:
            {
                //再生が終了したらリピート
                if(wParam == MCI_NOTIFY_SUCCESSFUL) {
                    mciPlayParms.dwFrom = 0;
                    MCIERROR mciError = mciSendCommand(mciDeviceID, MCI_PLAY, MCI_FROM | MCI_NOTIFY, reinterpret_cast<DWORD_PTR>(&mciPlayParms));
                    if(mciError > 0) { //エラー
                        ShowMciErrorMessage(hWnd, mciError);
                        break;
                    }
                }
            }
            break;
        case WM_CREATE:
            {
                //初期化
                ofn.lStructSize    = sizeof(OPENFILENAME);
                ofn.hwndOwner      = hWnd; 
                ofn.lpstrFile      = static_cast<LPTSTR>(AllocMemory(sizeof(TCHAR) * (MAX_PATH * sizeof(WCHAR) / sizeof(TCHAR))));
                ofn.nMaxFile       = MAX_PATH * sizeof(WCHAR) / sizeof(TCHAR);
                ofn.lpstrFileTitle = static_cast<LPTSTR>(AllocMemory(sizeof(TCHAR) * (MAX_PATH * sizeof(WCHAR) / sizeof(TCHAR))));
                ofn.nMaxFileTitle  = MAX_PATH * sizeof(WCHAR) / sizeof(TCHAR);
                ofn.lpstrFilter    = TEXT("WAV ファイル(*.wav)\0*.wav\0");
                ofn.lpstrDefExt    = TEXT("wav");
                ofn.Flags          = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
                if(ofn.lpstrFile == NULL || ofn.lpstrFileTitle == NULL) {
                    return -1;
                }
            }
            break;
        case WM_DESTROY:
            {
                SendMessage(hWnd, WM_COMMAND, IDM_CLOSE, 0);
                
                if(ofn.lpstrFile != NULL) {
                    FreeMemory(ofn.lpstrFile);
                }
                if(ofn.lpstrFileTitle != NULL) {
                    FreeMemory(ofn.lpstrFileTitle);
                }
                
                PostQuitMessage(0);
            }
            break;
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    
    return 0;
}

void ShowMciErrorMessage(HWND hwnd, MCIERROR mciError)
{
    TCHAR szErrorMsg[MAXERRORLENGTH];
    if(mciGetErrorString(mciError, szErrorMsg, sizeof(szErrorMsg))) {
        MessageBox(hwnd, szErrorMsg, lpszAppTitle, MB_ICONEXCLAMATION);
    }
}

一覧メニューへ