Platform SDK: DirectX

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

[Visual Basic]

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

[C++]

サンプル アプリケーション DMDonuts で DirectMusic の機能を設定する次のステップは、音楽の要素であるスタイル、テンプレート、モチーフ、コード マップ、バンドをファイルからロードすることである。前のステップと同様、このコードも InitializeGame 関数から抜粋したものである。

最初に、このアプリケーションはローダー オブジェクトを作成する。

if (!SUCCEEDED(::CoCreateInstance(
            CLSID_DirectMusicLoader,
            NULL,
            CLSCTX_INPROC, 
            IID_IDirectMusicLoader,
            (void**)&gpLoader
        )))
{
    return CleanupAndExit("ローダー オブジェクトを作成できませんでした。");
}
 

次にすべてのオブジェクトの検索ディレクトリを設定し、オブジェクトキャッシュを有効にする。2 番目の呼び出しは、単純にデフォルトのキャッシュ ステータスを確認する。

hr = E_FAIL;
 
/ * GetSearchPath 関数は、レジストリからメディア ディレクトリを
    取得し、これを wszSearchPath に返す。*/
 
if (GetSearchPath(wszSearchPath))
{
    hr = gpLoader->SetSearchDirectory(
           GUID_DirectMusicAllTypes, wszSearchPath, FALSE);
}
 
/* ディレクトリが存在しない場合は、現在のディレクトリで試してみる。*/
 
if (FAILED(hr))
{
    hr = gpLoader->SetSearchDirectory(GUID_DirectMusicAllTypes,
            L".", FALSE);
}
if (FAILED(hr))
{
    return CleanupAndExit("DirectMusic ローダーの検索ディレクトリを \
            設定できませんでした。");
}
gpLoader->EnableCache(GUID_DirectMusicAllTypes, TRUE);
 

次のコードの一部は、Donuts.sty ファイル内の「Donuts」というスタイルをロードする。IDirectMusicLoader::ScanDirectory を呼び出してデータベースオブジェクトを構築すると、内部名を指定してオブジェクトをロードできるが、このアプリケーションはこのメソッドを呼び出していないため、最初に IDirectMusicLoader::GetObject を呼び出すと失敗に終わる。fallback 手続きは、ファイル名を使ってオブジェクトを識別し、もう一度 GetObject を呼び出す。

IDirectMusicObject* pObject = NULL;
DMUS_OBJECTDESC ObjectDescript;
 
ObjectDescript.dwSize = sizeof(DMUS_OBJECTDESC);
ObjectDescript.guidClass = CLSID_DirectMusicStyle;
wcscpy(ObjectDescript.wszName, L"Donuts");
ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_NAME;
 
if (!SUCCEEDED(gpLoader->GetObject(&ObjectDescript,
        IID_IDirectMusicStyle, (void**)&gapStyle[1])))
{
    wcscpy(ObjectDescript.wszFileName, L"Donuts.sty");
    ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
    if (!SUCCEEDED(gpLoader->GetObject(&ObjectDescript,
            IID_IDirectMusicStyle, (void**)&gapStyle[1])))
    {
        return CleanupAndExit("Couldn't load style object 1");
    }
}
 

次に InitializeGame 関数は同様の方法で、もう 1 つのスタイルと 2 つのテンプレートをロードする。

その次のステップは、ゲーム内の特定のイベントをマーク (明示) するために使われるモチーフの配列を初期化することである。各モチーフはスタイル内に含まれており、IDirectMusicStyle::GetMotif メソッドを呼び出すことによって取得される。このメソッドは、このモチーフ用のセグメントを作成する。Donuts.cpp ファイル内の次の例のように、メソッドにはモチーフの内部名を渡さなければならない。

WCHAR awszMotifs[NUM_MOTIFS][64];
 
wcscpy(awszMotifs[MOTIF_BOUNCE], L"Bounce");
.
.
.
hr = gapStyle[0]->GetMotif(awszMotifs[MOTIF_BOUNCE],
        &(gapMotif[0][MOTIF_BOUNCE]));
 

省略のない完全なコードを参照すると、このアプリケーションが同じ名前を持つモチーフを 2 セット ロードしていることがわかる。1 つは「Donuts」スタイルから、もう 1 セットは「Donutz」からである。プレーヤーのレベルが変化するのに応じて、DMDonuts はこれら 2 つのスタイルを切り替える。gapMotif を演奏するときに、グローバルな gnCurrentStyle の値に基づいて最初のインデックスが決定され、モチーフが現在のレベルに適したものであることを保証する。

続いて、アプリケーションはスタイルごとに 4 つのコード マップを初期化する。これらは、別々のファイルから取得される。

WCHAR awszChordMap[NUM_STYLES][NUM_CHORDMAP][64];
wcscpy(awszChordMap[0][0], L"minaeo.per");
wcscpy(awszChordMap[0][1], L"minfunc.per");
wcscpy(awszChordMap[0][2], L"mipedpt.per");
wcscpy(awszChordMap[0][3], L"tension.per");
wcscpy(awszChordMap[1][0], L"dianoble.per");
wcscpy(awszChordMap[1][1], L"minpedpt.per");
wcscpy(awszChordMap[1][2], L"mippjazz.per");
wcscpy(awszChordMap[1][3], L"minjazz.per");

ObjectDescript.guidClass = CLSID_DirectMusicChordMap;
ObjectDescript.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;

for (short n = 0; n < NUM_STYLES; n++)
{
    for (short m = 0; m < NUM_CHORDMAP; m++)
    {
        if (hr == S_OK)
        {
            wcscpy(ObjectDescript.wszFileName,
                    awszChordMap[n][m]);
            hr = gpLoader->GetObject(&ObjectDescript,
                    IID_IDirectMusicChordMap,
                   (void**)&gapChordMap[n][m]);
        }
    }
}

if (hr != S_OK)
{
    return CleanupAndExit("コード マップをロードできませんでした。");
}
 

このスタイルから取り出すべき最後の要素はバンドである。各スタイルは 2 つの異なったバンドを備えている。1 つはプレーヤーの宇宙船にシールドがないとき、もう 1 つはシールドが張られているときである。バンドに割り当てられている名前が、モチーフやコード マップに割り当てられている名前とは異なる点に注意すること。どちらのバンドにも、WCHAR のローカル配列ではなく BSTR が割り当てられている。ただし、Win32® API では BSTR WCHAR 配列へのポインタなので、これらは同じエフェクトをもたらす。

各バンドをロードするときに、これらはパフォーマンスにダウンロードされ、DLS データが音色で利用可能となる。

BSTR bstrDefault = SysAllocString(L"Default 2");
BSTR bstrShields = SysAllocString(L"Shields");
 
for (n = 0; n < NUM_STYLES; n++)
{
    if (hr == S_OK)
    {
        hr = gapStyle[n]->GetBand(bstrShields, &gapShieldBand[n]);
    }
    if (hr == S_OK)
    {
        hr = gapShieldBand[n]->Download(gpPerformance);
    }
    if (hr == S_OK)
    {
        hr = gapStyle[n]->GetBand(bstrDefault, &gapDefaultBand[n]);
    }
    if (hr == S_OK)
    {
        hr = gapDefaultBand[n]->Download(gpPerformance);
    }
}
 
SysFreeString(bstrDefault);
SysFreeString(bstrShields);
 

いくつかのエラーチェック コードの後で、InitializeGame 関数は自ら取得した 4 つのバンドからセグメントを作成する。これらのバンドを使って、適切なときにバンド チェンジを「演奏」する。セグメントを作成した後、バンド インターフェイスを解放する。

for (n = 0; n < NUM_STYLES; n++)
{
    if (hr == S_OK)
    {
        hr = gapShieldBand[n]->CreateSegment(&gapShieldSegment[n]);
    }
    if (hr == S_OK)
    {
        hr = gapDefaultBand[n]->CreateSegment(&gapDefaultSegment[n]);
    }
    apShieldBand[n]->Release();
    apDefaultBand[n]->Release();
}

次項 : ステップ 4 : 通知の設定