┌vod
Instalace Ogg SDK
Torie k DirectSound
╚ßst 1
╚ßst 2
╚ßst 3
╚ßst 4
Funkce knihovny vorbisfile.dll
Odkazy
Ke sta₧enφ
R.Henys@seznam.cz
ICQ: 159629842
|
|
V tΘto Φßsti vytvo°φme projekty se kter²mi budeme dßle pracovat a budeme se tΘ₧ v∞novat implementaci
zvukovΘho bufferu.
Obsah:
Vytvo°φme si dva novΘ projekty. Oba budou typu Win32. Bude se jednat o jednu dynamickou knihovnu (dll) a spustiteln²
soubor (exe). V knihovn∞ bude implementovßna samotnß t°φda a spustitelnß aplikace bude slou₧it jako testovacφ program.
Jß jsem si pro knihovnu zvolil nßzev OggCodec a pro aplikaci Tester.
Otev°ete v²vojovΘ prost°edφ a vytvo°te nov² projekt typu Win32 Project, zadejte nßzev projektu jak² je vßm nejbli₧Üφ a zaÜkrtn∞te volbu
Create directory for Solution (zobrazφ se po stisku tlaΦφtka More). Klepn∞te na Ok. Zobrazφ se pr∙vodce. Na kart∞ Application Settings
vyberte p°epφnaΦ Dll a vygenerujte zßkladnφ soubory kliknutφm na Finish. Te∩ p°idßme druh² projekt p°es menu File->Add Project->New Project....
Dßle postupujeme stejn∞ jako p°i vytvß°enφ prvnφho projektu, jen vybereme p°epφnaΦ Windows Application.
Obsah
Dßle je t°eba provΘst jeÜt∞ n∞jakß nastavenφ ne₧ budeme moci zaΦφt. Klepn∞te na prvnφ projekt prav²m myÜφtkem a z kontextovΘho menu
vyberte Properties. Ve stromovΘ struktu°e v levΘ Φßsti okna vyberte Configuration Properties/General a upravte vlastnost
Output Directory na ..\Debug u Debug konfigurace projektu, respektive na ..\Release u Release konfigurace projektu. Takto uΦi≥te i pro
druh² projekt.
Dßle u projektu OggCodec (dynamickß knihovna) p°ejd∞te do zßlo₧ky Linker a do °ßdku Input vlo₧te, zapiÜte nßsledujφcφ
knihovny: vorbisfile_static.lib ogg.lib vorbis.lib dxerr9.lib dsound.lib winmm.lib strmiids.lib dxguid.lib. Zb²vß u₧ jen nastavit
zßvislost projekt∙, respektive aplikace Tester na knihovn∞ OggCodec. StaΦφ navÜtφvit dialog Dependencies pomocφ nabφdky Project->Project Dependencies....
V menu vybereme projekt Tester a zaÜkrtneme polφΦko u OggCodec v seznamu. Pokud nynφ °eÜenφ p°elo₧φte (Build->Build Solution), dostane se vßm chybovΘho hlßÜenφ p°i sestavovßnφ ve smyslu ₧e
nelze nßlezt soubor OggCodec.lib. To je zp∙sobeno tφm, ₧e jste z projektu jeÜt∞ neexportovali ₧ßdnou funkci, t°φdu ani rozhranφ.
Obsah
Jeliko₧ od tohoto odstavce u₧ vlastn∞ zaΦφnßme s cel²m projektem, doporuΦil bych vßm hned na zaΦßtku vytvo°it si v projektu OggCodec nov²
hlaviΦkov² soubor Common.h, kter² bude slou₧it definicφm kterΘ budou spoleΦnΘ pro vφce soubor∙. Navφc se tak vyhnete problΘm∙m s vφcenßsobn²m
vlo₧enφm hlaviΦkovΘho souboru a chybov²m hlßÜenφm a v neposlednφ °ad∞ je to vφc p°ejhledn∞jÜφ, aspo≥ podle mΘho nßzoru, ne₧ vklßdat takovou definici do ka₧dΘho
cpp souboru nebo hlaviΦkovΘho souboru. Do souboru vlo₧te, napiÜte tyto °ßdky:
Soubor Common.h:
#include <dmusici.h>
#include <vector>
#include <dsound.h>
#include <dxerr9.h>
#include "vorbisfile.h"
#include "codec.h"
#include <math.h>
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if(p) {delete [] (p); (p) = NULL; } }
#define OGGCODEC_API __declspec(dllexport)
Do souboru jsou vlo₧eny hlaviΦkovΘ soubory nezbytn∞ nutnΘ pro b∞h naÜeho "kodeku", jako je
dsound.h. HlaviΦkovΘ soubory z Ogg SDK: vorbisfile.h, codec.h. Makra SAFE_RELEASE, SAFE_DELETE a SAFE_DELETE_ARRAY kterß budeme Φasto
pou₧φvat. Prvnφ makro slou₧φ k uvoln∞nφ rozhranφ z pam∞ti, druhΘ ke smazßnφ dynamicky vytvo°enΘho objektu a t°etφ ke smazßnφ dynamicky
vytvo°enΘho pole. OGGCODEC_API pou₧ijeme u definic funkcφ, t°φd nebo rozhranφ kterΘ budeme chtφt z knihovny exportovat abychom je mohli
pou₧φt v dalÜφch programech.
Nynφ u₧ se m∙₧eme pustit do t°φdy CSoundBuffer :)
Metody t°φdy CSoundBuffer
Create |
Vytvo°φ rozhranφ reprezentujφcφ zvukov² buffer. |
RestoreBuffer |
Obnovφ buffer p°i jeho ztrßt∞. |
Reset |
Nastavφ pozici hracφho kurzoru v bufferu na 0. |
Play |
Spustφ p°ehrßvßnφ bufferu |
Stop |
Zastavφ p°ehrßvßnφ bufferu. |
SetFrequency |
Nastavφ frekvenci p°ehrßvan²ch zvukov²ch dat. |
SetPan |
Nastavenφ vyvß₧enosti levΘho a pravΘho kanßlu. |
SetVolume |
Nastavφ hlasitost bufferu. |
IsSoundPlaying |
Zjistφ zda buffer data p°ehrßvß nebo ne. |
Implementace bufferu je velice podobnß tΘ kterou je mo₧nΘ najφt v p°φkladech SDK k DirectX, konkrΘtn∞ u DirectSound,
ale tato t°φda je tak jednoduchß, ₧e se u nφ snad ani mnoho novΘho vymyslet nedß. Jednß se vlastn∞ jen o volßnφ metod
rozhranφ IDirectSoundBuffer pomocφ naÜich vlastnφch metod, kterΘ navφc jen oÜet°ujφ mo₧nΘ chybovΘ stavy.
Vlo₧te do projektu OggCodec novou t°φdu CSoundBuffer a zapiÜte implementaci t°φdy. Podφvejme se na soubor SoundBuffer.h:
#pragma once
//********************************************************************************************
//Trida zapouzdrujici fce pro praci se zvukovymi buffery
//********************************************************************************************
class CSoundBuffer
{
protected:
LPDIRECTSOUNDBUFFER m_DSSoundBuffer; //ukazatel na rozhrani IDirectSoundBuffer
DWORD m_dwBufferSize; //velikost bufferu v bajtech
DWORD m_dwCreationFlags; //volby ktere jsem pouzili pri vytvareni bufferu
public:
virtual HRESULT Create(LPDIRECTSOUND lpDSound,DSBUFFERDESC* dsBufferDesc);
HRESULT RestoreBuffer(bool* bWasRestored);
HRESULT Play(DWORD dwPriority = 0,DWORD dwFlags = 0);
HRESULT Stop();
HRESULT Reset();
HRESULT SetFrequency(long lFrequency);
HRESULT SetPan(long lPan);
HRESULT SetVolume(long lVolume);
bool IsSoundPlaying();
LPDIRECTSOUNDBUFFER GetBuffer() {return m_DSSoundBuffer;}
CSoundBuffer(void);
~CSoundBuffer(void);
};
Nynφ se m∙₧eme podbobn∞ji podφvat na jednotlivΘ funkce. Prvnφ bude konstruktor a destruktor, kde se provßdφ jen inicializace a ·klid
a myslφm ₧e to nenφ t°eba podbrobn∞ji rozebφrat. Soubor SoundBuffer.cpp:
#include "StdAfx.h"
#include "Common.h"
#include "soundbuffer.h"
//********************************************************************************************
//Konstruktor
//********************************************************************************************
CSoundBuffer::CSoundBuffer(void)
{
m_DSSoundBuffer = NULL; //neplatny ukazatel na rozhrani, neni jeste vytvoreno
m_dwBufferSize = 0; //vychozi hodnoty promennych
m_dwCreationFlags = 0;
}
//********************************************************************************************
//Destruktor
//********************************************************************************************
CSoundBuffer::~CSoundBuffer(void)
{
SAFE_RELEASE(m_DSSoundBuffer); //uvolneni rozhrani z pameti
}
DalÜφ si pobereme funkci Create
//*************************************************************************************************************
//Fce pro vytvoreni rozhrani pro zvukovy buffer
//*************************************************************************************************************
HRESULT CSoundBuffer::Create(LPDIRECTSOUND lpDSound,DSBUFFERDESC* dsBufferDesc)
{
HRESULT hRet = DS_OK;
if (FAILED(hRet = lpDSound->CreateSoundBuffer(dsBufferDesc,&m_DSSoundBuffer,NULL))) //pokud vytvareni rozhrani selze
return hRet; //vratime chybu dal
m_dwBufferSize = dsBufferDesc->dwBufferBytes; //ulozeni velikosti bufferu
m_dwCreationFlags = dsBufferDesc->dwFlags; //ulozeni p°φznak∙
return hRet; //vraceni vysledku, sem uz by se melo dostat jen S_OK
}
Funkce oΦekßvß ₧e jφ p°edßme ukazatel na rozhranφ IDirectSound a strukturu obsahujφcφ popis bufferu.
Volßnφm funkce CreateSoundBuffer zmφn∞nΘho rozhranφ vytvo°φme rozhranφ kterΘ bude reprezentovat zvukov² buffer. P°edßme jφ popis
bufferu, do druhΘho argumentu se ulo₧φ ukazatel na nov∞ vytvo°enΘ rozhranφ a poslednφ argument souvisφ s technologiφ COM a je v₧dy NULL.
Pokud funkce vrßtφ chybnou hodnotu, nepokraΦuje se dßl. V opaΦnΘm p°φpad∞ si jen ulo₧φme velikost bufferu a p°φznaky.
//*************************************************************************************************************
//Fce pro obnoveni bufferu
//*************************************************************************************************************
HRESULT CSoundBuffer::RestoreBuffer(bool *bWasRestored)
{
HRESULT hRet;
if (!m_DSSoundBuffer) //kontrola jestli je rozhrani vubec vytvorene
return CO_E_NOTINITIALIZED;
if (bWasRestored) //kontrola ukazatele
*bWasRestored = false;
DWORD dwStatus;
if (FAILED(hRet = m_DSSoundBuffer->GetStatus(&dwStatus))) //pokud se nam nepodari ziskat stav bufferu
return hRet; //tak rovnou koncime vracenim chyby
if (dwStatus & DSBSTATUS_BUFFERLOST) //pokud byl buffer ztracen
{
do //budeme se v cyklu snazit ho obnovit
{ //dokud se to nepovede
hRet = m_DSSoundBuffer->Restore();
if (hRet == DSERR_BUFFERLOST)
Sleep(10);
}
while ((hRet = m_DSSoundBuffer->Restore()) == DSERR_BUFFERLOST);
if (bWasRestored) //ulozime do uzivatelske promenne ze buffer
*bWasRestored = true; //byl obnoven
return S_OK;
}
return S_FALSE;
}
Funkce nejd°φv kontroluje ukazatel na rozhranφ bufferu a poslΘze ukazatel kter² byl zadßn jako parametr. Na mφsto kam ukazuje bWasRestored se
v p°φpad∞ ₧e je ukazatel platn² ulo₧φ zda byl buffer obnoven nebo ne. Bude-li tato hodnota po vykonßnφ funkce nab²vat false, nemusφ to znamenat ₧e fuknce selhala, ale
takΘ ₧e nebylo t°eba buffer obnovit. Pokud je pot°eba buffer obnovit, provßdφ se to v cyklu, kter² trvß tak dlouho, dokud funkce Restore rozhranφ
IDirectSoundBuffer nevrßtφ jinou hodnotu ne₧ DSBSTATUS_BUFFERLOST. Pokud je buffer ztracen, je mo₧nΘ ₧e ho nebudeme moci obnovit prßv∞ v dob∞ volßnφ
tΘto funkce, ale a₧ pozd∞ji. T°eba proto ₧e aplikace nemß fokus.
//*************************************************************************************************************
//Fce spusti prehravani bufferu
//*************************************************************************************************************
HRESULT CSoundBuffer::Play(DWORD dwPriority,DWORD dwFlags)
{
if (!m_DSSoundBuffer) //kontrola platnosti ukazatele na rozhrani
return CO_E_NOTINITIALIZED;
return m_DSSoundBuffer->Play(0,dwPriority,dwFlags);
}
Funkce Play je jednoduchß. Kontroluje jen platnost ukazatele na rozhranφ, abychom se neodkazovali na neplatnΘ mφsto v pam∞ti a nezp∙sobili tak krach programu
a pak u₧ jen volß metodu Play rozhranφ IDirectSoundBuffer a p°edßvß jφ argumenty kterΘ dostala. Jak si m∙₧ete vÜimnout v hlaviΦkovΘm souboru t°φdy CSoundBuffer, jsou
pro oba parametry zadßny v²chozφ hodnoty, funkci proto m∙₧ete volat bez, s jednφm nebo s ob∞ma parametry. Prvnφ parametr je priorita a pokud je nula a budete mφt takovΘ buffery
t°eba dva, v²sledn² efekt bude ten, ₧e budou hrßt oba najednou. Pokud bude u jednoho priorita 1, poΦkß se a₧ dohraje buffer s prioritou 0 a pak se spustφ buffer s prioritou 1.
//*************************************************************************************************************
//Fce nastavi frekvenci
//*************************************************************************************************************
HRESULT CSoundBuffer::SetFrequency(long lFrequency)
{
if (!m_DSSoundBuffer)
return CO_E_NOTINITIALIZED;
if (lFrequency != -1 && m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY)
return m_DSSoundBuffer->SetFrequency(lFrequency);
return S_FALSE;
}
//*************************************************************************************************************
//Fce nastavi hlasitost
//*************************************************************************************************************
HRESULT CSoundBuffer::SetVolume(long lVolume)
{
if (!m_DSSoundBuffer)
return CO_E_NOTINITIALIZED;
if (m_dwCreationFlags & DSBCAPS_CTRLVOLUME)
return m_DSSoundBuffer->SetVolume(lVolume);
return S_FALSE;
}
//*************************************************************************************************************
//Fce pro nastaveni vyvazenosti leveho a preveho kanalu
//*************************************************************************************************************
HRESULT CSoundBuffer::SetPan(long lPan)
{
if (!m_DSSoundBuffer)
return CO_E_NOTINITIALIZED;
if (m_dwCreationFlags & DSBCAPS_CTRLPAN)
return m_DSSoundBuffer->SetPan(lPan);
return S_FALSE;
}
//*************************************************************************************************************
//Fce zastavi prehravani bufferu
//*************************************************************************************************************
HRESULT CSoundBuffer::Stop()
{
if (!m_DSSoundBuffer)
return CO_E_NOTINITIALIZED;
return m_DSSoundBuffer->Stop();
}
//*************************************************************************************************************
//Fce nastavi pozici hraciho kurzoru v bufferu na nula
//*************************************************************************************************************
HRESULT CSoundBuffer::Reset()
{
if (!m_DSSoundBuffer)
return CO_E_NOTINITIALIZED;
return m_DSSoundBuffer->SetCurrentPosition(0);
}
Prvnφ t°i funkce manipulujφ s r∙zn²mi parametry kterΘ jsou zvukov²m dat∙m vlastnφ :) Jde o nastavenφ frekvence (SetFrequency), vyvß₧enosti levΘho
a pravΘho kanßlu (SetPan) a hlasitosti (SetVolume. VÜechny tyto funkce kontrolujφ ukazatel na rozhranφ a pak takΘ p°φznaky s jak²mi byl buffer vytvo°en. Pokud
nenφ p°φznak pro danou vlastnost nastaven, znamenß to ₧e ji u befferu nem∙₧eme °φdit, m∞nit, jen ji Φφst. Pokud ano, zavolß se jen p°φsluÜnß funkce rozhranφ IDirectSoundBuffer a p°edß se jφ zadan² parametr.
DalÜφ dv∞ funkce jsou Stop a Reset. Zase se jen kontroluje ukazatel na rozhranφ. Funkce Reset funguje tak, ₧e nastavφ pozici hracφho kurzoru na 0, dalo by se jφ takΘ °φkat Rewind.
Poslednφ funkcφ t°φdy CSoundBuffer je IsSoundPlaying:
//*************************************************************************************************************
//Fce rekne jestli je buffer prehravan ci ne
//*************************************************************************************************************
bool CSoundBuffer::IsSoundPlaying()
{
if (!m_DSSoundBuffer)
return false;
DWORD dwStatus;
m_DSSoundBuffer->GetStatus(&dwStatus);
return (dwStatus & DSBSTATUS_PLAYING) ? true : false;
}
Funkce je op∞t jednoduchß. Zda je buffer p°ehrßvßn zjistφme jednoduÜe tak, ₧e se ho zeptßme na stav pomocφ fuknce GetStatus.
Pokud je buffer p°ehrßvßn vrßtφ se nßm DSBSTATUS_PLAYING a podle toho vrßtφme bu∩ true nebo false
To je ke t°φd∞ CSoundBuffer vÜe. Pokud °eÜenφ p°elo₧φte (Build->Build Solution), ob∞vφ se vßm op∞t
chyba o nenalezenφ lib souboru knihovny OggCodec. Otev°ete soubor SoundBuffer.h a definici t°φdy upravte takto:
class OGGCODEC_API CSoundBuffer
P°idßnφm konstanty ze souboru Common.h jste v²vojovΘmu prost°edφ °ekli, ₧e chcete t°φdu exportovat a soubor lib bude automaticky
vytvo°en. Pokud nynφ °eÜenφ zkusφte p°elo₧it znovu, nem∞la by se objevit ji₧ ₧ßdnß chyba. Upravte definici zp∞t na p∙vodnφ, proto₧e
tuto t°φdu exportovat nebudeme. Ale pokud chcete, m∙₧ete ji samoz°ejm∞ takto ponechat. Na dalÜφ d∞nφ to nemß vliv :)
M∙₧ete se pustit do dalÜφ Φßsti :)
Obsah
|