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.