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

3.1 Rozhranφ ISoundManager

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

3.2 T°φda CSoundManager

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