Nedílnou součástí každé hry je samozřejmě zvuk. A my si dnes ukážeme, jak vnést do vaší aplikace toto oživení pomocí DirectX, respektive DirectSound.
DirectSound DirectSound a DelphiX
V DelphiX je DirectSound zastoupeno třemi komponentami: DXSound, DXWave a DXWaveList. DXSound nám umožní pomocí několika tříd a rozhraní snadno a rychle pracovat právě s DirectSound. DXWave slouží k uložení jednoho Wav souboru a DXWaveList umožní ukládat těchto souborů více a nastavit u nich některé vlastnosti. Nejjednodušší způsob jak začít pracovat s DirectSound v DelphiX je umístění na formulář jedné komponenty DXSound a DXWaveList, u které nastavíte vlastnost DXSound na právě umístěnou komponentu DXSound. Položka Items u DXWaveListu je opět klasická kolekce, do které nahrajte požadovaný počet wav souborů. Při vámi vybrané události stačí zavolat tuto metodu:
TDXWaveList.Items[#].Play(Wait: Boolean);
Číslo # je index do Wave kolekce se zvuky a metoda Play tento zvuk přehraje. Parametrem Wait nastavíte, má-li aplikace počkat, až soubor skončí. DirectSound má jednu skvělou výhodu: pokud se právě přehrává nějaký zvuk a vy chcete přehrát další, nevyvolá se vyjímka typu: "Chyba xxx, zařízení je právě používáno..." ale soubor se prostě přehraje přes původní, takže jsou slyšet oba. Tímto způsobem se dají skvěle mixovat zvuky: jeden třeba jako hudba do pozadí a další jako zvukové efekty. Teoreticky můžete namixovat neomezené množství wavů, ale už při zhruba 5 zvucích už téměř není možné je rozeznat a z bedniček se začíná linout rozličné chrčení. Pozor, podporován je pouze formát PCM, žádný ADPCM, CCITT, ACELP apod. DirectSound ale umožňuje více než jen přehrání souboru. Jak, na to se teď podíváme:
Tato třída slouží k podobnému účelu a pracuje na podobném principu jako TDirectDrawSurface u DirectDraw, ale neukládá obrázky, nýbrž zvuky. Pro každý wav soubor je vytvořena samostatná instance této třídy, poté se nastaví několik dalších vlastností zvuku (opakování, hlasitost, pozice, frekvence apod.). Na požádání se zvuk přehraje. Nabízí tyto vlastnosti na úpravu přehrávání wav souboru:
- Looped - zde nastavuje, zda-li se má zvuk automaticky opakovat, je-li true, nemá pak vliv parametr Wait u metody Play
- Frequency - udává frekvenci zvuku v Hertzech(Hz), po nahrání souboru se zjistí frekvence a automaticky se dosadí, ale vy tuto hodnotu můžete měnit, čímž se přehrávaný zvuk deformuje. Nejběžnější frekvence jsou 22,05 a 44,1 kHz.
- Pan - vyvážení zvuku mezi pravým a levým reproduktorem, je-li -10000 je pravý reproduktor umlčen a hraje pouze levý, je-li +10000, tak jest tomu naopak
- Volume - umožňuje nastavit hlasitost zvuku, bohužel (bohudík) pouze jenom ztišit. Hodnota 0 znamená normální hlasitost a -10000 je úplné umlčení
- Position - pozice v bufferu, kde se zrovna přehrává. S tím souvisí také
- Size - což je velikost bufferu. Obě tyto vlastnosti jsou v bytech. Vlastnost Size je ReadOnly.
- Playing - umožňuje detekovat, zda-li je daný buffer přehráván. Také jen pro čtení.
- Potom jsou zde ještě dvě metody. O první, Play, jsem se již zmiňoval a metoda Stop přehrávání zastaví, a to i tehdy spustili jste přehrávání wavu vícekrát-zastaví se vše.
Pomocí této třídy se dá efektivně přehrát větší soubor, u kterého si nemůžete dovolit nahrát ho celý do paměti. Proměnnou BufferLength nastavíte velikost zásobníku (v milisekundách), do kterého se "přednahraje" část zvuku. Velikost musí být alespoň 10ms. Taktéž nabízí vlastnosti Playing, Looped, Frequency, Pan a Volume, které nastavují vlastnosti zásobníku. Dceřiná třída
TAudioFileStream umožňuje snadnější nahrání souboru z disku.
Třída TWaveCollectionItem
Tato třída se podobá třídě TPictureCollectionItem. Je to položka kolekce TWaveCollection, jež je obsažena v komponentě DXWaveList. Budou nás zajímat tyto dvě vlastnosti:
- MaxPlayingCount - kolikrát se maximálně v jednom okamžiku může daný zvuk přehrávat, je-li 0 není množství omezeno
- Wave - vlastní wav soubor
I zde lze použít vlastnosti Playing, Looped, Frequency, Pan a Volume na změnu vlastností bufferu.
Nyní si ukážeme jednoduchý příklad na přehrání souboru pomocí třídy TAudioFileStream. Umístěte na formulář jeden DXSound a poté si nadeklarujte globální proměnnou :
Zvuk:TAudioFileStream;
a tu pak po skončení inicializace objektu DXSound (událost OnInitialize) zavedeme do paměti :
Zvuk:=TAudioFileStream.Create(DXSound1.DSound);
Jako parametr předáme ukazatel na objekt TDirectSound, který obsahuje rozhraní na DirectSound. Instanci při události OnFinalize objektu DXSound uvolníme :
Zvuk.Free;
Na formulář dejte třebas OpenDialog, pomocí něhož bude uživatel zadávat cestu k wav souboru (cesta k souboru může být samozřejmě zadána jakkoliv jinak). Vybere-li uživatel pomocí dialogu nějaký soubor, nastavíme vlastnosti našeho Zvuku:
if OpenDialog1.Execute then
begin
with zvuk do
begin
AutoUpdate := True;
BufferLength := 1000;
FileName := OpenDialog1.FileName;
end;
end;
Proměnná AutoUpdate udává, zda-li se mají data z disku automaticky načítat do zásobníku. Pokud byste zadali false, tak byste museli ručně aktualizovat data voláním metody Update a to tak často, aby nedošlo vyčerpání zásobníku.
BufferLength udává délku bufferu, jak jsem se již zmiňoval.
FileName je vlastní cesta k souboru na disku.
Při vámi zvolené události se soubor přehraje:
Zvuk.Play;
nebo zastaví :
Zvuk.Stop;
Zjišťování a nastavování vlastností zvuku
Nastavení vlastností Pan, Frequency, Volume a Position je jednoduché. Nejprve na formulář umisťte něco vhodného na ovládání, třeba TrackBar. V události OnChange napište :
Zvuk.Volume:=TrackBar1.Position;
Tímto příkazem změníte hlasitost zvuku na hodnotu, která je na TrackBaru. Pokud chcete měnit třeba vyvážení, tak prostě místo Zvuk.Volume napíšete Zvuk.Pan. Akorát si dejte pozor na rozsah hodnot TrackBaru. Pro hlasitost by Max mělo být 0 a Min -10000, pro Pan pak -10000 - +10000. Pro Frequency je to celkem jedno, ale pro nějaké experimentování by vám mělo stačit +1000 - +100000. Rozsah pro Position může být různý, a proto ho musíte při každém otevření nového souboru nastavit. Min je vždy 0 a Max je roven velikosti wavu:
TrackBar4.Max:=Zvuk.Size;
Looping zvuku také není problém. Měnit ho můžeme například pří kliknutí na CheckBox:
Zvuk.Looped:=CheckBox2.Checked;
Ke zjištění formátu souboru použijeme vlastnost TAudioStream.Format typu PWaveFormatEx, což je ukazatel na typ TWaveFormatEx (popsaný v jednotce MMSystem):
Label11.Caption:=IntToStr(Zvuk.Format.nSamplesPerSec);
Label12.Caption:=IntToStr(Zvuk.Format.nChannels);
Label13.Caption:=IntToStr(Zvuk.Format.wBitsPerSample);
Z této proměnné můžeme přečíst leckteré informace o zvuku. nSamplesPerSec je Frekvence zvuku, nChannels je počet kanálů a wBitsPerSample je počet bitů. Tyto údaje nám také umožní přepočítat velikost a pozici zvuku z bajtů na sekundy.Tímto vzorcem zjistím, kolik sekund zvuk trvá:
Zvuk.Size div ((TrackBar3.Position div 100)*(Zvuk.Format.wBitsPerSample div 8));
Vím že nSamplesPerSec-krát za sekundu se přehraje wBitsPerSample bitů. Jelikož vlastnost Zvuk.Size je v bytech, musím vydělit wBitsPerSample osmi (1 byte=8 bitů, to snad ví každý). TrackBar3.Position jsem použil proto, že frekvenci budeme během přehrávání měnit právě pomocí tohoto TracBaru; byla-li by konstantní můžete toto nahradit Zvuk.Format.wBitsPerSample. Tak či tak, musíme frekvenci vydělit stem, protože čas budeme udávat v setinách. Pokud byste chtěli výsledek v sekundách, tak frekvenci ničím dělit nebudete. Zvuk.Size můžete nahradit proměnnou Zvuk.Position, potřebujete-li zjistit pozici. Zbývá ještě výsledný čas nějak kloudně zformátovat (údaj "zvuk trvá 75814 setin" nevypadá nejlépe):
var
x,y:Integer;
begin
x := Zvuk.Position div ((TrackBar3.Position div 100)*(Zvuk.Format.wBitsPerSample div 8));
y := Zvuk.Size div ((TrackBar3.Position div 100)*(Zvuk.Format.wBitsPerSample div 8));
Label15.Caption := Format(`%.2d:%.2d,%.2d / %.2d:%.2d,%2d `,
[(x div 100)div 60,(x div 100)mod 60,x mod 100,
(y div 100)div 60,(y div 100)mod 60,y mod 100]);
end; Aby byl zápis kratší a rychlejší, tak jsem si do proměnné x uložil pozici zvuku a do y velikost. Tímto bych kapitolu DirectSound uzavřel; zde si můžete stáhnout můj ukázkový program na to, co jsme dnes probrali. Další příklady naleznete v adresáři DelphiX\Samples\Sound.
Příště se podíváme na DirectInput, snadný způsob jak pracovat s nejrozmanitějšími polohovacími zařízení.