void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { EffectsMap::iterator iter = s_effects.find(pszFilePath); // check if we have this already if (iter == s_effects.end()) { ALuint buffer; ALuint source; soundData *data = new soundData; string path = pszFilePath; buffer = alutCreateBufferFromFile(path.data()); if (buffer == AL_NONE) { fprintf(stderr, "Error loading file: '%s'\n", path.data()); alDeleteBuffers(1, &buffer); return; } alGenSources(1, &source); alSourcei(source, AL_BUFFER, buffer); data->isLooped = false; data->buffer = buffer; data->source = source; s_effects.insert(EffectsMap::value_type(pszFilePath, data)); } }
unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop) { EffectsMap::iterator iter = s_effects.find(pszFilePath); if (iter == s_effects.end()) { preloadEffect(pszFilePath); // let's try again iter = s_effects.find(pszFilePath); if (iter == s_effects.end()) { fprintf(stderr, "could not find play sound %s\n", pszFilePath); return -1; } } checkALError("playEffect"); iter->second->isLooped = bLoop; alSourcei(iter->second->source, AL_LOOPING, iter->second->isLooped ? AL_TRUE : AL_FALSE); alSourcePlay(iter->second->source); checkALError("playEffect"); return iter->second->source; }
unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop) { // Changing file path to full path std::string fullPath = CCFileUtils::sharedFileUtils()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); if (iter == s_effects.end()) { preloadEffect(fullPath.c_str()); // let's try again iter = s_effects.find(fullPath); if (iter == s_effects.end()) { fprintf(stderr, "could not find play sound %s\n", fullPath.c_str()); return -1; } } checkALError("playEffect"); iter->second->isLooped = bLoop; alSourcei(iter->second->source, AL_LOOPING, iter->second->isLooped ? AL_TRUE : AL_FALSE); alSourcePlay(iter->second->source); checkALError("playEffect"); return iter->second->source; }
void SimpleAudioEngine::end() { checkALError("end"); // clear all the sounds EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::iterator it = s_effects.begin(); it != end; it++) { alSourceStop(it->second->source); checkALError("end"); alDeleteBuffers(1, &it->second->buffer); checkALError("end"); alDeleteSources(1, &it->second->source); checkALError("end"); delete it->second; } s_effects.clear(); // and the background too stopBackground(true); for (BackgroundMusicsMap::iterator it = s_backgroundMusics.begin(); it != s_backgroundMusics.end(); ++it) { alSourceStop(it->second->source); checkALError("end"); alDeleteBuffers(1, &it->second->buffer); checkALError("end"); alDeleteSources(1, &it->second->source); checkALError("end"); delete it->second; } s_backgroundMusics.clear(); }
void SimpleAudioEngine::pauseAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { alSourcePause(iter->second->source); checkALError("pauseAllEffects"); } }
void SimpleAudioEngine::resumeAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { checkALError("resumeAllEffects"); alSourcePlay(iter->second->source); checkALError("resumeAllEffects"); } }
void SimpleAudioEngine::stopAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { checkALError("stopAllEffects:init"); alSourceStop(iter->second->source); checkALError("stopAllEffects:alSourceStop"); } }
void SimpleAudioEngine::stopAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { alSourceStop(iter->second->source); int err = alGetError(); if (err != AL_NO_ERROR) printALError(err); } }
void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { // Changing file path to full path std::string fullPath = CCFileUtils::sharedFileUtils()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); // check if we have this already if (iter == s_effects.end()) { ALuint buffer; ALuint source; soundData *data = new soundData; string path = fullPath; checkALError("preloadEffect"); if (isOGGFile(path.data())) { buffer = createBufferFromOGG(path.data()); } else { buffer = alutCreateBufferFromFile(path.data()); checkALError("preloadEffect"); } if (buffer == AL_NONE) { fprintf(stderr, "Error loading file: '%s'\n", path.data()); alDeleteBuffers(1, &buffer); return; } alGenSources(1, &source); if (checkALError("preloadEffect") != AL_NO_ERROR) { alDeleteBuffers(1, &buffer); return; } alSourcei(source, AL_BUFFER, buffer); checkALError("preloadEffect"); data->isLooped = false; data->buffer = buffer; data->source = source; s_effects.insert(EffectsMap::value_type(fullPath, data)); } }
void SimpleAudioEngine::resumeAllEffects() { EffectsMap::iterator iter = s_effects.begin(); ALint state; while (iter != s_effects.end()) { alGetSourcei(iter->second->source, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) alSourcePlay(iter->second->source); checkALError("resumeAllEffects:alSourcePlay"); ++iter; } }
void SimpleAudioEngine::pauseAllEffects() { EffectsMap::iterator iter = s_effects.begin(); ALint state; while (iter != s_effects.end()) { alGetSourcei(iter->second->source, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) alSourcePause(iter->second->source); checkALError("pauseAllEffects"); ++iter; } }
void SimpleAudioEngine::setEffectsVolume(float volume) { if (volume != s_effectVolume) { EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::const_iterator it = s_effects.begin(); it != end; it++) { alSourcef(it->second->source, AL_GAIN, volume * it->second->gain); } s_effectVolume = volume; } }
void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { // Changing file path to full path std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); // check if we have this already if (iter == s_effects.end()) { ALuint buffer = AL_NONE; ALuint source = AL_NONE; checkALError("preloadEffect:init"); OpenALFile file; file.debugName = pszFilePath; file.file = fopen(fullPath.c_str(), "rb"); if (!file.file) { fprintf(stderr, "Cannot read file: '%s'\n", fullPath.data()); return; } bool success = false; const std::vector<OpenALDecoder *> &decoders = OpenALDecoder::getDecoders(); for (size_t i = 0, n = decoders.size(); !success && i < n; ++i) success = decoders[i]->decode(file, buffer); file.clear(); alGenSources(1, &source); if (checkALError("preloadEffect:alGenSources") != AL_NO_ERROR) { alDeleteBuffers(1, &buffer); return; } alSourcei(source, AL_BUFFER, buffer); checkALError("preloadEffect:alSourcei"); soundData *data = new soundData; data->isLooped = false; data->buffer = buffer; data->source = source; data->pitch = 1.0; data->pan = 0.0; data->gain = 1.0; s_effects.insert(EffectsMap::value_type(fullPath, data)); } }
void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { std::string key = std::string(pszFilePath); if(!s_effects.count(key)) { return; } struct soundData *sound = s_effects[key]; Mix_FreeChunk(sound->chunk); delete sound; s_effects.erase(key); }
unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop, float pitch, float pan, float gain) { std::string key = std::string(pszFilePath); struct soundData *sound; if(!s_effects.count(key)) { sound = new struct soundData(); sound->chunk = Mix_LoadWAV(pszFilePath); sound->isLooped = bLoop; s_effects[key] = sound; } else { sound = s_effects[key]; } // This is safe here since Emscripten is just passing back an // incrementing integer each time you use the Mix_LoadWAV method. unsigned int result = (unsigned int) sound->chunk; // XXX: This is a bit of a hack, but... Choose a channel based on the // modulo of the # of channels. This allows us to set the volume // without passing around both chunk address and channel. Mix_PlayChannel(result % NR_CHANNELS, sound->chunk, bLoop ? -1 : 0); return result; }
void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { EffectsMap::iterator iter = s_effects.find(pszFilePath); if (iter != s_effects.end()) { alSourceStop(iter->second->source); alDeleteSources(1, &iter->second->source); alDeleteBuffers(1, &iter->second->buffer); delete iter->second; int err = alGetError(); if (err != AL_NO_ERROR) printALError(err); s_effects.erase(iter); } }
void SimpleAudioEngine::end() { checkALError("end:init"); // clear all the sound effects EffectsMap::const_iterator end = s_effects.end(); for (auto it = s_effects.begin(); it != end; ++it) { alSourceStop(it->second->source); checkALError("end:alSourceStop"); alDeleteSources(1, &it->second->source); checkALError("end:alDeleteSources"); alDeleteBuffers(1, &it->second->buffer); checkALError("end:alDeleteBuffers"); delete it->second; } s_effects.clear(); // and the background music too stopBackground(true); for (auto it = s_backgroundMusics.begin(); it != s_backgroundMusics.end(); ++it) { alSourceStop(it->second->source); checkALError("end:alSourceStop"); alDeleteSources(1, &it->second->source); checkALError("end:alDeleteSources"); alDeleteBuffers(1, &it->second->buffer); checkALError("end:alDeleteBuffers"); delete it->second; } s_backgroundMusics.clear(); CC_SAFE_DELETE(s_engine); }
void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { EffectsMap::iterator iter = s_effects.find(pszFilePath); if (iter != s_effects.end()) { checkALError("unloadEffect"); alSourceStop(iter->second->source); checkALError("unloadEffect"); alDeleteSources(1, &iter->second->source); checkALError("unloadEffect"); alDeleteBuffers(1, &iter->second->buffer); checkALError("unloadEffect"); delete iter->second; s_effects.erase(iter); } }
void SimpleAudioEngine::end() { // clear all the sounds EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::iterator it = s_effects.begin(); it != end; it++) { Mix_FreeChunk(it->second->chunk); delete it->second; } s_effects.clear(); // and the background too stopBackground(true); for (BackgroundMusicsMap::iterator it = s_backgroundMusics.begin(); it != s_backgroundMusics.end(); ++it) { Mix_FreeMusic(it->second->music); delete it->second; } s_backgroundMusics.clear(); }
void SimpleAudioEngine::end() { // clear all the sounds EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::iterator it = s_effects.begin(); it != end; it++) { alSourceStop(it->second->source); alDeleteBuffers(1, &it->second->buffer); alDeleteSources(1, &it->second->source); delete it->second; } s_effects.clear(); if (s_isBackgroundInitialized) { s_isBackgroundInitialized = false; } // and the background too stopBackground(true); }
unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop, float pitch, float pan, float gain) { std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); if (iter == s_effects.end()) { preloadEffect(fullPath.c_str()); // let's try again iter = s_effects.find(fullPath); if (iter == s_effects.end()) { fprintf(stderr, "could not find play sound %s\n", fullPath.c_str()); return -1; } } checkALError("playEffect:init"); soundData &d = *iter->second; d.isLooped = bLoop; d.pitch = pitch; d.pan = pan; d.gain = gain; alSourcei(d.source, AL_LOOPING, d.isLooped ? AL_TRUE : AL_FALSE); alSourcef(d.source, AL_GAIN, s_effectVolume * d.gain); alSourcef(d.source, AL_PITCH, d.pitch); float sourcePosAL[] = {d.pan, 0.0f, 0.0f};//Set position - just using left and right panning alSourcefv(d.source, AL_POSITION, sourcePosAL); alSourcePlay(d.source); checkALError("playEffect:alSourcePlay"); return d.source; }
void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { // Changing file path to full path std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); if (iter != s_effects.end()) { checkALError("unloadEffect:init"); alSourceStop(iter->second->source); checkALError("unloadEffect:alSourceStop"); alDeleteSources(1, &iter->second->source); checkALError("unloadEffect:DeletSources"); alDeleteBuffers(1, &iter->second->buffer); checkALError("unloadEffect:alDeleteBuffers"); delete iter->second; s_effects.erase(iter); } }
void System<EffectsComp>::update(double elapsed) { std::map<ObjectId,EffectsComp>::iterator iCom = components_.begin(); while(iCom!=components_.end()) { EffectsComp* effectsComp = &iCom->second; EffectsMap* effectsMap = effectsComp->getEffects(); // std::cout << "Address of effectsMap: "<< effectsMap << std::endl; // std::cout << "copy of effects map size : "<< effectsMap->size() << std::endl; // std::cout << "orig effects map size : " << effectsComp->getEffects()->size() << std::endl; //update each effect in component as necessary EffectsMap::iterator iEffect = effectsMap->begin(); while(iEffect!=effectsMap->end()) { //update timer if necessary if(iEffect->second->hasDuration()) { iEffect->second->updateDuration(elapsed); //check if timer has expired if (iEffect->second->hasExpired()) { //do on end messages std::vector<Parameters> endParams = iEffect->second->getOnEnd(); std::vector<Parameters>::iterator iParams = endParams.begin(); while(iParams!= endParams.end()) { if(iParams->size()>0) { Message msg(effectsComp->getId(), effectsComp->getId(), *iParams); Telegram tel(effectsComp->getId(), effectsComp->getId(), 0.0, msg); core_->getMessageCentre()->addTelegram(tel); } ++iParams; } //delete params effectsMap->erase(iEffect++); continue; } } //carry out onUpdate messages std::vector<Parameters> updateParams = iEffect->second->getOnUpdate(); std::vector<Parameters>::iterator iParams = updateParams.begin(); while(iParams!= updateParams.end()) { if(iParams->size()>0) { Message msg(effectsComp->getId(), effectsComp->getId(), *iParams); Telegram tel(effectsComp->getId(), effectsComp->getId(), 0.0, msg); core_->getMessageCentre()->addTelegram(tel); } ++iParams; } ++iEffect; } ++iCom; } }
namespace CocosDenshion { struct soundData { ALuint buffer; ALuint source; bool isLooped; }; typedef map<string, soundData *> EffectsMap; EffectsMap s_effects; typedef enum { PLAYING, STOPPED, PAUSED, } playStatus; static int s_audioOid; static float s_volume = 1.0f; static float s_effectVolume = 1.0f; static bool s_isBackgroundInitialized = false; static bool s_hasMMRError = false; static playStatus s_playStatus = STOPPED; static string s_currentBackgroundStr; static mmr_connection_t *s_mmrConnection = 0; static mmr_context_t *s_mmrContext = 0; static strm_dict_t *s_repeatDictionary = 0; static strm_dict_t *s_volumeDictionary = 0; static SimpleAudioEngine *s_engine = 0; static void printALError(int err) { switch (err) { case AL_NO_ERROR: fprintf(stderr, "AL_NO_ERROR"); break; case AL_INVALID_NAME: fprintf(stderr, "AL_INVALID_NAME"); break; case AL_INVALID_ENUM: fprintf(stderr, "AL_INVALID_ENUM"); break; case AL_INVALID_VALUE: fprintf(stderr, "AL_INVALID_VALUE"); break; case AL_INVALID_OPERATION: fprintf(stderr, "AL_INVALID_OPERATION"); break; case AL_OUT_OF_MEMORY: fprintf(stderr, "AL_OUT_OF_MEMORY"); break; }; } static void mmrerror(mmr_context_t *ctxt, const char *msg) { const mmr_error_info_t *err = mmr_error_info( ctxt ); unsigned errcode = (err) ? err->error_code : -1; const char *name; fprintf(stderr, "%s: error %d \n", msg, errcode); s_hasMMRError = true; } static void stopBackground(bool bReleaseData) { s_playStatus = STOPPED; if (s_mmrContext) mmr_stop(s_mmrContext); if (bReleaseData) { if (s_mmrContext) { mmr_input_detach(s_mmrContext); mmr_context_destroy(s_mmrContext); } if (s_mmrConnection) mmr_disconnect(s_mmrConnection); if (s_repeatDictionary) strm_dict_destroy(s_repeatDictionary); if (s_volumeDictionary) strm_dict_destroy(s_volumeDictionary); s_mmrContext = 0; s_mmrConnection = 0; s_repeatDictionary = 0; s_volumeDictionary = 0; s_hasMMRError = false; s_currentBackgroundStr = ""; s_isBackgroundInitialized = false; } } static void setBackgroundVolume(float volume) { if (!s_isBackgroundInitialized) { return; } char volume_str[128]; // set it up the background volume strm_dict_t *dictionary = strm_dict_new(); sprintf(volume_str, "%d", (int)(volume * 100) ); s_volumeDictionary = strm_dict_set(dictionary, "volume", volume_str); if (mmr_output_parameters(s_mmrContext, s_audioOid, s_volumeDictionary) != 0) { mmrerror(s_mmrContext, "output parameters"); return; } } SimpleAudioEngine::SimpleAudioEngine() { alutInit(0, 0); } SimpleAudioEngine::~SimpleAudioEngine() { alutExit(); } SimpleAudioEngine* SimpleAudioEngine::sharedEngine() { if (!s_engine) s_engine = new SimpleAudioEngine(); return s_engine; } void SimpleAudioEngine::end() { // clear all the sounds EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::iterator it = s_effects.begin(); it != end; it++) { alSourceStop(it->second->source); alDeleteBuffers(1, &it->second->buffer); alDeleteSources(1, &it->second->source); delete it->second; } s_effects.clear(); if (s_isBackgroundInitialized) { s_isBackgroundInitialized = false; } // and the background too stopBackground(true); } void SimpleAudioEngine::setResource(const char* pszZipFileName) { } // // background audio (using mmrenderer) // void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) { if (!s_isBackgroundInitialized) { const char *mmrname = NULL; const char *ctxtname = "mmrplayer"; char cwd[PATH_MAX]; mode_t mode = S_IRUSR | S_IXUSR; getcwd(cwd, PATH_MAX); string path = "file://"; path += cwd; path += "/"; path += pszFilePath; s_mmrConnection = mmr_connect(mmrname); if (!s_mmrConnection) { perror("mmr_connect"); s_hasMMRError = true; return; } s_mmrContext = mmr_context_create(s_mmrConnection, ctxtname, 0, mode); if (!s_mmrContext) { perror(ctxtname); s_hasMMRError = true; return; } if ((s_audioOid = mmr_output_attach(s_mmrContext, "audio:default", "audio")) < 0) { mmrerror(s_mmrContext, "audio:default"); return; } if (mmr_input_attach(s_mmrContext, path.data(), "autolist") < 0) { fprintf(stderr, "unable to load %s\n", path.data()); mmrerror(s_mmrContext, path.data()); return; } s_currentBackgroundStr = pszFilePath; s_isBackgroundInitialized = true; setBackgroundVolume(s_volume); } } void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) { if (0 != strcmp(s_currentBackgroundStr.c_str(), pszFilePath)) { stopBackgroundMusic(true); } else { if (s_playStatus == PAUSED) resumeBackgroundMusic(); else rewindBackgroundMusic(); } if (!s_isBackgroundInitialized) preloadBackgroundMusic(pszFilePath); if (bLoop) { // set it up to loop strm_dict_t *dictionary = strm_dict_new(); s_repeatDictionary = strm_dict_set(dictionary, "repeat", "all"); if (mmr_input_parameters(s_mmrContext, s_repeatDictionary) != 0) { mmrerror(s_mmrContext, "input parameters (loop)"); return; } } if (s_hasMMRError || !s_mmrContext) return; if (mmr_play(s_mmrContext) < 0) { mmrerror(s_mmrContext, "mmr_play"); s_hasMMRError = true; } if (!s_hasMMRError) s_playStatus = PLAYING; } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { // if we were paused then we need to resume first so that we can play if (s_playStatus == PAUSED) resumeBackgroundMusic(); stopBackground(bReleaseData); } void SimpleAudioEngine::pauseBackgroundMusic() { if (s_mmrContext && mmr_speed_set(s_mmrContext, 0) < 0) { mmrerror(s_mmrContext, "pause"); } s_playStatus = PAUSED; } void SimpleAudioEngine::resumeBackgroundMusic() { if (s_mmrContext && mmr_speed_set(s_mmrContext, 1000) < 0) { mmrerror(s_mmrContext, "resume"); } s_playStatus = PLAYING; } void SimpleAudioEngine::rewindBackgroundMusic() { if (s_mmrContext && mmr_seek(s_mmrContext, "1:0") < 0) { mmrerror(s_mmrContext, "rewind"); } } bool SimpleAudioEngine::willPlayBackgroundMusic() { return true; } bool SimpleAudioEngine::isBackgroundMusicPlaying() { return (s_playStatus == PLAYING) && s_isBackgroundInitialized; } float SimpleAudioEngine::getBackgroundMusicVolume() { return s_volume; } void SimpleAudioEngine::setBackgroundMusicVolume(float volume) { if (s_volume != volume && volume >= -0.0001 && volume <= 1.0001) { s_volume = volume; setBackgroundVolume(volume); } } // // Effect audio (using OpenAL) // float SimpleAudioEngine::getEffectsVolume() { return s_effectVolume; } void SimpleAudioEngine::setEffectsVolume(float volume) { if (volume != s_effectVolume) { EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::const_iterator it = s_effects.begin(); it != end; it++) { alSourcef(it->second->source, AL_GAIN, volume); } s_effectVolume = volume; } } unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop) { EffectsMap::iterator iter = s_effects.find(pszFilePath); if (iter == s_effects.end()) { preloadEffect(pszFilePath); // let's try again iter = s_effects.find(pszFilePath); if (iter == s_effects.end()) { fprintf(stderr, "could not find play sound %s\n", pszFilePath); return -1; } } iter->second->isLooped = bLoop; alSourcei(iter->second->source, AL_LOOPING, iter->second->isLooped ? AL_TRUE : AL_FALSE); alSourcePlay(iter->second->source); return iter->second->source; } void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { alSourceStop(nSoundId); } void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { EffectsMap::iterator iter = s_effects.find(pszFilePath); // check if we have this already if (iter == s_effects.end()) { ALuint buffer; ALuint source; soundData *data = new soundData; string path = pszFilePath; buffer = alutCreateBufferFromFile(path.data()); if (buffer == AL_NONE) { fprintf(stderr, "Error loading file: '%s'\n", path.data()); alDeleteBuffers(1, &buffer); return; } alGenSources(1, &source); alSourcei(source, AL_BUFFER, buffer); data->isLooped = false; data->buffer = buffer; data->source = source; s_effects.insert(EffectsMap::value_type(pszFilePath, data)); } } void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { EffectsMap::iterator iter = s_effects.find(pszFilePath); if (iter != s_effects.end()) { alSourceStop(iter->second->source); alDeleteSources(1, &iter->second->source); alDeleteBuffers(1, &iter->second->buffer); delete iter->second; int err = alGetError(); if (err != AL_NO_ERROR) printALError(err); s_effects.erase(iter); } } void SimpleAudioEngine::pauseEffect(unsigned int nSoundId) { alSourcePause(nSoundId); } void SimpleAudioEngine::pauseAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { alSourcePause(iter->second->source); int err = alGetError(); if (err != AL_NO_ERROR) printALError(err); } } void SimpleAudioEngine::resumeEffect(unsigned int nSoundId) { alSourcePlay(nSoundId); } void SimpleAudioEngine::resumeAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { alSourcePlay(iter->second->source); int err = alGetError(); if (err != AL_NO_ERROR) printALError(err); } } void SimpleAudioEngine::stopAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { alSourceStop(iter->second->source); int err = alGetError(); if (err != AL_NO_ERROR) printALError(err); } } }
namespace CocosDenshion { struct soundData { ALuint buffer; ALuint source; bool isLooped; }; typedef map<string, soundData *> EffectsMap; EffectsMap s_effects; typedef enum { PLAYING, STOPPED, PAUSED, } playStatus; static float s_volume = 1.0f; static float s_effectVolume = 1.0f; static bool s_isBackgroundInitialized = false; static std::string s_currentBackgroundStr; ALuint s_backgroundBuffer; ALuint s_backgroundSource; static SimpleAudioEngine *s_engine = 0; static int checkALError(const char *funcName) { int err = alGetError(); if (err != AL_NO_ERROR) { switch (err) { case AL_INVALID_NAME: fprintf(stderr, "AL_INVALID_NAME in %s\n", funcName); break; case AL_INVALID_ENUM: fprintf(stderr, "AL_INVALID_ENUM in %s\n", funcName); break; case AL_INVALID_VALUE: fprintf(stderr, "AL_INVALID_VALUE in %s\n", funcName); break; case AL_INVALID_OPERATION: fprintf(stderr, "AL_INVALID_OPERATION in %s\n", funcName); break; case AL_OUT_OF_MEMORY: fprintf(stderr, "AL_OUT_OF_MEMORY in %s\n", funcName); break; } } return err; } static void stopBackground(bool bReleaseData) { alSourceStop(s_backgroundSource); if (bReleaseData) { s_currentBackgroundStr = ""; s_isBackgroundInitialized = false; alDeleteBuffers(1, &s_backgroundBuffer); checkALError("stopBackground"); alDeleteSources(1, &s_backgroundSource); checkALError("stopBackground"); } } static void setBackgroundVolume(float volume) { alSourcef(s_backgroundSource, AL_GAIN, volume); } SimpleAudioEngine::SimpleAudioEngine() { alutInit(0, 0); } SimpleAudioEngine::~SimpleAudioEngine() { alutExit(); } SimpleAudioEngine* SimpleAudioEngine::sharedEngine() { if (!s_engine) s_engine = new SimpleAudioEngine(); return s_engine; } void SimpleAudioEngine::end() { checkALError("end"); // clear all the sounds EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::iterator it = s_effects.begin(); it != end; it++) { alSourceStop(it->second->source); checkALError("end"); alDeleteBuffers(1, &it->second->buffer); checkALError("end"); alDeleteSources(1, &it->second->source); checkALError("end"); delete it->second; } s_effects.clear(); // and the background too stopBackground(true); } void SimpleAudioEngine::setResource(const char* pszZipFileName) { } // // OGG support // static bool isOGGFile(const char *pszFilePath) { FILE *file; OggVorbis_File ogg_file; int result; file = fopen(pszFilePath, "rb"); result = ov_test(file, &ogg_file, 0, 0); ov_clear(&ogg_file); return (result == 0); } static ALuint createBufferFromOGG(const char *pszFilePath) { ALuint buffer; OggVorbis_File ogg_file; vorbis_info* info; ALenum format; int result; int section; int err; unsigned int size = 0; if (ov_fopen(pszFilePath, &ogg_file) < 0) { ov_clear(&ogg_file); fprintf(stderr, "Could not open OGG file %s\n", pszFilePath); return -1; } info = ov_info(&ogg_file, -1); if (info->channels == 1) format = AL_FORMAT_MONO16; else format = AL_FORMAT_STEREO16; // size = #samples * #channels * 2 (for 16 bit) unsigned int data_size = ov_pcm_total(&ogg_file, -1) * info->channels * 2; char* data = new char[data_size]; while (size < data_size) { result = ov_read(&ogg_file, data + size, data_size - size, 0, 2, 1, §ion); if (result > 0) { size += result; } else if (result < 0) { delete [] data; fprintf(stderr, "OGG file problem %s\n", pszFilePath); return -1; } else { break; } } if (size == 0) { delete [] data; fprintf(stderr, "Unable to read OGG data\n"); return -1; } // clear al errors checkALError("createBufferFromOGG"); // Load audio data into a buffer. alGenBuffers(1, &buffer); if (checkALError("createBufferFromOGG") != AL_NO_ERROR) { fprintf(stderr, "Couldn't generate a buffer for OGG file\n"); delete [] data; return buffer; } alBufferData(buffer, format, data, data_size, info->rate); checkALError("createBufferFromOGG"); delete [] data; ov_clear(&ogg_file); return buffer; } // // background audio // void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) { if (!s_isBackgroundInitialized || s_currentBackgroundStr != pszFilePath) { string path = pszFilePath; if (isOGGFile(path.data())) { s_backgroundBuffer = createBufferFromOGG(path.data()); } else { s_backgroundBuffer = alutCreateBufferFromFile(path.data()); } checkALError("preloadBackgroundMusic"); if (s_backgroundBuffer == AL_NONE) { fprintf(stderr, "Error loading file: '%s'\n", path.data()); alDeleteBuffers(1, &s_backgroundBuffer); return; } alGenSources(1, &s_backgroundSource); checkALError("preloadBackgroundMusic"); alSourcei(s_backgroundSource, AL_BUFFER, s_backgroundBuffer); checkALError("preloadBackgroundMusic"); s_currentBackgroundStr = pszFilePath; } s_currentBackgroundStr = pszFilePath; s_isBackgroundInitialized = true; } void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) { if (!s_isBackgroundInitialized) preloadBackgroundMusic(pszFilePath); alSourcei(s_backgroundSource, AL_LOOPING, bLoop ? AL_TRUE : AL_FALSE); alSourcePlay(s_backgroundSource); checkALError("playBackgroundMusic"); } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { stopBackground(bReleaseData); } void SimpleAudioEngine::pauseBackgroundMusic() { alSourcePause(s_backgroundSource); checkALError("pauseBackgroundMusic"); } void SimpleAudioEngine::resumeBackgroundMusic() { alSourcePlay(s_backgroundSource); checkALError("resumeBackgroundMusic"); } void SimpleAudioEngine::rewindBackgroundMusic() { alSourceRewind(s_backgroundSource); checkALError("rewindBackgroundMusic"); } bool SimpleAudioEngine::willPlayBackgroundMusic() { return true; } bool SimpleAudioEngine::isBackgroundMusicPlaying() { ALint play_status; alGetSourcei(s_backgroundSource, AL_SOURCE_STATE, &play_status); return (play_status == AL_PLAYING); } float SimpleAudioEngine::getBackgroundMusicVolume() { return s_volume; } void SimpleAudioEngine::setBackgroundMusicVolume(float volume) { if (s_volume != volume && volume >= -0.0001 && volume <= 1.0001) { s_volume = volume; setBackgroundVolume(volume); } } // // Effect audio (using OpenAL) // float SimpleAudioEngine::getEffectsVolume() { return s_effectVolume; } void SimpleAudioEngine::setEffectsVolume(float volume) { if (volume != s_effectVolume) { EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::const_iterator it = s_effects.begin(); it != end; it++) { alSourcef(it->second->source, AL_GAIN, volume); } s_effectVolume = volume; } } unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop) { EffectsMap::iterator iter = s_effects.find(pszFilePath); if (iter == s_effects.end()) { preloadEffect(pszFilePath); // let's try again iter = s_effects.find(pszFilePath); if (iter == s_effects.end()) { fprintf(stderr, "could not find play sound %s\n", pszFilePath); return -1; } } checkALError("playEffect"); iter->second->isLooped = bLoop; alSourcei(iter->second->source, AL_LOOPING, iter->second->isLooped ? AL_TRUE : AL_FALSE); alSourcePlay(iter->second->source); checkALError("playEffect"); return iter->second->source; } void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { alSourceStop(nSoundId); checkALError("stopEffect"); } void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { EffectsMap::iterator iter = s_effects.find(pszFilePath); // check if we have this already if (iter == s_effects.end()) { ALuint buffer; ALuint source; soundData *data = new soundData; string path = pszFilePath; checkALError("preloadEffect"); if (isOGGFile(path.data())) { buffer = createBufferFromOGG(path.data()); } else { buffer = alutCreateBufferFromFile(path.data()); checkALError("preloadEffect"); } if (buffer == AL_NONE) { fprintf(stderr, "Error loading file: '%s'\n", path.data()); alDeleteBuffers(1, &buffer); return; } alGenSources(1, &source); if (checkALError("preloadEffect") != AL_NO_ERROR) { alDeleteBuffers(1, &buffer); return; } alSourcei(source, AL_BUFFER, buffer); checkALError("preloadEffect"); data->isLooped = false; data->buffer = buffer; data->source = source; s_effects.insert(EffectsMap::value_type(pszFilePath, data)); } } void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { EffectsMap::iterator iter = s_effects.find(pszFilePath); if (iter != s_effects.end()) { checkALError("unloadEffect"); alSourceStop(iter->second->source); checkALError("unloadEffect"); alDeleteSources(1, &iter->second->source); checkALError("unloadEffect"); alDeleteBuffers(1, &iter->second->buffer); checkALError("unloadEffect"); delete iter->second; s_effects.erase(iter); } } void SimpleAudioEngine::pauseEffect(unsigned int nSoundId) { alSourcePause(nSoundId); checkALError("pauseEffect"); } void SimpleAudioEngine::pauseAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { alSourcePause(iter->second->source); checkALError("pauseAllEffects"); } } void SimpleAudioEngine::resumeEffect(unsigned int nSoundId) { alSourcePlay(nSoundId); checkALError("resumeEffect"); } void SimpleAudioEngine::resumeAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { checkALError("resumeAllEffects"); alSourcePlay(iter->second->source); checkALError("resumeAllEffects"); } } void SimpleAudioEngine::stopAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { checkALError("stopAllEffects"); alSourceStop(iter->second->source); checkALError("stopAllEffects"); } } }
namespace CocosDenshion { struct soundData { ALuint buffer; ALuint source; bool isLooped; float pitch; float pan; float gain; }; typedef map<string, soundData *> EffectsMap; EffectsMap s_effects; typedef enum { PLAYING, STOPPED, PAUSED, } playStatus; static float s_volume = 1.0f; static float s_effectVolume = 1.0f; struct backgroundMusicData { ALuint buffer; ALuint source; }; typedef map<string, backgroundMusicData *> BackgroundMusicsMap; BackgroundMusicsMap s_backgroundMusics; static ALuint s_backgroundSource = AL_NONE; static SimpleAudioEngine *s_engine = nullptr; static int checkALError(const char *funcName) { int err = alGetError(); if (err != AL_NO_ERROR) { switch (err) { case AL_INVALID_NAME: fprintf(stderr, "AL_INVALID_NAME in %s\n", funcName); break; case AL_INVALID_ENUM: fprintf(stderr, "AL_INVALID_ENUM in %s\n", funcName); break; case AL_INVALID_VALUE: fprintf(stderr, "AL_INVALID_VALUE in %s\n", funcName); break; case AL_INVALID_OPERATION: fprintf(stderr, "AL_INVALID_OPERATION in %s\n", funcName); break; case AL_OUT_OF_MEMORY: fprintf(stderr, "AL_OUT_OF_MEMORY in %s\n", funcName); break; } } return err; } static void stopBackground(bool bReleaseData) { // The background music might have been already stopped // Stop request can come from // - stopBackgroundMusic(..) // - end(..) if (s_backgroundSource != AL_NONE) alSourceStop(s_backgroundSource); if (bReleaseData) { for (auto it = s_backgroundMusics.begin(); it != s_backgroundMusics.end(); ++it) { if (it->second->source == s_backgroundSource) { alDeleteSources(1, &it->second->source); checkALError("stopBackground:alDeleteSources"); alDeleteBuffers(1, &it->second->buffer); checkALError("stopBackground:alDeleteBuffers"); delete it->second; s_backgroundMusics.erase(it); break; } } } s_backgroundSource = AL_NONE; } static void setBackgroundVolume(float volume) { alSourcef(s_backgroundSource, AL_GAIN, volume); } SimpleAudioEngine::SimpleAudioEngine() { alutInit(0, 0); #ifdef ENABLE_MPG123 mpg123_init(); #endif checkALError("SimpleAudioEngine:alutInit"); OpenALDecoder::installDecoders(); } SimpleAudioEngine::~SimpleAudioEngine() { #ifdef ENABLE_MPG123 mpg123_exit(); #endif alutExit(); } SimpleAudioEngine* SimpleAudioEngine::getInstance() { if (!s_engine) s_engine = new SimpleAudioEngine(); return s_engine; } void SimpleAudioEngine::end() { checkALError("end:init"); // clear all the sound effects EffectsMap::const_iterator end = s_effects.end(); for (auto it = s_effects.begin(); it != end; ++it) { alSourceStop(it->second->source); checkALError("end:alSourceStop"); alDeleteSources(1, &it->second->source); checkALError("end:alDeleteSources"); alDeleteBuffers(1, &it->second->buffer); checkALError("end:alDeleteBuffers"); delete it->second; } s_effects.clear(); // and the background music too stopBackground(true); for (auto it = s_backgroundMusics.begin(); it != s_backgroundMusics.end(); ++it) { alSourceStop(it->second->source); checkALError("end:alSourceStop"); alDeleteSources(1, &it->second->source); checkALError("end:alDeleteSources"); alDeleteBuffers(1, &it->second->buffer); checkALError("end:alDeleteBuffers"); delete it->second; } s_backgroundMusics.clear(); CC_SAFE_DELETE(s_engine); } // // background audio // void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) { // Changing file path to full path std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pszFilePath); BackgroundMusicsMap::const_iterator it = s_backgroundMusics.find(fullPath); if (it == s_backgroundMusics.end()) { ALuint buffer = AL_NONE; bool success = false; OpenALFile file; file.debugName = pszFilePath; file.file = fopen(fullPath.c_str(), "rb"); if (!file.file) { fprintf(stderr, "Cannot read file: '%s'\n", fullPath.data()); return; } const std::vector<OpenALDecoder *> &decoders = OpenALDecoder::getDecoders(); for (size_t i = 0, n = decoders.size(); !success && i < n; ++i) success = decoders[i]->decode(file, buffer); file.clear(); ALuint source = AL_NONE; alGenSources(1, &source); checkALError("preloadBackgroundMusic:alGenSources"); alSourcei(source, AL_BUFFER, buffer); checkALError("preloadBackgroundMusic:alSourcei"); backgroundMusicData* data = new backgroundMusicData(); data->buffer = buffer; data->source = source; s_backgroundMusics.insert(BackgroundMusicsMap::value_type(fullPath, data)); } } void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) { // If there is already a background music source we stop it first if (s_backgroundSource != AL_NONE) stopBackgroundMusic(false); // Changing file path to full path std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pszFilePath); BackgroundMusicsMap::const_iterator it = s_backgroundMusics.find(fullPath); if (it == s_backgroundMusics.end()) { preloadBackgroundMusic(fullPath.c_str()); it = s_backgroundMusics.find(fullPath); } if (it != s_backgroundMusics.end()) { s_backgroundSource = it->second->source; alSourcei(s_backgroundSource, AL_LOOPING, bLoop ? AL_TRUE : AL_FALSE); setBackgroundVolume(s_volume); alSourcePlay(s_backgroundSource); checkALError("playBackgroundMusic:alSourcePlay"); } } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { // If there is no source, then there is nothing that can be stopped if (s_backgroundSource == AL_NONE) return; ALint state; alGetSourcei(s_backgroundSource, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) stopBackground(bReleaseData); } void SimpleAudioEngine::pauseBackgroundMusic() { // If there is no source, then there is nothing that can be paused if (s_backgroundSource == AL_NONE) return; ALint state; alGetSourcei(s_backgroundSource, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) alSourcePause(s_backgroundSource); checkALError("pauseBackgroundMusic:alSourcePause"); } void SimpleAudioEngine::resumeBackgroundMusic() { // If there is no source, then there is nothing that can be resumed if (s_backgroundSource == AL_NONE) return; ALint state; alGetSourcei(s_backgroundSource, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) alSourcePlay(s_backgroundSource); checkALError("resumeBackgroundMusic:alSourcePlay"); } void SimpleAudioEngine::rewindBackgroundMusic() { // If there is no source, then there is nothing that can be rewinded if (s_backgroundSource == AL_NONE) return; // Rewind and prevent the last state the source had ALint state; alGetSourcei(s_backgroundSource, AL_SOURCE_STATE, &state); alSourceRewind(s_backgroundSource); if (state == AL_PLAYING) { alSourcePlay(s_backgroundSource); } else if (state == AL_PAUSED) { alSourcePlay(s_backgroundSource); alSourcePause(s_backgroundSource); } checkALError("rewindBackgroundMusic:alSourceRewind"); } bool SimpleAudioEngine::willPlayBackgroundMusic() { // We are able to play background music // if we have a valid background source if (s_backgroundSource == AL_NONE) return false; return (alIsSource(s_backgroundSource) == AL_TRUE ? true : false); } bool SimpleAudioEngine::isBackgroundMusicPlaying() { // If there is no source, then there is nothing that is playing if (s_backgroundSource == AL_NONE) return false; ALint play_status; alGetSourcei(s_backgroundSource, AL_SOURCE_STATE, &play_status); checkALError("isBackgroundMusicPlaying:alGetSourcei"); return (play_status == AL_PLAYING); } float SimpleAudioEngine::getBackgroundMusicVolume() { return s_volume; } void SimpleAudioEngine::setBackgroundMusicVolume(float volume) { if (s_volume != volume && volume >= -0.0001 && volume <= 1.0001) { s_volume = volume; // No source, no background music, no volume adjustment if (s_backgroundSource != AL_NONE) { setBackgroundVolume(volume); } } } // // Effect audio (using OpenAL) // float SimpleAudioEngine::getEffectsVolume() { return s_effectVolume; } void SimpleAudioEngine::setEffectsVolume(float volume) { if (volume != s_effectVolume) { EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::const_iterator it = s_effects.begin(); it != end; it++) { alSourcef(it->second->source, AL_GAIN, volume * it->second->gain); } s_effectVolume = volume; } } unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop, float pitch, float pan, float gain) { std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); if (iter == s_effects.end()) { preloadEffect(fullPath.c_str()); // let's try again iter = s_effects.find(fullPath); if (iter == s_effects.end()) { fprintf(stderr, "could not find play sound %s\n", fullPath.c_str()); return -1; } } checkALError("playEffect:init"); soundData &d = *iter->second; d.isLooped = bLoop; d.pitch = pitch; d.pan = pan; d.gain = gain; alSourcei(d.source, AL_LOOPING, d.isLooped ? AL_TRUE : AL_FALSE); alSourcef(d.source, AL_GAIN, s_effectVolume * d.gain); alSourcef(d.source, AL_PITCH, d.pitch); float sourcePosAL[] = {d.pan, 0.0f, 0.0f};//Set position - just using left and right panning alSourcefv(d.source, AL_POSITION, sourcePosAL); alSourcePlay(d.source); checkALError("playEffect:alSourcePlay"); return d.source; } void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { alSourceStop(nSoundId); checkALError("stopEffect:alSourceStop"); } void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { // Changing file path to full path std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); // check if we have this already if (iter == s_effects.end()) { ALuint buffer = AL_NONE; ALuint source = AL_NONE; checkALError("preloadEffect:init"); OpenALFile file; file.debugName = pszFilePath; file.file = fopen(fullPath.c_str(), "rb"); if (!file.file) { fprintf(stderr, "Cannot read file: '%s'\n", fullPath.data()); return; } bool success = false; const std::vector<OpenALDecoder *> &decoders = OpenALDecoder::getDecoders(); for (size_t i = 0, n = decoders.size(); !success && i < n; ++i) success = decoders[i]->decode(file, buffer); file.clear(); alGenSources(1, &source); if (checkALError("preloadEffect:alGenSources") != AL_NO_ERROR) { alDeleteBuffers(1, &buffer); return; } alSourcei(source, AL_BUFFER, buffer); checkALError("preloadEffect:alSourcei"); soundData *data = new soundData; data->isLooped = false; data->buffer = buffer; data->source = source; data->pitch = 1.0; data->pan = 0.0; data->gain = 1.0; s_effects.insert(EffectsMap::value_type(fullPath, data)); } } void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { // Changing file path to full path std::string fullPath = FileUtils::getInstance()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); if (iter != s_effects.end()) { checkALError("unloadEffect:init"); alSourceStop(iter->second->source); checkALError("unloadEffect:alSourceStop"); alDeleteSources(1, &iter->second->source); checkALError("unloadEffect:DeletSources"); alDeleteBuffers(1, &iter->second->buffer); checkALError("unloadEffect:alDeleteBuffers"); delete iter->second; s_effects.erase(iter); } } void SimpleAudioEngine::pauseEffect(unsigned int nSoundId) { ALint state; alGetSourcei(nSoundId, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) alSourcePause(nSoundId); checkALError("pauseEffect:alSourcePause"); } void SimpleAudioEngine::pauseAllEffects() { EffectsMap::iterator iter = s_effects.begin(); ALint state; while (iter != s_effects.end()) { alGetSourcei(iter->second->source, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) alSourcePause(iter->second->source); checkALError("pauseAllEffects:alSourcePause"); ++iter; } } void SimpleAudioEngine::resumeEffect(unsigned int nSoundId) { ALint state; alGetSourcei(nSoundId, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) alSourcePlay(nSoundId); checkALError("resumeEffect:alSourcePlay"); } void SimpleAudioEngine::resumeAllEffects() { EffectsMap::iterator iter = s_effects.begin(); ALint state; while (iter != s_effects.end()) { alGetSourcei(iter->second->source, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) alSourcePlay(iter->second->source); checkALError("resumeAllEffects:alSourcePlay"); ++iter; } } void SimpleAudioEngine::stopAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { checkALError("stopAllEffects:init"); alSourceStop(iter->second->source); checkALError("stopAllEffects:alSourceStop"); } } } // namespace CocosDenshion {
namespace CocosDenshion { struct soundData { Mix_Chunk *chunk; bool isLooped; }; typedef map<string, soundData *> EffectsMap; EffectsMap s_effects; float s_effectsVolume = 1.0; typedef enum { PLAYING, STOPPED, PAUSED, } playStatus; struct backgroundMusicData { Mix_Music *music; }; typedef map<string, backgroundMusicData *> BackgroundMusicsMap; BackgroundMusicsMap s_backgroundMusics; float s_backgroundVolume = 1.0; static SimpleAudioEngine *s_engine = 0; // Unfortunately this is just hard-coded in Emscripten's SDL // implementation. static const int NR_CHANNELS = 32; static void stopBackground(bool bReleaseData) { SimpleAudioEngine *engine = SimpleAudioEngine::getInstance(); engine->stopBackgroundMusic(); } SimpleAudioEngine::SimpleAudioEngine() { } SimpleAudioEngine::~SimpleAudioEngine() { } SimpleAudioEngine* SimpleAudioEngine::getInstance() { if (!s_engine) s_engine = new SimpleAudioEngine(); return s_engine; } void SimpleAudioEngine::end() { // clear all the sounds EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::iterator it = s_effects.begin(); it != end; it++) { Mix_FreeChunk(it->second->chunk); delete it->second; } s_effects.clear(); // and the background too stopBackground(true); for (BackgroundMusicsMap::iterator it = s_backgroundMusics.begin(); it != s_backgroundMusics.end(); ++it) { Mix_FreeMusic(it->second->music); delete it->second; } s_backgroundMusics.clear(); } // // background audio // void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) { } void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) { std::string key = std::string(pszFilePath); struct backgroundMusicData *musicData; if(!s_backgroundMusics.count(key)) { musicData = new struct backgroundMusicData(); musicData->music = Mix_LoadMUS(pszFilePath); s_backgroundMusics[key] = musicData; } else { musicData = s_backgroundMusics[key]; } Mix_PlayMusic(musicData->music, bLoop ? -1 : 0); } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { Mix_HaltMusic(); } void SimpleAudioEngine::pauseBackgroundMusic() { Mix_PauseMusic(); } void SimpleAudioEngine::resumeBackgroundMusic() { Mix_ResumeMusic(); } void SimpleAudioEngine::rewindBackgroundMusic() { CCLOGWARN("Cannot rewind background in Emscripten"); } bool SimpleAudioEngine::willPlayBackgroundMusic() { return true; } bool SimpleAudioEngine::isBackgroundMusicPlaying() { return Mix_PlayingMusic(); } float SimpleAudioEngine::getBackgroundMusicVolume() { return s_backgroundVolume; } void SimpleAudioEngine::setBackgroundMusicVolume(float volume) { // Ensure volume is between 0.0 and 1.0. volume = volume > 1.0 ? 1.0 : volume; volume = volume < 0.0 ? 0.0 : volume; Mix_VolumeMusic(volume * MIX_MAX_VOLUME); s_backgroundVolume = volume; } float SimpleAudioEngine::getEffectsVolume() { return s_effectsVolume; } void SimpleAudioEngine::setEffectsVolume(float volume) { volume = volume > 1.0 ? 1.0 : volume; volume = volume < 0.0 ? 0.0 : volume; // Need to set volume on every channel. SDL will then read this volume // level and apply it back to the individual sample. for(int i = 0; i < NR_CHANNELS; i++) { Mix_Volume(i, volume * MIX_MAX_VOLUME); } s_effectsVolume = volume; } unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop, float pitch, float pan, float gain) { std::string key = std::string(pszFilePath); struct soundData *sound; if(!s_effects.count(key)) { sound = new struct soundData(); sound->chunk = Mix_LoadWAV(pszFilePath); sound->isLooped = bLoop; s_effects[key] = sound; } else { sound = s_effects[key]; } // This is safe here since Emscripten is just passing back an // incrementing integer each time you use the Mix_LoadWAV method. unsigned int result = (unsigned int) sound->chunk; // XXX: This is a bit of a hack, but... Choose a channel based on the // modulo of the # of channels. This allows us to set the volume // without passing around both chunk address and channel. Mix_PlayChannel(result % NR_CHANNELS, sound->chunk, bLoop ? -1 : 0); return result; } void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { Mix_HaltChannel(nSoundId % NR_CHANNELS); } void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { } void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { std::string key = std::string(pszFilePath); if(!s_effects.count(key)) { return; } struct soundData *sound = s_effects[key]; Mix_FreeChunk(sound->chunk); delete sound; s_effects.erase(key); } void SimpleAudioEngine::pauseEffect(unsigned int nSoundId) { Mix_Pause(nSoundId % NR_CHANNELS); } void SimpleAudioEngine::pauseAllEffects() { for(int i = 0; i < NR_CHANNELS; i++) { Mix_Pause(i); } } void SimpleAudioEngine::resumeEffect(unsigned int nSoundId) { Mix_Resume(nSoundId % NR_CHANNELS); } void SimpleAudioEngine::resumeAllEffects() { for(int i = 0; i < NR_CHANNELS; i++) { Mix_Resume(i); } } void SimpleAudioEngine::stopAllEffects() { for(int i = 0; i < NR_CHANNELS; i++) { Mix_HaltChannel(i); } } }
namespace CocosDenshion { struct soundData { ALuint buffer; ALuint source; bool isLooped; }; typedef map<string, soundData *> EffectsMap; EffectsMap s_effects; typedef enum { PLAYING, STOPPED, PAUSED, } playStatus; static float s_volume = 1.0f; static float s_effectVolume = 1.0f; struct backgroundMusicData { ALuint buffer; ALuint source; }; typedef map<string, backgroundMusicData *> BackgroundMusicsMap; BackgroundMusicsMap s_backgroundMusics; static ALuint s_backgroundSource = AL_NONE; static SimpleAudioEngine *s_engine = 0; static int checkALError(const char *funcName) { int err = alGetError(); if (err != AL_NO_ERROR) { switch (err) { case AL_INVALID_NAME: fprintf(stderr, "AL_INVALID_NAME in %s\n", funcName); break; case AL_INVALID_ENUM: fprintf(stderr, "AL_INVALID_ENUM in %s\n", funcName); break; case AL_INVALID_VALUE: fprintf(stderr, "AL_INVALID_VALUE in %s\n", funcName); break; case AL_INVALID_OPERATION: fprintf(stderr, "AL_INVALID_OPERATION in %s\n", funcName); break; case AL_OUT_OF_MEMORY: fprintf(stderr, "AL_OUT_OF_MEMORY in %s\n", funcName); break; } } return err; } static void stopBackground(bool bReleaseData) { s_backgroundSource = AL_NONE; } static void setBackgroundVolume(float volume) { } SimpleAudioEngine::SimpleAudioEngine() { } SimpleAudioEngine::~SimpleAudioEngine() { } SimpleAudioEngine* SimpleAudioEngine::sharedEngine() { if (!s_engine) s_engine = new SimpleAudioEngine(); return s_engine; } void SimpleAudioEngine::end() { checkALError("end"); // clear all the sounds EffectsMap::const_iterator end = s_effects.end(); for (EffectsMap::iterator it = s_effects.begin(); it != end; it++) { alSourceStop(it->second->source); checkALError("end"); alDeleteBuffers(1, &it->second->buffer); checkALError("end"); alDeleteSources(1, &it->second->source); checkALError("end"); delete it->second; } s_effects.clear(); // and the background too stopBackground(true); for (BackgroundMusicsMap::iterator it = s_backgroundMusics.begin(); it != s_backgroundMusics.end(); ++it) { alSourceStop(it->second->source); checkALError("end"); alDeleteBuffers(1, &it->second->buffer); checkALError("end"); alDeleteSources(1, &it->second->source); checkALError("end"); delete it->second; } s_backgroundMusics.clear(); } // // OGG support // static bool isOGGFile(const char *pszFilePath) { return true; } static ALuint createBufferFromOGG(const char *pszFilePath) { } // // background audio // void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) { } void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath, bool bLoop) { } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { } void SimpleAudioEngine::pauseBackgroundMusic() { } void SimpleAudioEngine::resumeBackgroundMusic() { } void SimpleAudioEngine::rewindBackgroundMusic() { } bool SimpleAudioEngine::willPlayBackgroundMusic() { return false; } bool SimpleAudioEngine::isBackgroundMusicPlaying() { return false; } float SimpleAudioEngine::getBackgroundMusicVolume() { return s_volume; } void SimpleAudioEngine::setBackgroundMusicVolume(float volume) { } // // Effect audio (using OpenAL) // float SimpleAudioEngine::getEffectsVolume() { return s_effectVolume; } void SimpleAudioEngine::setEffectsVolume(float volume) { } unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop) { // Changing file path to full path std::string fullPath = CCFileUtils::sharedFileUtils()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); if (iter == s_effects.end()) { preloadEffect(fullPath.c_str()); // let's try again iter = s_effects.find(fullPath); if (iter == s_effects.end()) { fprintf(stderr, "could not find play sound %s\n", fullPath.c_str()); return -1; } } checkALError("playEffect"); iter->second->isLooped = bLoop; alSourcei(iter->second->source, AL_LOOPING, iter->second->isLooped ? AL_TRUE : AL_FALSE); alSourcePlay(iter->second->source); checkALError("playEffect"); return iter->second->source; } void SimpleAudioEngine::stopEffect(unsigned int nSoundId) { alSourceStop(nSoundId); checkALError("stopEffect"); } void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { } void SimpleAudioEngine::unloadEffect(const char* pszFilePath) { // Changing file path to full path std::string fullPath = CCFileUtils::sharedFileUtils()->fullPathForFilename(pszFilePath); EffectsMap::iterator iter = s_effects.find(fullPath); if (iter != s_effects.end()) { checkALError("unloadEffect"); alSourceStop(iter->second->source); checkALError("unloadEffect"); alDeleteSources(1, &iter->second->source); checkALError("unloadEffect"); alDeleteBuffers(1, &iter->second->buffer); checkALError("unloadEffect"); delete iter->second; s_effects.erase(iter); } } void SimpleAudioEngine::pauseEffect(unsigned int nSoundId) { ALint state; alGetSourcei(nSoundId, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) alSourcePause(nSoundId); checkALError("pauseEffect"); } void SimpleAudioEngine::pauseAllEffects() { EffectsMap::iterator iter = s_effects.begin(); ALint state; while (iter != s_effects.end()) { alGetSourcei(iter->second->source, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) alSourcePause(iter->second->source); checkALError("pauseAllEffects"); ++iter; } } void SimpleAudioEngine::resumeEffect(unsigned int nSoundId) { ALint state; alGetSourcei(nSoundId, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) alSourcePlay(nSoundId); checkALError("resumeEffect"); } void SimpleAudioEngine::resumeAllEffects() { EffectsMap::iterator iter = s_effects.begin(); ALint state; while (iter != s_effects.end()) { alGetSourcei(iter->second->source, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) alSourcePlay(iter->second->source); checkALError("resumeAllEffects"); ++iter; } } void SimpleAudioEngine::stopAllEffects() { EffectsMap::iterator iter = s_effects.begin(); if (iter != s_effects.end()) { checkALError("stopAllEffects"); alSourceStop(iter->second->source); checkALError("stopAllEffects"); } } }