ホーム > サンプルプログラム > OggVorbisの再生

/*------------------------------------------------------------
    DirectMusic サンプルプログラム

    2007 Copyright(C) Toru

    ToruのDirectXプログラミング講座
        URL  : http://toruweb.web.fc2.com/
        Mail : toru_website@hotmail.com
--------------------------------------------------------------*/
#define STRICT


// インクルード
//#include 
#include "OggVorbis.h"
#include 
#include 


// インターフェイス解放
#define RELEASE(p)  { if(p){(p)->Release();p=NULL;} }


// アプリケーション情報
HINSTANCE   g_hInst;                                    // インスタンスハンドル
HWND        g_hWnd;                                     // ウインドウハンドル
CHAR        g_szAppName[] = "DirectMusic Sample";       // アプリケーション名


// DirectMusicの変数
IDirectMusicPerformance8*   g_lpPerformance = NULL;     // パフォーマンス
IDirectMusicLoader8*        g_lpLoader      = NULL;     // ローダー
IDirectMusicSegment8*       g_lpSegment     = NULL;     // セグメント
CHAR*                       g_lpWaveData    = NULL;     // メモリ領域

/* 注意:OggVorbisファイルを各自で用意してください */
/*      サイズが大きくなるので用意していません    */
CHAR                        g_szFileName[]  = "bgm.ogg";    // 再生するファイル


// メッセージ関数の定義
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam );


// アプリケーションの初期化
BOOL    InitApp( HINSTANCE hInst, INT nCmdShow )
{
    // インスタンスハンドル保存
    g_hInst = hInst;

    // COMの初期化
    HRESULT hr = CoInitialize( NULL );
    if( FAILED(hr) )
    {
        DXTRACE_ERR( "COMの初期化に失敗", hr );
        return FALSE;
    }

    // ウインドウクラスの登録
    WNDCLASS wc;
    ZeroMemory( &wc, sizeof(wc) );
    wc.hCursor          = LoadCursor( NULL, IDC_ARROW );
    wc.lpszClassName    = "Main Window";
    wc.hbrBackground    = (HBRUSH)GetStockObject( WHITE_BRUSH );
    wc.hInstance        = hInst;
    wc.style            = CS_BYTEALIGNCLIENT | CS_VREDRAW|CS_HREDRAW;
    wc.lpfnWndProc      = (WNDPROC)MainWndProc;
    if( ! RegisterClass(&wc) )
    {
        DXTRACE_MSG( "ウインドウクラスの登録に失敗" );
        return FALSE;
    }

    // メインウインドウの作成
    g_hWnd = CreateWindowEx( 0, "Main Window", g_szAppName,
                             WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION,
                             CW_USEDEFAULT, CW_USEDEFAULT, 320, 240,
                             (HWND)NULL, (HMENU)NULL, hInst, (LPSTR)NULL);
    if( g_hWnd == NULL )
    {
        DXTRACE_MSG( "メインウインドウ作成に失敗" );
        return FALSE;
    }

    // メインウインドウの表示
    ShowWindow( g_hWnd, nCmdShow );
    UpdateWindow( g_hWnd );

    return TRUE;
}


// DirectMusicの初期化
BOOL    InitDMusic()
{
    HRESULT hr;

    // パフォーマンスの作成
    hr = CoCreateInstance( CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC,
                           IID_IDirectMusicPerformance8, (LPVOID*)&g_lpPerformance );
    if( FAILED(hr) )
    {
        DXTRACE_ERR( "DirectMusicPerformance8オブジェクトの作成に失敗", hr );
        return FALSE;
    }

    // パフォーマンスの初期化
    hr = g_lpPerformance->InitAudio( 
        NULL,                                   // IDirectMusicインターフェイスは不要
        NULL,                                   // IDirectSoundインターフェイスは不要
        g_hWnd,                                 // ウィンドウハンドル
        DMUS_APATH_SHARED_STEREOPLUSREVERB,     // デフォルトのオーディオパスタイプ
        64,                                     // パフォーマンスチャンネルの数
        DMUS_AUDIOF_ALL,                        // シンセサイザの機能
        NULL );                                 // オーディオパラメータにはデフォルトを使用
    if( FAILED(hr) )
    {
        DXTRACE_ERR( "DirectMusicPerformance8の初期化に失敗", hr );
        return FALSE;
    }

    // ローダーの作成
    hr = CoCreateInstance( CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC,
                           IID_IDirectMusicLoader8, (LPVOID*)&g_lpLoader );
    if( FAILED(hr) )
    {
        DXTRACE_ERR( "DirectMusicLoader8オブジェクトの作成に失敗", hr );
        return FALSE;
    }

    // ローダーの初期化(検索パスをカレントディレクトリに設定)
    CHAR strPath[ MAX_PATH ];
    DWORD i = GetCurrentDirectory( MAX_PATH, strPath );
    if( i==0 || MAX_PATHSetSearchDirectory( GUID_DirectMusicAllTypes, wstrSearchPath, FALSE );
    if( FAILED(hr) )
    {
        DXTRACE_ERR( "検索パスの設定に失敗", hr );
        return FALSE;
    }

    // OggVorbisをWaveへデコード
    LONG lWaveSize;
    if( ! LoadOggVorbis( g_szFileName, 2, &g_lpWaveData, &lWaveSize ) )
    {
        DXTRACE_MSG( "OggVorbisをWaveへのデコードに失敗" );
        return FALSE;
    }

    // セグメント作成
    DMUS_OBJECTDESC desc;
    ZeroMemory( &desc, sizeof(DMUS_OBJECTDESC) );
    desc.dwSize         = sizeof(DMUS_OBJECTDESC);
    desc.dwValidData    = DMUS_OBJ_CLASS | DMUS_OBJ_MEMORY;
    desc.guidClass      = CLSID_DirectMusicSegment;
    desc.pbMemData      = (LPBYTE)g_lpWaveData;
    desc.llMemLength    = lWaveSize;
    hr = g_lpLoader->GetObject( &desc, IID_IDirectMusicSegment8, (LPVOID*)&g_lpSegment );
    if( FAILED(hr) )
    {
        DXTRACE_ERR( "セグメント作成に失敗", hr );
        return FALSE;
    }

    // バンドのロード
    hr = g_lpSegment->Download( g_lpPerformance );
    if( FAILED(hr) )
    {
        DXTRACE_ERR( "バンドのロードに失敗", hr );
        return FALSE;
    }


    // セグメントの再生
    g_lpPerformance->PlaySegmentEx(
        g_lpSegment,    // 演奏するセグメント
        NULL,           // 使用しない
        NULL,           // トランザクション用
        0,              // フラグ
        0,              // 開始タイム、0 は即時
        NULL,           // セグメント状態を受け取るポインタ
        NULL,           // 停止するオブジェクト
        NULL            // オーディオパス、デフォルトでない場合
    );

    return TRUE;
}


// DirectMusicの終了処理
BOOL    ReleaseDMusic()
{
    HRESULT hr;

    // 演奏停止
    if( g_lpPerformance )
    {
        hr = g_lpPerformance->Stop( NULL, NULL, 0, 0 );
        if( FAILED(hr) )
            DXTRACE_ERR( "全セグメントの演奏停止に失敗", hr );
    }

    // セグメントのアンロード
    if( g_lpSegment )
    {
        hr = g_lpSegment->Unload( g_lpPerformance );
        if( FAILED(hr) )
            DXTRACE_ERR( "セグメントのアンロードに失敗", hr );
    }

    // セグメントを開放
    RELEASE( g_lpSegment );

    // ローダを開放
    RELEASE( g_lpLoader );

    // パフォーマンスを解放
    if( g_lpPerformance )
    {
        hr = g_lpPerformance->CloseDown();
        if( FAILED(hr) )
            DXTRACE_ERR( "IDirectMusicPerformance8::CloseDownに失敗", hr );
    }
    RELEASE( g_lpPerformance );

    // 確保したメモリを解放
    SAFE_DELETE( g_lpWaveData );

    return TRUE;
}


// アプリケーションの終了処理
BOOL    EndApp()
{
    // COMを解放
    CoUninitialize();

    return TRUE;
}


// ウインドウ処理
LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam )
{
    switch( msg )
    {
        // ウインドウが破棄される
        case WM_DESTROY:    
            PostQuitMessage( 0 );
            break;

        // その他のメッセージ
        default:            
            return DefWindowProc( hWnd, msg, wParam, lParam );
    }

    return 0L;
}


// メイン
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, INT nCmdShow)
{
    MSG msg;

    // アプリケーションの初期化
    if( InitApp( hInst, nCmdShow ) )
    {
        // DirectMusicの初期化
        if( InitDMusic() )
        {
            // メッセージループ
            while( GetMessage( &msg, 0, 0, 0 ) )
            {
                if( msg.message == WM_QUIT )    break;
                TranslateMessage( &msg );
                DispatchMessage( &msg );
            }
        }
    }

    // DirectMusicの終了処理
    ReleaseDMusic();

    // アプリケーションの終了処理
    EndApp();

    return msg.wParam;
}
#include "OggVorbis.h"


//-----------------------------------------------------------------------------
// Name: LoadOggVorbis()
// Desc: OggVorbisをWaveへ変換
// Argu: szName             ファイル名
//       iWord              量子化バイト数。1(8bit)か2(16bit)を指定。
//       lplpWaveData       Waveを保存するメモリ領域のポインタのポインタ
//       lplWaveDataSize    Waveのサイズを保存する変数のポインタ
// Rtn : TRUE   成功
//       FALSE  失敗
//-----------------------------------------------------------------------------
BOOL    LoadOggVorbis( LPCSTR szName, INT iWord, CHAR **lplpWaveData, LPLONG lplWaveDataSize )
{
    // 量子化バイト数が正しい値か
    if( ! ( iWord == 1 || iWord == 2 ) )    return FALSE;

    // ファイルを開く
    FILE *lpFile = fopen( szName, "rb" );
    if( lpFile == NULL )    return FALSE;

    // OggVorbisのファイル情報を取得
    OggVorbis_File vf;
    if( ov_open( lpFile, &vf, NULL, 0 ) < 0 )
    {
        fclose( lpFile );
        return FALSE;
    }

    // OggVorbisの情報を取得
    vorbis_info *vi = ov_info( &vf, -1 );
    if( vi == NULL )
    {
        ov_clear( &vf );
        return FALSE;
    }

    // ヘッダサイズの取得。sizeof(wh) だと正確なサイズが出ない
    WAVEFILEHEADER wh;
    LONG lWHSize =  sizeof(wh.cRIFF) + sizeof(wh.iSizeRIFF) + sizeof(wh.cType) +
                    sizeof(wh.cFmt)  + sizeof(wh.iSizeFmt)  + sizeof(wh.WaveFmt) +
                    sizeof(wh.cData) + sizeof(wh.iSizeData);

    // デコード後のデータサイズを求め、メモリ確保
    LONG lDataSize = (LONG)ceil( vi->channels * vi->rate * ov_time_total( &vf,-1 ) * iWord );
    *lplpWaveData = new CHAR[ lDataSize + lWHSize ];
    if( lplpWaveData == NULL )
    {
        ov_clear( &vf );
        return FALSE;
    }

    // OggVorbisをWaveへデコード
    INT  iCurrentSection;
    LONG lWriteSize;
    LONG lReadSize = 0;
    while( 1 )
    {
        // デコード
        lWriteSize = ov_read( &vf, *lplpWaveData + lReadSize + lWHSize, lDataSize - lReadSize, 0, iWord, 1, &iCurrentSection );

        // 終了
        if( ! lWriteSize )
        {
            break;
        }
        // エラー
        else if ( lWriteSize < 0 )
        {
            SAFE_DELETE( *lplpWaveData );
            ov_clear( &vf );
            return FALSE;
        }

        // 全てデコードできなかった
        lReadSize += lWriteSize;
    }

    // ヘッダの初期化
    memcpy( wh.cRIFF, "RIFF", 4 );
    wh.iSizeRIFF = lWHSize + lReadSize - 8;
    memcpy( wh.cType, "WAVE", 4 );
    memcpy( wh.cFmt, "fmt ", 4 );
    wh.iSizeFmt = sizeof(WAVEFORMATEX);
    wh.WaveFmt.cbSize          = sizeof(WAVEFORMATEX);
    wh.WaveFmt.wFormatTag      = WAVE_FORMAT_PCM;
    wh.WaveFmt.nChannels       = vi->channels;
    wh.WaveFmt.nSamplesPerSec  = vi->rate;
    wh.WaveFmt.nAvgBytesPerSec = vi->rate * vi->channels * iWord;
    wh.WaveFmt.nBlockAlign     = vi->channels * iWord;
    wh.WaveFmt.wBitsPerSample  = iWord * 8;
    memcpy( wh.cData, "data", 4 );
    wh.iSizeData = lReadSize;

    // メモリ内のヘッダへ書き込み
    INT iSize = 0;
    memcpy(*lplpWaveData,         &wh.cRIFF,     sizeof(wh.cRIFF));     iSize += sizeof(wh.cRIFF);
    memcpy(*lplpWaveData + iSize, &wh.iSizeRIFF, sizeof(wh.iSizeRIFF)); iSize += sizeof(wh.iSizeRIFF);
    memcpy(*lplpWaveData + iSize, &wh.cType,     sizeof(wh.cType));     iSize += sizeof(wh.cType);
    memcpy(*lplpWaveData + iSize, &wh.cFmt,      sizeof(wh.cFmt));      iSize += sizeof(wh.cFmt);
    memcpy(*lplpWaveData + iSize, &wh.iSizeFmt,  sizeof(wh.iSizeFmt));  iSize += sizeof(wh.iSizeFmt);
    memcpy(*lplpWaveData + iSize, &wh.WaveFmt,   sizeof(wh.WaveFmt));   iSize += sizeof(wh.WaveFmt);
    memcpy(*lplpWaveData + iSize, &wh.cData,     sizeof(wh.cData));     iSize += sizeof(wh.cData);
    memcpy(*lplpWaveData + iSize, &wh.iSizeData, sizeof(wh.iSizeData));

    // 終了処理
    ov_clear( &vf );

    // デコードしたWave形式のサイズ
    *lplWaveDataSize = lReadSize + lWHSize;

    return TRUE;
}
#pragma once


// インクルード
#include 
#include 
#include 
#include 


// Waveファイルのヘッダ
typedef struct{
    char            cRIFF[4];
    int             iSizeRIFF;
    char            cType[4];
    char            cFmt[4];
    int             iSizeFmt;
    WAVEFORMATEX    WaveFmt;
    char            cData[4];
    int             iSizeData;
} WAVEFILEHEADER;


// メモリ解放
#define SAFE_DELETE(p)  if(p){delete []p;p=NULL;}


// OggVorbisをWaveへ変換
BOOL    LoadOggVorbis( LPCSTR szName, INT iWord, CHAR **lplpWaveData, LPLONG lplWaveDataSize );


inserted by FC2 system