・音楽プレーヤ作成
目的がmciSendCommandの使い方なので、できるだけ簡単にするために VC++ 2005 MFCでダイアログ形式のアプリで作ります。 また、対応できる形式はWave、MIDI、MP3とします。Visual Studioのツールバーの ファイル(F)→新規作成(N)→プロジェクト(P)で新しいプロジェクト ダイアログボックスで以下のように設定してください。
プロジェクトの種類(P) ・・・ Visual C++ テンプレート(T) ・・・ MFCアプリケーション プロジェクト名 ・・・ 任意 (今回はSoundsで説明します)
OKをクリックするとアプリケーションウィザードが始まります。次をクリックしてください。
<アプリケーションの種類>
・アプリケーションの種類・・・ダイアログベースにチェック ドキュメントビューカーキテクチャのチェックをはずす ユニコードライブラリを使用するのチェックをはずす ・プロジェクト形式 ・・・MFC標準 ・MFCの使用法 ・・・共有DLLでMFC使用 (次をクリック)
<ユーザインターフェイス機能>
・システムメニューのみにチェック ・ダイアログタイトル・・・任意
<高度な機能>
・すべてのチェックをはずす
<生成されてクラス>
CWinAppの派生クラス・・・CSoundsApp CDialogの派生クラス・・・CSoundsDlg ヘッダファイル・実装ファイルを確認して完了をクリック
・mciSendCommandラッパクラス作成
前項でスケルトンができたのでとりあえずビルドしてください。 2つのクラスができてますが今はまだ手をつけません。まず、音楽再生を扱う mciSendCommandのラッパクラスを先に作成します。ツールバーの プロジェクト(P)→クラスの追加(C)でC++クラスをCSoundという クラス名で作成してください。
Sound.hとSound.cppができているので以下のように書いてください。
//Sound.h ヘッダファイル/////////////////////// // #pragma once #include "Mmsystem.h" //MIDI WAV MP3の音源再生用クラス class CSound { public: enum DEV_TYPE {MIDI, WAV, MP3}; //デバイスの種類 //メンバ変数/////////////////////////////////////////// protected: MCI_OPEN_PARMS m_mop; //デバイスID取得等 //メンバ関数////////////////////////////////// private: CSound(const CSound &obj); //コピーコンストラクタ public: CSound(); //コンストラクタ virtual ~CSound(); //デストラクタ //デバイスOpen pPath : 音源のパス // eType : 音源の種類(MIDI, WAV, MP3) BOOL Open(LPCTSTR pPath, CSound::DEV_TYPE eType); //デバイスの状態取得 //戻値 MCI_MODE_NOT_READY, MCI_MODE_PAUSE, MCI_MODE_PLAY, MCI_MODE_STOP, // MCI_MODE_OPEN, MCI_MODE_RECORD, MCI_MODE_SEEK DWORD_PTR Status() const; //現在の位置取得現在の位置を0-1000で返す(失敗時-1) int CurrentPosition() const; //再生 hWnd : MM_MCINOTIFYメッセージの送信先Windowハンドル // iFrom : 0-1000までの値 // iTo : 0-1000までの値 BOOL Play(HWND hWnd = 0, int iFrom = -1, int iTo = -1); //再生停止 BOOL Stop(); //デバイスClose BOOL Close(); //現在位置の移動dwPos : 0-1000の範囲で現在位置を変更) BOOL Seek(DWORD dwPos = 0); //一時停止 BOOL Pause(); //再開 BOOL Resume(); }; |
//Sound.cpp 実装ファイル/////////////////////// // #include "StdAfx.h" #include "Sound.h" //#include "Mmsystem.h" #pragma comment(lib, "Winmm.lib") //コンストラクタ CSound::CSound() { ::ZeroMemory((PVOID)&m_mop, sizeof(m_mop)); } //コピーコンストラクタ CSound::CSound(const CSound & obj) { } //デストラクタ CSound::~CSound() { Close(); } //デバイスのオープン //引数 pPath : 音源ファイルのパス // eType : デバイスの種類(MIDI, WAV, MP3) //戻値 成功時TRUE BOOL CSound::Open(LPCTSTR pPath, CSound::DEV_TYPE eType) { LPCTSTR pType[] = {_T("Sequencer"), _T("WaveAudio"), _T("MPEGVideo")}; //現在のデバイスClose Close(); //ファイルパス文字数がの時 if (!lstrlen(pPath)) return FALSE; //mciSendCommandでMCI_OPENコマンド発行 m_mop.lpstrDeviceType = pType[eType]; //"Sequencer" "WaveAudio" "MPEGVideo" m_mop.lpstrElementName = pPath; if (::mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, reinterpret_cast<DWORD_PTR>(&m_mop)) ) return FALSE; //現在位置の単位をミリ秒単位に設定 MCI_SET_PARMS msp; ::ZeroMemory((PVOID)&msp, sizeof(msp)); msp.dwTimeFormat = MCI_FORMAT_MILLISECONDS; ::mciSendCommand(m_mop.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&msp); return TRUE; } //デバイスの状態取得 //戻値 MCI_MODE_NOT_READY, MCI_MODE_PAUSE, MCI_MODE_PLAY, MCI_MODE_STOP, // MCI_MODE_OPEN, MCI_MODE_RECORD, MCI_MODE_SEEKまたは 0 DWORD_PTR CSound::Status() const { MCI_STATUS_PARMS msp; ::ZeroMemory((PVOID)&msp, sizeof(msp)); msp.dwItem = MCI_STATUS_MODE; if (::mciSendCommand(m_mop.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&msp)) return 0; return msp.dwReturn; } //現在位置の取得 //戻値0-1000の範囲で現在演奏位置を返す(失敗時は-1) int CSound::CurrentPosition() const { MCI_STATUS_PARMS msp_cur; MCI_STATUS_PARMS msp_total; //現在の位置をミリ秒単位で取得 ::ZeroMemory((PVOID)&msp_cur, sizeof(msp_cur)); msp_cur.dwItem = MCI_STATUS_POSITION; if (::mciSendCommand(m_mop.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&msp_cur) ) return -1; //全体の長さをミリ秒単位で取得 ::ZeroMemory((PVOID)&msp_total, sizeof(msp_total)); msp_total.dwItem = MCI_STATUS_LENGTH; if (::mciSendCommand(m_mop.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&msp_total) ) return -1; double dPercent = (double)msp_cur.dwReturn / msp_total.dwReturn; return (int)(dPercent * 1000); } //演奏 //引数 hWnd : 終了時/中止時などに発生するMM_MCINOTIFYメッセージの送信先ウィンドウハンドル // iFrom : 開始位置(0-1000の範囲) // iTo : 終了位置(0-1000の範囲) //戻値 mciSendCommandの実行が成功時TRUE BOOL CSound::Play(HWND hWnd /*= 0*/, int iFrom /*= -1*/, int iTo /*= -1*/) { MCI_STATUS_PARMS msp; MCI_PLAY_PARMS mpp; BOOL bFrom = ((iFrom < 0) || (iFrom > 1000)) ? FALSE : TRUE; BOOL bTo = ((iTo < 0) || (iTo > 1000)) ? FALSE : TRUE; ::ZeroMemory((PVOID)&mpp, sizeof(mpp)); if (bFrom || bTo) { //全体の長さをミリ秒単位で取得 ::ZeroMemory((PVOID)&msp, sizeof(msp)); msp.dwItem = MCI_STATUS_LENGTH; if (::mciSendCommand(m_mop.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&msp) ) { bFrom = FALSE; bTo = FALSE; } //開始位置の特定 if (bFrom) { double dPercent = (double)iFrom / 1000; mpp.dwFrom = static_cast<DWORD>(msp.dwReturn * dPercent); } //終了位置の特定 if (bTo) { double dPercent = (double)iTo / 1000; mpp.dwTo = static_cast<DWORD>(msp.dwReturn * dPercent); } } mpp.dwCallback = (DWORD_PTR)hWnd; return !::mciSendCommand(m_mop.wDeviceID, MCI_PLAY, MCI_NOTIFY | (bFrom ? MCI_FROM : 0) | (bTo ? MCI_TO :0), reinterpret_cast<DWORD_PTR>(&mpp)); } //演奏停止 BOOL CSound::Stop() { if (::mciSendCommand(m_mop.wDeviceID, MCI_STOP, 0, 0)) return FALSE; return !::mciSendCommand(m_mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0); } //デバイスClose BOOL CSound::Close() { if (Status() == MCI_MODE_PLAY || Status() == MCI_MODE_PAUSE) Stop(); MCIERROR nRet = ::mciSendCommand(m_mop.wDeviceID, MCI_CLOSE, 0, 0); ::ZeroMemory((PVOID)&m_mop, sizeof(m_mop)); return !nRet; } //現在位置の検索移動 //引数 dwPos : 移動する位置を-1000までで設定 //戻値 位置変更が成功TRUE BOOL CSound::Seek(DWORD dwPos /*=0*/) { DWORD dwCurPos; //移動すべき位置(ミリ秒単位) MCI_STATUS_PARMS msp; MCI_SEEK_PARMS mseekp; const DWORD DIST = 200; //Wait間隔 const DWORD MAXWAIT = 5000; //最大Wait時間 //範囲外のとき if (dwPos < 0 || dwPos > 1000) return FALSE; if (!dwPos) //dwPosがの時最初に移す { if (::mciSendCommand(m_mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, 0)) return FALSE; } else if (dwPos == 1000) //dwPosがの時最後に移す { if (::mciSendCommand(m_mop.wDeviceID, MCI_SEEK, MCI_SEEK_TO_END, 0)) return FALSE; } else if (dwPos > 1000) //0-1000の範囲にない時 { return FALSE; } else { //全体の長さを取得(ミリ秒単位) ::ZeroMemory((PVOID)&msp, sizeof(msp)); msp.dwItem = MCI_STATUS_LENGTH; if (::mciSendCommand(m_mop.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&msp) ) return FALSE; //移動すべき位置をdwCurPosに取得 dwCurPos = static_cast<DWORD>(msp.dwReturn) * dwPos / 1000; //現在位置を移動 ::ZeroMemory((PVOID)&mseekp, sizeof(mseekp)); mseekp.dwTo = dwCurPos; if (::mciSendCommand(m_mop.wDeviceID, MCI_SEEK, MCI_TO, (DWORD_PTR)&mseekp)) return FALSE; } //Seek完了までWait DWORD dwCnt = 0; while ((Status() == MCI_MODE_SEEK) && (dwCnt < MAXWAIT)) { dwCnt += DIST; ::Sleep(DIST); } return dwCnt < MAXWAIT ? TRUE : FALSE; } //一時停止 BOOL CSound::Pause() { if (Status() != MCI_MODE_PLAY) return FALSE; return !::mciSendCommand(m_mop.wDeviceID, MCI_PAUSE, 0, 0); } //再開 BOOL CSound::Resume() { if (Status() != MCI_MODE_PAUSE) return FALSE; return !::mciSendCommand(m_mop.wDeviceID, MCI_RESUME, 0, 0); } |
CSoundクラスのメンバ関数がmciSendCommandの各コマンドの使い方に対応しているので 確認してください。このクラスを使って次に音楽再生プレーヤをつくります。