●オーディオプレイヤ開発記 その21
それでは、bass.dll を使った音声ファイルの再生を管理する CBass クラスを作ってみます。
とりあえず、追加の依存ファイルに bass.lib を追加します。それで、bass.dll を使うアプリケーションでは、bass.h ファイルをインクルードする必要があるんですが、Bass.h という名前を CBass クラスのヘッダファイルに使いたいので、もともとの bass.h ファイルの名前を bassinc.h などに変更しておきます。
それでは、CBass クラスを作成します。例によって、順次、必要な機能だけを追加していきます。
//----------------------------------------------------------------------------
// Bass.h : bass.dll の管理を行う
//----------------------------------------------------------------------------
#ifndef BassH
#define BassH
#include "bassinc.h"
//----------------------------------------------------------------------------
// bass.dll の管理を行うクラス
//----------------------------------------------------------------------------
class CBass
{
public: // 関数
CBass(): m_hStream(0) { }
virtual ~CBass() { BASS_Free(); }
virtual QWORD ChannelGetLength() {
return BASS_ChannelGetLength(m_hStream);
}
virtual QWORD ChannelGetPosition() {
return BASS_ChannelGetPosition(m_hStream);
}
virtual float ChannelGetSecondsLength() {
return BASS_ChannelBytes2Seconds(m_hStream, ChannelGetLength());
}
virtual float ChannelGetSecondsPosition() {
return BASS_ChannelBytes2Seconds(m_hStream, ChannelGetPosition());
}
virtual BOOL ChannelPause() {
return BASS_ChannelPause(m_hStream);
}
virtual BOOL ChannelPlay() {
return BASS_ChannelPlay(m_hStream, FALSE);
}
virtual BOOL Init(HWND hWnd) {
return BASS_Init(-1, 44100, 0, hWnd, NULL);
}
virtual BOOL Pause() {
return BASS_Pause();
}
virtual BOOL Start() {
return BASS_Start();
}
virtual BOOL StreamCreateFile(LPCTSTR lpFilePath) {
StreamFree();
m_hStream = BASS_StreamCreateFile(FALSE, lpFilePath, 0, 0, 0);
return m_hStream ? TRUE : FALSE;
}
virtual void StreamFree() {
if(m_hStream) BASS_StreamFree(m_hStream), m_hStream = 0;
}
protected: // メンバ変数
HSTREAM m_hStream;
};
//----------------------------------------------------------------------------
#endif
完全にラップを被せてるだけですね。
CMainWnd クラスに CBass m_bass; メンバ変数を追加し、OnCreate 関数内で m_bass.Init(m_hWnd); と初期化するようにしたら、次は ファイル → 開く メニューが選択された場合に「ファイルを開く」ダイアログを表示し、指定された音声ファイルを再生するようにします。
メニューが選ばれると CMenu_MainWnd クラスの OnCommand 関数が呼ばれるので、そこから OnOpenFileMenuSelected 関数を呼ぶようにします。
//----------------------------------------------------------------------------
// メニューが選択された
//----------------------------------------------------------------------------
void CMenu_MainWnd::OnCommand(int id, HWND/* hwndCtl*/, UINT/* codeNotify*/)
{
switch(id)
{
case ID_OPENFILE:
OnOpenFileMenuSelected();
break;
case ID_XXXX:
OnXxxxMenuSelected();
break;
}
}
//----------------------------------------------------------------------------
// ファイル → 開くメニューが選択された
//----------------------------------------------------------------------------
void CMenu_MainWnd::OnOpenFileMenuSelected()
{
m_rMainWnd.OpenFile();
}
//----------------------------------------------------------------------------
CMainWnd::OpenFile 関数の方も追加しておきます。
//----------------------------------------------------------------------------
// ファイルを開く
//----------------------------------------------------------------------------
void CMainWnd::OpenFile()
{
TCHAR filePath[MAX_PATH] = "";
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hInstance = GetModuleHandle(NULL);
ofn.hwndOwner = m_hWnd;
ofn.lpstrFilter = TEXT("再生可能な音声ファイル(*.wav;*.mp3;*.ogg)\0*.wav;*.mp3;*.ogg\0すべてのファイル (*.*)\0*.*\0\0");
ofn.lpstrFile = filePath;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST;
if(GetOpenFileName(&ofn))
{
m_bass.StreamCreateFile(filePath);
m_bass.ChannelPlay();
m_timeLabel.SetTime((int)m_bass.ChannelGetSecondsPosition(), (int)m_bass.ChannelGetSecondsLength());
m_timeSlider.SetTime((LONG)m_bass.ChannelGetPosition(), (LONG)m_bass.ChannelGetLength());
}
}
//----------------------------------------------------------------------------
これで、指定された音声ファイルが再生されるようになりました。ここまでのソースコードはこちら ( Hayaemon20060226_src.lzh ) 。
次は、ファイルの再生位置にあわせて、再生位置表示用ラベルやスライダを変更するようにします。これは、0.5 秒間隔のタイマーでやることにします。まず、CWnd クラスに SetTimer, KillTimer, OnTimer 関数を追加し、WndProc から OnTimer に分岐するようにします。
virtual void KillTimer(UINT_PTR nIDEvent) {
::KillTimer(m_hWnd, nIDEvent);
}
virtual void SetTimer(UINT_PTR nIDEvent, UINT nElapse) {
::SetTimer(m_hWnd, nIDEvent, nElapse, NULL);
}
virtual void OnTimer(UINT id) {
WindowProc(WM_TIMER, (WPARAM)id, 0);
}
// CWnd::WndProc 関数内
case WM_TIMER:
pWnd->OnTimer((UINT)wParam);
return 0;
それで、CWnd::OnTimer 関数をオーバーライドした CMainWnd::OnTimer 関数を追加し、ファイルが開かれた時点で、SetTimer(1, 500); とするようにしておきます。
virtual void OnTimer(UINT id) {
m_timeLabel.SetTime(m_bass.ChannelGetSecondsPosition(), m_bass.ChannelGetSecondsLength());
m_timeSlider.SetThumbPos(m_bass.ChannelGetPosition());
CFrameWnd::OnTimer(id);
}
これで、ファイルの再生位置にあわせて、再生位置表示用ラベルやスライダが変更されるようになりました。ここまでのソースコードはこちら ( Hayaemon20060226_2_src.lzh ) 。
続いて、ツールバーの「ファイルを開く」ボタンが押された場合にも、「ファイルを開く」ダイアログを出すようにします。まず、CMainWnd::OnCommand 関数からメニューやツールバーの OnCommand 関数を呼び出すようにします。
virtual void OnCommand(int id, HWND hwndCtl, UINT codeNotify) {
if(!hwndCtl)
m_menu.OnCommand(id, hwndCtl, codeNotify);
else if(hwndCtl == (HWND)m_toolBar)
m_toolBar.OnCommand(id, hwndCtl, codeNotify);
CFrameWnd::OnCommand(id, hwndCtl, codeNotify);
}
CToolBar_MainWnd クラスに OnCommand, OnOpenFileButtonSelected 関数を追加しておきます。
//----------------------------------------------------------------------------
// ファイルを開くボタンが選択された
//----------------------------------------------------------------------------
void CToolBar_MainWnd::OnOpenFileButtonSelected()
{
m_rMainWnd.OpenFile();
}
//----------------------------------------------------------------------------
// ボタンが選択された
//----------------------------------------------------------------------------
void CToolBar_MainWnd::OnCommand(int id, HWND/* hwndCtl*/, UINT/* codeNotify*/)
{
switch(id)
{
case ID_OPENFILE:
OnOpenFileButtonSelected();
break;
}
}
//----------------------------------------------------------------------------
これで、ツールバーの「ファイルを開く」ボタンが押された場合にも、「ファイルを開く」ダイアログが出るようになりました。ここまでのソースコードはこちら ( Hayaemon20060226_3_src.lzh ) 。