2014-01-07 11:47:11 +08:00
|
|
|
/****************************************************************************
|
|
|
|
Copyright (c) 2011 Laschweinski
|
|
|
|
Copyright (c) 2013-2014 Chukong Technologies Inc.
|
|
|
|
|
|
|
|
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.
|
|
|
|
****************************************************************************/
|
2012-08-02 13:02:59 +08:00
|
|
|
|
|
|
|
#include "FmodAudioPlayer.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "stdlib.h"
|
|
|
|
#include "assert.h"
|
|
|
|
#include "string.h"
|
|
|
|
|
|
|
|
#define szMusicSuffix "|"
|
|
|
|
|
|
|
|
namespace CocosDenshion {
|
|
|
|
|
|
|
|
FmodAudioPlayer* FmodAudioPlayer::sharedPlayer() {
|
|
|
|
static FmodAudioPlayer s_SharedPlayer;
|
|
|
|
return &s_SharedPlayer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ERRCHECKWITHEXIT(FMOD_RESULT result) {
|
|
|
|
if (result != FMOD_OK) {
|
|
|
|
printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
|
|
|
|
// exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ERRCHECK(FMOD_RESULT result) {
|
|
|
|
if (result != FMOD_OK) {
|
|
|
|
printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FmodAudioPlayer::FmodAudioPlayer() :
|
|
|
|
pMusic(0), pBGMChannel(0), iSoundChannelCount(0) {
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::init() {
|
|
|
|
//init
|
|
|
|
FMOD_RESULT result;
|
|
|
|
FMOD::ChannelGroup *masterChannelGroup;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Create a System object and initialize.
|
|
|
|
*/
|
|
|
|
result = FMOD::System_Create(&pSystem);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
result = pSystem->setOutput(FMOD_OUTPUTTYPE_ALSA);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
result = pSystem->init(32, FMOD_INIT_NORMAL, 0);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
result = pSystem->createChannelGroup("Channel Group", &pChannelGroup);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
result = pSystem->getMasterChannelGroup(&masterChannelGroup);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
result = masterChannelGroup->addGroup(pChannelGroup);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
mapEffectSound.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::close() {
|
|
|
|
FMOD_RESULT result;
|
|
|
|
//BGM
|
|
|
|
if (pBGMChannel != NULL) {
|
|
|
|
result = pBGMChannel->stop();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
pBGMChannel = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pMusic != NULL) {
|
|
|
|
result = pMusic->release();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
pMusic = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = pChannelGroup->release();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
sMusicPath.clear();
|
|
|
|
|
|
|
|
result = pSystem->close();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
result = pSystem->release();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
FmodAudioPlayer::~FmodAudioPlayer() {
|
|
|
|
FMOD_RESULT result;
|
|
|
|
//BGM
|
|
|
|
if (pBGMChannel != NULL) {
|
|
|
|
result = pBGMChannel->stop();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pMusic != NULL) {
|
|
|
|
result = pMusic->release();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
result = pChannelGroup->release();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
result = pSystem->close();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
result = pSystem->release();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// BGM
|
|
|
|
void FmodAudioPlayer::preloadBackgroundMusic(const char* pszFilePath) {
|
|
|
|
FMOD_RESULT result;
|
|
|
|
pSystem->update();
|
|
|
|
string sNewMusicPath = string(pszFilePath) + szMusicSuffix;
|
|
|
|
if (pMusic && sNewMusicPath != sMusicPath) {
|
|
|
|
//release old
|
|
|
|
result = pMusic->release();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
sMusicPath = sNewMusicPath;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
result = pSystem->createSound(pszFilePath, FMOD_LOOP_NORMAL, 0, &pMusic);
|
|
|
|
ERRCHECK(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::playBackgroundMusic(const char* pszFilePath, bool bLoop) {
|
|
|
|
pSystem->update();
|
|
|
|
if (pMusic == NULL) {
|
|
|
|
//did not load it
|
|
|
|
//load the new music
|
|
|
|
FMOD_RESULT result = pSystem->createSound(pszFilePath, FMOD_LOOP_NORMAL,
|
|
|
|
0, &pMusic);
|
|
|
|
if (!ERRCHECK(result)) {
|
|
|
|
sMusicPath = string(pszFilePath) + szMusicSuffix;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
string sNewMusicPath = string(pszFilePath) + szMusicSuffix;
|
|
|
|
if (pBGMChannel) {
|
|
|
|
pBGMChannel->stop();
|
|
|
|
pBGMChannel = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sNewMusicPath != sMusicPath) {
|
|
|
|
|
|
|
|
pMusic->release();
|
|
|
|
//load the new music
|
|
|
|
FMOD_RESULT result = pSystem->createSound(pszFilePath,
|
|
|
|
FMOD_LOOP_NORMAL, 0, &pMusic);
|
|
|
|
|
|
|
|
if (!ERRCHECK(result)) {
|
|
|
|
sMusicPath = sNewMusicPath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
FMOD_RESULT result = pSystem->playSound(FMOD_CHANNEL_FREE, pMusic, true,
|
|
|
|
&pBGMChannel);
|
|
|
|
if (!ERRCHECK(result)) {
|
2013-03-03 17:27:03 +08:00
|
|
|
pBGMChannel->setLoopCount((bLoop) ? -1 : 0);
|
2012-08-02 13:02:59 +08:00
|
|
|
result = pBGMChannel->setPaused(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::stopBackgroundMusic(bool bReleaseData) {
|
|
|
|
FMOD_RESULT result;
|
|
|
|
pSystem->update();
|
|
|
|
|
|
|
|
if (pBGMChannel == NULL || pMusic == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (bReleaseData) {
|
|
|
|
result = pBGMChannel->stop();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
result = pMusic->release();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
pBGMChannel = 0;
|
|
|
|
pMusic = 0;
|
|
|
|
} else {
|
|
|
|
result = pBGMChannel->stop();
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
pBGMChannel = 0;
|
|
|
|
}
|
|
|
|
sMusicPath.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::pauseBackgroundMusic() {
|
|
|
|
if (pBGMChannel == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pSystem->update();
|
|
|
|
FMOD_RESULT result = pBGMChannel->setPaused(true);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::resumeBackgroundMusic() {
|
|
|
|
if (pBGMChannel == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pSystem->update();
|
|
|
|
FMOD_RESULT result = pBGMChannel->setPaused(false);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::rewindBackgroundMusic() {
|
|
|
|
if (pBGMChannel == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pSystem->update();
|
|
|
|
FMOD_RESULT result = pBGMChannel->setPosition(0, FMOD_TIMEUNIT_MS);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FmodAudioPlayer::willPlayBackgroundMusic() {
|
|
|
|
pSystem->update();
|
|
|
|
return false; //do it according to win
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FmodAudioPlayer::isBackgroundMusicPlaying() {
|
|
|
|
bool bPlaying;
|
|
|
|
if (pBGMChannel == NULL) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pSystem->update();
|
|
|
|
FMOD_RESULT result = pBGMChannel->isPlaying(&bPlaying);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
return bPlaying;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
float FmodAudioPlayer::getBackgroundMusicVolume() {
|
|
|
|
float fVolumn;
|
|
|
|
if (pBGMChannel == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
pSystem->update();
|
|
|
|
FMOD_RESULT result = pBGMChannel->getVolume(&fVolumn);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
return fVolumn;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::setBackgroundMusicVolume(float volume) {
|
|
|
|
if (pBGMChannel == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pSystem->update();
|
|
|
|
FMOD_RESULT result = pBGMChannel->setVolume(volume);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
}
|
|
|
|
//~BGM
|
|
|
|
|
|
|
|
// for sound effects
|
|
|
|
float FmodAudioPlayer::getEffectsVolume() {
|
|
|
|
float fVolumn;
|
|
|
|
pSystem->update();
|
|
|
|
FMOD_RESULT result = pChannelGroup->getVolume(&fVolumn);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
2013-03-02 08:12:42 +08:00
|
|
|
return fVolumn;
|
2012-08-02 13:02:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::setEffectsVolume(float volume) {
|
|
|
|
pSystem->update();
|
|
|
|
FMOD_RESULT result = pChannelGroup->setVolume(volume);
|
|
|
|
ERRCHECKWITHEXIT(result);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-06-03 20:59:50 +08:00
|
|
|
unsigned int FmodAudioPlayer::playEffect(const char* pszFilePath, bool bLoop,
|
|
|
|
float pitch, float pan, float gain) {
|
2012-08-02 13:02:59 +08:00
|
|
|
FMOD::Channel* pChannel;
|
|
|
|
FMOD::Sound* pSound = NULL;
|
|
|
|
|
|
|
|
do {
|
|
|
|
pSystem->update();
|
|
|
|
|
|
|
|
map<string, FMOD::Sound*>::iterator l_it = mapEffectSound.find(
|
|
|
|
string(pszFilePath));
|
|
|
|
if (l_it == mapEffectSound.end()) {
|
|
|
|
//no load it yet
|
|
|
|
preloadEffect(pszFilePath);
|
|
|
|
l_it = mapEffectSound.find(string(pszFilePath));
|
|
|
|
}
|
|
|
|
pSound = l_it->second;
|
|
|
|
if (pSound==NULL){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
FMOD_RESULT result = pSystem->playSound(FMOD_CHANNEL_FREE, pSound, true,
|
|
|
|
&pChannel);
|
|
|
|
|
|
|
|
if (ERRCHECK(result)) {
|
|
|
|
printf("sound effect in %s could not be played", pszFilePath);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pChannel->setChannelGroup(pChannelGroup);
|
2013-06-03 20:59:50 +08:00
|
|
|
pChannel->setPan(pan);
|
|
|
|
float freq = 0;
|
|
|
|
pChannel->getFrequency(&freq);
|
|
|
|
pChannel->setFrequency(pitch * freq);
|
|
|
|
pChannel->setVolume(gain);
|
2012-08-02 13:02:59 +08:00
|
|
|
|
|
|
|
//set its loop
|
2013-03-03 17:27:03 +08:00
|
|
|
pChannel->setLoopCount((bLoop) ? -1 : 0);
|
2012-08-02 13:02:59 +08:00
|
|
|
result = pChannel->setPaused(false);
|
|
|
|
|
|
|
|
mapEffectSoundChannel[iSoundChannelCount] = pChannel;
|
|
|
|
return iSoundChannelCount++;
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::stopEffect(unsigned int nSoundId) {
|
|
|
|
FMOD::Channel* pChannel;
|
|
|
|
pSystem->update();
|
|
|
|
|
|
|
|
map<unsigned int, FMOD::Channel*>::iterator l_it =
|
|
|
|
mapEffectSoundChannel.find(nSoundId);
|
|
|
|
if (l_it == mapEffectSoundChannel.end()) {
|
|
|
|
//no play yet
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pChannel = l_it->second;
|
|
|
|
//stop the channel;
|
|
|
|
pChannel->stop();
|
|
|
|
|
|
|
|
//delete from the map;
|
|
|
|
mapEffectSoundChannel.erase(nSoundId);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::pauseEffect(unsigned int uSoundId) {
|
|
|
|
FMOD::Channel* pChannel;
|
|
|
|
pSystem->update();
|
|
|
|
|
|
|
|
map<unsigned int, FMOD::Channel*>::iterator l_it =
|
|
|
|
mapEffectSoundChannel.find(uSoundId);
|
|
|
|
if (l_it == mapEffectSoundChannel.end()) {
|
|
|
|
//no play yet
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pChannel = l_it->second;
|
|
|
|
//pause the channel;
|
|
|
|
pChannel->setPaused(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::pauseAllEffects() {
|
|
|
|
FMOD::Channel* pChannel;
|
|
|
|
pSystem->update();
|
|
|
|
|
|
|
|
map<unsigned int, FMOD::Channel*>::iterator l_it =
|
|
|
|
mapEffectSoundChannel.begin();
|
|
|
|
|
|
|
|
for (; l_it != mapEffectSoundChannel.end(); l_it++) {
|
|
|
|
pChannel = l_it->second;
|
|
|
|
//pause the channel;
|
|
|
|
pChannel->setPaused(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::resumeEffect(unsigned int uSoundId) {
|
|
|
|
FMOD::Channel* pChannel;
|
|
|
|
pSystem->update();
|
|
|
|
|
|
|
|
map<unsigned int, FMOD::Channel*>::iterator l_it =
|
|
|
|
mapEffectSoundChannel.find(uSoundId);
|
|
|
|
if (l_it == mapEffectSoundChannel.end()) {
|
|
|
|
//no play yet
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pChannel = l_it->second;
|
|
|
|
//resume the channel;
|
|
|
|
pChannel->setPaused(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::resumeAllEffects() {
|
|
|
|
FMOD::Channel* pChannel;
|
|
|
|
pSystem->update();
|
|
|
|
|
|
|
|
map<unsigned int, FMOD::Channel*>::iterator l_it =
|
|
|
|
mapEffectSoundChannel.begin();
|
|
|
|
|
|
|
|
for (; l_it != mapEffectSoundChannel.end(); l_it++) {
|
|
|
|
pChannel = l_it->second;
|
|
|
|
//resume the channel;
|
|
|
|
pChannel->setPaused(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::stopAllEffects() {
|
|
|
|
FMOD::Channel* pChannel;
|
|
|
|
pSystem->update();
|
|
|
|
|
|
|
|
map<unsigned int, FMOD::Channel*>::iterator l_it =
|
|
|
|
mapEffectSoundChannel.begin();
|
|
|
|
|
|
|
|
for (; l_it != mapEffectSoundChannel.end(); l_it++) {
|
|
|
|
pChannel = l_it->second;
|
|
|
|
//resume the channel;
|
|
|
|
pChannel->stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
mapEffectSoundChannel.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::preloadEffect(const char* pszFilePath) {
|
|
|
|
FMOD::Sound* pLoadSound;
|
|
|
|
|
|
|
|
pSystem->update();
|
|
|
|
FMOD_RESULT result = pSystem->createSound(pszFilePath, FMOD_LOOP_NORMAL, 0,
|
|
|
|
&pLoadSound);
|
|
|
|
if (ERRCHECK(result)){
|
|
|
|
printf("sound effect in %s could not be preload", pszFilePath);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mapEffectSound[string(pszFilePath)] = pLoadSound;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FmodAudioPlayer::unloadEffect(const char* pszFilePath) {
|
|
|
|
FMOD::Sound* pSound;
|
|
|
|
pSystem->update();
|
|
|
|
|
|
|
|
map<string, FMOD::Sound*>::iterator l_it = mapEffectSound.find(
|
|
|
|
string(pszFilePath));
|
|
|
|
if (l_it == mapEffectSound.end()) {
|
|
|
|
//no load yet
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pSound = l_it->second;
|
|
|
|
|
|
|
|
//release the sound;
|
|
|
|
pSound->release();
|
|
|
|
|
|
|
|
//delete from the map
|
|
|
|
mapEffectSound.erase(string(pszFilePath));
|
|
|
|
}
|
|
|
|
|
|
|
|
//~for sound effects
|
|
|
|
|
|
|
|
} /* namespace CocosDenshion */
|