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; }
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::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::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::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) { // Changing file path to full path std::string fullPath = CCFileUtils::sharedFileUtils()->fullPathForFilename(pszFilePath); BackgroundMusicsMap::const_iterator it = s_backgroundMusics.find(fullPath); if (it == s_backgroundMusics.end()) { ALuint buffer = AL_NONE; if (isOGGFile(fullPath.data())) { buffer = createBufferFromOGG(fullPath.data()); } else { buffer = alutCreateBufferFromFile(fullPath.data()); } checkALError("preloadBackgroundMusic"); if (buffer == AL_NONE) { fprintf(stderr, "Error loading file: '%s'\n", fullPath.data()); alDeleteBuffers(1, &buffer); return; } ALuint source = AL_NONE; alGenSources(1, &source); checkALError("preloadBackgroundMusic"); alSourcei(source, AL_BUFFER, buffer); checkALError("preloadBackgroundMusic"); 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 (s_backgroundSource != AL_NONE) stopBackgroundMusic(false); // Changing file path to full path std::string fullPath = CCFileUtils::sharedFileUtils()->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); alSourcePlay(s_backgroundSource); checkALError("playBackgroundMusic"); } }
static void stopBackground(bool bReleaseData) { alSourceStop(s_backgroundSource); if (bReleaseData) { for (BackgroundMusicsMap::iterator it = s_backgroundMusics.begin(); it != s_backgroundMusics.end(); ++it) { if (it->second->source == s_backgroundSource) { alDeleteBuffers(1, &it->second->buffer); checkALError("stopBackground"); alDeleteSources(1, &it->second->source); checkALError("stopBackground"); delete it->second; s_backgroundMusics.erase(it); break; } } } s_backgroundSource = AL_NONE; }
// // 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) { 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); }
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"); } } }
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) { alSourceStop(s_backgroundSource); if (bReleaseData) { for (BackgroundMusicsMap::iterator it = s_backgroundMusics.begin(); it != s_backgroundMusics.end(); ++it) { if (it->second->source == s_backgroundSource) { alDeleteBuffers(1, &it->second->buffer); checkALError("stopBackground"); alDeleteSources(1, &it->second->source); checkALError("stopBackground"); 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); } 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); 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) { 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; 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) { // Changing file path to full path std::string fullPath = CCFileUtils::sharedFileUtils()->fullPathForFilename(pszFilePath); BackgroundMusicsMap::const_iterator it = s_backgroundMusics.find(fullPath); if (it == s_backgroundMusics.end()) { ALuint buffer = AL_NONE; if (isOGGFile(fullPath.data())) { buffer = createBufferFromOGG(fullPath.data()); } else { buffer = alutCreateBufferFromFile(fullPath.data()); } checkALError("preloadBackgroundMusic"); if (buffer == AL_NONE) { fprintf(stderr, "Error loading file: '%s'\n", fullPath.data()); alDeleteBuffers(1, &buffer); return; } ALuint source = AL_NONE; alGenSources(1, &source); checkALError("preloadBackgroundMusic"); alSourcei(source, AL_BUFFER, buffer); checkALError("preloadBackgroundMusic"); 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 (s_backgroundSource != AL_NONE) stopBackgroundMusic(false); // Changing file path to full path std::string fullPath = CCFileUtils::sharedFileUtils()->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); alSourcePlay(s_backgroundSource); checkALError("playBackgroundMusic"); } } void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData) { stopBackground(bReleaseData); } void SimpleAudioEngine::pauseBackgroundMusic() { ALint state; alGetSourcei(s_backgroundSource, AL_SOURCE_STATE, &state); if (state == AL_PLAYING) alSourcePause(s_backgroundSource); checkALError("pauseBackgroundMusic"); } void SimpleAudioEngine::resumeBackgroundMusic() { ALint state; alGetSourcei(s_backgroundSource, AL_SOURCE_STATE, &state); if (state == AL_PAUSED) 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) { // 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) { // 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::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"); } } }