Cocos2dx Win32下SimpleAudioEngine::setBackgroundMusicVolume(float volume)函数实现

最近在做项目的过程中遇到一个需求,需要改变项目中原有背景音乐的音量

但是cocos2dx在win32平台下setBackgroundMusicVolume(float volume)函数是没有实现的

这就尴尬了

我设置了半天这玩意儿不起作用

但是项目中又需要实现这样的功能

那么问题就来了?

挖掘机技术哪家强!!!!

其实cocos2dx对安卓以及ios系统这个函数是实现了的,在安卓版本中是可以实现对背景音量的控制的

但是在TestCpp项目中,这个改变背景音乐的功能是不起作用的

在对项目功能实现之后我也把源码拿出来分享了

这免得走弯路啊

虽然改的东西不是很多

但是涉及到的东西还是比较多的

下面是引擎源码有改动的地方


1. CocosDenshion\include文件夹下的SimpleAudioEngine.h文件

/****************************************************************************
Copyright (c) 2010-2012 cocos2d-x.org
Copyright (c) 2010      Steve Oldmeadow

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

#ifndef _SIMPLE_AUDIO_ENGINE_H_
#define _SIMPLE_AUDIO_ENGINE_H_

#include <stddef.h>
#include "Export.h"
#include <typeinfo>
#include <ctype.h>
#include <string.h>

namespace CocosDenshion {

class TypeInfo
{
public:
    virtual long getClassTypeInfo() = 0;
};

static inline unsigned int getHashCodeByString(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);
}

/**
@class          SimpleAudioEngine
@brief          offer a VERY simple interface to play background music & sound effect
*/

class EXPORT_DLL SimpleAudioEngine : public TypeInfo
{
public:
    SimpleAudioEngine();
    ~SimpleAudioEngine();

    virtual long getClassTypeInfo() {
        return getHashCodeByString(typeid(CocosDenshion::SimpleAudioEngine).name());
    }

    /**
    @brief Get the shared Engine object,it will new one when first time be called
    */
    static SimpleAudioEngine* sharedEngine();

    /**
    @brief Release the shared Engine object
    @warning It must be called before the application exit, or a memroy leak will be casued.
    */
    static void end();

    /**
     @brief Preload background music
     @param pszFilePath The path of the background music file,or the FileName of T_SoundResInfo
     */
    void preloadBackgroundMusic(const char* pszFilePath);
    
    /**
    @brief Play background music
    @param pszFilePath The path of the background music file,or the FileName of T_SoundResInfo
    @param bLoop Whether the background music loop or not
    */
    void playBackgroundMusic(const char* pszFilePath, bool bLoop);
    void playBackgroundMusic(const char* pszFilePath) {
    	this->playBackgroundMusic(pszFilePath, false);
    }

    /**
    @brief Stop playing background music
    @param bReleaseData If release the background music data or not.As default value is false
    */
    void stopBackgroundMusic(bool bReleaseData);
    void stopBackgroundMusic() {
    	this->stopBackgroundMusic(false);
    }

    /**
    @brief Pause playing background music
    */
    void pauseBackgroundMusic();

    /**
    @brief Resume playing background music
    */
    void resumeBackgroundMusic();

    /**
    @brief Rewind playing background music
    */
    void rewindBackgroundMusic();

    bool willPlayBackgroundMusic();

    /**
    @brief Whether the background music is playing
    @return If is playing return true,or return false
    */
    bool isBackgroundMusicPlaying();

    // properties
    /**
    @brief The volume of the background music max value is 1.0,the min value is 0.0
    */
    float getBackgroundMusicVolume();

    /**
    @brief set the volume of background music
    @param volume must be in 0.0~1.0
    */
    void setBackgroundMusicVolume(float volume);

    /**
    @brief The volume of the effects max value is 1.0,the min value is 0.0
    */
    float getEffectsVolume();

    /**
    @brief set the volume of sound effecs
    @param volume must be in 0.0~1.0
    */
    void setEffectsVolume(float volume);

    // for sound effects
    /**
    @brief Play sound effect
    @param pszFilePath The path of the effect file,or the FileName of T_SoundResInfo
    @bLoop Whether to loop the effect playing, default value is false
    */
    unsigned int playEffect(const char* pszFilePath, bool bLoop);
    unsigned int playEffect(const char* pszFilePath) {
    	return this->playEffect(pszFilePath, false);
    }

    /**
    @brief Pause playing sound effect
    @param nSoundId The return value of function playEffect
    */
    void pauseEffect(unsigned int nSoundId);

    /**
    @brief Pause all playing sound effect
    @param nSoundId The return value of function playEffect
    */
    void pauseAllEffects();

    /**
    @brief Resume playing sound effect
    @param nSoundId The return value of function playEffect
    */
    void resumeEffect(unsigned int nSoundId);

    /**
    @brief Resume all playing sound effect
    @param nSoundId The return value of function playEffect
    */
    void resumeAllEffects();

    /**
    @brief Stop playing sound effect
    @param nSoundId The return value of function playEffect
    */
    void stopEffect(unsigned int nSoundId);

    /**
    @brief Stop all playing sound effects
    */
    void stopAllEffects();

    /**
    @brief          preload a compressed audio file
    @details        the compressed audio will be decode to wave, then write into an 
    internal buffer in SimpleaudioEngine
    */
    void preloadEffect(const char* pszFilePath);

    /**
    @brief          unload the preloaded effect from internal buffer
    @param[in]        pszFilePath        The path of the effect file,or the FileName of T_SoundResInfo
    */
    void unloadEffect(const char* pszFilePath);

private:
    float m_effectsVolume;
};

} // end of namespace CocosDenshion

#endif // _SIMPLE_AUDIO_ENGINE_H_


2. CocosDenshion\win32文件夹下的SimpleAudioEngine.cpp文件

#include "SimpleAudioEngine.h"

#include <map>
#include <cstdlib>

#include "MciPlayer.h"
#include "cocos2d.h"
USING_NS_CC;

using namespace std;

namespace CocosDenshion {

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);
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() : m_effectsVolume(1.0f)
{
}

SimpleAudioEngine::~SimpleAudioEngine()
{
}

SimpleAudioEngine* SimpleAudioEngine::sharedEngine()
{
	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)
{
	unsigned int nRet = _Hash(pszFilePath);

	preloadEffect(pszFilePath);

	EffectList::iterator p = sharedList().find(nRet);
	if (p != sharedList().end())
	{
		p->second->Play((bLoop) ? -1 : 1);
		p->second->SetVolume((UINT) (m_effectsVolume * 1000.0));
	}

	return nRet;
}

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];
		pPlayer->Open(_FullPath(pszFilePath).c_str(), nRet);

		BREAK_IF(nRet == pPlayer->GetSoundID());

		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();
	}
}

void SimpleAudioEngine::stopAllEffects()
{
	EffectList::iterator iter;
	for (iter = sharedList().begin(); iter != sharedList().end(); iter++)
	{
		iter->second->Stop();
	}
}

void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath)
{

}

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 sharedMusic().GetVolume() / 1000.0f;
}

void SimpleAudioEngine::setBackgroundMusicVolume(float volume)
{
	sharedMusic().SetVolume((UINT) (volume * 1000.0));
}

float SimpleAudioEngine::getEffectsVolume()
{
	return m_effectsVolume;
}

void SimpleAudioEngine::setEffectsVolume(float volume)
{
	m_effectsVolume = volume;
	EffectList::iterator iter;
	for (iter = sharedList().begin(); iter != sharedList().end(); iter++)
	{
		iter->second->SetVolume((UINT) (volume * 1000.0));
	}
}

//
// static function
//

static std::string _FullPath(const char * szPath)
{
	return CCFileUtils::sharedFileUtils()->fullPathForFilename(szPath);
}

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);
}

} // end of namespace CocosDenshion


3. CocosDenshion\win32文件夹下的MciPlayer.h文件

#ifndef _MCI_PLAYER_WIN32_H_
#define _MCI_PLAYER_WIN32_H_

#include "CCStdC.h"
#include <mmsystem.h>

namespace CocosDenshion {

class MciPlayer
{
public:
    MciPlayer();
    ~MciPlayer();

    void Close();

    /**
    @brief 播放声音文件
    @param pFileName 播放的声音文件名称,需要包含文件的路径
    @param nTimes    播放声音文件的循环次数,默认值为 1,即播放一次
    */
    void Open(const char* pFileName, UINT uId);

    void Play(UINT uTimes = 1);

    /**
    @brief 暂停播放声音
    */
    void Pause();

    /**
    @brief 继续播放声音
    */
    void Resume();

    /**
    @brief 停止播放声音
    */
    void Stop();

    /**
    @brief 重新播放
    */
    void Rewind();

    /**
    @brief 获取播放器当前是否正在播放中
    */
    bool IsPlaying();

    /**
    @brief 获取当前播放的音效 ID
    @return 当前播放的音效ID
    */
    UINT GetSoundID();

    // @volume value ranges from 0 .. 1000
    void SetVolume(UINT volume);

    // @return value ranges from 0 .. 1000
    UINT GetVolume() const;

private:
    friend LRESULT WINAPI _SoundPlayProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

    void _SendGenericCommand(int nCommand);

    HWND        m_hWnd;
    MCIDEVICEID m_hDev;
    UINT        m_nSoundID;
    UINT        m_uTimes;
    bool        m_bPlaying;
};

} // end of namespace CocosDenshion

#endif


4. CocosDenshion\win32文件夹下的MciPlayer.cpp文件

#include "MciPlayer.h"
#include <Digitalv.h>

#define WIN_CLASS_NAME        "CocosDenshionCallbackWnd"
#define BREAK_IF(cond)      if (cond) break;

namespace CocosDenshion {

static HINSTANCE s_hInstance;
static MCIERROR  s_mciError;

static LRESULT WINAPI _SoundPlayProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

MciPlayer::MciPlayer()
: m_hWnd(NULL)
, m_hDev(NULL)
, m_nSoundID(0)
, m_uTimes(0)
, m_bPlaying(false)
{
	if (! s_hInstance)
	{
		s_hInstance = GetModuleHandle( NULL );            // Grab An Instance For Our Window

		WNDCLASS  wc;        // Windows Class Structure

		// Redraw On Size, And Own DC For Window.
		wc.style          = 0;  
		wc.lpfnWndProc    = _SoundPlayProc;                    // WndProc Handles Messages
		wc.cbClsExtra     = 0;                              // No Extra Window Data
		wc.cbWndExtra     = 0;                                // No Extra Window Data
		wc.hInstance      = s_hInstance;                    // Set The Instance
		wc.hIcon          = 0;                                // Load The Default Icon
		wc.hCursor        = LoadCursor( NULL, IDC_ARROW );    // Load The Arrow Pointer
		wc.hbrBackground  = NULL;                           // No Background Required For GL
		wc.lpszMenuName   = NULL;                           // We Don't Want A Menu
		wc.lpszClassName  = WIN_CLASS_NAME;                 // Set The Class Name

		if (! RegisterClass(&wc)
			&& 1410 != GetLastError())
		{
			return;
		}
	}

	m_hWnd = CreateWindowEx(
		WS_EX_APPWINDOW,                                    // Extended Style For The Window
		WIN_CLASS_NAME,                                        // Class Name
		NULL,                                        // Window Title
		WS_POPUPWINDOW,/*WS_OVERLAPPEDWINDOW*/               // Defined Window Style
		0, 0,                                                // Window Position
		0,                                                    // Window Width
		0,                                                    // Window Height
		NULL,                                                // No Parent Window
		NULL,                                                // No Menu
		s_hInstance,                                        // Instance
		NULL );
	if (m_hWnd)
	{
		SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this);
	}
}

MciPlayer::~MciPlayer()
{
	Close();
	DestroyWindow(m_hWnd);
}

void MciPlayer::Open(const char* pFileName, UINT uId)
{
	//     WCHAR * pBuf = NULL;
	do 
	{
		BREAK_IF(! pFileName || ! m_hWnd);
		int nLen = (int)strlen(pFileName);
		BREAK_IF(! nLen);
		//         pBuf = new WCHAR[nLen + 1];
		//         BREAK_IF(! pBuf);
		//         MultiByteToWideChar(CP_ACP, 0, pFileName, nLen + 1, pBuf, nLen + 1);

		Close();

		MCI_OPEN_PARMS mciOpen = {0};
		MCIERROR mciError;
		mciOpen.lpstrDeviceType = (LPCTSTR)MCI_ALL_DEVICE_ID;
		mciOpen.lpstrElementName = pFileName;

		mciError = mciSendCommand(0,MCI_OPEN, MCI_OPEN_ELEMENT, (DWORD)&mciOpen);
		BREAK_IF(mciError);

		m_hDev = mciOpen.wDeviceID;
		m_nSoundID = uId;
		m_bPlaying = false;
	} while (0);
}

void MciPlayer::SetVolume(UINT volume)
{
	if (!m_hDev)
		return;
	MCI_DGV_SETAUDIO_PARMS mciParams = {0};
	mciParams.dwItem = MCI_DGV_SETAUDIO_VOLUME;
	mciParams.dwValue = volume;
	mciSendCommand(m_hDev, MCI_SETAUDIO, MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE, (DWORD)&mciParams);
}

UINT MciPlayer::GetVolume() const
{
	if (!m_hDev)
		return 0;
	MCI_STATUS_PARMS mciParams = {0};
	mciParams.dwItem = MCI_DGV_STATUS_VOLUME;
	mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)&mciParams);
	return mciParams.dwReturn;
}

void MciPlayer::Play(UINT uTimes /* = 1 */)
{
	if (! m_hDev)
	{
		return;
	}
	MCI_PLAY_PARMS mciPlay = {0};
	mciPlay.dwCallback = (DWORD_PTR)m_hWnd;
	s_mciError = mciSendCommand(m_hDev,MCI_PLAY, MCI_FROM|MCI_NOTIFY,(DWORD)&mciPlay);
	if (! s_mciError)
	{
		m_bPlaying = true;
		m_uTimes = uTimes;
	}
}

void MciPlayer::Close()
{
	if (m_bPlaying)
	{
		Stop();
	}
	if (m_hDev)
	{
		_SendGenericCommand(MCI_CLOSE);
	}
	m_hDev = 0;
	m_bPlaying = false;
}

void MciPlayer::Pause()
{
	_SendGenericCommand(MCI_PAUSE);
}

void MciPlayer::Resume()
{
	_SendGenericCommand(MCI_RESUME);
}

void MciPlayer::Stop()
{
	_SendGenericCommand(MCI_STOP);
	m_bPlaying = false;
}

void MciPlayer::Rewind()
{
	if (! m_hDev)
	{
		return;
	}
	mciSendCommand(m_hDev, MCI_SEEK, MCI_SEEK_TO_START, 0);

	MCI_PLAY_PARMS mciPlay = {0};
	mciPlay.dwCallback = (DWORD)m_hWnd;
	m_bPlaying = mciSendCommand(m_hDev, MCI_PLAY, MCI_NOTIFY,(DWORD)&mciPlay) ? false : true;
}

bool MciPlayer::IsPlaying()
{
	return m_bPlaying;
}

UINT MciPlayer::GetSoundID()
{
	return m_nSoundID;
}

//
// private member
//

void MciPlayer::_SendGenericCommand(int nCommand)
{
	if (! m_hDev)
	{
		return;
	}
	mciSendCommand(m_hDev, nCommand, 0, 0);
}

//
// static function
//

LRESULT WINAPI _SoundPlayProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	MciPlayer * pPlayer = NULL;
	if (MM_MCINOTIFY == Msg 
		&& MCI_NOTIFY_SUCCESSFUL == wParam
		&&(pPlayer = (MciPlayer *)GetWindowLong(hWnd, GWL_USERDATA)))
	{
		if (pPlayer->m_uTimes)
		{
			--pPlayer->m_uTimes;
		}

		if (pPlayer->m_uTimes)
		{
			mciSendCommand(lParam, MCI_SEEK, MCI_SEEK_TO_START, 0);

			MCI_PLAY_PARMS mciPlay = {0};
			mciPlay.dwCallback = (DWORD)hWnd;
			mciSendCommand(lParam, MCI_PLAY, MCI_NOTIFY,(DWORD)&mciPlay);
		}
		else
		{
			pPlayer->m_bPlaying = false;
		}
		return 0;
	}
	return DefWindowProc(hWnd, Msg, wParam, lParam);
}

} // end of namespace CocosDenshion


如果上面的看着麻烦,需要源码,我已经把CocosDenshion文件夹的内容上传到资源库中了,不需要积分就可以下载。下面是链接地址:

http://download.csdn.net/detail/u013476751/8162815

不要问我名字,请叫我雷锋。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值