hspdx.dll によって提供される DirectDraw や、MIAさんの dsoundex.dll によって提供される DirectSound などなど、HSPでもお馴染みとなっている DirectX の存在は、皆さんも知っていることと思います。
DirectX は、Windowsが提供するシステムコンポーネントの1つです。ハードウェアの持つ能力を直接制御することによって、できる限り細かく、高速な機能を提供できるように設計されています。
DirectX は、用途に応じた複数のコンポーネントを提供しています。以下に、その例をいくつか示します。
DirectX は COM の形で提供されていて、そのオブジェクトクラスの数は多く、使われるインターフェースもまた膨大なものになります。このページでは、それらすべてを取り上げていくことはできないため、DirectX の機能のごく一部のみを取り扱っていくつもりです。もしもほかのインターフェースが提供する機能を使いたい場合は、このページで記述されているものだけでは足りません。マイクロソフトのページから DirectX SDK をダウンロードし、インストールすることで DirectX に関係するヘッダファイルやリファレンス(英語版)が手に入ります。
また、マイクロソフトのホームページでは DirectX 7.0 および DirectX 8.0 の日本語版のリファレンスが公開されているので、そちらもあわせて参照してください。
今回は、MIDIファイルを演奏する目的で DirectMusic を使ってみたいと思います。
DirectMusic は、DirectX 6.1 より追加されたコンポーネントで、MIDIなどのメッセージベースのサウンドを再生させる機能を持ち、主に音楽を再生するのに使用されます。内部では、シンセサイザがメッセージに対応するウェーブ(波形)データを DirectSound に送り、それを DirectSound が合成して実際に音を発生させる、ということが行なわれます。(実際にはもっと複雑ですが。)
先に言っておきますが、 DirectMusic を使ってうまく再生されるMIDIファイルは GM フォーマットのものだけです。 Roland 88 (GS) とか XG とかは、ほとんどがうまく演奏されないようです。
では、実際に MIDI ファイルを再生させてみることにします。手順は以下のようになります。かなり複雑ですが、注意してみていきましょう。
パフォーマンスオブジェクトを作成してインターフェースを取得し、 IDirectMusicPerformance::Init メソッドで初期化する。
IDirectMusicPerformance::AddPort メソッドを呼び出してパフォーマンスにポートを割り当てる。
ローダーオブジェクトを作成して IDirectMusicLoader インターフェースを取得する。
DMUS_OBJECTDESC 構造体にロードするファイルの情報を格納して IDirectMusicLoader::GetObject メソッドでファイルからセグメントオブジェクトを作成し、 IDirectMusicSegment インターフェースを取得する。
IDirectMusicSegment::SetParam メソッドで、GUID_StandardMIDIFile を指定し、SMF(スタンダードMIDIファイル)として再生されるように設定する。
IDirectMusicSegment::SetParam メソッドで GUID_Download を指定し、音色データをダウンロードしてパフォーマンスに割り当てる。
IDirectMusicPerformance::PlaySegment メソッドでセグメントを再生する。
演奏を停止させる場合には IDirectMusicPerformance::Stop メソッドを呼び出す。
IDirectMusicSegment::SetParam メソッドで GUID_Unload を指定し、音色データをアンロードする。
IDirectMusicPerformance::CloseDown メソッドでパフォーマンスオブジェクトをクローズする。
IDirectMusicSegment、 IDirectMusicLoader、 IDirectMusicPerformance インターフェースの Release メソッドを呼び出して、オブジェクトを解放する。
IID Explorer によって取得された各 CLSID ・ IID や、各メソッドのインデックスなどの定義は、定義用のスクリプトを別ファイル(def.as)で作成しておきます。
DirectMusic では、 DirectMusic パフォーマンスオブジェクト(以下パフォーマンスと呼ぶ)が演奏全体の管理・処理を行ないます。
まずはパフォーマンスを作成し、IDirectMusicPerformance インターフェースを取得することから行ないます。
パフォーマンスのクラスIDは
{d2ac2881-b39b-11d1-8704-00600893b1bd}
です。また、 IDirectMusicPerformance インターフェースのインターフェースIDは
{07d43d03-6523-11d2-871d-00600893b1bd}
になります。これら2つを createobj 命令に渡すことで、インターフェースポインタを取得できます。
これらのクラスID・インターフェースIDは、別スクリプト def.as で定義しておきます。
#include "llmod.as"
#include "rrmod/com/lollipop.as"
#include "def.as"
; パフォーマンスオブジェクトの作成
createobj pPerformance, CLSID_DirectMusicPerformance, IID_IDirectMusicPerformance
その後、IDirectMusicPerformance::Init メソッドを呼び出して、パフォーマンスを初期化しなくてはなりません。
HRESULT Init( IDirectMusic** ppDirectMusic, LPDIRECTSOUND pDirectSound, HWND hwnd );
ppDirectMusic には、今回は DirectMusic オブジェクトが内部管理されるように 0 (NULL) を指定します。
pDirectSound には、アプリケーションが他で DirectSound を使用している場合は、そのオブジェクトの IDirectSound インターフェイスポインタを指定しなければいけないことになっています。これは、DirectSound オブジェクトが1つのプロセス1つだけしか作成できないことになっているためです。今回はそのようなことはないので、 0 (NULL) を指定しておくことで、内部で自動的に DirectSound オブジェクトが作成され管理されます。
hwnd には、 DirectSound の作成に使うウィンドウハンドルを指定します。 0 (NULL) を指定することで、前面ウィンドウが指定されます。
; IDirectMusicPerformance::Init メソッド
pm = 0, 0, 0
icall pPerformance, IDirectMusicPerformance_Init, pm, 3
次に、パフォーマンスにポートを割り当てます。これには IDirectMusicPerformance::AddPort メソッドを呼び出します。
HRESULT AddPort( IDirectMusicPort* pPort );
pPort にはポートオブジェクトを表すインターフェースポインタを指定しますが、今回はデフォルトポートを使用するので 0 (NULL) を指定します。
; IDirectMusicPerformance::AddPort メソッド
pm = 0
icall pPerformance, IDirectMusicPerformance_AddPort, pm, 1
DirectMusic では、 DirectMusic ローダーオブジェクト(以下ローダーと呼ぶ)が、他のオブジェクトのロードを行ないます。スタンダードMIDIファイル(SMF)のロードもローダーで行なうことができます。
ローダーオブジェクトを作成して、IDirectMusicLoader インターフェースを取得しなくてはなりません。ローダーのクラスIDは
{d2ac2892-b39b-11d1-8704-00600893b1bd}
です。また、 IDirectMusicLoader インターフェースのインターフェースIDは
{2ffaaca2-5dca-11d2-afa6-00aa0024d8b6}
になります。これらを createobj 命令に渡すことで、ローダーのインターフェースポインタを取得できます。
; ローダーオブジェクトの作成
createobj pLoader, CLSID_DirectMusicLoader, IID_IDirectMusicLoader
DirectMusic セグメントオブジェクト(以下セグメントと呼ぶ)は、シーケンス化されたサウンドデータを表すオブジェクトです。DirectMusic では、1つのSMFのデータを、1つのセグメントオブジェクトとして扱います。
ファイルをロードしてその内容からセグメントを作成するには、 DMUS_OBJECTDESC 構造体にロードするファイルの情報を格納して IDirectMusicLoader::GetObject メソッドを呼び出します。
DMUS_OBJECTDESC 構造体は以下のように定義されています。
typedef struct _DMUS_OBJECTDESC { DWORD dwSize; DWORD dwValidData; GUID guidObject; GUID guidClass; FILETIME ftDate; DMUS_VERSION vVersion; WCHAR wszName[64]; WCHAR wszCategory[64]; WCHAR wszFileName[260]; LONGLONG llMemLength; PBYTE pbMemData; IStream * pStream; } DMUS_OBJECTDESC, *LPDMUS_OBJECTDESC;
dwSize メンバはこの構造体のサイズを表すもので、ここでは 848 を指定します。dwValidData メンバは構造体の有効メンバを指定するもので、今回はファイル名をフルパス指定できるように DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH を指定します。
今回は、まず guidClass メンバに、セグメントオブジェクトのクラスIDを格納しなくてはなりません。セグメントのクラス ID は、
{d2ac2882-b39b-11d1-8704-00600893b1bd}
で表されますが、これは文字列形式で表したものなので、 GUID (CLSID) 構造体の形に直してから格納します。クラスIDを文字列形式から構造体に変換するには、 lollipop モジュールで定義されている clsidconv 命令を使用することができます。
この命令はちょっと特殊なもので、パラメータ n3 を省略した場合と、 n3 を明示的に指定した場合とで、動作がやや異なってきます。 n3 を省略した場合、この命令は、メソッドのパラメータとして CLSID の参照(構造体のアドレス)が渡せるように、 v1.0 には構造体のアドレスが格納され、実際の構造体データは v1.1 〜 v1.4 に格納される仕組みになっています。一方、 n3 を明示的に指定した場合には、変数 v1 の先頭から n3 バイトの位置に、変換したCLSID構造体を格納するようになります。
今回は DMUS_OBJECTDESC 構造体の guidClass メンバ、すなわち、構造体として割り当てた変数の24バイト目の位置に格納するので、パラメータ n3 には明示的に 24 を指定すればよいことになります。
次に、wszFileName メンバにファイル名を格納します。dwValidData メンバに DMUS_OBJ_FULLPATH フラグを指定した場合は、フルパスで指定することになりますが、このファイル名はワイド文字列(Unicode 文字列)で指定しなくてはなりません。したがって、いったん Unicode に変換してから、コピーすることになります。(WCHAR は、2バイトのワイド文字を表す型なので、wszFileName メンバのサイズは 520 バイトになります。)
; DMUS_OBJECTDESC 構造体 dim objdesc, 212 objdesc.0 = 848 objdesc.1 = 0x00000032 ; DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME ; | DMUS_OBJ_FULLPATH ; CLSID を文字列形式から構造体に変換し objdesc の24バイト目に格納 clsidconv objdesc, CLSID_DirectMusicSegment, 24 ; ファイル名のUnicode変換 sdim filename, 260 sdim w_filename, 520 ; Unicode文字列を格納 filename = "C:\\My Documents\\test.mid" to_uni w_filename, filename, -1 ; Unicodeに変換 memcpy objdesc.78, w_filename, 520
DMUS_OBJECTDESC 構造体にデータを格納できたら、 IDirectMusicLoader::GetObject メソッドを呼び出して IDirectMusicSegment インターフェースを取得します。
HRESULT GetObject( LPDMUS_OBJECTDESC pDesk, REFIID riid, LPVOID *ppv );
pDesk には、情報を格納した DMUS_OBJECTDESC 構造体のアドレスを指定します。 riid には、取得するインターフェースのインターフェースIDを指定します。 ppv には、取得したインターフェースポインタを格納するための変数のアドレスを指定します。
riid には、 IDirectMusicSegment インターフェースのインターフェースIDを指定します。このインターフェースIDは、
{f96029a2-4282-11d2-8717-00600893b1bd}
で表されます。ただし、ここでは、インターフェースIDを格納した GUID 構造体(IID 構造体)のアドレスを指定しなければなりません。インターフェースIDを構造体の形式に変換するには、 lollipop モジュールで定義されている iidconv 命令を使います。
この命令もまた clsidconv 命令と同じで、 n3 を省略した場合と明示的に指定した場合とで、動作が異なってきます。ここでは n3 を省略することによって、 v1.0 には構造体のアドレスが格納され、実際の構造体データが v1.1 〜 v1.4 に格納されます。そして、 GetObject メソッドのパラメータとしては、構造体のアドレスを渡さなければならないので、 v1.0 に格納された値を渡すことになります。
getptr pm.0, objdesc ; DMUS_OBJECTDESC 構造体アドレス取得 iidconv iid, IID_IDirectMusicSegment ; IID を文字列形式から構造体に変換 pm.1 = iid.0 ; IID 構造体のアドレス getptr pm.2, pSegment ; インターフェースを格納する変数 ; IDirectMusicLoader::GetObject メソッド icall pLoader, IDirectMusicLoader_GetObject, pm, 3
次に、セグメントのパラメータを設定します。
まずは、 GUID_StandardMIDIFile をパラメータとして IDirectMusicSegment::SetParam メソッドを呼び出します。
HRESULT SetParam( REFGUID rguidType, DWORD dwGroupBits, DWORD dwIndex, MUSIC_TIME mtTime, void* pParam );
このメソッドは、セグメントが所有しているトラックのパラメータを設定するものです。
rguidType パラメータはどのパラメータを設定するのかを指定するもので、いくつかの定義された GUID のうちの1つを指定します。ここでは、 GUID_StandardMIDIFile を指定して、トラックがSMFとして再生されるように設定します。この GUID は、
{06621075-E92E-11D1-A8C5-00C04FA3726E}
と定義されています。実際には、この GUID を格納した GUID 構造体のアドレスを格納します。この GUID はインターフェースIDではありませんが、インターフェースIDの場合と同様に iidconv 命令を使うことができます。
SetParam メソッドの dwGroupBits パラメータはグループビットと呼ばれるもので、どのグループに属するトラックを設定するかを指定するものですが、ここではすべてのトラックグループを指定するために 0xFFFFFFFF (すなわち -1 )を指定します。 dwIndex は、グループ中のどのトラックに設定するかを指定しますが、ここではすべてのトラックに設定するために 0x80000000 (DMUS_SEG_ALLTRACKS) を指定します。 mtTime はここでは使われませんから、 0 を指定しておきます。 pParam もまたここでは使用されないので、 0 (NULL) を指定しておきます。
; pSegment->SetParam( GUID_StandardMIDIFile, 0xFFFFFFFF, ; DMUS_SEG_ALLTRACKS, 0, NULL ); iidconv guid, GUID_StandardMIDIFile pm = guid, -1, 0x80000000, 0, 0 icall pSegment, IDirectMusicSegment_SetParam, pm, 5
次に、音色データをパフォーマンスにダウンロードします。これには、 GUID_Download をパラメータとして IDirectMusicSegment::SetParam メソッドを呼び出します。
rguidType パラメータには GUID_Download を指定します。この GUID は、
{d2ac28a7-b39b-11d1-8704-00600893b1bd}
と定義されています。 pParam パラメータには、パフォーマンスオブジェクトの pParam インターフェースポインタを指定します。他のパラメータは前と同じです。
; pSegment->SetParam( GUID_Download, 0xFFFFFFFF, DMUS_SEG_ALLTRACKS, ; 0, (void*)pPerformance ); iidconv guid, GUID_Download pm = guid, -1, 0x80000000, 0, pPerformance icall pSegment, IDirectMusicSegment_SetParam, pm, 5
セグメントを再生させるには、IDirectMusicPerformance::PlaySegment メソッドを呼び出します。
HRESULT PlaySegment( IDirectMusicSegment* pSegment, DWORD dwFlags, __int64 i64StartTime, IDirectMusicSegmentState** ppSegmentState );
pSegment パラメータには、再生させるセグメントオブジェクトの IDirectMusicSegment インターフェースポインタを指定します。 dwFlags には動作を指定するフラグを指定します。ここでは、 0 を指定しておいて問題ありません。 i64StartTime は、セグメントの開始タイムを指定する64ビット値です。すぐに再生を開始する場合は 0 を指定します。 ppSegmentState には、演奏するセグメントに関してのセグメント状態を表す IDirectMusicSegmentState インターフェースポインタを受け取る変数のアドレスを指定しますが、必要ない場合は 0 (NULL) を指定することができます。
このメソッドを呼び出すときに注意しなければならないのは、 i64StartTime パラメータが __int64 型である、すなわち、64ビット(8バイト)値であることです。メソッド呼び出し時には、この値は2つの4バイト値に分解されて渡されるという仕組みになっています。そのため、スクリプト上で記述する場合にはこのパラメータを2つぶんの引数として扱う必要があります。パラメータ数も 4 ではなく 5 を指定しなければなりません。
; pPerformance->PlaySegment( pSegment, 0, (__int64) 0, NULL ); pm.0 = pSegment pm.1 = 0 pm.2 = 0, 0 ; 64ビット値は2つ分のパラメータとして扱う pm.4 = 0 icall pPerformance, IDirectMusicPerformance_PlaySegment, pm, 5
演奏を停止させるには、 IDirectMusicPerformance::Stop メソッドを呼び出します。
HRESULT Stop( IDirectMusicSegment* pSegment, IDirectMusicSegmentState* pSegmentState, MUSIC_TIME mtTime, DWORD dwFlags );
各パラメータの説明は省略します。直ちに演奏を停止させるには、すべてのパラメータに 0 を指定すれば OK です。
; pPerformance->Stop( NULL, NULL, 0, 0 );
pm = 0, 0, 0, 0
icall pPerformance, IDirectMusicPerformance_Stop, pm, 4
パフォーマンスにダウンロードしてあった音色データをアンロードします。これには、 GUID_Unload をパラメータとして IDirectMusicSegment::SetParam メソッドを呼び出します。 GUID_Unload は、
{d2ac28a8-b39b-11d1-8704-00600893b1bd}
と定義されています。
音色をアンロードできたら、 release 命令でセグメントを解放します。
; pSegment->SetParam( GUID_Unload, 0xFFFFFFFF, DMUS_SEG_ALLTRACKS, ; 0, (void*)pPerformance ); iidconv guid, GUID_Unload pm = guid, -1, 0x80000000, 0, pPerformance icall pSegment, IDirectMusicSegment_SetParam, pm, 5 ; セグメントの解放 release pSegment
実際には、あとでパフォーマンスをクローズするときにアンロードされていない音色はすべて自動的に解放されるため、明示的にアンロードする必要はありませんが。
パフォーマンスオブジェクトを閉じるには、 IDirectMusicPerformance::CloseDown メソッドを呼び出します。
HRESULT CloseDown();
このメソッドのパラメータはありません。パラメータなしのメソッドを呼び出す場合、 icall 命令の第3および第4パラメータを省略することができます。
このメソッドは、 IDirectMusicPerformance::Init メソッドに対応するもので、 Init メソッドを呼び出してパフォーマンスの初期化を行なった場合には必ず CloseDown メソッドによってパフォーマンスを閉じなければならないことになってます。
パフォーマンスをクローズできたら、 release 命令でパフォーマンスをを解放します。
; pPerformance->CloseDown(); icall pPerformance, IDirectMusicPerformance_CloseDown ; パフォーマンスの解放 release pPerformance
最後に、ローダーオブジェクトがまだ残っているので、これを解放します。
; ローダーの解放
release pLoader
今回は終了時にローダーの解放を行なっていますが、これ以上ファイルを読み込むことはないと判った時点で、解放してしまっても問題ありません。
ファイルを読み込むたびにローダーオブジェクトを作成・解放するということもできますが、ローダーが読み込んだオブジェクトはローダー自身によってキャッシュされているため、複数のファイルを読み込む場合には、1つのローダーを作成して、それを繰り返し使って読み込むほうが高速になります。
IID Explorer から取得されたオブジェクトのクラスID・インターフェースIDや、インターフェースのメソッドのインデックス、また、その他の GUID の定義を行なっています。メインスクリプトでこのファイルをインクルードする必要があります。
; 定義用スクリプト def.as ; クラスIDの定義 #define CLSID_DirectMusicPerformance "{d2ac2881-b39b-11d1-8704-00600893b1bd}" #define CLSID_DirectMusicLoader "{d2ac2892-b39b-11d1-8704-00600893b1bd}" #define CLSID_DirectMusicSegment "{d2ac2882-b39b-11d1-8704-00600893b1bd}" ; インターフェースIDとメソッドインデックスの定義 #define IID_IDirectMusicPerformance "{07D43D03-6523-11D2-871D-00600893B1BD}" ; IDirectMusicPerformance Methods in VTable Order #define IDirectMusicPerformance_QueryInterface 0 #define IDirectMusicPerformance_AddRef 1 #define IDirectMusicPerformance_Release 2 #define IDirectMusicPerformance_Init 3 #define IDirectMusicPerformance_PlaySegment 4 #define IDirectMusicPerformance_Stop 5 #define IDirectMusicPerformance_GetSegmentState 6 #define IDirectMusicPerformance_SetPrepareTime 7 #define IDirectMusicPerformance_GetPrepareTime 8 #define IDirectMusicPerformance_SetBumperLength 9 #define IDirectMusicPerformance_GetBumperLength 10 #define IDirectMusicPerformance_SendPMsg 11 #define IDirectMusicPerformance_MusicToReferenceTime 12 #define IDirectMusicPerformance_ReferenceToMusicTime 13 #define IDirectMusicPerformance_IsPlaying 14 #define IDirectMusicPerformance_GetTime 15 #define IDirectMusicPerformance_AllocPMsg 16 #define IDirectMusicPerformance_FreePMsg 17 #define IDirectMusicPerformance_GetGraph 18 #define IDirectMusicPerformance_SetGraph 19 #define IDirectMusicPerformance_SetNotificationHandle 20 #define IDirectMusicPerformance_GetNotificationPMsg 21 #define IDirectMusicPerformance_AddNotificationType 22 #define IDirectMusicPerformance_RemoveNotificationType 23 #define IDirectMusicPerformance_AddPort 24 #define IDirectMusicPerformance_RemovePort 25 #define IDirectMusicPerformance_AssignPChannelBlock 26 #define IDirectMusicPerformance_AssignPChannel 27 #define IDirectMusicPerformance_PChannelInfo 28 #define IDirectMusicPerformance_DownloadInstrument 29 #define IDirectMusicPerformance_Invalidate 30 #define IDirectMusicPerformance_GetParam 31 #define IDirectMusicPerformance_SetParam 32 #define IDirectMusicPerformance_GetGlobalParam 33 #define IDirectMusicPerformance_SetGlobalParam 34 #define IDirectMusicPerformance_GetLatencyTime 35 #define IDirectMusicPerformance_GetQueueTime 36 #define IDirectMusicPerformance_AdjustTime 37 #define IDirectMusicPerformance_CloseDown 38 #define IDirectMusicPerformance_GetResolvedTime 39 #define IDirectMusicPerformance_MIDIToMusic 40 #define IDirectMusicPerformance_MusicToMIDI 41 #define IDirectMusicPerformance_TimeToRhythm 42 #define IDirectMusicPerformance_RhythmToTime 43 #define IID_IDirectMusicLoader "{2FFAACA2-5DCA-11D2-AFA6-00AA0024D8B6}" ; IDirectMusicLoader Methods in VTable Order #define IDirectMusicLoader_QueryInterface 0 #define IDirectMusicLoader_AddRef 1 #define IDirectMusicLoader_Release 2 #define IDirectMusicLoader_GetObject 3 #define IDirectMusicLoader_SetObject 4 #define IDirectMusicLoader_SetSearchDirectory 5 #define IDirectMusicLoader_ScanDirectory 6 #define IDirectMusicLoader_CacheObject 7 #define IDirectMusicLoader_ReleaseObject 8 #define IDirectMusicLoader_ClearCache 9 #define IDirectMusicLoader_EnableCache 10 #define IDirectMusicLoader_EnumObject 11 #define IID_IDirectMusicSegment "{F96029A2-4282-11D2-8717-00600893B1BD}" ; IDirectMusicSegment Methods in VTable Order #define IDirectMusicSegment_QueryInterface 0 #define IDirectMusicSegment_AddRef 1 #define IDirectMusicSegment_Release 2 #define IDirectMusicSegment_GetLength 3 #define IDirectMusicSegment_SetLength 4 #define IDirectMusicSegment_GetRepeats 5 #define IDirectMusicSegment_SetRepeats 6 #define IDirectMusicSegment_GetDefaultResolution 7 #define IDirectMusicSegment_SetDefaultResolution 8 #define IDirectMusicSegment_GetTrack 9 #define IDirectMusicSegment_GetTrackGroup 10 #define IDirectMusicSegment_InsertTrack 11 #define IDirectMusicSegment_RemoveTrack 12 #define IDirectMusicSegment_InitPlay 13 #define IDirectMusicSegment_GetGraph 14 #define IDirectMusicSegment_SetGraph 15 #define IDirectMusicSegment_AddNotificationType 16 #define IDirectMusicSegment_RemoveNotificationType 17 #define IDirectMusicSegment_GetParam 18 #define IDirectMusicSegment_SetParam 19 #define IDirectMusicSegment_Clone 20 #define IDirectMusicSegment_SetStartPoint 21 #define IDirectMusicSegment_GetStartPoint 22 #define IDirectMusicSegment_SetLoopPoints 23 #define IDirectMusicSegment_GetLoopPoints 24 #define IDirectMusicSegment_SetPChannelsUsed 25 ; その他のGUIDの定義 #define GUID_StandardMIDIFile "{06621075-e92e-11d1-a8c5-00c04fa3726e}" #define GUID_Download "{d2ac28a7-b39b-11d1-8704-00600893b1bd}" #define GUID_Unload "{d2ac28a8-b39b-11d1-8704-00600893b1bd}"
#include "llmod.as" #include "unicode.as" #include "rrmod/com/lollipop.as" #include "def.as" ; ファイルのロード dialog "mid", 16 if stat == 0 : end sdim filename, 260 ; ファイル名を格納する変数 filename = refstr ; パフォーマンス作成 createobj pPerformance, CLSID_DirectMusicPerformance, IID_IDirectMusicPerformance if pPerformance == 0 { dialog "パフォーマンス作成に失敗", 1 goto *lb_free } ; パフォーマンス初期化 ; pPerformance->Init( NULL, NULL, NULL); pm = 0, 0, 0 icall pPerformance, IDirectMusicPerformance_Init, pm, 3 if dllret < 0 { dialog "パフォーマンスの初期化に失敗", 1 goto *lb_free } ; パフォーマンス初期化済みを示すフラグ f_init = 1 ; ポートの割り当て ; pPerformance->AddPort( NULL ); pm = 0 icall pPerformance, IDirectMusicPerformance_AddPort, pm, 1 if dllret < 0 { dialog "ポートの割り当てに失敗に失敗", 1 goto *lb_free } ; ローダー作成 createobj pLoader, CLSID_DirectMusicLoader, IID_IDirectMusicLoader ; DMUS_OBJECTDESC 構造体 dim objdesc, 212 objdesc.0 = 848 objdesc.1 = 0x00000032 ; DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME ; | DMUS_OBJ_FULLPATH ; CLSID を文字列形式から構造体に変換し objdesc の24バイト以降に格納 clsidconv objdesc, CLSID_DirectMusicSegment, 24 ; ファイル名のUnicode変換 sdim w_filename, 520 ; Unicodeを格納する変数 to_uni w_filename, filename, -1 ; Unicodeに変換 memcpy objdesc.78, w_filename, 520 ; IDirectMusicLoader::GetObject メソッド getptr pm.0, objdesc ; DMUS_OBJECTDESC 構造体アドレス取得 iidconv iid, IID_IDirectMusicSegment ; IID を文字列形式から構造体に変換 pm.1 = iid.0 ; IID 構造体のアドレス getptr pm.2, pSegment ; インターフェースを格納する変数 icall pLoader, IDirectMusicLoader_GetObject, pm, 3 if (dllret < 0)|(pSegment == 0) { dialog "ファイルロードに失敗", 1 goto *lb_free } ; pSegment->SetParam( GUID_StandardMIDIFile, 0xFFFFFFFF, ; DMUS_SEG_ALLTRACKS, 0, NULL ); iidconv guid, GUID_StandardMIDIFile pm = guid, -1, 0x80000000, 0, 0 icall pSegment, IDirectMusicSegment_SetParam, pm, 5 if dllret < 0 { dialog "トラックパラメータ設定1 失敗", 1 goto *lb_free } ; pSegment->SetParam( GUID_Download, 0xFFFFFFFF, DMUS_SEG_ALLTRACKS, ; 0, (void*)pPerformance ); iidconv guid, GUID_Download pm = guid, -1, 0x80000000, 0, pPerformance icall pSegment, IDirectMusicSegment_SetParam, pm, 5 if dllret < 0 { dialog "トラックパラメータ設定2(音色ダウンロード)失敗", 1 goto *lb_free } ; セグメントの再生 ; pPerformance->PlaySegment( pSegment, 0, (__int64) 0, NULL ); pm.0 = pSegment, 0, 0, 0, 0 ; 64ビット値は2つのパラメータとして扱う icall pPerformance, IDirectMusicPerformance_PlaySegment, pm, 5 if dllret < 0 { dialog "セグメントの再生に失敗", 1 goto *lb_free } ; 停止ボタン button "停止", *lb_stop onexit *lb_stop stop *lb_stop ; 演奏の停止 ; pPerformance->Stop( NULL, NULL, 0, 0 ); pm = 0, 0, 0, 0 icall pPerformance, IDirectMusicPerformance_Stop, pm, 4 *lb_free ; 終了時の処理(各オブジェクトの解放) if pSegment { ; pSegment->SetParam( GUID_Unload, 0xFFFFFFFF, DMUS_SEG_ALLTRACKS, ; 0, (void*)pPerformance ); iidconv guid, GUID_Unload pm = guid, -1, 0x80000000, 0, pPerformance icall pSegment, IDirectMusicSegment_SetParam, pm, 5 ; セグメントの解放 release pSegment pSegment = 0 } if pPerformance { if f_init { ; pPerformance->CloseDown(); icall pPerformance, IDirectMusicPerformance_CloseDown } ; パフォーマンスの解放 release pPerformance pPerformance = 0 } if pLoader { ; ローダーの解放 release pLoader pLoader = 0 } end