/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Benjamin Grauer co-programmer: ... code has been taken from http://www.devmaster.net/articles.php?catID=6 The code has been applied to our needs, and many things have been changed. */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_SOUND #include "sound_engine.h" #include "class_list.h" #include "p_node.h" #include "list.h" #include "resource_manager.h" #include "debug.h" #include "ini_parser.h" #include "globals.h" using namespace std; ////////////////// /* SOUND-ENGINE */ ////////////////// /** * standard constructor */ SoundEngine::SoundEngine () { this->setClassID(CL_SOUND_ENGINE, "SoundEngine"); this->setName("SoundEngine"); this->listener = NULL; this->bufferList = NULL; this->sourceList = NULL; } /** * the singleton reference to this class */ SoundEngine* SoundEngine::singletonRef = NULL; /** * standard deconstructor */ SoundEngine::~SoundEngine () { // deleting all the SoundSources if(this->sourceList != NULL) { while (this->sourceList->size() > 0) delete dynamic_cast(this->sourceList->front()); } // deleting all the SoundBuffers if (this->bufferList != NULL) { while(this->bufferList->size() > 0) ResourceManager::getInstance()->unload(dynamic_cast(this->bufferList->front())); } // removing openAL from AudioResource //! @todo this should be terminated through alc //alutExit(); SoundEngine::singletonRef = NULL; } /** * loads the settings of the SoundEngine from an ini-file * @param iniParser the IniParser of the inifile */ void SoundEngine::loadSettings(IniParser* iniParser) { const char* musicVolume = iniParser->getVar(CONFIG_NAME_MUSIC_VOLUME, CONFIG_SECTION_AUDIO, "80"); this->musicVolume = atof(musicVolume)/100.0; const char* effectsVolume = iniParser->getVar(CONFIG_NAME_EFFECTS_VOLUME, CONFIG_SECTION_AUDIO, "80"); this->effectsVolume = atof(effectsVolume)/100.0; } /** * creates a new SoundSource. * @param fileName The Name to load the SoundBuffer from * @param sourceNode The sourceNode to bind this SoundSource to. * @returns The newly created SoundSource acctualy this is nothing more than a wrapper around the ResourceManager. */ SoundSource* SoundEngine::createSource(const char* fileName, PNode* sourceNode) { return new SoundSource(sourceNode, (SoundBuffer*)ResourceManager::getInstance()->load(fileName, WAV, RP_LEVEL)); } /** * Sets the doppler values of openAL * @param dopplerFactor the extent of the doppler-effect * @param dopplerVelocity the Speed the sound travels */ void SoundEngine::setDopplerValues(ALfloat dopplerFactor, ALfloat dopplerVelocity) { alDopplerFactor(dopplerFactor); alDopplerVelocity(dopplerVelocity); } /** * adds a SoundBuffer to the bufferList of the SoundEngine * @param buffer The buffer to add to the bufferList */ void SoundEngine::addBuffer(SoundBuffer* buffer) { if (unlikely(this->bufferList == NULL)) this->bufferList = ClassList::getList(CL_SOUND_BUFFER); } /** * removes a SoundBuffer from the bufferList of the SoundEngine * @param buffer The buffer to delete from the SoundEngine */ void SoundEngine::removeBuffer(SoundBuffer* buffer) { // look if there are any sources that have the buffer still loaded if (this->sourceList != NULL) { list::iterator source; for (source = this->sourceList->begin(); source != this->sourceList->end(); source++) { if (buffer == static_cast(*source)->getBuffer()) delete (*source); } } } /** * adds a SoundSource to the sourceList of the SoundEngine * @param source The source to add to the sourceList */ void SoundEngine::addSource(SoundSource* source) { this->sourceList = ClassList::getList(CL_SOUND_SOURCE); } /** * updates all The positions, Directions and Velocities of all Sounds */ void SoundEngine::update() { // updating the Listeners Position if (likely(this->listener != NULL)) { alListener3f(AL_POSITION, this->listener->getAbsCoor().x, this->listener->getAbsCoor().y, this->listener->getAbsCoor().z); alListener3f(AL_VELOCITY, this->listener->getVelocity().x, this->listener->getVelocity().y, this->listener->getVelocity().z); Vector absDirV = this->listener->getAbsDirV(); ALfloat orientation [6] = {1,0,0, absDirV.x, absDirV.y, absDirV.z}; alListenerfv(AL_ORIENTATION, orientation); } else PRINTF(2)("no listener defined\n"); // updating all the Sources positions if (likely(this->sourceList != NULL)) { list::iterator sourceIT; SoundSource* source; for (sourceIT = this->sourceList->begin(); sourceIT != this->sourceList->end(); sourceIT++) { source = static_cast(*sourceIT); if (likely(source->getNode() != NULL)) { alSource3f(source->getID(), AL_POSITION, source->getNode()->getAbsCoor().x, source->getNode()->getAbsCoor().y, source->getNode()->getAbsCoor().z); alSource3f(source->getID(), AL_VELOCITY, source->getNode()->getVelocity().x, source->getNode()->getVelocity().y, source->getNode()->getVelocity().z); } } } } /** * Removes all the Buffers that are not anymore needed by any Sources */ void SoundEngine::flushUnusedBuffers() { /// FIXME /* if(this->sourceList && this->bufferList) { tIterator* bufferIterator = this->bufferList->getIterator(); SoundBuffer* enumBuffer = (SoundBuffer*)bufferIterator->firstElement(); while (enumBuffer) { tIterator* sourceIterator = this->sourceList->getIterator(); SoundSource* enumSource = (SoundSource*)sourceIterator->firstElement(); while (enumSource) { if (enumBuffer == enumSource->getBuffer()) break; enumSource = (SoundSource*)sourceIterator->nextElement(); } delete sourceIterator; if (enumSource == NULL) ResourceManager::getInstance()->unload(enumBuffer); enumBuffer = (SoundBuffer*)bufferIterator->nextElement(); } delete bufferIterator; }*/ /// FIXME } /** * flushes all the Buffers * deletes them from the BufferList, and also removes them via the ResourceManager. */ void SoundEngine::flushAllBuffers() { if (this->bufferList) { while (this->bufferList->size() > 0) ResourceManager::getInstance()->unload(static_cast(this->bufferList->front()), RP_LEVEL); } } /** * deletes all the Sources. */ void SoundEngine::flushAllSources() { if (this->sourceList) { while(this->sourceList->size() > 0) delete this->sourceList->front(); } } /** * initializes Audio in general */ bool SoundEngine::initAudio() { ALenum result; PRINTF(3)("Initialisazing openAL sound engine\n"); const char* defaultDevice =(const char*) alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); const char* deviceList = (const char*)alcGetString(NULL,ALC_DEVICE_SPECIFIER); const char* devWalk = deviceList; // if (alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE) { // try out enumeration extension PRINTF(3)("Enumeration-extension found\n"); PRINTF(3)("Default device: %s\n", defaultDevice); do { PRINTF(3)("%s\n", devWalk); devWalk += strlen(devWalk)+1; } while (devWalk[0] != '\0'); } // INITIALIZING THE DEVICE: #ifndef AL_VERSION_1_1 ALubyte deviceName[] = #else ALCchar deviceName[] = #endif #ifdef __WIN32__ "native"; #else "'( ( devices '( native arts null ) ) )"; #endif // this->device = alcOpenDevice(deviceName); this->context = alcCreateContext(this->device, NULL); alcMakeContextCurrent(this->context); if ((result = alGetError()) != AL_NO_ERROR) SoundEngine::PrintALErrorString(result); this->setDopplerValues(SOUND_DOPPLER_FACTOR, SOUND_DOPPLER_VELOCITY); } /** * Transforms AL-errors into something readable * @param err The error found */ void SoundEngine::PrintALErrorString(ALenum err) { switch(err) { case AL_NO_ERROR: PRINTF(4)("AL_NO_ERROR\n"); break; case AL_INVALID_NAME: PRINTF(2)("AL_INVALID_NAME\n"); break; case AL_INVALID_ENUM: PRINTF(2)("AL_INVALID_ENUM\n"); break; case AL_INVALID_VALUE: PRINTF(2)("AL_INVALID_VALUE\n"); break; case AL_INVALID_OPERATION: PRINTF(2)("AL_INVALID_OPERATION\n"); break; case AL_OUT_OF_MEMORY: PRINTF(2)("AL_OUT_OF_MEMORY\n"); break; }; } void SoundEngine::listDevices() { printf("%s\n",(const char*)alcGetString(NULL, ALC_DEVICE_SPECIFIER)); } /* void SoundEngine::PrintALCErrorString(ALenum err) { switch(err) { case ALC_NO_ERROR: PRINTF(4)("AL_NO_ERROR\n"); break; case ALC_INVALID_DEVICE: PRINTF(2)("ALC_INVALID_DEVICE\n"); break; case ALC_INVALID_CONTEXT: PRINTF(2)("ALC_INVALID_CONTEXT\n"); break; case ALC_INVALID_ENUM: PRINTF(2)("ALC_INVALID_ENUM\n"); break; case ALC_INVALID_VALUE: PRINTF(2)("ALC_INVALID_VALUE\n"); break; case ALC_OUT_OF_MEMORY: PRINTF(2)("ALC_OUT_OF_MEMORY\n"); break; }; } */