Juhara.com
Language : English Indonesia

Pemrograman DirectX Audio

Zamrony P. Juhara
19 September 2008 15:42:00
 (6443 views)
Tutorial dasar pemrograman DirectX Audio

(Artikel ini pertama kali terbit di majalah PC Media edisi 08/2007)

Setelah cukup banyak berkutat dengan pemrograman grafik 3D dengan Direct3D di artikel-artikel sebelumnya, agar tidak bosan, saya ingin mengajak Anda menjelajahi topik pemrograman lain yang tidak kalah menarik, yakni pemrograman suara menggunakan komponen DirectX yang lain, DirectX Audio.

Yang ingin saya diskusikan bersama Anda kali ini adalah dasar-dasar mengenai DirectX Audio meliputi: arsitektur DirectX Audio, istilah-istilah yang sering digunakan dan tentu saja bagian yang paling menarik adalah bagaimana menggunakan DirectX Audio untuk memainkan file audio.

Mengapa DirectX Audio?

Windows telah lama memiliki fitur multimedia melalui Multimedia Control Interface (MCI), Wave API dan MIDI API. Untuk aplikasi-aplikasi sederhana, MCI sudah cukup memadai untuk digunakan untuk memainkan file WAV atau MIDI.

Namun jika Anda bermaksud mengembangkan aplikasi sound recording kelas berat seperti produk milik CakeWalk atau game dengan kualitas suara yang ok, MCI tidak cocok.

DirectX Audio disediakan oleh Microsoft untuk pengembangan aplikasi audio berkinerja tinggi pada platform Windows. Dengan DirectX Audio, Anda dapat melakukan beberapa hal berikut dengan mudah:

  • Memainkan file atau resource berformat WAV, MIDI atau SGT.
  • Memainkan beberapa suara bersamaan.
  • Mengubah pitch, tempo, reverb dan menerapkan efek suara.
  • Merekam suara.
  • Memainkan suara 3D.

Arsitektur DirectX Audio

DirectX Audio terdiri atas dua komponen penyusun yakni DirectSound dan DirectMusic. DirectSound, yang diciptakan lebih dulu, ditujukan untuk akses hardware audio yang efisien dan cepat. DirectSound menyediakan mekanisme low-level untuk mengatur hardware audio secara langsung. DirectMusic diciptakan beberapa waktu kemudian, untuk menyediakan pemrograman low-level untuk perangkat MIDI yang disebut DirectMusic Core dan pemrograman level tinggi untuk proses loading dan memainkan (playback) media musik, disebut DirectMusic Performance.

Pada DirectX versi 7, DirectMusic dan DirectSound adalah komponen yang berdiri sendiri (lihat Gambar 1). MIDI dan musik berbasis style diload oleh DirectMusic Performance dan selanjutnya dikirim ke DirectMusic Core yang menangani langsung device MIDI dan synthesizer. Suara dalam bentuk file wave di-load ke memori dan disiapkan oleh aplikasi dan selanjutnya diberikan ke DirectSound yang menangani hardware wave.

Gambar 1. Arsitektur DirectMusic dan DirectSound pada DirectX versi 7 ke bawah.

Gambar 1. Arsitektur DirectMusic dan DirectSound pada DirectX versi 7 ke bawah.

Setelah rilis DirectMusic, para pengembang aplikasi lebih menyukai DirectMusic Performance untuk menghandle proses loading dan memainkan file musik. Pada DirectX 8, arsitektur DirectMusic dan DirectSound disatukan sehingga DirectMusic Performance digunakan untuk proses loading dan memainkan MIDI dan suara berformat wave. Penyatuan DirectMusic dan DirectSound ini disebut DirectX Audio (Gambar 2). Arsitektur ini tidak berubah pada DirectX 9.

Gambar 2. Arsitektur DirectMusic dan DirectSound pada DirectX 8 dan 9

Gambar 2. Arsitektur DirectMusic dan DirectSound pada DirectX 8 dan 9.

Pada DirectX 8, Microsoft menambahkan fungsionalitas pada Performance sehingga dapat membaca file wave dan memainkan suara berformat wave yang tersimpan dalam segment. Perubahan signifikan pada arsitektur ini adalah diperkenalkannya konsep audiopath yang memisahkan DirectMusic Performance dengan DirectMusic Core. Sebuah audiopath adalah audio channel virtual yang mengontrol aliran data suara. DirectMusic Performance menangani satu atau lebih audiopath

Performance

Performance adalah jantung DirectX Audio. Performance melakukan inisialisasi audio, mengatur penjadwalan segment-segment, menciptakan dan memetakan audiopath ke segment serta mengontrol proses playback suara.

Loader

Loader berfungsi untuk proses file Input/Output juga membaca data audio dari memori atau resource. Penggunaan loader menyederhanakan tugas programmer untuk membaca data audio.

Segment

Segment mewakili segala macam audio yang dapat dimainkan. Dapat berupa file MIDI atau wave atau file DirectMusic Segment (format default DirectMusic, berekstensi SGT). Anda dapat membuat lebih dari satu segment dalam sebuah aplikasi. Anda bahkan bisa memainkan beberapa segment secara bersamaan.

AudioPath

AudioPath adalah objek DirectMusic yang bertugas mengatur rute yang harus diambil oleh instrument musik atau efek suara. Tiap segement yang dimainkan melalui sebuah audiopath. Aplikasi dapat memiliki lebih dari satu audiopath.

Menciptakan Performance dan Loader

DirectMusic tidak menyediakan fungsi pembantu untuk menciptakan instance performance dan loader. Anda harus menggunakan fungsi CoCreateInstance() untuk menciptakan instance performance dan loader (lihat Listing 1)

Listing 1

  CoCreateInstance(
    CLSID_DirectMusicPerformance,
    nil,
    CLSCTX_INPROC,
    IID_IDirectMusicPerformance8,
    FPerformance);

  CoCreateInstance(
    CLSID_DirectMusicLoader,
    nil,
    CLSCTX_INPROC,
    IID_IDirectMusicLoader8,
    FLoader);

Setelah pemanggilan kode pada Listing 1, jika sukses, FPerformance akan diisi dengan pointer ke instance interface IDirectMusicPerformance8, sedangkan FLoader akan diisi alamat instance interface IDirectMusicLoader8.

Sebelum fungsi CoCreateInstance() ini dipanggil, Anda harus melakukan inisialisasi COM, dengan memanggil CoInitialize() atau CoInitializeEx() (lihat Listing 2). Setelah selesai dengan COM, sebaiknya Anda panggil CoUnitialize(). Di Delphi, fungsi-fungsi COM dideklarasi di unit ActiveX.pas.

Listing 2

unit ..;
interface
...
implementation
uses ...,ActiveX,..;
...
initialization
  CoInitialize(nil);
finalization
  CoUninitialize;
end.

Saya pribadi lebih suka memanggil fungsi inisialisasi COM dibagian inisialisasi unit sehingga kode insialisasi COM otomatis akan dipanggil tiap kali unit direferensi.

Inisialisasi Audio

Setelah selesai inisialisasi COM dan menciptakan performance, kita perlu memanggil InitAudio milik IDirectMusicPerformance8 untuk melakukan inisialisasi audio (Listing 3). Fungsi InitAudio hanya perlu dipanggil sekali saja.

Listing 3

function InitAudio (ppDirectMusic: PIDirectMusic; 
        ppDirectSound: PIDirectSound;
        hWnd: hWnd; 
        dwDefaultPathType, 
        dwPChannelCount, 
        dwFlags: DWORD;
        pParams: PDMUS_AudioParams) : HResult; stdcall;

Contoh pemanggilan InitAudio adalah seperti pada Listing 4:

Listing 4

FPerformance.InitAudio(nil,
    nil,
    WindowHandle,
    DMUS_APATH_SHARED_STEREOPLUSREVERB,
    64,
    DMUS_AUDIOF_ALL,
    nil);

Ok, mari kita bahas satu persatu parameter fungsi InitAudio ini. Parameter ppDirectMusic dan ppDirectSound masing-masing adalah instance DirectMusic dan DirectSound. Jika Anda ingin instance DirectMusic atau DirectSound diciptakan otomatis isi saja dengan nil. hWnd adalah handle window yang digunakan untuk menciptakan interface IDirectSound. Jika ppDirectSound berisi instance DirectSound yang valid, hWnd diabaikan. Parameter dwDefaultPathType berisi tipe audiopath yang diinginkan seperti yang tercantum di Tabel 1. Jika Anda tidak membutuhkan audiopath default, bisa diisi dengan nol.

Tabel 1. Tipe audiopath
Nilai Deskripsi
DMUS_APATH_DYNAMIC_3D Audiopath untuk suara 3D.
DMUS_APATH_DYNAMIC_MONO Mono
DMUS_APATH_DYNAMIC_STEREO Audiopath stereo.
DMUS_APATH_SHARED_STEREOPLUSREVERB Stereo dan reverb.

dwPChannelCount adalah jumlah performance channel yang diinginkan. Tiap channel memiliki setting volume dan balance sendiri-sendiri. dwFlags menentukan fitur yang Anda inginkan. Flag yang dapat Anda gunakan tercantum pada Tabel 2. Sebenarnya ada beberapa flag lain namun flag-flag tersebut belum diimplementasikan.

Tabel 2. Flag Fitur
Flag Deskripsi
DMUS_AUDIOF_3D 3D buffer.
DMUS_AUDIOF_ALL Semua fitur
DMUS_AUDIOF_BUFFERS Multiple buffer
DMUS_AUDIOF_STREAMING Mendukung streaming waveform

pParams berisi alamat ke struktur data bertipe D3DMUS_AUDIOPARAMS. Jika diisi dengan nil, maka parameter default akan digunakan. Agar sesuai dengan konvensi penamaan tipe di Delphi, tipe data ini diberi nama TDMus_AudioParams. Record ini memiliki field dwSize, ukuran data. Harus diisi dengan sizeof(TDMus_AudioParams). fInitNow, bertipe Boolean. Jika diisi true, synthesizer akan diciptakan saat ini juga. dwValidData, bertipe Dword berisi flag yang menentukan data apa yang valid. Flag yang dapat digunakan adalah seperti Tabel 3.

Tabel 3 Flag untuk dwValidData
Flag Deskripsi
DMUS_AUDIOPARAMS_FEATURES Field dwFeatures berisi data yang valid.
DMUS_AUDIOPARAMS_VOICES Field dwVoices berisi data yang valid.
DMUS_AUDIOPARAMS_SAMPLERATE Field dwSampleRate berisi data yang valid.
DMUS_AUDIOPARAMS_DEFAULTSYNTH Field clsidDefaultSynth berisi data valid. Jika flag ini tidak diset, Microsoft software synthesizer yang akan digunakan.
  • dwFeatures, fitur yang diinginkan. Flag yang dapat digunakan tercantum di Tabel 2.
  • dwVoices, jumlah voice, defaultnya adalah 64.
  • dwSampleRate, sample rate yang digunakan. Nilai yang bias digunakan adalah 11025 Hz hingga 96000 kHz. Jika tidak diset, defaultnya 22050 Hz.
  • clsidDefaultSynth, Default synthesizer yang digunakan.

Loading File Audio

Untuk membaca file MIDI atau WAV atau file segment (SGT), Anda menggunakan objek loader dengan fungsi LoadObjectFromFile() (Listing 5).

Listing 5

function LoadObjectFromFile(const rguidClassID: TGUID; 
      const iidInterfaceID: TGUID;
      pwzFilePath: PWideChar; 
      out ppObject): HResult; stdcall;

rquidClassID adalah class ID objek yang kita ingin load. Untuk membaca file audio ke segment kita menggunakan CLSID_DirectMusicSegment.

iidInterfaceID adalah pengenal interface bisa kita isi dengan IID_IDirectMusicSegment8 untuk menciptakan segment bertipe IDirectMusicSegment8. Dengan Delphi, Anda bisa langsung menggunakan nama interface menggantikan pengenal interface. Jadi menggantikan IID_IDirectMusicSegment8 dengan IDirectMusicSegment8 boleh saja dilakukan.

pwzFilePath adalah nama file yang hendak kita baca. Nama ini harus dalam format widestring (2 byte per character). Jika Anda menggunakan ANSI string, pastikan terlebih dahulu mengkonversi string ke tipe widestring. Setelah nama file tersebut bertipe widestring, lakukan typecast ke PWidechar.

ppObject adalah variable yang akan menampung alamat objek yang diciptakan. Untuk kasus kita, objeknya adalah instance IDirectMusicSegment8. Listing 6 berisi contoh bagaimana membaca file WAV ke segment bernama FSound1.

Listing 6

procedure LoadAudioFile;
var afilename:widestring;
    apath:string;
begin
  apath:=ExtractFilePath(
         application.ExeName)+'sound';
  afilename:=apath+'explosion.wav';
  FLoader.LoadObjectFromFile(
         CLSID_DirectMusicSegment,
         IID_IDirectMusicSegment8,
         PWideChar(afilename),
         FSound1);
end;

LoadObjectFromFile sesuai namanya hanya mampu membaca data dari file. Lalu bagaimana bila data tersebut sudah ada, misalnya, di memori. Untuk kasus ini, Anda membutuhkan GetObject() (Listing 7).

Listing 7

function GetObject (const pDesc: TDMus_ObjectDesc; 
        const riid : TGUID;
        out ppv) : HResult; stdcall;

pDesc adalah deskripsi objek yang hendak di-load. Kita akan membasa tipe TDMus_ObjectDesc segera. riid adalah pengenal interface. ppv berisi variable yang akan menampung pointer instance objek.

TDMus_ObjectDesc

Tipe data ini mendeskripsikan bagaimana objek yang akan dibaca, terdiri atas field-field berikut:

  • dwSize, ukuran struktur data. Harus diisi dengan sizeof(TDMus_ObjectDesc).
  • dwValidData, flag yang menentukan field-field mana yang mengandung data valid. Flag yang bias digunakan adalah seperti Tabel 4.
  • guidObject, GUID objek.
  • guidClass, pengenal kelas objek.
  • ftDate, tanggal objek diedit.
  • vVersion, informasi versi.
  • wszName, nama objek.
  • wszCategory, kategori objek
  • wszFilename, nama file yang hendak dibaca.
  • llMemLength, ukuran memori buffer.
  • pbMemData, buffer berisi data
  • pStream, alamat instance IStream.
Tabel 4. Flag TDMus_ObjectDesc
Flag Deskripsi
DMUS_OBJ_CATEGORY Field wszCategory mengandung data valid.
DMUS_OBJ_CLASS guidClass berisi data valid.
DMUS_OBJ_OBJECT quidObject berisi data valid.
DMUS_OBJ_DATE ftDate berisi data valid.
DMUS_OBJ_VERSION vVersion berisi data valid.
DMUS_OBJ_NAME wszName berisi data valid.
DMUS_OBJ_FILENAME wszFilename berisi data valid.
DMUS_OBJ_FULLPATH wszFilename berisi data valid dan berupa nama file lengkap dengan path.
DMUS_OBJ_MEMORY llMemLength dan pbMemData berisi data valid.
DMUS_OBJ_STREAM pStream berisi data valid.

Contoh bagaimana membaca data audio yang ada dalam stream bisa Anda pelajari di Listing 8. Saya biasanya menginisialisasi struktur ini dengan nol sebelum mengisi field-field menggunakan ZeroMemory().

Untuk membaca data yang ada di memori ke segment, Anda membutuhkan alamat buffer berisi data dan ukuran buffer tersebut. Anda juga membutuhkan field guidClass untuk memberitahukan DirectMusic agar menciptakan instance segment. Oleh karena itu Anda paling tidak harus menggunakan kombinasi flag DMUS_OBJ_CLASS dan DMUS_OBJ_MEMORY.

Listing 8

procedure LoadFromStream(Stream: TStream);
var objdesc:TDMus_ObjectDesc;
begin
    if FInternalStream=nil then 
       FInternalStream:=TMemoryStream.Create;
 
  FInternalStream.CopyFrom(Stream,0);

  ZeroMemory(@objDesc,
             sizeof(TDMus_ObjectDesc));
  objdesc.dwSize:=sizeof(TDMus_ObjectDesc);
  objdesc.dwValidData:=DMUS_OBJ_CLASS or 
                       DMUS_OBJ_MEMORY;
  objdesc.guidClass:=CLSID_DirectMusicSegment;
  objdesc.llMemLength:=FInternalStream.Size;
  objdesc.pbMemData:=FInternalStream.Memory;

  FLoader.GetObject(objdesc,
                    IID_IDirectMusicSegment8,
                    FSegment);
end;

Loader melakukan cache data yang ada di buffer. Buffer yang berisi data tidak boleh dibebaskan sampai loader dibebaskan. Hal ini disebabkan karena loader mungkin membutuhkan data yang ada di buffer tersebut sewaktu-waktu akibat mekanisme cache.

Jika Anda menggunakan DMUS_OBJ_FILENAME atau DMUS_OBJ_FULLPATH, GetObject menjadi mirip LoadObjectFromFile().

Mendownload Segment ke Performance

Sebelum segment dapat dimainkan, segment perlu didownload ke performance atau audiopath. Proses download, memindahkan data-data instrument dan waveform yang dipakai oleh segment ke performance ke performance.nkan, segment perlua Listing 7. belajar dasarnya.. Untuk mendownload, kita memanggil fungsi Download() milik interface IDirectMusicSegment8 (Listing 9).

Listing 9

function Download (pAudioPath: IUnknown) : HResult; stdcall;

Contoh kode pada Listing 10 mendownload segment bernama FSound1 ke performance.

Listing 10

FSound1.Download(FPerformance);

Memainkan Suara

Untuk memainkan suara yang tersimpan dalam segment, tersedia dua fungsi PlaySegment() dan PlaySegmentEx() (lihat Listing 11). Fungsi pertama tersedia pada interface IDirectMusicPerformance dan IDirectMusicPerformance8 sedangkan fungsi terakhir hanya tersedia pada interface IDirectMusicPerformance8. PlaySegmentEx adalah perluasan fungsi PlaySegment().

Listing 11

function PlaySegment (pSegment: IDirectMusicSegment; 
        dwFlags: DWORD;
        i64StartTime: LongLong; 
       ppSegmentState: PIDirectMusicSegmentState) : HResult; stdcall;

function PlaySegmentEx (pSource: IUnknown; 
        pwzSegmentName: PWChar;
        pTransition: IUnknown; 
        dwFlags: DWORD; 
        i64StartTime: int64;
        out ppSegmentState: IDirectMusicSegmentState; 
        pFrom, pAudioPath: IUnknown) : HResult; stdcall;

pSegment dan pSource adalah objek segment yang akan dimainkan. pwzSegmentName adalah nama segment. Untuk saat ini belum digunakan, jadi harus diisi nil. dwFlags berisi flags yang mengatur bagaimana segment dimainkan. Beberapa flag yang dapat Anda pergunakan tercantum pada Tabel 5. Flag yang tersedia cukup banyak namun menurut saya tidak terlalu relevan karena kita baru belajar dasarnya.

Tabel 5. Flag PlaySegment
Flag Deskripsi
DMUS_SEGF_REFTIME Waktu menggunakan satuan waktu referensi
DMUS_SEGF_SECONDARY Segment sekunder
DMUS_SEGF_QUEUE Segment dimainkan setelah segment utama selesai. Jika menggunakan segment sekunder, maka segement dimainkan setelah segment yang ada pada pFrom.
DMUS_SEGF_CONTROL Segment dimainkan sebagai segment control.

i64StartTime adalah posisi dimana suara mulai dimainkan. ppSegmentState adalah interface yang berisi status segment yang sedang dimainkan. pFrom berisi segment yang dihentikan ketika segment yang ada di pSource dimainkan, bisa diisi dengan nil. pAudioPath berisi audiopath yang digunakan untuk memainkan segment. Jika diisi nil, audiopath default digunakan.

Contoh kode pada Listing 12 memainkan segment FSound1 dari awal segment menggunakan audiopath default. Status segment disimpan di variable state.

Listing 12

FPerformance.PlaySegmentEx(FSound1,
             nil,nil,
             0,0,
             state,
             nil,nil);

Kode pada Listing 13 menghasilkan output yang sama dengan kode pada Listing 12.

Listing 13

FPerformance.PlaySegment(FSound1,
             0,0,nil);

Anda bisa mencoba demo DM1.pr dan DM2.dpr yang ada di CD/DVD.

Memainkan Beberapa Suara Bersamaan

Jika Anda, coba demo DM1.dpr atau DM2.dpr, tiap kali Anda menekan sebuah tombol, segment suara yang sedang dimainkan akan dihentikan. Anda tidak dapat memainkan dua atau lebih segment bersamaan dengan cara di atas. Teknik tersebut hanya cocok untuk aplikasi sound player, di mana musik dimainkan satu per satu.

Dalam aplikasi game, beberapa suara dapat dimainkan bersama sekaligus. Dalam game perang misalnya, suara dentuman meriam, suara senapan dan suara tentara terluka harus dapat dimainkan bersama-sama untuk memberi ilusi perang sesungguhnya.

Untuk dapat memainkan beberapa segment bersamaan, Anda membutuhkan audiopath untuk masing-masing segment. Di demo DM1.dpr dan DM2.dpr, kita hanya menggunakan satu audiopath, yakni audiopath default.

Untuk menciptakan audiopath, Anda dapat menggunakan CreateStandardAudioPath() milik interface IDirectMusicPerformance8 (Listing 14).

Listing 14

function CreateStandardAudioPath (dwType, 
        dwPChannelCount: DWORD; 
        fActivate: BOOL;
        out ppNewPath: IDirectMusicAudioPath) : HResult; stdcall;

dwType diisi dengan tipe audiopath. Lihat Tabel 1 untuk flag yang tersedia. dwPChannelCount, Anda isi dengan jumlah performance channel yang Anda inginkan. fActivate kita set dengan true untuk mengaktifkan audiopath. Jika Anda set false, Anda dapat mengaktifkannya lain waktu menggunakan fungsi Activate() milik interface IDirectMusicAudioPath8. ppNewPath akan diisi dengan pointer ke instance audiopath. Contoh kode dapat Anda pelajari di Listing 15.

Listing 15

FPerformance.CreateStandardAudioPath(
       DMUS_APATH_SHARED_STEREOPLUSREVERB,
       64,true,
       FAudioPath1);

Selanjutnya audiopath yang hendak digunakan digunakan ketika memanggil PlaySegmentEx(). Tidak cukup dengan itu, Anda juga harus memainkannya menggunakan segment sekunder yakni dengan flag DMUS_SEGF_SECONDARY (Listing 16). Tanpa flag ini, segment akan dimainkan sebagai segment primer. Hanya ada satu segment primer yang dapat dimainkan pada satu saat. Oleh karena itu, segment primer baru akan menggantikan segment primer yang sedang dimainkan.

Listing 16

FPerformance.PlaySegmentEx(FSound1,
                     nil,nil,
                     DMUS_SEGF_SECONDARY,
                     0,
                     state,
                     nil,
                     FAudioPath1);

Silakan Anda coba demo DM3.dpr. Jika Anda tekan tombol meriam, senapan dan bom berulang-ulang, Anda seolah-olah berada dalam suasana perang.

Memainkan suara berulang-ulang

Ada kalanya Anda ingin memainkan musik sebagai latar secara berulang-ulang. Untuk mengatur berapa banyak sebuah segment dimainkan, Anda mengaturnya dengan menggunakan fungsi SetRepeats milik interface IDirectMusicSegment8. Parameter fungsi ini adalah jumlah pengulangan yang Anda inginkan. Jika diisi dengan 0, segment akan dimainkan sekali tanpa pengulangan. Jika diisi dengan konstanta DMUS_SEG_REPEAT_INFINITE, segment akan dimainkan berulang-ulang sampai dihentikan secara ekplisit. Contoh pemanggilan SetRepeats() bisa Anda pelajari di Listing 17.

Listing 17

//segment diulang sekali
FSegment1.SetRepeats(1);
//looping terus menerus
FSegment1.SetRepeats(DMUS_SEG_REPEAT_INFINITE);

Apakah segment sedang dimainkan?

Untuk mengetahui apakah suatu segment sedang dimainkan, Anda dapat menggunakan fungsi isPlaying() milik interface IDirectMusicPerformance8 (Listing18).

Listing 18

function IsPlaying (pSegment: IDirectMusicSegment; 
    pSegState: IDirectMusicSegmentState) : HResult; stdcall;

Kita dapat mengecek menggunakan segment atau segment state. Jika pSegment berisi nil, yang digunakan adalah pSegState atau sebaliknya pSegState nil maka pSegment yang digunakan.

Jika segment sedang dimainkan, nilai kembali fungsi ini adalah S_OK atau S_FALSE bila sebaliknya.

Menghentikan Suara

Segment yang sedang dimainkan dapat dihentikan dengan menggunakan Stop() atau StopEx() (Listing 19). Kedua fungsi adalah fungsi objek performance. Fungsi StopEx adalah perluasan Stop() dan tersedia pada interface IDirectMusicPerformance8.

Listing 19

function Stop (pSegment: IDirectMusicSegment; 
         pSegmentState: IDirectMusicSegmentState;
         mtTime: TMusic_Time; 
         dwFlags: DWORD) : HResult; stdcall;
function StopEx (pObjectToStop: IUnknown; 
        i64StopTime: int64; 
        dwFlags: DWORD) : HResult; stdcall;

pSegment adalah segment yang hendak dihentikan Jika diisi nil, semua segment yang sedang dimainkan akan dihentikanada padahenti. Jika diisi nol, segment dihentikan seketika.idownload.ggil Unload() untuk mengunl. pObjectToStop adalah segment atau segment state atau audiopath yang hendak dihentikan. mtTime dan i64StopTime adalah waktu berhenti. Jika diisi nol, segment dihentikan seketika. dwFlags adalah flag yang mempengaruhi bagaimana segment dihentikan bisa diisi nol atau flag yang ada pada Tabel 5. Contoh bagaimana menghentikan segment dapat Anda lihat di Listing 20.

Listing 20

//menghentikan semua segment
FPerformance.Stop(nil,nil,0,0);
//Menghentikan segment FSound1
FPerformance.StopEx(FSound1,0,0);

Menghentikan Suara Sementara (Pause)

DirectX Audio tidak menyediakan fungsi khusus untuk melakukan pause, namun Anda bisa menghasilkan aksi yang mirip dengan pause dengan menggunakan StopEx() dan PlaySegmentEx().

Sebelum Anda menghentikan segment, posisi segment saat ini harus Anda simpan. Ketika hendak melakukan resume, posisi yang anda simpan, digunakan untuk mengubah start point playback. Anda mengubah start playback segment menggunakan fungsi SetStartPoint() milik interface IDirectMusicPerformance8. Setelah memanggil SetStartPoint(), Anda memainkan segment seperti biasa dengan PlaySegmentEx().

Menutup DirectX Audio

Ketika selesai dengan DirectX Audio, Anda harus memanggil fungsi CloseDown() milik objek performance. Fungsi ini tidak membutuhkan parameter apa-apa.

Sebelum memanggil CloseDown() ada baiknya anda memanggil Unload() untuk meng-unload segment-segment yang sebelumnya sudah didownload ke performance. Parameternya sama dengan fungsi Download yakni audiopath atau performance di mana segment didownload.

Sebenarnya memanggil Unload() tidak wajib dilakukan ketika menutup performance, karena CloseDown otomatis akan meng-unload segment-segment yang ada. Listing 21 berisi contoh kode bagaimana menutup DirectX Audio.

Listing 21

FSound1.Unload(FPerformance);
FPerformance.CloseDown();
FPerformance:=nil;

Loader menggunakan mekanisme cache untuk mempercepat proses playback. Objek yang diciptakan dengan GetObject() atau LoadObjectFromFile() mungkin mereferensi objek lain. Sebuah file MIDI mungkin memiliki referensi ke file MIDI lain. GetObject otomatis akan menciptakan object yang direferensi dan menambahkan ke cache.

Untuk membebaskan object-object tersebut secara menyeluruh, ada beberapa hal yang harus Anda kerjakan.

  • Memanggil ReleaseObjectByUnknown() untuk tiap objek yang dibuat menggunakan GetObject() atau LoadObjectFromFile()
  • Memanggil CollectGarbage().

Jika anda tidak menggunakan object yang mereferensi objek lain, Anda tidak perlu memanggil ReleaseObjectByUnknown() dan CollectGarbage(). Contohnya jika me-load WAV ke segment, Anda tidak perlu melakukan langkah di atas karena WAV tidak mereferensi file eksternal. Namun hal ini adalah kebiasan baik untuk memastikan memori yang kita pergunakan benar-benar dibebaskan semua.

Listing 22

FLoader.ReleaseObjectByUnknown(FSound1);
FLoader.CollectGarbage;
FLoader:=nil;

Aplikasi Demo

Aplikasi demo dapat Anda dapatkan source code-nya di CD/DVD. Demo DM1.dpr berisi demo bagaimana melakukan inisialisasi DirectX Audio dan memainkan segment menggunakan PlaySegment(). Demo DM2.dpr hampir sama dengan DM1, namun yang digunakan adalah PlaySegmentEx().

Demo DM3.dpr adalah perluasan demo DM2.dpr. Di aplikasi ini, kita mampu memainkan beberapa suara sekaligus. Demo DM4.dpr merupakan perluasan DM3.dpr dengan penambahan musik latar berformat MIDI yang akan dimainkan terus menerus sampai aplikasi ditutup.

Secara umum user interface aplikasi demo tampak seperti pada Gambar 3.

Gambar 3. User interface aplikasi demo

Gambar 3. User interface aplikasi demo.

Source code aplikasi demo dapat di download di sini

Ringkasan

Anda telah sampai pada bagian akhir artikel ini. Saya harapkan Anda telah mengetahui teknik dasar memanfaatkan DirectX Audio dalam aplikasi Anda. Di artikel ini, Anda telah belajar tentang arsitektur DirectX Audio, melakukan inisialisasi, membaca dan memainkan file suara menggunakan DirectX Audio, serta bagaimana memainkan beberapa suara bersamaan.

Artikel Terkait

Anda suka artikel ini? Bantu website ini berkembang dengan menyumbang. Berapapun jumlahnya akan sangat dihargai.

Atau Anda dapat membantu dengan membuat bookmark. Delicious Bookmark this on Delicious