From 25dea73abc00d298a16393161369e55c58292544 Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Sat, 27 Mar 2010 18:35:47 +0000 Subject: [PATCH] Added some debug tracing abilities for sound related issues. Added a little protected to the open_al sound wrapper to avoid having queued sound buffers not being cleaned up properly in some cases. (Need to test on Windows now) --- source/glest_game/main/intro.cpp | 160 ++++++ source/glest_game/main/main.cpp | 11 +- source/glest_game/sound/sound_renderer.cpp | 37 +- .../sound/openal/sound_player_openal.h | 126 ++++ .../sound/openal/sound_player_openal.cpp | 537 ++++++++++++++++++ .../sources/sound/sound_interface.cpp | 40 ++ 6 files changed, 903 insertions(+), 8 deletions(-) create mode 100644 source/glest_game/main/intro.cpp create mode 100644 source/shared_lib/include/sound/openal/sound_player_openal.h create mode 100644 source/shared_lib/sources/sound/openal/sound_player_openal.cpp create mode 100644 source/shared_lib/sources/sound/sound_interface.cpp diff --git a/source/glest_game/main/intro.cpp b/source/glest_game/main/intro.cpp new file mode 100644 index 00000000..a54cd4b9 --- /dev/null +++ b/source/glest_game/main/intro.cpp @@ -0,0 +1,160 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Martiņo Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== +#include "intro.h" + +#include "main_menu.h" +#include "util.h" +#include "game_util.h" +#include "config.h" +#include "program.h" +#include "renderer.h" +#include "sound_renderer.h" +#include "core_data.h" +#include "metrics.h" +#include "auto_test.h" +#include "util.h" +#include "leak_dumper.h" + +using namespace Shared::Util; +using namespace Shared::Graphics; + +namespace Glest{ namespace Game{ + +// ===================================================== +// class Text +// ===================================================== + +Text::Text(const string &text, const Vec2i &pos, int time, const Font2D *font){ + this->text= text; + this->pos= pos; + this->time= time; + this->texture= NULL; + this->font= font; +} + +Text::Text(const Texture2D *texture, const Vec2i &pos, const Vec2i &size, int time){ + this->pos= pos; + this->size= size; + this->time= time; + this->texture= texture; + this->font= NULL; +} + +// ===================================================== +// class Intro +// ===================================================== + +const int Intro::introTime= 24000; +const int Intro::appearTime= 2500; +const int Intro::showTime= 2500; +const int Intro::disapearTime= 2500; + +Intro::Intro(Program *program): + ProgramState(program) +{ + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + CoreData &coreData= CoreData::getInstance(); + const Metrics &metrics= Metrics::getInstance(); + int w= metrics.getVirtualW(); + int h= metrics.getVirtualH(); + timer=0; + + texts.push_back(Text(coreData.getLogoTexture(), Vec2i(w/2-128, h/2-64), Vec2i(256, 128), 4000)); + texts.push_back(Text(glestVersionString, Vec2i(w/2+64, h/2-32), 4000, coreData.getMenuFontNormal())); + texts.push_back(Text("www.glest.org", Vec2i(w/2, h/2), 12000, coreData.getMenuFontVeryBig())); + SoundRenderer &soundRenderer= SoundRenderer::getInstance(); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + soundRenderer.playMusic(CoreData::getInstance().getIntroMusic()); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +void Intro::update(){ + timer++; + if(timer>introTime*GameConstants::updateFps/1000){ + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + program->setState(new MainMenu(program)); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + } + + if(Config::getInstance().getBool("AutoTest")){ + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + AutoTest::getInstance().updateIntro(program); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + } +} + +void Intro::render(){ + Renderer &renderer= Renderer::getInstance(); + int difTime; + + renderer.reset2d(); + renderer.clearBuffers(); + for(int i=0; igetTime(); + + if(difTime>0 && difTime0 && difTime(difTime)/appearTime; + } + else if(difTime>0 && difTime(difTime-appearTime-showTime)/disapearTime; + } + if(!text->getText().empty()){ + renderer.renderText( + text->getText(), text->getFont(), alpha, + text->getPos().x, text->getPos().y, true); + } + if(text->getTexture()!=NULL){ + renderer.renderTextureQuad( + text->getPos().x, text->getPos().y, + text->getSize().x, text->getSize().y, + text->getTexture(), alpha); + } + } + } + renderer.swapBuffers(); +} + +void Intro::keyDown(char key){ + mouseUpLeft(0, 0); +} + +void Intro::mouseUpLeft(int x, int y){ + SoundRenderer &soundRenderer= SoundRenderer::getInstance(); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + soundRenderer.stopMusic(CoreData::getInstance().getIntroMusic()); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + soundRenderer.playMusic(CoreData::getInstance().getMenuMusic()); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + program->setState(new MainMenu(program)); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +}}//end namespace diff --git a/source/glest_game/main/main.cpp b/source/glest_game/main/main.cpp index 38ce0d80..01708291 100644 --- a/source/glest_game/main/main.cpp +++ b/source/glest_game/main/main.cpp @@ -22,11 +22,12 @@ #include "game_util.h" #include "platform_util.h" #include "platform_main.h" -#include "leak_dumper.h" #include "network_interface.h" - +#include "sound_renderer.h" #include "ImageReaders.h" +#include "leak_dumper.h" + using namespace std; using namespace Shared::Platform; using namespace Shared::Util; @@ -269,6 +270,8 @@ int glestMain(int argc, char** argv){ program->initNormal(mainWindow); } + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + // test //Shared::Platform::MessageBox(NULL,"Mark's test.","Test",0); //throw runtime_error("test!"); @@ -285,7 +288,11 @@ int glestMain(int argc, char** argv){ ExceptionHandler::handleRuntimeError(e.what()); } + //SoundRenderer &soundRenderer= SoundRenderer::getInstance(); + //soundRenderer.stopAllSounds(); + delete mainWindow; + //SystemFlags::Close(); return 0; diff --git a/source/glest_game/sound/sound_renderer.cpp b/source/glest_game/sound/sound_renderer.cpp index 8312aac3..7a9373a5 100644 --- a/source/glest_game/sound/sound_renderer.cpp +++ b/source/glest_game/sound/sound_renderer.cpp @@ -15,8 +15,10 @@ #include "config.h" #include "sound_interface.h" #include "factory_repository.h" +#include "util.h" #include "leak_dumper.h" +using namespace Shared::Util; using namespace Shared::Graphics; using namespace Shared::Sound; @@ -30,27 +32,50 @@ const float SoundRenderer::audibleDist= 50.f; // ===================================================== SoundRenderer::SoundRenderer(){ + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + soundPlayer = NULL; loadConfig(); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); } void SoundRenderer::init(Window *window){ + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + SoundInterface &si= SoundInterface::getInstance(); FactoryRepository &fr= FactoryRepository::getInstance(); Config &config= Config::getInstance(); - si.setFactory(fr.getSoundFactory(config.getString("FactorySound"))); - soundPlayer= si.newSoundPlayer(); + //if(soundPlayer == NULL) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + si.setFactory(fr.getSoundFactory(config.getString("FactorySound"))); - SoundPlayerParams soundPlayerParams; - soundPlayerParams.staticBufferCount= config.getInt("SoundStaticBuffers"); - soundPlayerParams.strBufferCount= config.getInt("SoundStreamingBuffers"); - soundPlayer->init(&soundPlayerParams); + stopAllSounds(); + + soundPlayer= si.newSoundPlayer(); + + SoundPlayerParams soundPlayerParams; + soundPlayerParams.staticBufferCount= config.getInt("SoundStaticBuffers"); + soundPlayerParams.strBufferCount= config.getInt("SoundStreamingBuffers"); + soundPlayer->init(&soundPlayerParams); + //} + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); } SoundRenderer::~SoundRenderer(){ + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + stopAllSounds(); + delete soundPlayer; + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + soundPlayer = NULL; + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); } SoundRenderer &SoundRenderer::getInstance(){ diff --git a/source/shared_lib/include/sound/openal/sound_player_openal.h b/source/shared_lib/include/sound/openal/sound_player_openal.h new file mode 100644 index 00000000..881dc688 --- /dev/null +++ b/source/shared_lib/include/sound/openal/sound_player_openal.h @@ -0,0 +1,126 @@ +//This file is part of Glest Shared Library (www.glest.org) +//Copyright (C) 2005 Matthias Braun + +//You can redistribute this code and/or modify it under +//the terms of the GNU General Public License as published by the Free Software +//Foundation; either version 2 of the License, or (at your option) any later +//version. +#ifndef _SHARED_SOUND_SOUNDPLAYEROPENAL_H_ +#define _SHARED_SOUND_SOUNDPLAYEROPENAL_H_ + +#include "sound_player.h" +#include "platform_util.h" + +#include +#include +#include + +#include + +using std::vector; + +namespace Shared{ namespace Sound{ namespace OpenAL{ + +class SoundSource { +public: + SoundSource(); + virtual ~SoundSource(); + + bool playing(); + void stop(); + void unQueueBuffers(); + +protected: + friend class SoundPlayerOpenAL; + ALenum getFormat(Sound* sound); + + ALuint source; +}; + +class StaticSoundSource : public SoundSource { +public: + StaticSoundSource(); + virtual ~StaticSoundSource(); + + void play(StaticSound* sound); + +protected: + friend class SoundPlayerOpenAL; + bool bufferAllocated; + ALuint buffer; +}; + +class StreamSoundSource : public SoundSource { +public: + StreamSoundSource(); + virtual ~StreamSoundSource(); + + void play(StrSound* sound, int64 fade); + void update(); + void stop(); + void stop(int64 fade); + +protected: + friend class SoundPlayerOpenAL; + static const size_t STREAMBUFFERSIZE = 1024 * 500; + static const size_t STREAMFRAGMENTS = 5; + static const size_t STREAMFRAGMENTSIZE + = STREAMBUFFERSIZE / STREAMFRAGMENTS; + + bool fillBufferAndQueue(ALuint buffer); + + StrSound* sound; + ALuint buffers[STREAMFRAGMENTS]; + ALenum format; + + enum FadeState { NoFading, FadingOn, FadingOff }; + FadeState fadeState; + Chrono chrono; // delay-fade chrono + int64 fade; +}; + +// ============================================================== +// class SoundPlayerSDL +// +/// SoundPlayer implementation using SDL_mixer +// ============================================================== + +class SoundPlayerOpenAL : public SoundPlayer { +public: + SoundPlayerOpenAL(); + virtual ~SoundPlayerOpenAL(); + virtual void init(const SoundPlayerParams *params); + virtual void end(); + virtual void play(StaticSound *staticSound); + virtual void play(StrSound *strSound, int64 fadeOn=0); + virtual void stop(StrSound *strSound, int64 fadeOff=0); + virtual void stopAllSounds(); + virtual void updateStreams(); //updates str buffers if needed + +private: + friend class SoundSource; + friend class StaticSoundSource; + friend class StreamSoundSource; + + void printOpenALInfo(); + + StaticSoundSource* findStaticSoundSource(); + StreamSoundSource* findStreamSoundSource(); + void checkAlcError(const char* message); + static void checkAlError(const char* message); + + ALCdevice* device; + ALCcontext* context; + + typedef std::vector StaticSoundSources; + StaticSoundSources staticSources; + typedef std::vector StreamSoundSources; + StreamSoundSources streamSources; + + SoundPlayerParams params; +}; + +}}}//end namespace + +#endif + diff --git a/source/shared_lib/sources/sound/openal/sound_player_openal.cpp b/source/shared_lib/sources/sound/openal/sound_player_openal.cpp new file mode 100644 index 00000000..a5bc0900 --- /dev/null +++ b/source/shared_lib/sources/sound/openal/sound_player_openal.cpp @@ -0,0 +1,537 @@ +//This file is part of Glest Shared Library (www.glest.org) +//Copyright (C) 2005 Matthias Braun + +//You can redistribute this code and/or modify it under +//the terms of the GNU General Public License as published by the Free Software +//Foundation; either version 2 of the License, or (at your option) any later +//version. +#include "sound_player_openal.h" + +#include +#include +#include +#include + +#include "platform_util.h" +#include "util.h" +#include "leak_dumper.h" + +namespace Shared{ namespace Sound{ namespace OpenAL{ + +using namespace Util; + +SoundSource::SoundSource() +{ + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + alGenSources(1, &source); + SoundPlayerOpenAL::checkAlError("Couldn't create audio source: "); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +SoundSource::~SoundSource() +{ + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + stop(); + alDeleteSources(1, &source); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +bool SoundSource::playing() +{ + ALint state = AL_PLAYING; + alGetSourcei(source, AL_SOURCE_STATE, &state); + return state != AL_STOPPED; +} + +void SoundSource::unQueueBuffers() { + int queued; + alGetSourcei(source, AL_BUFFERS_QUEUED, &queued); + while(queued--) { + ALuint buffer; + alSourceUnqueueBuffers(source, 1, &buffer); + } + +} + +void SoundSource::stop() +{ + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + alSourceStop(source); + + SoundPlayerOpenAL::checkAlError("Problem stopping audio source: "); + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + unQueueBuffers(); + + SoundPlayerOpenAL::checkAlError("Problem unqueuing buffers in audio source: "); + + alSourcei(source, AL_BUFFER, AL_NONE); + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + SoundPlayerOpenAL::checkAlError("Problem stopping audio source: "); + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +ALenum SoundSource::getFormat(Sound* sound) +{ + if(sound->getInfo()->getChannels() == 2) { + if(sound->getInfo()->getBitsPerSample() == 16) + return AL_FORMAT_STEREO16; + else if(sound->getInfo()->getBitsPerSample() == 8) + return AL_FORMAT_STEREO8; + else + throw std::runtime_error("Sample format not supported"); + } else if(sound->getInfo()->getChannels() == 1) { + if(sound->getInfo()->getBitsPerSample() == 16) + return AL_FORMAT_MONO16; + else if(sound->getInfo()->getBitsPerSample() == 8) + return AL_FORMAT_MONO8; + else + throw std::runtime_error("Sample format not supported"); + } + + throw std::runtime_error("Sample format not supported"); +} + +//--------------------------------------------------------------------------- + +StaticSoundSource::StaticSoundSource() { + bufferAllocated = false; +} + +StaticSoundSource::~StaticSoundSource() { + if(bufferAllocated) { + stop(); + alDeleteBuffers(1, &buffer); + } +} + +void StaticSoundSource::play(StaticSound* sound) +{ + if(bufferAllocated) { + stop(); + alDeleteBuffers(1, &buffer); + } + ALenum format = getFormat(sound); + + alGenBuffers(1, &buffer); + SoundPlayerOpenAL::checkAlError("Couldn't create audio buffer: "); + + bufferAllocated = true; + alBufferData(buffer, format, sound->getSamples(), + static_cast (sound->getInfo()->getSize()), + static_cast (sound->getInfo()->getSamplesPerSecond())); + SoundPlayerOpenAL::checkAlError("Couldn't fill audio buffer: "); + + alSourcei(source, AL_BUFFER, buffer); + alSourcef(source, AL_GAIN, sound->getVolume()); + alSourcePlay(source); + SoundPlayerOpenAL::checkAlError("Couldn't start audio source: "); +} + +StreamSoundSource::StreamSoundSource() +{ + sound = 0; + alGenBuffers(STREAMFRAGMENTS, buffers); + SoundPlayerOpenAL::checkAlError("Couldn't allocate audio buffers: "); +} + +StreamSoundSource::~StreamSoundSource() +{ + stop(); + alDeleteBuffers(STREAMFRAGMENTS, buffers); + SoundPlayerOpenAL::checkAlError("Couldn't delete audio buffers: "); +} + +void StreamSoundSource::stop() +{ + sound = 0; + SoundSource::stop(); +} + +void StreamSoundSource::stop(int64 fadeoff) +{ + if(fadeoff > 0) { + fadeState = FadingOff; + fade = fadeoff; + chrono.start(); + } else { + stop(); + } +} + +void StreamSoundSource::play(StrSound* sound, int64 fadeon) +{ + stop(); + + this->sound = sound; + + format = getFormat(sound); + for(size_t i = 0; i < STREAMFRAGMENTS; ++i) { + fillBufferAndQueue(buffers[i]); + } + if(fadeon > 0) { + alSourcef(source, AL_GAIN, 0); + fadeState = FadingOn; + fade = fadeon; + chrono.start(); + } else { + fadeState = NoFading; + alSourcef(source, AL_GAIN, sound->getVolume()); + } + alSourcePlay(source); +} + +void StreamSoundSource::update() +{ + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + if(sound == 0) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + return; + } + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + ALint processed = 0; + alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); + while(processed > 0) { + processed--; + + ALuint buffer; + alSourceUnqueueBuffers(source, 1, &buffer); + SoundPlayerOpenAL::checkAlError("Couldn't unqueue audio buffer: "); + + if(!fillBufferAndQueue(buffer)) + break; + } + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + // we might have to restart the source if we had a buffer underrun + if(!playing()) { + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + std::cerr + << "Restarting audio source because of buffer underrun.\n"; + alSourcePlay(source); + SoundPlayerOpenAL::checkAlError("Couldn't restart audio source: "); + } + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + // handle fading + switch(fadeState) { + case FadingOn: + if(chrono.getMillis() > fade) { + alSourcef(source, AL_GAIN, sound->getVolume()); + fadeState = NoFading; + } else { + alSourcef(source, AL_GAIN, sound->getVolume() * + static_cast (chrono.getMillis())/fade); + } + break; + case FadingOff: + if(chrono.getMillis() > fade) { + stop(); + } else { + alSourcef(source, AL_GAIN, sound->getVolume() * + (1.0f - static_cast(chrono.getMillis())/fade)); + } + break; + default: + break; + } + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +bool StreamSoundSource::fillBufferAndQueue(ALuint buffer) +{ + // fill buffer + int8* bufferdata = new int8[STREAMFRAGMENTSIZE]; + uint32 bytesread = 0; + do { + bytesread += sound->read(bufferdata + bytesread, + STREAMFRAGMENTSIZE - bytesread); + if(bytesread < STREAMFRAGMENTSIZE) { + StrSound* next = sound->getNext(); + if(next == 0) + next = sound; + next->restart(); + next->setVolume(sound->getVolume()); + sound = next; + } + } while(bytesread < STREAMFRAGMENTSIZE); + + alBufferData(buffer, format, bufferdata, STREAMFRAGMENTSIZE, + sound->getInfo()->getSamplesPerSecond()); + delete[] bufferdata; + SoundPlayerOpenAL::checkAlError("Couldn't refill audio buffer: "); + + alSourceQueueBuffers(source, 1, &buffer); + SoundPlayerOpenAL::checkAlError("Couldn't queue audio buffer: "); + + return true; +} + +// ================================ +// Sound Player OpenAL +// ================================ + +SoundPlayerOpenAL::SoundPlayerOpenAL() { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + device = 0; + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +SoundPlayerOpenAL::~SoundPlayerOpenAL() { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + end(); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +void SoundPlayerOpenAL::printOpenALInfo() +{ + std::cout << "OpenAL Vendor: " << alGetString(AL_VENDOR) << "\n" + << "OpenAL Version: " << alGetString(AL_VERSION) << "\n" + << "OpenAL Renderer: " << alGetString(AL_RENDERER) << "\n" + << "OpenAl Extensions: " << alGetString(AL_RENDERER) << "\n"; +} + +void SoundPlayerOpenAL::init(const SoundPlayerParams* params) { + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + this->params = *params; + + device = alcOpenDevice(0); + if(device == 0) { + printOpenALInfo(); + throw std::runtime_error("Couldn't open audio device."); + } + try { + int attributes[] = { 0 }; + context = alcCreateContext(device, attributes); + checkAlcError("Couldn't create audio context: "); + alcMakeContextCurrent(context); + checkAlcError("Couldn't select audio context: "); + + checkAlError("Audio error after init: "); + } catch(...) { + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + printOpenALInfo(); + throw; + } +} + +void SoundPlayerOpenAL::end() { + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + + for(StaticSoundSources::iterator i = staticSources.begin(); + i != staticSources.end(); ++i) { + StaticSoundSource *src = (*i); + src->stop(); + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + for(StreamSoundSources::iterator i = streamSources.begin(); + i != streamSources.end(); ++i) { + StreamSoundSource *src = (*i); + src->stop(); + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + for(StaticSoundSources::iterator i = staticSources.begin(); + i != staticSources.end(); ++i) { + delete *i; + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + for(StreamSoundSources::iterator i = streamSources.begin(); + i != streamSources.end(); ++i) { + delete *i; + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + alcMakeContextCurrent( NULL ); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + if(context != 0) { + alcDestroyContext(context); + context = 0; + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + if(device != 0) { + alcCloseDevice(device); + device = 0; + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); +} + +void SoundPlayerOpenAL::play(StaticSound* staticSound) { + assert(staticSound != 0); + + try { + StaticSoundSource* source = findStaticSoundSource(); + if(source == 0) + return; + source->play(staticSound); + } catch(std::exception& e) { + std::cerr << "Couldn't play static sound: " << e.what() << "\n"; + } +} + +void SoundPlayerOpenAL::play(StrSound* strSound, int64 fadeOn) { + assert(strSound != 0); + + try { + StreamSoundSource* source = findStreamSoundSource(); + source->play(strSound, fadeOn); + } catch(std::exception& e) { + std::cerr << "Couldn't play streaming sound: " << e.what() << "\n"; + } +} + +void SoundPlayerOpenAL::stop(StrSound* strSound, int64 fadeOff) { + assert(strSound != 0); + + for(StreamSoundSources::iterator i = streamSources.begin(); + i != streamSources.end(); ++i) { + StreamSoundSource* source = *i; + if(source->sound == strSound) { + source->stop(fadeOff); + } + } +} + +void SoundPlayerOpenAL::stopAllSounds() { + for(StaticSoundSources::iterator i = staticSources.begin(); + i != staticSources.end(); ++i) { + StaticSoundSource* source = *i; + source->stop(); + } + for(StreamSoundSources::iterator i = streamSources.begin(); + i != streamSources.end(); ++i) { + StreamSoundSource* source = *i; + source->stop(); + } +} + +void SoundPlayerOpenAL::updateStreams() { + assert(context != 0); + try { + for(StreamSoundSources::iterator i = streamSources.begin(); + i != streamSources.end(); ++i) { + StreamSoundSource* source = *i; + try { + source->update(); + } catch(std::exception& e) { + std::cerr << "Error while updating sound stream: " + << e.what() << "\n"; + } + } + alcProcessContext(context); + checkAlcError("Error while processing audio context: "); + } catch(...) { + printOpenALInfo(); + throw; + } +} + +StaticSoundSource* SoundPlayerOpenAL::findStaticSoundSource() { + // try to find a stopped source + for(StaticSoundSources::iterator i = staticSources.begin(); + i != staticSources.end(); ++i) { + StaticSoundSource* source = *i; + if(! source->playing()) { + return source; + } + } + + // create a new source + if(staticSources.size() >= params.staticBufferCount) { + return 0; + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + StaticSoundSource* source = new StaticSoundSource(); + staticSources.push_back(source); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + return source; +} + +StreamSoundSource* SoundPlayerOpenAL::findStreamSoundSource() { + // try to find a stopped source + for(StreamSoundSources::iterator i = streamSources.begin(); + i != streamSources.end(); ++i) { + StreamSoundSource* source = *i; + if(! source->playing()) { + return source; + } + } + + // create a new source + if(streamSources.size() >= params.strBufferCount) { + throw std::runtime_error("Too many stream sounds played at once"); + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + StreamSoundSource* source = new StreamSoundSource(); + streamSources.push_back(source); + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + return source; +} + +void SoundPlayerOpenAL::checkAlcError(const char* message) +{ + int err = alcGetError(device); + if(err != ALC_NO_ERROR) { + std::stringstream msg; + msg << message << alcGetString(device, err); + throw std::runtime_error(msg.str()); + } +} + +void SoundPlayerOpenAL::checkAlError(const char* message) +{ + int err = alGetError(); + if(err != AL_NO_ERROR) { + std::stringstream msg; + msg << message << alGetString(err); + throw std::runtime_error(msg.str()); + } +} + +}}} // end of namespace + diff --git a/source/shared_lib/sources/sound/sound_interface.cpp b/source/shared_lib/sources/sound/sound_interface.cpp new file mode 100644 index 00000000..1ed04461 --- /dev/null +++ b/source/shared_lib/sources/sound/sound_interface.cpp @@ -0,0 +1,40 @@ +// ============================================================== +// This file is part of Glest Shared Library (www.glest.org) +// +// Copyright (C) 2001-2008 Martiņo Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#include "sound_interface.h" +#include "util.h" +#include "leak_dumper.h" + +using namespace Shared::Util; + +namespace Shared{ namespace Sound{ + +// ===================================================== +// class SoundInterface +// ===================================================== + +SoundInterface &SoundInterface::getInstance(){ + static SoundInterface soundInterface; + return soundInterface; +} + +void SoundInterface::setFactory(SoundFactory *soundFactory){ + this->soundFactory= soundFactory; +} + +SoundPlayer *SoundInterface::newSoundPlayer(){ + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s %d]\n",__FILE__,__FUNCTION__,__LINE__); + + return soundFactory->newSoundPlayer(); +} + +}}//end namespace