Platform SDK: DirectX

ステップ 2 : パフォーマンスの初期化

[Visual Basic]

ここでは、C++ でのアプリケーション開発について説明する。Visual Basic については、「DirectMusic Visual Basic チュートリアル」を参照すること。

[C++]

Donuts.cpp ファイル内の InitializeGame 関数で DirectMusic パフォーマンスを設定する。

アプリケーションは最初に GetSearchPath 関数を呼び出すことにより、レジストリへのクエリを行って、DirectX のサンプル ミュージック ファイルの検索パスを取得する。その後、次のようにコンポーザ用とパフォーマンス用の COM オブジェクトを作成する。

CoInitialize(NULL);
 
if ( !SUCCEEDED(::CoCreateInstance(
        CLSID_DirectMusicComposer,
        NULL,
        CLSCTX_INPROC, 
        IID_IDirectMusicComposer,
        (void**)&gpComposer
)))
{
    return CleanupAndExit("Couldn't create a composer object");
}
 
if ( !SUCCEEDED( CoCreateInstance( CLSID_DirectMusicPerformance, 
        NULL, 
        CLSCTX_INPROC, 
        IID_IDirectMusicPerformance,
        (void**)&gpPerformance )))
{
    return CleanupAndExit("Couldn't create a performance object");
}
 

続いて、このアプリケーションは IDirectMusicPerformance::Init を呼び出してパフォーマンスを初期化する。このメソッドは、ポートの作成とアクティブ化を行う DirectMusic オブジェクトを作成する。DirectSound がほかのサウンド エフェクトに使用されているかどうかに応じて、lpDS に渡してパフォーマンスに既存の DirectSound オブジェクトをアタッチするか、NULL を渡してオブジェクトを作成する。

#ifdef USE_DSOUND
    if( !SUCCEEDED(gpPerformance->Init(&gpDirectMusic, 
           lpDS, hWndMain)))
    {
        return CleanupAndExit("Couldn't initialize the performance");
    }
#else
    if( !SUCCEEDED(gpPerformance->Init(&gpDirectMusic, 
            NULL, hWndMain)))
    {
        return CleanupAndExit("Couldn't initialize the performance");
    }
#endif
 

アプリケーションはここでデフォルト ポートを取得し、1 つのチャンネル グループでポートのインスタンスを作成し、その能力を取得する。

IDirectMusicPort* pPort = NULL;
DMUS_PORTPARAMS dmos;
DMUS_PORTCAPS dmpc;
GUID guidSynthGUID;
HRESULT hr = S_OK;

if ( !SUCCEEDED(gpDirectMusic->GetDefaultPort(&guidSynthGUID)))
{
    return CleanupAndExit("Could't GetDefaultPort on IDirectMusic");
}
 
ZeroMemory(&dmos, sizeof(dmos));
dmos.dwSize = sizeof(DMUS_PORTPARAMS);
dmos.dwChannelGroups = 1;
dmos.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
 
if( !SUCCEEDED(gpDirectMusic->CreatePort(guidSynthGUID,
            &dmos,
            &pPort,
            NULL)))
{
    return CleanupAndExit("Couldn't CreatePort on IDirectMusic");
}
 
ZeroMemory(&dmpc, sizeof(dmpc));
dmpc.dwSize = sizeof(DMUS_PORTCAPS);
 
if( !SUCCEEDED(pPort->GetCaps(&dmpc)))
{
    if (pPort) pPort->Release();
    return CleanupAndExit("Couldn't GetCaps on IDirectMusicPort");
}
 

ここで、_SOFTWARE_SYNTH_ が定義されているかどうかに応じて、アプリケーションの動作が変わる。_SOFTWARE_SYNTH_ が定義されている場合、DLS 機能を持つシンセサイザが要求され、アプリケーションはデフォルト ポートで DMUS_PC_DLS 能力フラグを確認する。フラグが見つからない場合は、デフォルト ポートを解放し、DMUS_PC_DLS 機能を持つ出力ポートが見つかるまで、利用可能なポートを列挙し続ける。最終的に、見つかったポートのインスタンスが作成される。

if ((dmpc.dwClass != DMUS_PC_OUTPUTCLASS) 
        || !(dmpc.dwFlags & DMUS_PC_DLS))
{
    pPort->Release();
    pPort = NULL;
}
 
if (!pPort)
{
    for (DWORD index = 0; hr == S_OK; index++)
    {
        ZeroMemory(&dmpc, sizeof(dmpc));
        dmpc.dwSize = sizeof(DMUS_PORTCAPS);
 
        hr = gpDirectMusic->EnumPort(index, &dmpc);
        if(hr == S_OK)
        {
            if ( (dmpc.dwClass == DMUS_PC_OUTPUTCLASS) && 
                 (dmpc.dwFlags & DMUS_PC_DLS) )
            {
                CopyMemory(&guidSynthGUID, &dmpc.guidPort,
                        sizeof(GUID));
 
                ZeroMemory(&dmos, sizeof(dmos));
                dmos.dwSize = sizeof(DMUS_PORTPARAMS);
                dmos.dwChannelGroups = 1;
                dmos.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS;
 
                hr = gpDirectMusic->CreatePort(guidSynthGUID, 
                        &dmos, &pPort, NULL);
                break;
            }
        }
    }
    if (hr != S_OK)
    {
        if (pPort) pPort->Release();
        return CleanupAndExit("Couldn't initialize the Synth port");
    }
}
 

一方、_SOFTWARE_SYNTH_ が定義されていない場合は、従来のハードウェア ポートが要求され、アプリケーションは MIDI マッパーが見つかるまで、ポートを列挙し続ける(ここでは、コードを示していない)。

次に、このポートをアクティブ化して、パフォーマンスに付加する。

pPort->Activate(TRUE);
gpPerformance->AddPort(pPort);
 

次の呼び出しで、P チャンネル 0-15 がこのポート上の最初の MIDI チャンネル グループへマップされる。このステップは、アプリケーションが AddPort に NULL を渡していないために必要である点に注意すること。

gpPerformance->AssignPChannelBlock(0, pPort, 1);
 

この時点で、ポートへのオリジナル参照を解放できる。この呼び出しは、パフォーマンスからポートを削除することはない。

if (pPort) pPort->Release();

次項 : ステップ 3 : ミュージック要素のロード