┌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 p°edposlednφ Φßsti vytvo°φme sprßvce zvukov²ch soubor∙ CSoundManager, kter² budeme pou₧φvat k p°ehrßvßnφ hudby.
Obsah:
Stejn∞ jako t°φda COggFile je navenek p°φstupnß jako rozhranφ IOggFile, tak t°φda CSoundManager bude p°φstupnß jen jako rozhranφ ISoundManager. Metody t°φdy
i rozhranφ jsou stejnΘ a jsou tyto:
Metody t°φdy CSoundManager / rozhranφ ISoundManager
LoadOgg |
Otev°e ogg soubor. |
UnloadOgg |
Zav°e ogg soubor. |
PlayOgg |
Spustφ p°ehrßvßnφ otev°enΘho ogg souboru. |
StopOgg |
Zastavφ p°ehrßvßnφ otev°enΘho ogg souboru. |
PauseOgg |
Pozastavφ p°ehrßvßnφ otev°enΘho ogg souboru. |
StopAllOgg |
Zastavφ p°ehrßvßnφ vÜech otev°en²ch ogg soubor∙. |
PauseAllOgg |
Pozastavφ p°ehrßvßnφ vÜech ogg soubor∙. |
CheckOggIfNeedReFillBuffer |
Kontroluje zda otev°en² ogg soubor pot°ebuje obnovit data ve zvukovΘm bufferu. |
CheckAllOggIfNeedReFillBuffer |
Kontroluje vÜechny otev°enΘ ogg soubory zda pot°ebujφ obnovit data ve zvukovΘm bufferu. |
SetRepeatsOfOgg |
Nastavφ poΦet opakovßnφ p°ehrßvßnφ otev°enΘhp ogg souboru. |
HandleAppActivateStateChanges |
Reakce na ztrßtu/zφskßnφ fokusu aplikacφ kterß vyu₧φvß t°φdu. |
GetDirectSound |
Vrßtφ ukazatel na rozhranφ IDirectSound. |
GetOggFile |
Vrßtφ ukazatel na otev°en² ogg soubor, pro p°φstup k dalÜφm funkcφm. |
AddRef |
P°idßnφ instance rozhranφ do pam∞ti. |
Release |
Uvoln∞nφ instance rozhranφ z pam∞ti. |
Do souboru Interfaces.h p°idejte takΘ definici rozhranφ ISoundManager:
__interface OGGCODEC_API ISoundManager
{
public:
HRESULT CreateDirectSoundSystem(HWND hWnd,DWORD dwCooperativeLevel = DSSCL_PRIORITY) = 0; //vytvoreni objektu DirectSound
HRESULT LoadOgg(DWORD dwId, const char* cFileName) = 0; //nacteni ogg souboru
HRESULT UnloadOgg(DWORD dwId) = 0; //uvolneni nacteneho ogg souboru
HRESULT PlayOgg(DWORD dwId, DWORD dwPriority = 0) = 0; //spusti prehravani ogg souboru
HRESULT StopOgg(DWORD dwId) = 0; //zastaveni prehravani ogg souboru
HRESULT PauseOgg(DWORD dwId) = 0; //pozastaveni prehravani ogg souboru
HRESULT StopAllOgg() = 0; //zastaveni prehravani vsech ogg souboru
HRESULT PauseAllOgg() = 0; //pozastaveni prehravani vsech ogg souboru
HRESULT CheckOggIfNeedReFillBuffer(DWORD dwId) = 0; //zjisteni zda ogg soubor potrebuje obnovit data bufferu
HRESULT CheckAllOggIfNeedReFillBuffer() = 0; //zjisteni zda nektery ze vsech ogg souboru potrebuje obnovit data v bufferu
bool SetRepetsOfOgg(DWORD dwId,int dwRepeats) = 0; //nastavi pocet opakovani urciteho ogg souboru
void HandleAppActiveStateChanges(bool bIsAppActive) = 0; //reakce na ztratu a ziskani fokusu ridici aplikace
LPDIRECTSOUND8 GetDirectSound() = 0; //vraceni ukazatele na ukazatel na zarizeni DirectSound
IOggFile* GetOggFile(DWORD dwID);
HRESULT AddRef() = 0;
HRESULT Release() = 0;
};
Obsah
T°φda CsoundManager ned∞lß nic slo₧itΘho ani nijak slo₧itß nenφ. Kdo Φte serißly o DirectX, tak to pro n∞j nebude nic novΘho. Jednß se o analogickΘho sprßvce
zdroj∙ jak² byl v t∞chto serißlech ji₧ n∞kolikrßt vid∞t. Jde jen o to vytvo°it ₧dy pro nov² ogg soubor novΘ rozhranφ IOggFile, p°idat ukazatel na n∞j do pole a poskytnout p°φstup
k funkcφm rozhranφ. Dßle jeÜt∞ n∞jakΘ funkce pro sprßvu otev°en²ch ogg soubor∙. Vlastn∞ jen prßce s polem a volßnφ funkcφ kterΘ u₧ mßme hotovΘ.
Soubor SoundManager.h:
#pragma once
struct OggData //struktura pro ulozeni dat o nactenem ogg souboru
{
IOggFile* oggFile;
DWORD dwID; //id pomoci nehoz se bude s ogg pracovat
DWORD dwPlayPriority; //priorita prehravani
};
//**************************************************************************************************************
//Manager zvuku, zatim predevsim ogg souboru
//**************************************************************************************************************
class CSoundManager: public ISoundManager
{
private:
LPDIRECTSOUND8 m_DSound; //objekt DirectSound
std::vector m_arOggFiles; //pole pro ukladani ogg souboru
DWORD m_dwNotifyCount; //pocet overovacich pozic
WORD m_wBufferLength; //velikost, delka bufferu v sekundach
void FindPlaceForOgg();
long GetOggPositionInArray(DWORD dwID,DWORD dwLeft,DWORD dwRight);
DWORD m_dwRef;
public:
virtual HRESULT CreateDirectSoundSystem(HWND hWnd,DWORD dwCooperativeLevel = DSSCL_PRIORITY); //vytvoreni objektu DirectSound
virtual HRESULT LoadOgg(DWORD dwId,const char* cFileName); //nacteni ogg souboru
virtual HRESULT UnloadOgg(DWORD dwId); //uvolneni nacteneho ogg souboru
virtual HRESULT PlayOgg(DWORD dwId, DWORD dwPriority = 0); //spusti prehravani ogg souboru
virtual HRESULT StopOgg(DWORD dwId); //zastaveni prehravani ogg souboru
virtual HRESULT PauseOgg(DWORD dwId); //pozastaveni prehravani ogg souboru
virtual HRESULT StopAllOgg(); //zastaveni prehravani vsech ogg souboru
virtual HRESULT PauseAllOgg(); //pozastaveni prehravani vsech ogg souboru
virtual HRESULT CheckOggIfNeedReFillBuffer(DWORD dwId); //zjisteni zda ogg soubor potrebuje obnovit data bufferu
virtual HRESULT CheckAllOggIfNeedReFillBuffer(); //zjisteni zda nektery ze vsech ogg souboru potrebuje obnovit data v bufferu
virtual bool SetRepetsOfOgg(DWORD dwId,int dwRepeats); //nastavi pocet opakovani urciteho ogg souboru
virtual void HandleAppActiveStateChanges(bool bIsAppActive); //reakce na ztratu a ziskani fokusu ridici aplikace
virtual LPDIRECTSOUND8 GetDirectSound() {return m_DSound;} //vraceni ukazatele na ukazatel na zarizeni DirectSound
virtual IOggFile* GetOggFile(DWORD dwID);
virtual HRESULT AddRef();
virtual HRESULT Release();
CSoundManager(void);
~CSoundManager(void);
};
Definujeme strukturu OggData pro ulo₧enφ dat o ka₧dΘm ogg souboru. SamotnΘ t°φda COggFile si neuklßdß jmΘno otev°enΘho souboru, to nenφ pot°eba. My v mana₧eru ale pot°ebujeme
ka₧d² soubor n∞jak odliÜit, proto definujeme identifikßtor v∞tÜφ ne₧ nula (dwID) pro ka₧d² soubor. Abychom mohli vyu₧φt priority p°ehrßvßnφ, mßme jeÜt∞ prom∞nnou dwPlayPriority pro
ka₧d² soubor. Ve t°φd∞ CSoundManager je pomocφ Üablony vector definovßno dynamickΘ pole ukazatel∙ na strukturu OggData (std::vector m_arOggFiles; ). DalÜφ prom∞nnΘ jsou ukazatel na rozhranφ IDirectSound, prom∞nnΘ souvisejφcφ s
rozd∞lenφm zvukovΘho bufferu na menÜφ Φßsti kterΘ se budou obnovovat (m_dwNotifyCount a m_dwBufferLenght). Proto₧e vÜechno co je v mana₧eru ogg soubor∙ bylo ji₧ n∞kdy probrßno v serißlech o C++ nebo
DirectX, budu se v∞novat jen nejd∙le₧it∞jÜφm v∞cem kterΘ je dobrΘ si zopakovat. Nap°φklad vynechßm metodu FindPlaceForOgg kterß t°φdφ prvky pole podle ID metodou quicksort a funkci GetOggPositionInArray kterß
hledß polo₧ky v poli, respektive zjiÜ¥uje jestli v poli je prvek s dwID metodou p∙lenφ interval∙. Na t∞la funkcφ se podφvejte do p°ilo₧enΘho projektu, nebo pokud nemßte Visual C++, prost∞ otev°ete cpp soubor v textovΘm editoru.
Nejd°φve tedy opakovßnφ zprovozn∞nφ systΘmu DirectSound:
//*************************************************************************************************************
//Zprovozneni DirectSound
//*************************************************************************************************************
HRESULT CSoundManager::CreateDirectSoundSystem(HWND hWnd,DWORD dwCooperativeLevel)
{
HRESULT hRet = DS_OK;
if (FAILED(hRet = DirectSoundCreate8(NULL,&m_DSound,NULL)))
return hRet;
hRet = m_DSound->SetCooperativeLevel(hWnd,dwCooperativeLevel);
return hRet;
}
Moc toho nenφ. Nejd°φve pot°ebujeme rozhranφ pro p°φstup k metodßm DirectSound. To zφskßme volßnφm funkce DirectSoundCreate8. Prvnφ parametr je GUID (global unique identifier)
urΦujφcφ pro kterΘ audio za°φzenφ chceme rozhranφ vytvo°it. NULL znamenß v²chozφ za°φzenφ. Do druhΘho parametru se ulo₧φ ukazatel na rozhranφ pokud se ho poda°φ vytvo°it. Poslednφ
souvisφ s technologiφ COM a zatφm musφ b²t v₧dy NULL. Druh²m krokem je nastavenφ m≤du spoluprßce aplikace a audio za°φzenφ, (SetCooperativeLevel).
Parametry jsou jen dva, handle (dr₧adlo) okna s kter²m mß b²t audio za°φzenφ spojeno a druh² je m≤d spoluprßce, kter² takΘ urΦuje jakΘ funkce budete a nebudete moci pou₧φvat.
Mo₧nosti jsou tyto:
DSSCL_NORMAL - B∞₧n² m≤d spoluprßce. Neumo₧≥uje m∞nit formßt primßrnφho bufferu a v²stup je omezen jen na 8bitov² formßt.
DSSCL_PRIORITY - Prioritnφ re₧im. Aplikace s tφmto re₧imem m∙₧e nastavit formßt primßrnφho bufferu.
DSSCL_EXCLUSIVE - Pro DirectX 8 a vyÜÜφ mß stejn² ·Φinek jako DSSCL_PRIORITY. Ni₧Üφ verzi u₧ urΦit∞ stejn∞ nemßte :)
DSSCL_WRITEPRIMARY - Aplikace m∙₧e zapisovat p°φmo do primßrnφho bufferu, sekundßrnφ buffery nemohou b²t p°ehrßvßny. Nem∙₧e b²t nastaven pokud je za°φzenφ emulovßno.
ÄßdnΘ jasno na obloze to asi ned∞lß, je to to mßlo co jsem vyΦetl z dokumentace. Ale jen pro ·Φely fungovßnφ tohoto p°φkladu stΦφ m≤d DSSCL_PRIORITY, kter² je takΘ v²chozφ hodnotou pro parametr funkce CreateDirectSoundSystem.
A₧ budete d∞lat vlastnφ Media Player, urΦit∞ si prostudujte celΘ DirectSound v dokumetaci k DirectX :) A nejen DirectSound.
//*************************************************************************************************************
//Nacteni ogg souboru
//*************************************************************************************************************
HRESULT CSoundManager::LoadOgg(DWORD dwId,const char* cFileName)
{
HRESULT hRet = S_OK;
//kontrola jestli uz ogg se stejnym id neni v seznamu
if (GetOggPositionInArray(dwId,0,(DWORD)m_arOggFiles.size()-1) >= 0)
return S_FALSE;
OggData* TmpPtr = new OggData;
if (!TmpPtr)
return E_OUTOFMEMORY;
CreateOggCodecObject(OGGIID_IOggFile,(void**)&(TmpPtr->oggFile));
if (!TmpPtr->oggFile)
{
SAFE_DELETE(TmpPtr);
return E_OUTOFMEMORY;
}
if(FAILED(hRet = TmpPtr->oggFile->Open(cFileName,m_DSound,m_dwNotifyCount,m_dwBufferLength)))
{
SAFE_DELETE(TmpPtr);
return hRet;
}
TmpPtr->dwID = dwId;
TmpPtr->dwPlayPriority = 0;
m_arOggFiles.push_back(TmpPtr);
FindPlaceForOgg(); //setrideni polozek
return hRet;
}
Prvnφm krokem je hledßnφ ogg souboru s id dwId v poli otev°en²ch ogg soubor∙. Pokud usp∞jeme, znamenß to ₧e u₧ je otev°en²
soubor se stejn²m id jako by m∞l mφt nov∞ otev°en² soubor. V tom p°φpad∞ nem∙₧eme pokraΦovat v otvφrßnφ ogg souboru, nem∙₧eme mφt dva se stejn²m id.
Nezp∙sobilo by to p°φmo chybu, ale jeden ze soubor∙ by nebyl nikdy vyhledßn. Vyhledßvacφ funkce by naÜla v₧dy jen jeden. Kdy₧ soubor s id
nenajdeme, pokraΦujeme dßl. Vytvo°φme novou strukturu OggData a pot°ebujeme taky rozhranφ IOggFile pro prßci s ogg souborem. Rozhranφ zφskßmne pomocφ funkce CreateOggCodecObject (tu napφÜeme ve ΦtvrtΘ Φßsti). Pokud se to povede, zavolßme funkci
pro otev°enφ ogg souboru a pokud ani ta nesel₧e, ulo₧φme id souboru, prioritu p°ehrßvßnφ a ulo₧φme ukazatel na novou strukturu OggData do pole (m_arOggFiles.push_back(TmpPtr) ). Poslednφ krok je volßnφ funkce pro
set°φd∞nφ pole.
//*************************************************************************************************************
//Zavreni ogg souboru a odstraneni zaznamu z pole
//*************************************************************************************************************
HRESULT CSoundManager::UnloadOgg(DWORD dwId)
{
long i;
UINT j;
bool bWasFind = false;
OggData* TmpPtr;
if ((i = (UINT)GetOggPositionInArray(dwId,0,(DWORD)m_arOggFiles.size()-1)) >= 0)
bWasFind = true;
if (bWasFind)
{
TmpPtr = (OggData*)m_arOggFiles[i];
for (j = i; j < m_arOggFiles.size() - 1; j++)
{
m_arOggFiles[j] = m_arOggFiles[j+1];
}
SAFE_RELEASE(TmpPtr->oggFile);
SAFE_DELETE(TmpPtr);
m_arOggFiles.pop_back();
return 0;
}
return -1;
}
Funkce ned∞lß nic jinΘho ne₧ ₧e najde soubor s id dwId, jeho pozici v poli. Ulo₧φ se ukazatel na strukturu OggData. Pak vÜechny polo₧ky na pravo od tΘto pozice
p°esune o jedno mφsto doleva. Tφm vlastn∞ dojde k p°epsßnφ ukazatele na hledan² soubor, co₧ ale nevadφ, proto₧e ho mßme ulo₧en² v TmpPtr.
Zavolßme metodu Release rozhranφ IOggFile pomocφ makra SAFE_RELEASE a sma₧eme z pam∞ti strukturu reprezentujφcφ soubor. Nakonec zmenÜφme pole
o jednu polo₧ku pomocφ metody pop_back. Na poslednφm mφst∞ byl stejn∞ jen ukazatel, kter² se p°esunem o jedno mφsto doleva dostal i na pozici konec-1, byl tedy
v poli dvakrßt a nevadφ, kdy₧ zmenÜφme pole o 1 zprava. Dßl tu mßme funkce PlayOgg,StopOgg, PauseOgg, CheckOggIfNeedReFillBuffer a SetRepeatsOfOgg. VÜechny pracujφ stejn∞, hledajφ soubor s dwId v poli
a pokud ho najdou, volajφ p°φsluÜnou funkci rozhranφ IOggFile.
HRESULT CSoundManager::PlayOgg(DWORD dwId,DWORD dwPriority)
{
OggData* tmpPtr;
long index;
index = GetOggPositionInArray(dwId,0,(DWORD)m_arOggFiles.size()-1);
if (index >= 0)
{
tmpPtr = (OggData*)m_arOggFiles[index];
return tmpPtr->oggFile->Play(dwPriority);
}
return -1;
}
HRESULT CSoundManager::StopOgg(DWORD dwId)
{
OggData* tmpPtr;
long index;
index = GetOggPositionInArray(dwId,0,(DWORD)m_arOggFiles.size()-1);
if (index >= 0)
{
tmpPtr = (OggData*)m_arOggFiles[index];
return tmpPtr->oggFile->Stop();
}
return -1;
}
HRESULT CSoundManager::PauseOgg(DWORD dwId)
{
OggData* tmpPtr;
long index;
index = GetOggPositionInArray(dwId,0,(DWORD)m_arOggFiles.size()-1);
if (index >= 0)
{
tmpPtr = (OggData*)m_arOggFiles[index];
return tmpPtr->oggFile->Pause();
}
return -1;
}
HRESULT CSoundManager::CheckOggIfNeedReFillBuffer(DWORD dwId)
{
for (UINT i = 0; i < m_arOggFiles.size(); i++)
{
OggData* TmpPtr = (OggData*)m_arOggFiles[i];
if (TmpPtr)
if (TmpPtr->dwID == dwId)
return TmpPtr->oggFile->CheckIfNeedReFillBuffer();
}
return -1;
}
bool CSoundManager::SetRepetsOfOgg(DWORD dwId,int iRepeats)
{
OggData* tmpPtr;
long index;
index = GetOggPositionInArray(dwId,0,(DWORD)m_arOggFiles.size()-1);
if (index >= 0)
{
tmpPtr = (OggData*)m_arOggFiles[index];
return tmpPtr->oggFile->SetRepeats(iRepeats);
}
return false;
}
Funkce StopAllOgg, PauseAllOgg a CheckAllOggIfNeedReFillBuffer pracujφ analogicky, jen volajφ p°φsluÜnΘ funkce rozhranφ IOggFile pro vÜechny soubory
v poli.
HRESULT CSoundManager::StopAllOgg()
{
HRESULT hRet;
for (UINT i = 0; i < m_arOggFiles.size(); i++)
{
OggData* TmpPtr = (OggData*)m_arOggFiles[i];
if (TmpPtr)
hRet &= TmpPtr->oggFile->Stop();
}
return hRet;
}
HRESULT CSoundManager::PauseAllOgg()
{
HRESULT hRet;
for (UINT i = 0; i < m_arOggFiles.size(); i++)
{
OggData* TmpPtr = (OggData*)m_arOggFiles[i];
if (TmpPtr)
hRet &= TmpPtr->oggFile->Pause();
}
return hRet;
}
HRESULT CSoundManager::CheckAllOggIfNeedReFillBuffer()
{
HRESULT hRet;
for (UINT i = 0; i < m_arOggFiles.size(); i++)
{
OggData* TmpPtr = (OggData*)m_arOggFiles[i];
if (TmpPtr)
hRet &= TmpPtr->oggFile->CheckIfNeedReFillBuffer();
}
return hRet;
}
Funkce GetOggFile vracφ ukazatel na rozhranφ IOggFile pro soubor s dwId. Jist∞ jste si vÜimli ₧e ne vÜechny funkce rozhranφ IoggFile jsou zp°φstupn∞ny
pomocφ funkcφ rozhranφ ISoundManager. Abychom mohli pou₧φvat i ten zbytek, musφme mφt mo₧nost p°istoupit p°φmo k souboru p°es rozhranφ IOggFile.
IOggFile* CSoundManager::GetOggFile(DWORD dwID)
{
OggData* tmpPtr;
long index;
index = GetOggPositionInArray(dwID,0,(DWORD)m_arOggFiles.size() - 1);
if (index >= 0)
{
tmpPtr = (OggData*)m_arOggFiles[index];
return tmpPtr->oggFile;
}
return NULL;
}
Poslednφ funkce na kterou se podφvßme, je HandleAppActiveStateChanges. Tato funkce m∙₧e b²t volßna aplikacφ p°i ztßt∞ fokusu, tj. aplikace nenφ aktivnφ. Pokud aplikace ztratφ fokus,
pozastavφ funkce p°ehrßvßnφ vÜech soubor∙ kterΘ jsou p°ehrßvßny (jsou ve stavu OGGSTATUS_PLAYING). Pokud aplikace fokus zase zφskß, spustφ se p°ehrßvßnφ vÜech soubor∙ co jsou ve stavu OGGSTATUS_PAUSED.
void CSoundManager::HandleAppActiveStateChanges(bool bIsAppActive)
{
if (bIsAppActive) //ridici aplikace ma fokus
{
for (UINT i = 0; i < m_arOggFiles.size(); i++)
{
OggData* TmpPtr = (OggData*)m_arOggFiles[i];
if (TmpPtr)
{
if (TmpPtr->oggFile->GetStatus() == OGGSTATUS_PAUSED)
TmpPtr->oggFile->Play(TmpPtr->dwPlayPriority);
}
}
}
else //ridici aplikace nema fokus
{
for (UINT i = 0; i < m_arOggFiles.size(); i++)
{
OggData* TmpPtr = (OggData*)m_arOggFiles[i];
if (TmpPtr)
{
if (TmpPtr->oggFile->GetStatus() == OGGSTATUS_PLAYING)
TmpPtr->oggFile->Pause();
}
}
}
}
To je vÜe ohledn∞ rozhranφ ISoundManager. Na nejasnosti a zbytek k≤du se podφvejte do p°ilo₧enΘho projektu.
Obsah
|