/* 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_WORLD_ENTITY #include "sound_engine.h" //#include // maybe later #include "p_node.h" #include "list.h" #include "resource_manager.h" #include "debug.h" using namespace std; ////////////////// /* SOUND-BUFFER */ ////////////////// /** \brief Creates a Soundbuffer out of an inputfile \param fileName The name of the File */ SoundBuffer::SoundBuffer(const char* fileName) { this->setClassID(CL_SOUND_BUFFER, "SoundBuffer"); this->setName(fileName); SoundEngine::getInstance()->addBuffer(this); ALenum format; ALvoid* data; ALsizei freq; ALenum result; // generate a Buffer alGenBuffers(1, &this->bufferID); if ((result = alGetError()) != AL_NO_ERROR) SoundEngine::PrintALErrorString(result); // read in the wav data alutLoadWAVFile((ALbyte*)fileName, &format, &data, &this->size, &freq, &this->loop); if ((result = alGetError()) != AL_NO_ERROR) SoundEngine::PrintALErrorString(result); // send the loaded wav data to the buffer alBufferData(this->bufferID, format, data, this->size, freq); if ((result = alGetError()) != AL_NO_ERROR) SoundEngine::PrintALErrorString(result); // remove the wav data (redundant) alutUnloadWAV(format, data, this->size, freq); if ((result = alGetError()) != AL_NO_ERROR) SoundEngine::PrintALErrorString(result); } SoundBuffer::~SoundBuffer(void) { SoundEngine::getInstance()->removeBuffer(this); alDeleteBuffers(1, &this->bufferID); } ////////////////// /* SOUND-SOURCE */ ////////////////// /** \brief creates a SoundSource at position sourceNode with the SoundBuffer buffer */ SoundSource::SoundSource(SoundBuffer* buffer, PNode* sourceNode) { this->setClassID(CL_SOUND_SOURCE, "SoundSource"); ALenum result; // adding the Source to the SourcesList of the SoundEngine SoundEngine::getInstance()->addSource(this); this->buffer = buffer; this->sourceNode = sourceNode; alGenSources(1, &this->sourceID); if ((result = alGetError()) != AL_NO_ERROR) SoundEngine::PrintALErrorString(result); alSourcei (this->sourceID, AL_BUFFER, this->buffer->getID()); alSourcef (this->sourceID, AL_PITCH, 1.0 ); alSourcef (this->sourceID, AL_GAIN, 1.0 ); alSourcei (sourceID, AL_LOOPING, AL_FALSE ); } /** \brief deletes a SoundSource */ SoundSource::~SoundSource(void) { SoundEngine::getInstance()->removeSource(this); alDeleteSources(1, &this->sourceID); } /** \brief Plays back a SoundSource */ void SoundSource::play() { alSourcePlay(this->sourceID); } /** \brief Stops playback of a SoundSource */ void SoundSource::stop() { alSourceStop(this->sourceID); } /** \brief Pauses Playback of a SoundSource */ void SoundSource::pause() { alSourcePause(this->sourceID); } /** \brief Rewinds Playback of a SoundSource */ void SoundSource::rewind() { alSourceRewind(this->sourceID); } /** \brief sets the RolloffFactor of the Sound emitted from the SoundSource \param rolloffFactor The Factor described this tells openAL how fast the Sounds decay outward from the Source */ void SoundSource::setRolloffFactor(ALfloat rolloffFactor) { alSourcef(this->sourceID, AL_ROLLOFF_FACTOR, rolloffFactor); } ////////////////// /* SOUND-ENGINE */ ////////////////// /** \brief standard constructor */ SoundEngine::SoundEngine () { this->setClassID(CL_SOUND_ENGINE, "SoundEngine"); this->setName("SoundEngine"); this->listener = NULL; this->bufferList = new tList; this->sourceList = new tList; } /** \brief the singleton reference to this class */ SoundEngine* SoundEngine::singletonRef = NULL; /** \brief standard deconstructor */ SoundEngine::~SoundEngine () { SoundEngine::singletonRef = NULL; // deleting all the SoundSources tIterator* sourceIterator = this->sourceList->getIterator(); SoundSource* enumSource = sourceIterator->nextElement(); while (enumSource) { delete enumSource; enumSource = sourceIterator->nextElement(); } delete sourceIterator; // deleting all the SoundBuffers tIterator* bufferIterator = this->bufferList->getIterator(); SoundBuffer* enumBuffer = bufferIterator->nextElement(); while (enumBuffer) { ResourceManager::getInstance()->unload(enumBuffer); enumBuffer = bufferIterator->nextElement(); } delete bufferIterator; // removing openAL from AudioResource alutExit(); } /** \brief 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((SoundBuffer*)ResourceManager::getInstance()->load(fileName, WAV, RP_LEVEL), sourceNode); } /** \brief sets The listener (normaly the Camera) */ void SoundEngine::setListener(PNode* listener) { this->listener = listener; } /** \brief 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); } /** \brief adds a SoundBuffer to the bufferList of the SoundEngine \param buffer The buffer to add to the bufferList */ void SoundEngine::addBuffer(SoundBuffer* buffer) { this->bufferList->add(buffer); } /** \brief 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 tIterator* sourceIterator = this->sourceList->getIterator(); SoundSource* enumSource = sourceIterator->nextElement(); while (enumSource) { if (buffer == enumSource->getBuffer()) delete enumSource; enumSource = sourceIterator->nextElement(); } delete sourceIterator; // remove the Buffer this->bufferList->remove(buffer); } /** \brief 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->add(source); } /** \brief removes a SoundSource from the sourceList of the SoundEngine \param source The source to delete from the SoundEngine */ void SoundEngine::removeSource(SoundSource* source) { this->sourceList->remove(source); } /** \brief updates all The positions, Directions and Velocities of all Sounds */ void SoundEngine::update(void) { // 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 tIterator* iterator = this->sourceList->getIterator(); SoundSource* enumSource = iterator->nextElement(); while (enumSource) { if (likely(enumSource->getNode()!=NULL)) { alSource3f(enumSource->getID(), AL_POSITION, enumSource->getNode()->getAbsCoor().x, enumSource->getNode()->getAbsCoor().y, enumSource->getNode()->getAbsCoor().z); alSource3f(enumSource->getID(), AL_VELOCITY, enumSource->getNode()->getVelocity().x, enumSource->getNode()->getVelocity().y, enumSource->getNode()->getVelocity().z); } enumSource = iterator->nextElement(); } delete iterator; } /** \brief Removes all the Buffers that are not anymore needed by any Sources */ void SoundEngine::flushUnusedBuffers(void) { tIterator* bufferIterator = this->bufferList->getIterator(); SoundBuffer* enumBuffer = bufferIterator->nextElement(); while (enumBuffer) { tIterator* sourceIterator = this->sourceList->getIterator(); SoundSource* enumSource = sourceIterator->nextElement(); while (enumSource) { if (enumBuffer == enumSource->getBuffer()) break; enumSource = sourceIterator->nextElement(); } delete sourceIterator; if (enumSource == NULL) ResourceManager::getInstance()->unload(enumBuffer); enumBuffer = bufferIterator->nextElement(); } delete bufferIterator; } /** \brief SourceEngine::flushAllBuffers */ void SoundEngine::flushAllBuffers(void) { tIterator* bufferIterator = this->bufferList->getIterator(); SoundBuffer* enumBuffer = bufferIterator->nextElement(); while (enumBuffer) { ResourceManager::getInstance()->unload(enumBuffer, RP_LEVEL); enumBuffer = bufferIterator->nextElement(); } delete bufferIterator; } /** \brief initializes Audio in general */ bool SoundEngine::initAudio(void) { ALenum result; PRINTF(3)("Initialisazing openAL sound library\n"); alutInit(NULL, 0); if ((result = alGetError()) != AL_NO_ERROR) SoundEngine::PrintALErrorString(result); this->setDopplerValues(SOUND_DOPPLER_FACTOR, SOUND_DOPPLER_VELOCITY); } /** \brief 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::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; }; } */