525 lines
10 KiB
C++
525 lines
10 KiB
C++
#include "..\etools.h"
|
|
#include "..\Win\winbase.h"
|
|
#include <map>
|
|
#include <mmsystem.h>
|
|
#include <Digitalv.h>
|
|
#pragma comment(lib , "winmm.lib")
|
|
|
|
static size_t Hash(const e2d::EString & key);
|
|
static bool ExtractResource(LPCTSTR strDstFile, LPCTSTR strResType, LPCTSTR strResName);
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// MciPlayer
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
class MciPlayer
|
|
{
|
|
public:
|
|
MciPlayer();
|
|
~MciPlayer();
|
|
|
|
void close();
|
|
bool open(const e2d::EString & pFileName, size_t uId);
|
|
bool open(const e2d::EString & pResouceName, const e2d::EString & pResouceType, const e2d::EString & musicExtension, size_t uId);
|
|
void play(bool bLoop = false);
|
|
void pause();
|
|
void resume();
|
|
void stop();
|
|
void rewind();
|
|
void setVolume(float volume);
|
|
bool isPlaying();
|
|
size_t getSoundID();
|
|
|
|
private:
|
|
void _sendCommand(int nCommand, DWORD_PTR param1 = 0, DWORD_PTR parma2 = 0);
|
|
|
|
MCIDEVICEID m_dev;
|
|
size_t m_nSoundID;
|
|
bool m_bPlaying;
|
|
bool m_bLoop;
|
|
e2d::EString m_sTempFileName;
|
|
};
|
|
|
|
|
|
MciPlayer::MciPlayer() :
|
|
m_dev(0L),
|
|
m_nSoundID(0),
|
|
m_bPlaying(false),
|
|
m_bLoop(false)
|
|
{
|
|
}
|
|
|
|
MciPlayer::~MciPlayer()
|
|
{
|
|
close(); // 关闭播放器
|
|
}
|
|
|
|
bool MciPlayer::open(const e2d::EString & pFileName, size_t uId)
|
|
{
|
|
// 忽略不存在的文件
|
|
if (pFileName.empty())
|
|
return false;
|
|
|
|
// 停止当前音乐
|
|
close();
|
|
|
|
// 设置 MCI_OPEN_PARMS 参数
|
|
MCI_OPEN_PARMS mciOpen = { 0 };
|
|
mciOpen.lpstrElementName = pFileName.c_str();
|
|
|
|
// 打开这个文件
|
|
MCIERROR mciError;
|
|
mciError = mciSendCommand(
|
|
0,
|
|
MCI_OPEN,
|
|
MCI_OPEN_ELEMENT | MCI_NOTIFY,
|
|
reinterpret_cast<DWORD_PTR>(&mciOpen)
|
|
);
|
|
|
|
if (mciError)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// 保存设备等信息
|
|
m_dev = mciOpen.wDeviceID;
|
|
m_nSoundID = uId;
|
|
m_bPlaying = false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool MciPlayer::open(const e2d::EString & pResouceName, const e2d::EString & pResouceType, const e2d::EString & musicExtension, size_t uId)
|
|
{
|
|
// 忽略不存在的文件
|
|
if (pResouceName.empty() || pResouceType.empty() || musicExtension.empty()) return false;
|
|
|
|
// 获取临时文件目录
|
|
e2d::EString tempFileName = e2d::EFileUtils::getTempPath();
|
|
|
|
// 产生临时文件的文件名
|
|
tempFileName.append(L"\\");
|
|
tempFileName.append(std::to_wstring(uId));
|
|
tempFileName.append(L"." + musicExtension);
|
|
|
|
// 导出资源为临时文件
|
|
if (ExtractResource(tempFileName.c_str(), pResouceType.c_str(), pResouceName.c_str()))
|
|
{
|
|
if (open(tempFileName, uId))
|
|
{
|
|
m_sTempFileName = tempFileName;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MciPlayer::play(bool bLoop)
|
|
{
|
|
// 设备为空时,忽略这次操作
|
|
if (!m_dev)
|
|
{
|
|
return;
|
|
}
|
|
// 设置播放参数
|
|
MCI_PLAY_PARMS mciPlay = { 0 };
|
|
MCIERROR s_mciError;
|
|
|
|
// 播放声音
|
|
s_mciError = mciSendCommand(
|
|
m_dev,
|
|
MCI_PLAY,
|
|
MCI_FROM | MCI_NOTIFY | (bLoop ? MCI_DGV_PLAY_REPEAT : 0),
|
|
reinterpret_cast<DWORD_PTR>(&mciPlay)
|
|
);
|
|
|
|
// 未出错时,置 m_bPlaying 为 true
|
|
if (!s_mciError)
|
|
{
|
|
m_bPlaying = true;
|
|
m_bLoop = bLoop;
|
|
}
|
|
}
|
|
|
|
void MciPlayer::close()
|
|
{
|
|
// 停止音乐
|
|
if (m_bPlaying)
|
|
{
|
|
stop();
|
|
}
|
|
// 关闭设备
|
|
if (m_dev)
|
|
{
|
|
_sendCommand(MCI_CLOSE);
|
|
}
|
|
// 删除临时文件
|
|
if (!m_sTempFileName.empty())
|
|
{
|
|
DeleteFile(m_sTempFileName.c_str());
|
|
m_sTempFileName.clear();
|
|
}
|
|
// 恢复默认属性
|
|
m_dev = 0;
|
|
m_bPlaying = false;
|
|
}
|
|
|
|
void MciPlayer::pause()
|
|
{
|
|
// 暂停音乐
|
|
_sendCommand(MCI_PAUSE);
|
|
m_bPlaying = false;
|
|
}
|
|
|
|
void MciPlayer::resume()
|
|
{
|
|
// 继续播放音乐
|
|
_sendCommand(MCI_RESUME);
|
|
m_bPlaying = true;
|
|
}
|
|
|
|
void MciPlayer::stop()
|
|
{
|
|
// 停止音乐
|
|
_sendCommand(MCI_STOP);
|
|
m_bPlaying = false;
|
|
}
|
|
|
|
void MciPlayer::rewind()
|
|
{
|
|
// 设备为空时,忽略这次操作
|
|
if (!m_dev)
|
|
{
|
|
return;
|
|
}
|
|
// 重置播放位置
|
|
mciSendCommand(
|
|
m_dev,
|
|
MCI_SEEK,
|
|
MCI_SEEK_TO_START | MCI_NOTIFY,
|
|
0
|
|
);
|
|
// 播放音乐
|
|
MCI_PLAY_PARMS mciPlay = { 0 };
|
|
MCIERROR s_mciError;
|
|
|
|
// 播放声音
|
|
s_mciError = mciSendCommand(
|
|
m_dev,
|
|
MCI_PLAY,
|
|
MCI_NOTIFY | (m_bLoop ? MCI_DGV_PLAY_REPEAT : 0),
|
|
reinterpret_cast<DWORD_PTR>(&mciPlay)
|
|
);
|
|
m_bPlaying = s_mciError ? false : true;
|
|
}
|
|
|
|
void MciPlayer::setVolume(float volume)
|
|
{
|
|
MCI_DGV_SETAUDIO_PARMS mciSetAudioPara = { 0 };
|
|
mciSetAudioPara.dwItem = MCI_DGV_SETAUDIO_VOLUME;
|
|
mciSetAudioPara.dwValue = DWORD(1000 * min(max(volume, 0), 1));
|
|
mciSendCommand(
|
|
m_dev,
|
|
MCI_SETAUDIO,
|
|
MCI_NOTIFY | MCI_DGV_SETAUDIO_VALUE | MCI_DGV_SETAUDIO_ITEM,
|
|
(DWORD_PTR)&mciSetAudioPara
|
|
);
|
|
}
|
|
|
|
bool MciPlayer::isPlaying()
|
|
{
|
|
return m_bPlaying;
|
|
}
|
|
|
|
size_t MciPlayer::getSoundID()
|
|
{
|
|
return m_nSoundID;
|
|
}
|
|
|
|
void MciPlayer::_sendCommand(int nCommand, DWORD_PTR param1, DWORD_PTR parma2)
|
|
{
|
|
// 空设备时忽略这次操作
|
|
if (!m_dev)
|
|
{
|
|
return;
|
|
}
|
|
// 向当前设备发送操作
|
|
mciSendCommand(m_dev, nCommand, param1, parma2);
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// e2d::EMusicUtils
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
typedef std::map<size_t, MciPlayer *> MusicList;
|
|
typedef std::pair<size_t, MciPlayer *> Music;
|
|
|
|
|
|
static MusicList& getMciPlayerList()
|
|
{
|
|
static MusicList s_List;
|
|
return s_List;
|
|
}
|
|
|
|
static MciPlayer& getBgMciPlayer()
|
|
{
|
|
static MciPlayer s_Music;
|
|
return s_Music;
|
|
}
|
|
|
|
void e2d::EMusicUtils::end()
|
|
{
|
|
// 停止背景音乐
|
|
getBgMciPlayer().close();
|
|
// 停止其他所有音乐
|
|
for (auto& iter : getMciPlayerList())
|
|
{
|
|
SafeDelete(&iter.second);
|
|
}
|
|
// 清空音乐列表
|
|
getMciPlayerList().clear();
|
|
return;
|
|
}
|
|
|
|
void e2d::EMusicUtils::setVolume(float volume)
|
|
{
|
|
// 设置背景音乐音量
|
|
getBgMciPlayer().setVolume(volume);
|
|
// 设置其他音乐音量
|
|
for (auto& iter : getMciPlayerList())
|
|
{
|
|
iter.second->setVolume(volume);
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::setVolume(const EString & musicFilePath, float volume)
|
|
{
|
|
size_t nRet = ::Hash(musicFilePath);
|
|
|
|
MusicList::iterator p = getMciPlayerList().find(nRet);
|
|
if (p != getMciPlayerList().end())
|
|
{
|
|
p->second->setVolume(volume);
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::playBackgroundMusic(const EString & musicFilePath, bool bLoop)
|
|
{
|
|
if (musicFilePath.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
getBgMciPlayer().open(musicFilePath, ::Hash(musicFilePath));
|
|
getBgMciPlayer().play(bLoop);
|
|
}
|
|
|
|
void e2d::EMusicUtils::playBackgroundMusic(const EString & musicResourceName, const EString & musicResourceType, const EString & musicExtension, bool loop)
|
|
{
|
|
if (musicResourceName.empty() || musicResourceType.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
getBgMciPlayer().open(musicResourceName, musicResourceType, musicExtension, ::Hash(musicResourceName));
|
|
getBgMciPlayer().play(loop);
|
|
}
|
|
|
|
void e2d::EMusicUtils::stopBackgroundMusic(bool bReleaseData)
|
|
{
|
|
if (bReleaseData)
|
|
{
|
|
getBgMciPlayer().close();
|
|
}
|
|
else
|
|
{
|
|
getBgMciPlayer().stop();
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::pauseBackgroundMusic()
|
|
{
|
|
getBgMciPlayer().pause();
|
|
}
|
|
|
|
void e2d::EMusicUtils::resumeBackgroundMusic()
|
|
{
|
|
getBgMciPlayer().resume();
|
|
}
|
|
|
|
void e2d::EMusicUtils::rewindBackgroundMusic()
|
|
{
|
|
getBgMciPlayer().rewind();
|
|
}
|
|
|
|
bool e2d::EMusicUtils::isBackgroundMusicPlaying()
|
|
{
|
|
return getBgMciPlayer().isPlaying();
|
|
}
|
|
|
|
void e2d::EMusicUtils::setBackgroundMusicVolume(float volume)
|
|
{
|
|
getBgMciPlayer().setVolume(volume);
|
|
}
|
|
|
|
void e2d::EMusicUtils::playMusic(const EString & musicFilePath, bool bLoop)
|
|
{
|
|
size_t nRet = ::Hash(musicFilePath);
|
|
|
|
preloadMusic(musicFilePath);
|
|
|
|
MusicList::iterator p = getMciPlayerList().find(nRet);
|
|
if (p != getMciPlayerList().end())
|
|
{
|
|
p->second->play(bLoop);
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::playMusic(const EString & musicResourceName, const EString & musicResourceType, const EString & musicExtension, bool loop)
|
|
{
|
|
size_t nRet = ::Hash(musicResourceName);
|
|
|
|
preloadMusic(musicResourceName, musicResourceType, musicExtension);
|
|
|
|
MusicList::iterator p = getMciPlayerList().find(nRet);
|
|
if (p != getMciPlayerList().end())
|
|
{
|
|
p->second->play(loop);
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::_stopMusic(size_t nSoundId)
|
|
{
|
|
MusicList::iterator p = getMciPlayerList().find(nSoundId);
|
|
if (p != getMciPlayerList().end())
|
|
{
|
|
p->second->stop();
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::preloadMusic(const EString & musicFilePath)
|
|
{
|
|
if (musicFilePath.empty()) return;
|
|
|
|
size_t nRet = ::Hash(musicFilePath);
|
|
|
|
if (getMciPlayerList().end() != getMciPlayerList().find(nRet)) return;
|
|
|
|
getMciPlayerList().insert(Music(nRet, new MciPlayer()));
|
|
MciPlayer * pPlayer = getMciPlayerList()[nRet];
|
|
pPlayer->open(musicFilePath, nRet);
|
|
|
|
if (nRet == pPlayer->getSoundID()) return;
|
|
|
|
delete pPlayer;
|
|
getMciPlayerList().erase(nRet);
|
|
nRet = 0;
|
|
}
|
|
|
|
void e2d::EMusicUtils::preloadMusic(const EString & musicResourceName, const EString & musicResourceType, const EString & musicExtension)
|
|
{
|
|
if (musicResourceName.empty() || musicResourceType.empty()) return;
|
|
|
|
size_t nRet = ::Hash(musicResourceName);
|
|
|
|
if (getMciPlayerList().end() != getMciPlayerList().find(nRet)) return;
|
|
|
|
getMciPlayerList().insert(Music(nRet, new MciPlayer()));
|
|
MciPlayer * pPlayer = getMciPlayerList()[nRet];
|
|
pPlayer->open(musicResourceName, musicResourceType, musicExtension, nRet);
|
|
|
|
if (nRet == pPlayer->getSoundID()) return;
|
|
|
|
delete pPlayer;
|
|
getMciPlayerList().erase(nRet);
|
|
nRet = 0;
|
|
}
|
|
|
|
void e2d::EMusicUtils::_pauseMusic(size_t nSoundId)
|
|
{
|
|
MusicList::iterator p = getMciPlayerList().find(nSoundId);
|
|
if (p != getMciPlayerList().end())
|
|
{
|
|
p->second->pause();
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::pauseAllMusics()
|
|
{
|
|
for (auto& iter : getMciPlayerList())
|
|
{
|
|
iter.second->pause();
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::_resumeMusic(size_t nSoundId)
|
|
{
|
|
MusicList::iterator p = getMciPlayerList().find(nSoundId);
|
|
if (p != getMciPlayerList().end())
|
|
{
|
|
p->second->resume();
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::resumeAllMusics()
|
|
{
|
|
for (auto& iter : getMciPlayerList())
|
|
{
|
|
iter.second->resume();
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::stopAllMusics()
|
|
{
|
|
for (auto& iter : getMciPlayerList())
|
|
{
|
|
iter.second->stop();
|
|
}
|
|
}
|
|
|
|
void e2d::EMusicUtils::unloadMusic(const EString & musicFilePath)
|
|
{
|
|
size_t nID = ::Hash(musicFilePath);
|
|
|
|
MusicList::iterator p = getMciPlayerList().find(nID);
|
|
if (p != getMciPlayerList().end())
|
|
{
|
|
SafeDelete(&p->second);
|
|
getMciPlayerList().erase(nID);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t Hash(const e2d::EString & key)
|
|
{
|
|
static std::hash<e2d::EString> h;
|
|
return h(key);
|
|
}
|
|
|
|
bool ExtractResource(LPCTSTR strDstFile, LPCTSTR strResType, LPCTSTR strResName)
|
|
{
|
|
// 创建文件
|
|
HANDLE hFile = ::CreateFile(strDstFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
return false;
|
|
|
|
// 查找资源文件中、加载资源到内存、得到资源大小
|
|
HRSRC hRes = ::FindResource(NULL, strResName, strResType);
|
|
HGLOBAL hMem = ::LoadResource(NULL, hRes);
|
|
DWORD dwSize = ::SizeofResource(NULL, hRes);
|
|
|
|
// 写入文件
|
|
DWORD dwWrite = 0; // 返回写入字节
|
|
::WriteFile(hFile, hMem, dwSize, &dwWrite, NULL);
|
|
::CloseHandle(hFile);
|
|
|
|
return true;
|
|
} |