/* 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 */ ////////////////// /** * 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 /* according to http://www.edenwaith.com/products/pige/tutorials/openal.php the alutLoadWAVFile differs from platform to platform*/ #ifdef __APPLE__ alutLoadWAVFile(fileName, &format, &data, &this->size, &freq); #elifdef __WIN32__ alutLoadWAVFile(fileName, &format, &data, &size, &freq, &this->loop); #else alutLoadWAVFile((ALbyte*)fileName, &format, &data, &this->size, &freq, &this->loop); #endif 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() { SoundEngine::getInstance()->removeBuffer(this); alDeleteBuffers(1, &this->bufferID); } ////////////////// /* SOUND-SOURCE */ ////////////////// /** * creates a SoundSource at position sourceNode with the SoundBuffer buffer */ SoundSource::SoundSource(const PNode* sourceNode, const SoundBuffer* buffer) { 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); if (this->buffer != NULL) 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 ); } /** * deletes a SoundSource */ SoundSource::~SoundSource() { SoundEngine::getInstance()->removeSource(this); alDeleteSources(1, &this->sourceID); } /** * Plays back a SoundSource */ void SoundSource::play() { alSourcePlay(this->sourceID); } /** * Plays back buffer on this Source * @param buffer the buffer to play back on this Source */ void SoundSource::play(const SoundBuffer* buffer) { alSourcei (this->sourceID, AL_BUFFER, buffer->getID()); alSourcePlay(this->sourceID); if (unlikely(this->buffer != NULL)) alSourcei (this->sourceID, AL_BUFFER, this->buffer->getID()); } /** * Stops playback of a SoundSource */ void SoundSource::stop() { alSourceStop(this->sourceID); } /** * Pauses Playback of a SoundSource */ void SoundSource::pause() { alSourcePause(this->sourceID); } /** * Rewinds Playback of a SoundSource */ void SoundSource::rewind() { alSourceRewind(this->sourceID); } /** * 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 */ ////////////////// /** * standard constructor */ SoundEngine::SoundEngine () { this->setClassID(CL_SOUND_ENGINE, "SoundEngine"); this->setName("SoundEngine"); this->listener = NULL; this->bufferList = new tList; this->sourceList = new tList; } /** * the singleton reference to this class */ SoundEngine* SoundEngine::singletonRef = NULL; /** * 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(); } /** * 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 listener (normaly the Camera) */ void SoundEngine::setListener(PNode* listener) { this->listener = listener; } /** * 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) { this->bufferList->add(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 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); } /** * 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); } /** * 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); } /** * 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 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; } /** * Removes all the Buffers that are not anymore needed by any Sources */ void SoundEngine::flushUnusedBuffers() { 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; } /** * SourceEngine::flushAllBuffers */ void SoundEngine::flushAllBuffers() { tIterator* bufferIterator = this->bufferList->getIterator(); SoundBuffer* enumBuffer = bufferIterator->nextElement(); while (enumBuffer) { ResourceManager::getInstance()->unload(enumBuffer, RP_LEVEL); enumBuffer = bufferIterator->nextElement(); } delete bufferIterator; } /** * SourceEngine::flushAllBuffers */ void SoundEngine::flushAllSources() { tIterator* Iterator = this->sourceList->getIterator(); SoundSource* enumSource = Iterator->nextElement(); while (enumSource) { delete enumSource; enumSource = Iterator->nextElement(); } delete Iterator; } /** * initializes Audio in general */ bool SoundEngine::initAudio() { 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); } /** * 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; }; } */