V minulém dílu jsme zakončili grafickou část našeho projektu menu. V dnešním díle si povíme něco o DirectMusic, což je další komponenta knihovny DirectX. Předem upozorňuji, že to nebude nikterak podrobný popis knihovny.
Dříve než se pustíme do nové látky, pokusím se shrnout to, co jsme se do této doby naučili:
měli bychom plně ovládat knihovnu DirectDraw pro 2D vykreslování do okna. Principy DirectDraw se nám totiž budou částečně hodit až budeme rozebírat Direct3D (doufám, že k tomu dojde). Nejde o to, umět nazpaměť deklarace všech funkcí (od čeho máme nápovědu), ale o to, chápat jak systém pracuje.
Později jsme si něco pověděli o systému DirectInput, který se Vám bude velmi hodit, pokud budete programovat nejen s DirectX dále (třeba v Direct3D). Systém samozřejmě není závislý na grafickém API, takže grafiku můžete programovat v OpenGL a nezávisle na tom použít DirectInput (mnoho dnešních her takto pracuje).
Nakonec jsme to dali celé dohromady a vznikl projekt grafického menu, o kterém byla řeč v úvodu. Je třeba říci, že projekt je jen ukázkový příklad, jak by mohla vypadat aplikace podobného druhu a tudíž je jen na vás jak budete pokračovat. Na dnešním ChipCD si můžete stáhnout (skoro) funkční hru, která je nastavěna na zmíněném projektu. Tuto hru jsem pracovně nazval Rocket 7 alias Jet Fighter a byla to má semestrální práce v 1. semestru (stáhnout zde). Dal bych k dispozici i zdrojové kódy, ale projekt jsem psal "dávno" a slušně řečeno, kód není optimalizovaný:-)
V dnešní lekci si probereme úplné základy DirectMusic, přidáme do menu hudbu a nějaké ty zvuky. Chceme-li vidět postavení nové knihovny v projektu, podívejme se ještě jednou na schéma celého projektu:
Žluté bloky již máme za sebou a bílý blok Audio.dll vytvoříme v této lekci. Samozřejmě Game.exe a Engine.dll doznají taky několik změn (jinak by to celé bylo k ničemu). Vytvoříme novou knihovnu Audio.dll, která bude součást projektu z minulých lekcí. Přidat nový pod-projekt již umíme. Po té musíme nastavit "závislosti" (Dependencies) tak, aby knihovna Audio.dll mohla použít funkce z Common.dll a aby moduly Engine.dll a Game.exe mohly používat funkce z Audio.dll. Tudíž dialog závislostí by mohl vypadat zhruba takto:
Po té nastavíme na kartě Settings... projektu Audio tato nastavení:
Nastavení nezapomeňte pozměnit i pro verzi Release. V projektu bude jediná třída CMusic v souborech Music.h a Music.cpp. Exportované funkce budou v deklarovány a definovány v souborech Common.h a Common.cpp, které musíte vložit ručně. Co konkrétně bude v jednotlivých souborech si povíme později.
Pomocí této komponenty se dá přehrávat jak hudba tak normální zvukové efekty. S DirectMusic můžete dělat různá kouzla, ale my se zde budeme zabývat základy:
přehrát zvuk ve formátu .wav
přehrát hudbu ve formátu .mid
DirectMusic ještě podporuje formát .sgt (Segment), což je formát určený přímo pro DirectMusic.
Nyní si v několika krocích povíme, co je potřeba, aby jsme mohli přehrát zvuk:
Objekty v DirectMusic využívají technologii COM, takže první co musíme udělat je, že zavoláme funkci CoInitializeEx(), abychom mohli vytvořit objekty Performance a Loader.
Za druhé musíme vytvořit objekt tzv. Performance. Tento objekt řídí tok dat ze zdroje (zvukový soubor) do syntezéru (procesor zvukové karty). Navíc se stará o časování atd. Tento objekt má většina aplikací jediný.
Dále vytvoříme objekt Loader. Tento objekt se narozdíl od Performance stará a nahrávání dat ze souborů .mid, .wav nebo .sgt. Audio data navíc mohou být uložena ve zdrojích projektu.
V dalším kroku již můžeme nahrávat tzv. segmenty, což není nic jiného než objekty vytvořené z audio souborů. Tyto segmenty pak musíme "stáhnout" do syntezéru a teprve potom je můžeme přehrát.
Vše co jsme si řekli v předešlé části bude implementováno ve třídě CMusic. Tuto třídu již můžete vložit do našeho nového projektu Audio.
Návrh třídy by mohl vypadat takto:
Atributy | ||
Typ | Název | Popis |
BOOL | m_bInit | Inicializace objektu - TRUE nebo FALSE |
int | m_MusicVolume | Hlasitost (kanál master) |
CPtrArray | m_arSegments | Pole segmentů - jak bylo zmíněno výše, segment představuje audio data nahraná ze souboru .wav nebo .mid |
IDirectMusicLoader8* | m_lpDMLoader | Objekt Loader |
IDirectMusicPerformance8* | m_lpDMPerformance | Objekt Performance |
Metody | ||
Návratová hodnota | Název | Popis |
void | CreateDirectMusicSystem(HWND hWnd); | Vytváří systém DirectMusic. Podobné metody známe již z projektu Display nebo Input. |
void | LoadMusicFromFile(DWORD dwID, CString BMPFile); | Nahrává audio soubor, buď .wav nebo .mid. Prvním parametrem je určeno ID a toto ID také použijeme, když chceme zvuk přehrát. |
void | PlayMusic(DWORD dwID); | Spustí hudbu. V jeden okamžik může bát přehrávána pouze jedna hudební stopa. |
void | PlaySound(DWORD dwID); | Přehraje zvuk z .wav. Zvuky se dají trochu míchat. |
void | StopMusic(DWORD dwID); | Zastaví přehrávání hudební stopy. |
void | IncreaseMusicVolume(); | Zvýší hlasitost. |
void | DecreaseMusicVolume(); | Sníží hlasitost. |
int | GetMusicVolume() | Vrátí aktuální hlasitost. |
void | DeinitMusic(); | Zastaví všechny stopy a zruší všechny DirectMusic objekty. |
Vidíme, že třída je poměrně jednoduchá. Ani implementace nebude nikterak složitá. Dříve než se dostanu k deklaraci třídy, zmíním se ještě o jedné struktuře, která je použita v našem projektu. Každý nahraný soubor bude reprezentován objektem IDirectMusicSegment8*. My ale každém zvuku musíme přiřadit ID, proto je třeba vytvořit strukturu SAudio, která obsahuje zmíněné datové prvky. Ve třídě CMusic je pole ukazatelů právě těchto objektů.
Soubor Music.h vypadá takto:
struct SAudio {
DWORD m_dwID;
IDirectMusicSegment8* m_lpSegment;
};
class CMusic
{
private:
IDirectMusicLoader8* m_lpDMLoader;
IDirectMusicPerformance8* m_lpDMPerformance;
CPtrArray m_arSegments;
int m_MusicVolume;
BOOL m_bInit;
public:
//
// Initialization
void
CreateDirectMusicSystem(HWND hWnd);
void DeinitMusic();
//
// Get music from MIDI or WAV
void
LoadMusicFromFile(DWORD dwID, CString BMPFile);
//
// Music/sounds play & stop functions
void PlayMusic(DWORD dwID);
void PlaySound(DWORD dwID);
void StopMusic(DWORD dwID);
//
// Master volume
void IncreaseMusicVolume();
void DecreaseMusicVolume();
int GetMusicVolume() {return m_MusicVolume;}
public:
CMusic();
~CMusic();
};
Metody vesměs vrací void, protože chybové hlášení ošetříme pomocí výjimek (viz. Kurz C++). Nyní budeme postupně implementovat metody třídy CMusic.
Začneme logicky od inicializace:
void CMusic::CreateDirectMusicSystem(HWND
hWnd)
{
DXTRACE("Init DirectMusic system...");
DWORD dwRet;
//
// Check initialization of system
if(m_bInit) {
DXTHROW("System DirectMusic is
already initialized.");
}
//
// 1. COM initialization
CoInitialize(NULL);
//
// 2. Create DMLoader
dwRet = CoCreateInstance(CLSID_DirectMusicLoader, NULL,
CLSCTX_INPROC, IID_IDirectMusicLoader8,
(void**)&m_lpDMLoader);
if(dwRet != S_OK) {
DXTHROWERR("Cannot create DMLoader
due ", dwRet);
}
//
// 3. Create DMPerformance
dwRet = CoCreateInstance(CLSID_DirectMusicPerformance, NULL,
CLSCTX_INPROC, IID_IDirectMusicPerformance8,
(void**)&m_lpDMPerformance);
if(dwRet != S_OK) {
DXTHROWERR("Cannot create
DMPerformance due ", dwRet);
}
//
// Init DMPerformance
dwRet = m_lpDMPerformance->InitAudio(
NULL, // IDirectMusic interface not
needed.
NULL, // IDirectSound interface not
needed.
hWnd, // Window handle.
DMUS_APATH_DYNAMIC_STEREO , //
Default audiopath type.
64, // Number of performance
channels.
DMUS_AUDIOF_ALL, // Features on
synthesizer.
NULL // Audio parameters; use
defaults.
);
if(dwRet != S_OK) {
DXTHROWERR("Cannot init DMPerformance
due ", dwRet);
}
//
// Set search directory - default is Music
CString csPath = setGetDataFilePath("Music");
dwRet = m_lpDMLoader->SetSearchDirectory(GUID_DirectMusicAllTypes,
csPath.AllocSysString(), TRUE);
if(dwRet != S_OK) {
DXTHROWERR("Cannot set search
directory due ", dwRet);
}
//
// Initialization OK
m_bInit = TRUE;
}
Nejprve je třeba otestovat, zda-li metodu nevoláme podruhé. Dále jsou kroky očíslovány jako ve výše popsaném postupu. Takže za prvé inicializujeme COM funkcí CoInitialize(). Dále získáme ukazatel na rozhraní objektu Loaderu. To provedeme pomocí funkce CoCreateInstance(), která zároveň vytvoří i instanci objektu. První parametr této funkce je ID třídy objektu, dále mimo jiné zadáváme ID rozhraní, které požadujeme a ukazatel na toto rozhraní, který bude inicializován. Prakticky totéž provedeme pro objekt Performance. Nyní musíme tento objekt vnitřně zinicializovat. K tomu slouží metoda InitAudio(), která má následující parametry:
IDirectMusic**
ppDirectMusic - ukazatel na rozhraní
objektu DirectMusic. Tento parametr použijeme, pokud chceme ukazatel na tento
objekt. Zadáme-li hodnotu NULL, tento ukazatel se nikam neuloží.
IDirectSound**
ppDirectSound -
ukazatel na rozhraní objektu DirectSound. Platí totéž jako v předešlém
případě a opět tento ukazatel není v našem příkladu potřeba.
HWND
hWnd - handle okna, který do metody vstupuje
jako parametr
DWORD dwDefaultPathType
- nastavení tzv. audio path. V našem příkladu zadáme, že chceme
stereo.
DWORD
dwPChannelCount - počet kanálu. V našem případě 64.
DWORD
dwFlags
- pomocí této proměnné můžeme nastavit jaké speciální funkce karty
budeme využívat. Například EAX.
DMUS_AUDIOPARAMS *pParams
- ve struktuře DMUS_AUDIOPARAMS jsou uloženy
další nastavení zvuku a tím se nebudeme dále zabývat, takže NULL.
Nakonec nastavíme pomocí metody
SetSearchDirectory() cestu k audio souborům. Až program bude nahrávat
soubory, bude je hledat v adresáři Music.
Inicializaci bychom měli. Nyní se podíváme, jak systém
uvolníme. Uvolnění zajišťuje metoda DeinitMusic():
void CMusic::DeinitMusic()
{
DWORD dwRet;
//
// Check initialization of system
if(!m_bInit) {
DXTHROW("System DirectMusic is not
initialized.");
}
//
// Stop all music and sounds
if(m_lpDMPerformance) {
dwRet = m_lpDMPerformance->Stop(
NULL, // Stop all segments.
NULL, // Stop all segment states.
0, // Do it immediately.
0 // Flags.
);
if(dwRet != S_OK) {
DXTHROWERR("cannot
stop all tracks due", dwRet);
}
// Close performance
m_lpDMPerformance->CloseDown();
}
SAudio *pAudio;
//
// Delete all segments
for(int i = 0; i < m_arSegments.GetSize(); i++) {
pAudio = (SAudio*) m_arSegments[i];
SAFE_RELEASE(pAudio->m_lpSegment);
SAFE_DELETE(pAudio);
}
//
// Safe release loader and performance
SAFE_RELEASE(m_lpDMLoader);
SAFE_RELEASE(m_lpDMPerformance);
}
Nejprve zkontrolujeme, zda-li byl systém vůbec někdy
zinicializován. Všimněte si, že tuto kontrolu provádíme u každé metody
CMusic. Pokud nejprve nezavoláte metodu
CreateDirectMusicSystem(), všechny ostatní metody
budou vyhazovat výjimku.
Dále musíme zastavit veškeré audio, které se aktuálně přehrává. K tomu použijeme
objekt Performance a metodu Stop(). Pomocí
čtyř parametrů zajistíme, že se zastaví všechny segmenty, v libovolných stavech
a zastaví se okamžitě! Činnost objektu Performance ukončíme metodou
CloseDown(), která uvolní vnitřní reference atd.
Jak uvidíme později, každý segment je alokován dynamicky. Proto musí být uvolněn
a posléze vymazán z paměti. Tuto činnost provede následující cyklus, kdy
uvolníme a dealokujeme všechny segmenty. Nakonec uvolníme rozhraní objektů
Loader a Perfomance.
Bude potřeba nahrát zvuky a hudbu ze souborů
.wav nebo .mid. K tomu
slouží metoda LoadMusicFromFile():
void CMusic::LoadMusicFromFile(DWORD
dwID, CString BMPFile)
{
DWORD dwRet;
SAudio *pAudio;
//
// Check initialization of system
if(!m_bInit) {
DXTHROW("System DirectMusic is not
initialized.");
}
//
// Check if the specified ID is not already in array
for(int i = 0; i < m_arSegments.GetSize(); i++) {
pAudio = (SAudio*) m_arSegments[i];
if(pAudio->m_dwID == dwID) {
DXTHROW("Segment
%d - %s is already in the array.", dwID, BMPFile);
}
}
//
// Create new audio segment
SAudio *pNew = new SAudio;
pNew->m_dwID = dwID;
//
// Try to load audio file
dwRet = m_lpDMLoader->LoadObjectFromFile(
CLSID_DirectMusicSegment, // Class
identifier.
IID_IDirectMusicSegment8, // ID of
desired interface.
BMPFile.AllocSysString(), //
Filename.
(LPVOID*) &pNew->m_lpSegment //
Pointer that receives interface.
);
if(dwRet != S_OK) {
SAFE_DELETE(pNew);
DXTHROWERR("Cannot load audio from
file due", dwRet);
}
//
// Download audio to synthesizer
dwRet = pNew->m_lpSegment->Download( m_lpDMPerformance );
if(dwRet != S_OK) {
SAFE_DELETE(pNew);
DXTHROWERR("Cannot download audio due",
dwRet);
}
//
// Add audio segment pointer
m_arSegments.Add(pNew);
}
Metoda má dva parametry: první je ID zvuku, podle
kterého určíme, že chceme přehrát právě tento zvuk a druhý parametr je řetězec
daného souboru. V této metodě nejdříve musíme zkontrolovat, zda-li uživatel
nevložil zvuk se stejným ID dvakrát. Pokud je ID unikátní, pokračujeme dále a
vytvoříme vlastní objekt zvuku. Přiřadíme ID a zinicializujeme rozhraní
segmentu. To provedeme pomocí metody LoadObjectFromFile()
(zde si všimněte, že používáme objekt Loader). Metoda vyžaduje takzvaný
wide string a ten vrací metoda AllocSysString()
třídy CString. Nakonec musíme data stáhnout
do syntezéru (jinak by audio nešlo přehrát) a uložíme ukazatel do pole segmentů.
Nyní máme nahraná data a potřebujeme spustit přehrávání
ať už hudby nebo jen zvuku. K tomu nám slouží metody PlayMusic() a
PlaySound().
Obě metody jsou až na jeden řádek identické, proto tu uvedu jen jednu z nich a
na zmíněný řádek upozorním:
void CMusic::PlayMusic(DWORD dwID)
{
DWORD dwRet;
SAudio *pAudio;
//
// Check initialization of system
if(!m_bInit) {
DXTHROW("System DirectMusic is not
initialized.");
}
//
// Find source and start playing
for(int i = 0; i < m_arSegments.GetSize(); i++) {
pAudio = (SAudio*) m_arSegments[i];
if(pAudio->m_dwID == dwID) {
//
// Play
segment
dwRet = m_lpDMPerformance->PlaySegmentEx(
pAudio->m_lpSegment, // Segment to
play.
NULL, // Used for songs; not
implemented.
NULL, // For transitions.
0 , // Flags.
0, // Start time; 0 is immediate.
NULL, // Pointer that receives
segment state.
NULL, // Object to stop.
NULL // Audiopath, if not default.
);
if(dwRet !=
S_OK) {
DXTHROWERR("Cannot play music due", dwRet);
}
}
}
}
Princip je velice snadný. Podle ID najdeme požadovaný
segment v poli (pokud tam vůbec je). Pokud segment nalezneme, zavoláme metodu
objektu Performance PlaySegmentEx(). Tato
metoda má poněkud více parametrů a my si zde uvedeme jen ty pro nás podstatné:
IUnknown*
pSource
- zdrojový segment. V naše, případě je nalezený segment v poli
segmentů.
DWORD
dwFlags -
tento parametr je pro nás klíčový, pokud budeme chtít přehrát zvuk. Jak na to
vysvětlím dále.
__int64
i64StartTime -
čas mezi voláním metody a skutečným spuštěním přehrávání. Pro nás 0 znamená, že
se zvuk začne přehrávat ihned.
Nyní si vysvětlíme rozdíl metod
PlayMusic() a PlaySound():
dwRet = m_lpDMPerformance->PlaySegmentEx(
pAudio->m_lpSegment, // Segment to
play.
NULL, // Used for songs; not
implemented.
NULL, // For transitions.
DMUS_SEGF_SECONDARY , // Flags.
0, // Start time; 0 is immediate.
NULL, // Pointer that receives
segment state.
NULL, // Object to stop.
NULL // Audiopath, if not default.
);
Toto je výsek metody PlaySound()
a vyznačený řádek je právě ten řádek, ve kterém se obě metody liší. Hudba se
musí přehrávat tzv. primárním bufferu. V tomto bufferu může běžet
najednou pouze jedna stopa. My ale potřebujeme pouštět více stop najednou, takže
zvuky budou přehrávány v tzv. sekundárním bufferu. To nastavíme příznakem
DMUS_SEGF_SECONDARY.
Pokud chceme hudbu zastavit, voláme metodu
StopMusic():
void CMusic::StopMusic(DWORD dwID)
{
//
// Check initialization of system
if(!m_bInit) {
DXTHROW("System DirectMusic is not
initialized.");
}
SAudio *pAudio;
for(int i = 0; i < m_arSegments.GetSize(); i++) {
pAudio = (SAudio*) m_arSegments[i];
if(pAudio->m_dwID == dwID) {
m_lpDMPerformance->Stop(pAudio->m_lpSegment,
NULL , 0, 0);
}
}
}
Ta vlastně využívá stejnou metodu jako metoda
DeinitMusic(), ale použije konkrétní segment, který
se má zastavit. Takže najdeme požadovaný segment a zastavíme ho.
Nakonec nám zbývají dvě metody pro ovládání hlasitosti
IncreaseMusicVolume() a DecreaseMusicVolume(). Obě metody jsou skoro totožné,
takže zde opět uvedu jen jednu z nich a na jeden malý rozdíl upozorním:
void CMusic::IncreaseMusicVolume()
{
//
// Check initialization of system
if(!m_bInit) {
DXTHROW("System DirectMusic is not
initialized.");
}
int Volume = m_MusicVolume;
//
// Increment volume
Volume += 100;
// Set 0 if 0
if(Volume >= 0)
Volume = 0;
// Set volme to
performance
m_lpDMPerformance->SetGlobalParam( GUID_PerfMasterVolume,
(void*)&Volume, sizeof(long) );
// Remember
volume
m_MusicVolume = Volume;
}
V metodě pracujeme s pomocnou proměnnou, do které
nejprve uložíme aktuální hlasitost. Tu potom zvýšíme a zkontrolujeme, zda-li
jsme nepřekročili maximální či minimální hodnotu. Poté pomocí metody
SetGlobalParam() předáme hlasitost objektu
Performance. Nakonec zpětně uložíme hlasitost do proměnné
m_MusicVolume. Pomocí této metody můžeme také například měnit tempo
přehrávání pokud použijeme hodnotu
GUID_PerfMasterTempo.
Člověk by to nečekal, ale metody Increase a
DecreaseMusicVolume() se liší v tomto řádku:
Volume += 100; a Volume -= 100;
Tímto jsme zakončili implementaci třídy
CMusic. Ještě zbývá vytvořit globální objekt CMusic
a exportovat některé metody.
17.5. Export metod a úprava projektů Game a Engine
Exportované funkce budou v souborech
Common.h a Common.cpp.
Navíc zde také budeme vkládat hlavičkový soubor pro práci s DirectMusic.
V praxi pak bude stačit vložit hlavičkový soubor Common.h
a systém bude fungovat.
Výpis souboru Common.h:
#ifndef AUDIO_COMMON_H
#define AUDIO_COMMON_H
//
// Include own common
#include "..\Common\Common.h"
//
// Include DMusic
#define INITGUID
#define DWORD_PTR DWORD
#include <dmusici.h>
//
// Export/import macros
#ifndef AUDIO_API
#define AUDIO_API __declspec(
dllimport )
#endif //
AUDIO_API
#include "Music.h"
//
// Exported functions
AUDIO_API void audInitMusic(HWND hWnd);
AUDIO_API void audDeinitMusic();
AUDIO_API void audLoadMusicFromFile(DWORD dwID, CString
BMPFile);
AUDIO_API void audIncreaseMusicVolume();
AUDIO_API void audDecreaseMusicVolume();
AUDIO_API int audGetMusicVolume();
AUDIO_API void audPlayMusic(DWORD dwID);
AUDIO_API void audStopMusic(DWORD dwID);
AUDIO_API void audPlaySound(DWORD dwID);
#endif // AUDIO_COMMON_H
Zde jsou deklarovány exportované funkce. Na podobný
zápis jsme už zvyklí z minulých lekcí.
Výpis souboru Common.cpp:
#include "stdafx.h"
#define AUDIO_API __declspec(dllexport)
#include "Common.h"
CMusic theMusic;
AUDIO_API void audInitMusic(HWND hWnd)
{
theMusic.CreateDirectMusicSystem(hWnd);
}
AUDIO_API void audLoadMusicFromFile(DWORD dwID, CString BMPFile)
{
theMusic.LoadMusicFromFile(dwID, BMPFile);
}
AUDIO_API void audPlayMusic(DWORD dwID)
{
theMusic.PlayMusic(dwID);
}
AUDIO_API void audPlaySound(DWORD dwID)
{
theMusic.PlaySound(dwID);
}
AUDIO_API void audStopMusic(DWORD dwID)
{
theMusic.StopMusic(dwID);
}
AUDIO_API void audDeinitMusic()
{
theMusic.DeinitMusic();
}
AUDIO_API void audIncreaseMusicVolume()
{
theMusic.IncreaseMusicVolume();
}
AUDIO_API void audDecreaseMusicVolume()
{
theMusic.DecreaseMusicVolume();
}
AUDIO_API int audGetMusicVolume()
{
return theMusic.GetMusicVolume();
}
Ani zde není nic nového pod Sluncem. Exportujeme
vlastně všechny metody.
Na úplný závěr této lekce ještě upravíme projekty
Engine a Game, abychom vyzkoušeli novou knihovnu. Do projektu Engine vložíme
pouhý jeden řádek, který přehraje určitý zvuk při stisku tlačítka:
if(GetState()->GetID() != BS_DISABLE)
{
switch(_Action) {
case IA_MOUSEMOVE:
if(GetState()->GetID() != BS_PRESS) {
SetState(BS_FOCUS);
}
break;
case IA_MOUSECLICK_UP:
if((*((UINT*)_Data)) == LEFT_MOUSE_BUTTON)
{
SetState(BS_FOCUS);
}
audPlaySound(1);
break;
case IA_MOUSECLICK_DOWN:
if((*((UINT*)_Data)) == LEFT_MOUSE_BUTTON)
{
SetState(BS_PRESS);
}
break;
case IA_KEYPRESS:
//none handling
break;
case IA_NONE:
SetState(BS_NORMAL);
break;
}
}
V celé aplikaci máme dva zvuky, takže nepoužívám
symbolické konstanty, jak by se mělo, pokud bychom nahrávali více zvuků. V
projektu Game těch uprav bude trochu víc. Za prvé musíme zinicializovat celý
systém, po té musíme nahrát hudbu a zvuk kliknutí, dále spustit hudbu a nakonec
upravit funkci UpdateFrame() tak, aby šla ovládat
hlasitost.
Takto upravte kód ve funkci
WinMain():
try {
audInitMusic(g_hWnd);
audLoadMusicFromFile(0, "passport.mid");
audLoadMusicFromFile(1, "click.wav");
audPlayMusic(0);
disInit(g_hWnd, DDFLG_CLIPPER|DDFLG_FULLSCREEN);
inpCreateDirectInputSystem(hInstance, g_hWnd,
disGetResolution());
disDefineBackground(_S_BACKGROUND, 0);
}
catch(LPCSTR str) {
DXTRACE(str);
}
A takto upravte funkci
UpdateFrame():
void UpdateFrame()
{
disUpdateBackground();
inpProcessInput();
// Pri stisknuti klavesy Esc ukoncime aplikaci
if(inpIsKeyDown(DIK_ESCAPE, FALSE)) {
PostMessage(g_hWnd, WM_DESTROY, 0,
0);
}
if(inpIsKeyDown(DIK_ADD,
TRUE)) {
audIncreaseMusicVolume();
}
if(inpIsKeyDown(DIK_SUBTRACT, TRUE)) {
audDecreaseMusicVolume();
}
menTestMouseMove(inpGetCursor());
if(inpIsLButtonDown()) {
menTestMouseClick(inpGetCursor(),
LEFT_MOUSE_BUTTON, BA_DOWN);
}
if(inpIsLButtonUp()) {
menTestMouseClick(inpGetCursor(),
LEFT_MOUSE_BUTTON, BA_UP);
}
menUpdateMenu();
inpUpdateCursor();
disPresent();
}
Nakonec ještě přidejte volání funkce
audDeinitMusic() do procedury okna:
case WM_DESTROY:
// Cleanup and close the app
audDeinitMusic();
menReleaseMenu();
PostQuitMessage( 0 );
return 0L;
}
Tak a to je vše. Pokud jste vše udělali správně, po
kompilaci byste měli slyšet hudbu a při stisku tlačítka zvuk kliknutí.
17.6. Závěr
To je vše, co Vám k této komponentě mohu poskytnout. Podrobnější informace najdete v knihovně MSDN, kde jsou detailně popsány všechny možnosti DirectMusic a DirectSound.
V této lekci bych také chtěl definitivně zakončit projekt Game.
Těším se příště nashledanou.