33:BGMを再生しよう
wave形式は波形データがそのままはいっているため、数分だけ再生される音楽だとしても、そのファイルサイズは莫大なものになってしまいます。mp3やaacなどといった圧縮された音楽ファイルでも、waveデータに変換できるのであればDirectSoundでも再生できるのですが、そのための変換処理は自前で用意しなければなりません。そこでBGMの再生には、メディアファイルから直接音楽を再生できるDirectShowを使いたいと思います。実はこのメディアファイルを再生するためのAPIは最新バージョンのDirectXでは搭載されなくなり、ウィンドウズ標準のAPIへと移行されています。そのため、DirectShowを利用するためには最新のDirectX SDKではなく、Windows Server 2003以降に対応したWindows SDKをインストールする必要があります(Visual C++ 2008では搭載済み)。
#include <strmif.h>
#include <control.h>
#include <uuids.h>
#pragma comment (lib,"strmiids.lib")
CGameObject game;
CoInitialize(NULL);
game.Initialize(hWnd, hInstance);
CSound::CreateDirectSound(hWnd);
/* タスクに追加する処理 */
ShowWindow(hWnd, nCmdShow);
MSG msg;
while(TRUE){
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){
if(msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}else{
game.DoAllTasks();
}
}
game.Uninitialize();
CSound::ReleaseDirectSound();
CoUninitialize();
HRESULT hr = CoCreateInstance(
CLSID_FilterGraph, // COMの識別子
NULL, // 特別に取得する情報はないのでNULL
CLSCTX_INPROC_SERVER, // このプログラム内でのみ使うことを指定
IID_IGraphBuilder, // 取得するインターフェース
(LPVOID*)&pBuilder); // 格納先
if(FAILED(hr)){
DXTRACE_MSG(_T("IGraphBuilderの作成に失敗しました"));
return;
}
#ifdef _UNICODE
pBuilder->RenderFile(filename, NULL);
#else
wchar_t wfname[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, filename, -1, wfname, MAX_PATH);
pBuilder->RenderFile(wfname, NULL);
#endif
pBuilder->QueryInterface(IID_IMediaControl, (LPVOID*)&pMediaCtrl);
pBuilder->QueryInterface(IID_IMediaSeeking, (LPVOID*)&pMediaSeeking);
pBuilder->QueryInterface(IID_IBasicAudio, (LPVOID*)&pBasicAudio);
以上をふまえて作成したサンプルプログラムはこのようになります。
#pragma once
#include "gameobject.h"
#include <strmif.h>
#include <control.h>
#include <uuids.h>
#pragma comment (lib,"strmiids.lib")
class CBGMusic : public CGameObject
{
private:
IGraphBuilder *pBuilder;
IMediaControl *pMediaCtrl;
IMediaSeeking *pMediaSeeking;
IBasicAudio *pBasicAudio;
void InitializeBGM();
void Release();
public:
CBGMusic();
CBGMusic(LPCTSTR filename);
~CBGMusic();
void Load(LPCTSTR filename);
void Play();
void Stop();
};
#include "BGMusic.h"
void CBGMusic::InitializeBGM()
{
pBuilder = NULL;
pMediaCtrl = NULL;
pMediaSeeking = NULL;
pBasicAudio = NULL;
bLoop = FALSE;
bFading = FALSE;
}
void CBGMusic::Release()
{
RELEASE(pBasicAudio);
RELEASE(pMediaSeeking);
RELEASE(pMediaCtrl);
RELEASE(pBuilder);
}
CBGMusic::CBGMusic()
{
InitializeBGM();
}
CBGMusic::CBGMusic(LPCTSTR filename)
{
InitializeBGM();
Load(filename);
}
CBGMusic::~CBGMusic()
{
Release();
}
void CBGMusic::Load(LPCTSTR filename)
{
Release();
HRESULT hr = CoCreateInstance(
CLSID_FilterGraph, // COMの識別子
NULL, // 特別に取得する情報はないのでNULL
CLSCTX_INPROC_SERVER, // このプログラム内でのみ使うことを指定
IID_IGraphBuilder, // 取得するインターフェース
(LPVOID*)&pBuilder); // 格納先
if(FAILED(hr)){
DXTRACE_MSG(_T("IGraphBuilderの作成に失敗しました"));
return;
}
#ifdef _UNICODE
pBuilder->RenderFile(filename, NULL);
#else
wchar_t wfname[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, filename, -1, wfname, MAX_PATH);
pBuilder->RenderFile(wfname, NULL);
#endif
pBuilder->QueryInterface(IID_IMediaControl, (LPVOID*)&pMediaCtrl);
pBuilder->QueryInterface(IID_IMediaSeeking, (LPVOID*)&pMediaSeeking);
pBuilder->QueryInterface(IID_IBasicAudio, (LPVOID*)&pBasicAudio);
}
void CBGMusic::Play(BOOL loop)
{
if(pMediaCtrl) pMediaCtrl->Run();
}
void CBGMusic::Stop()
{
if(pMediaCtrl) pMediaCtrl->Stop();
}