DirectX (17.)

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.

17.1. Shrnutφ z minulΘho dφlu

D°φve ne₧ se pustφme do novΘ lßtky, pokusφm se shrnout to, co jsme se do tΘto doby nauΦili:

17.2. Knihovna Audio.dll

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.

17.3. Trocha teorie DirectMusic

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:

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:

  1.  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.

  2. 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².

  3. 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.

  4. 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.

17.4. T°φda CMusic

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:

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Θ:

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.

Ji°φ Formßnek