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