SimpleAudioEngine是提供了简单的 播放音效,以及播放背景音乐的功能。
class EXPORT_DLL SimpleAudioEngine { public: static SimpleAudioEngine* getInstance(); static void end(); protected: SimpleAudioEngine(); virtual ~SimpleAudioEngine(); public: //播放背景音乐 virtual void preloadBackgroundMusic(const char* pszFilePath); virtual void playBackgroundMusic(const char* pszFilePath, bool bLoop = false); virtual void stopBackgroundMusic(bool bReleaseData = false); virtual void pauseBackgroundMusic(); virtual void resumeBackgroundMusic(); virtual void rewindBackgroundMusic(); virtual bool willPlayBackgroundMusic(); virtual bool isBackgroundMusicPlaying(); virtual float getBackgroundMusicVolume(); virtual void setBackgroundMusicVolume(float volume); //播放音效 virtual float getEffectsVolume(); virtual void setEffectsVolume(float volume); virtual unsigned int playEffect(const char* pszFilePath, bool bLoop = false, float pitch = 1.0f, float pan = 0.0f, float gain = 1.0f); virtual void pauseEffect(unsigned int nSoundId); virtual void pauseAllEffects(); virtual void resumeEffect(unsigned int nSoundId); virtual void resumeAllEffects(); virtual void stopEffect(unsigned int nSoundId); virtual void stopAllEffects(); virtual void preloadEffect(const char* pszFilePath); virtual void unloadEffect(const char* pszFilePath); };以win32下的实现为例:
//用于处理 音效 每个播放音效 对应一个MCI typedef map<unsigned int, MciPlayer *> EffectList; //用于播放 背景音乐 typedef pair<unsigned int, MciPlayer *> Effect; static char s_szRootPath[MAX_PATH]; static DWORD s_dwRootLen; static char s_szFullPath[MAX_PATH]; //获取全路径 static std::string _FullPath(const char * szPath); //计算路径的hash值 static unsigned int _Hash(const char *key); #define BREAK_IF(cond) if (cond) break; //用于实现单例 音效 static EffectList& sharedList() { static EffectList s_List; return s_List; } //用于实现单例 背景音乐 static MciPlayer& sharedMusic() { static MciPlayer s_Music; return s_Music; } //单例模式 SimpleAudioEngine* SimpleAudioEngine::getInstance() { static SimpleAudioEngine s_SharedEngine; return &s_SharedEngine; } //一个个都给删除了 void SimpleAudioEngine::end() { sharedMusic().Close(); EffectList::iterator p = sharedList().begin(); while (p != sharedList().end()) { delete p->second; p->second = NULL; p++; } sharedList().clear(); return; } // // BackgroundMusic // //直接加载 然后播放 void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) { if (! pszFilePath) { return; } sharedMusic().Open(_FullPath(pszFilePath).c_str(), _Hash(pszFilePath)); sharedMusic().Play((bLoop) ? -1 : 1); } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { if (bReleaseData) { sharedMusic().Close(); } else { sharedMusic().Stop(); } } void SimpleAudioEngine::pauseBackgroundMusic() { sharedMusic().Pause(); } void SimpleAudioEngine::resumeBackgroundMusic() { sharedMusic().Resume(); } void SimpleAudioEngine::rewindBackgroundMusic() { sharedMusic().Rewind(); } //无语 bool SimpleAudioEngine::willPlayBackgroundMusic() { return false; } bool SimpleAudioEngine::isBackgroundMusicPlaying() { return sharedMusic().IsPlaying(); } // // effect function // //传了那么多参数 假的 unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop, float pitch, float pan, float gain) { unsigned int nRet = _Hash(pszFilePath); //先预加载 preloadEffect(pszFilePath); //此时必然能找到 EffectList::iterator p = sharedList().find(nRet); if (p != sharedList().end()) { p->second->Play((bLoop) ? -1 : 1); } return nRet; } //stop某一个 void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { EffectList::iterator p = sharedList().find(nSoundId); if (p != sharedList().end()) { p->second->Stop(); } } void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { int nRet = 0; do { BREAK_IF(! pszFilePath); nRet = _Hash(pszFilePath); BREAK_IF(sharedList().end() != sharedList().find(nRet)); sharedList().insert(Effect(nRet, new MciPlayer())); MciPlayer * pPlayer = sharedList()[nRet]; //就是 new一个MciPlayer 加入到表项中 //让他加载该音效 pPlayer->Open(_FullPath(pszFilePath).c_str(), nRet); //成功的 加载之后是走不下去的 所以没问题 BREAK_IF(nRet == pPlayer->GetSoundID()); delete pPlayer; sharedList().erase(nRet); nRet = 0; } while (0); } //暂停某一个 void SimpleAudioEngine::pauseEffect(unsigned int nSoundId) { EffectList::iterator p = sharedList().find(nSoundId); if (p != sharedList().end()) { p->second->Pause(); } } //暂停所有的音效 void SimpleAudioEngine::pauseAllEffects() { EffectList::iterator iter; for (iter = sharedList().begin(); iter != sharedList().end(); iter++) { iter->second->Pause(); } } //找到某一个 然后恢复 void SimpleAudioEngine::resumeEffect(unsigned int nSoundId) { EffectList::iterator p = sharedList().find(nSoundId); if (p != sharedList().end()) { p->second->Resume(); } } //对列表中 都恢复 void SimpleAudioEngine::resumeAllEffects() { EffectList::iterator iter; for (iter = sharedList().begin(); iter != sharedList().end(); iter++) { iter->second->Resume(); } } //对列表中每一个 都stop void SimpleAudioEngine::stopAllEffects() { EffectList::iterator iter; for (iter = sharedList().begin(); iter != sharedList().end(); iter++) { iter->second->Stop(); } } //假装的 void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) { } //简单的从map中删去 void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { unsigned int nID = _Hash(pszFilePath); EffectList::iterator p = sharedList().find(nID); if (p != sharedList().end()) { delete p->second; p->second = NULL; sharedList().erase(nID); } } // // volume interface // float SimpleAudioEngine::getBackgroundMusicVolume() { return 1.0; } //假装的 没有实现 void SimpleAudioEngine::setBackgroundMusicVolume(float volume) { } float SimpleAudioEngine::getEffectsVolume() { return 1.0; } void SimpleAudioEngine::setEffectsVolume(float volume) { } // // static function // //获取完整路径 static std::string _FullPath(const char * szPath) { return FileUtils::getInstance()->fullPathForFilename(szPath); } //计算hash unsigned int _Hash(const char *key) { unsigned int len = strlen(key); const char *end=key+len; unsigned int hash; for (hash = 0; key < end; key++) { hash *= 16777619; hash ^= (unsigned int) (unsigned char) toupper(*key); } return (hash); }可以看出来 SimpleAudioEngine的所有操作都是转交给了MciPlayer。
class MciPlayer { public: MciPlayer(); ~MciPlayer(); void Close(); void Open(const char* pFileName, UINT uId); void Play(UINT uTimes = 1); void Pause(); void Resume(); void Stop(); void Rewind(); bool IsPlaying(); UINT GetSoundID(); private: friend LRESULT WINAPI _SoundPlayProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void _SendGenericCommand(int nCommand, DWORD_PTR param1 = 0, DWORD_PTR parma2 = 0); HWND _wnd; MCIDEVICEID _dev; UINT _soundID; UINT _times; bool _playing; std::string strExt; }; //其实现是对MCI命令的包装 void MciPlayer::Open(const char* pFileName, UINT uId) { do { BREAK_IF(! pFileName || ! _wnd); int nLen = (int)strlen(pFileName); BREAK_IF(! nLen); std::string strFile(pFileName); int nPos = strFile.rfind(".") + 1; strExt = strFile.substr(nPos, strFile.length() - nPos); Close(); MCI_OPEN_PARMS mciOpen = {0}; MCIERROR mciError; mciOpen.lpstrDeviceType = (LPCTSTR)MCI_ALL_DEVICE_ID; WCHAR* fileNameWideChar = new WCHAR[nLen + 1]; BREAK_IF(! fileNameWideChar); MultiByteToWideChar(CP_ACP, 0, pFileName, nLen + 1, fileNameWideChar, nLen + 1); mciOpen.lpstrElementName = fileNameWideChar; mciError = mciSendCommand(0,MCI_OPEN, MCI_OPEN_ELEMENT, reinterpret_cast<DWORD_PTR>(&mciOpen)); CC_SAFE_DELETE_ARRAY(mciOpen.lpstrElementName); BREAK_IF(mciError); _dev = mciOpen.wDeviceID; _soundID = uId; _playing = false; } while (0); } void MciPlayer::Play(UINT uTimes /* = 1 */) { if (! _dev) { return; } MCI_PLAY_PARMS mciPlay = {0}; mciPlay.dwCallback = reinterpret_cast<DWORD_PTR>(_wnd); s_mciError = mciSendCommand(_dev,MCI_PLAY, MCI_FROM|MCI_NOTIFY,reinterpret_cast<DWORD_PTR>(&mciPlay)); if (! s_mciError) { _playing = true; _times = uTimes; } } void MciPlayer::Close() { if (_playing) { Stop(); } if (_dev) { _SendGenericCommand(MCI_CLOSE); } _dev = 0; _playing = false; } void MciPlayer::Pause() { _SendGenericCommand(MCI_PAUSE); } void MciPlayer::Resume() { if (strExt == "mid" || strExt == "MID") { // midi not supprt MCI_RESUME, should get the position and use MCI_FROM MCI_STATUS_PARMS mciStatusParms; MCI_PLAY_PARMS mciPlayParms; mciStatusParms.dwItem = MCI_STATUS_POSITION; _SendGenericCommand(MCI_STATUS, MCI_STATUS_ITEM, reinterpret_cast<DWORD_PTR>(&mciStatusParms)); // MCI_STATUS mciPlayParms.dwFrom = mciStatusParms.dwReturn; // get position _SendGenericCommand(MCI_PLAY, MCI_FROM, reinterpret_cast<DWORD_PTR>(&mciPlayParms)); // MCI_FROM } else { _SendGenericCommand(MCI_RESUME); } }下一篇分析 localStorage 的实现。
