Platform SDK: DirectX |
ここでは、C++ でのアプリケーション開発について説明する。Visual Basic については、「DirectMusic Visual Basic チュートリアル」を参照すること
サンプル アプリケーション 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 : 通知の設定