ホーム < ゲームつくろー! < Ogg Vorbis入門編

Ogg Vorbis入門編
その6 OggDecoderオブジェクトを複製して同時に鳴らす:サンプルプログラム


 Ogg Vorbis入門編その6「OggDecoderオブジェクトを複製して同時に鳴らす」で説明した内容を踏まえたサンプルプログラムです。実行するとコンソール画面が現れて、指定のOggファイルが20個ちょっとずつズレながら同時にストリーム再生されます。


サンプルスクリーンショット。味も素っ気も無い画面ですいません。

このサンプルは1つのOggファイルをメモリに展開し、その複製を20個作成してちょっとずつ遅延させながら(ついでに音量も小さくして)同時に鳴らしています。こういうのを「擬似リバーブ」と言います(昔MIDIをやっていた時に多用していました)。

 複製は同じメモリを参照しているため、実質のメモリ消費はほぼ複製元1つ分です。Playerにデコーダオブジェクトを渡す時に元ではなくてクローン側を渡すのがポイントです。

// 元を作成
Dix::sp< Dix::OggDecoderInMemory > spOggDecoder( new Dix::OggDecoderInMemory( "test.ogg" ) );

for ( int i = 0; i < cloneNum_g; ++i ) {
   playerAry[ i ].setDevice( cpDS8 );
   playerAry[ i ].setDecoder( spOggDecoder->clone() );
}

○ サンプルの動かし方

 サンプルを動かすために必要なファイルはこちらからダウンロードできます(OggSmp_No6.lzh)。空のコンソールアプリケーションを作成し、アーカイブに入っているクラスをすべて追加し、Ogg Vorbisライブラリを環境に設定するとビルドできます。実行して音楽を聴くにはプロジェクトフォルダ下に「Test.Ogg」というOggファイルが必要です。お手元の音楽をOggファイルに変換して試してみてください。

 PCMDecoderオブジェクトはスマートポインタに包む必要があります。またIDirectSound8インターフェイスはCOMポインタに包みます。これはポインタ先のアクセスを保障するためです。使用の際はご注意下さい。

○ Ogg Vorbisライブラリについて

 このサンプルを動かすには別途Ogg Vorbisライブラリを組み込む必要があります。組み込み方についてはOgg Vorbis入門編その1「Ogg Vorbisライブラリのインストール」に詳しく記載しておりますのでご参照ください。うまくいかない場合は掲示板にご報告下さい。

// Ogg Vorbisストリーム再生クラステストプログラム
//
//  製作者 : IKD
//  HP     : http://marupeke296.com
//


#pragma comment ( lib, "dxguid.lib" )
#pragma comment ( lib, "dsound.lib" )

#include <dsound.h>
#include <tchar.h>
#include "OggDecoderInMemory.h"
#include "PCMPlayer.h"
#include "DixSmartPtr.h"
#include "DixComPtr.h"

// コンソールのウィンドウハンドル取得
HWND GetConsoleHwnd(void)
{
    TCHAR pszWindowTitle[ 1024 ];
    GetConsoleTitle( pszWindowTitle, 1024 );
    return FindWindow( NULL, pszWindowTitle );
}

// 一時停止関数
void StopProc() {
    while ( 1 ) {
        Sleep( 200 );
        // Escapeキーを押したら抜ける
        if ( GetAsyncKeyState( VK_ESCAPE ) )
            break;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    // DirectSoundの作成
    IDirectSound8 *pDS8;
    DirectSoundCreate8( NULL, &pDS8, NULL );
    Dix::Com_ptr< IDirectSound8 > cpDS8( pDS8 );
    pDS8->SetCooperativeLevel( GetConsoleHwnd(), DSSCL_PRIORITY );

    // Oggオブジェクト作成
    Dix::sp< Dix::OggDecoderInMemory > spOggDecoder( new Dix::OggDecoderInMemory( "test.ogg" ) );
//    Dix::sp< Dix::OggDecoder > spOggDecoder( new Dix::OggDecoderInMemory( "test.ogg" ) );

    const int cloneNum_g = 20;

    Dix::PCMPlayer playerAry[ cloneNum_g ];
    for ( int i = 0; i < cloneNum_g; ++i ) {
        playerAry[ i ].setDevice( cpDS8 );
        playerAry[ i ].setDecoder( spOggDecoder->clone() );
    }

    bool isLoop = true;
    for ( int i = 0; i < cloneNum_g; ++i ) {
        Sleep( 100 );
        if( playerAry[ i ].play( isLoop ) == false ) {
            printf( "ファイル準備に失敗しています" );
            return 0;
        }
        playerAry[ i ].setVolume( -500 * i );
    }

    // 再生
    printf( "ただ今再生中\n" );
    StopProc();

    // 停止
    for ( int i = 0; i < cloneNum_g; ++i ) {
        playerAry[ i ].stop();
    }
    printf( "\n停止しました\n" );

    return 0;
}