[3655] | 1 | /* |
---|
| 2 | orxonox - the future of 3D-vertical-scrollers |
---|
| 3 | |
---|
| 4 | Copyright (C) 2004 orx |
---|
| 5 | |
---|
| 6 | This program is free software; you can redistribute it and/or modify |
---|
| 7 | it under the terms of the GNU General Public License as published by |
---|
| 8 | the Free Software Foundation; either version 2, or (at your option) |
---|
| 9 | any later version. |
---|
| 10 | |
---|
| 11 | ### File Specific: |
---|
[4195] | 12 | main-programmer: Benjamin Grauer |
---|
[3655] | 13 | co-programmer: ... |
---|
[4203] | 14 | |
---|
| 15 | code has been taken from http://www.devmaster.net/articles.php?catID=6 |
---|
| 16 | The code has been applied to our needs, and many things have been changed. |
---|
[3655] | 17 | */ |
---|
| 18 | |
---|
| 19 | //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY |
---|
| 20 | |
---|
[4195] | 21 | #include "sound_engine.h" |
---|
[4197] | 22 | |
---|
[4196] | 23 | #include "p_node.h" |
---|
| 24 | #include "list.h" |
---|
[4203] | 25 | #include "AL/alc.h" |
---|
[4204] | 26 | #include "resource_manager.h" |
---|
[3655] | 27 | using namespace std; |
---|
| 28 | |
---|
| 29 | |
---|
[4197] | 30 | ////////////////// |
---|
| 31 | /* SOUND-BUFFER */ |
---|
| 32 | ////////////////// |
---|
[3655] | 33 | /** |
---|
[4196] | 34 | \brief Creates a Soundbuffer out of an inputfile |
---|
| 35 | \param fileName The name of the File |
---|
| 36 | */ |
---|
| 37 | SoundBuffer::SoundBuffer(const char* fileName) |
---|
| 38 | { |
---|
| 39 | SoundEngine::getInstance()->addBuffer(this); |
---|
| 40 | |
---|
| 41 | ALenum format; |
---|
| 42 | ALvoid* data; |
---|
| 43 | ALsizei freq; |
---|
[4203] | 44 | |
---|
| 45 | ALenum result; |
---|
[4196] | 46 | |
---|
[4203] | 47 | // generate a Buffer |
---|
[4196] | 48 | alGenBuffers(1, &this->bufferID); |
---|
[4203] | 49 | if ((result = alGetError()) != AL_NO_ERROR) |
---|
| 50 | SoundEngine::PrintALErrorString(result); |
---|
| 51 | |
---|
| 52 | // read in the wav data |
---|
[4196] | 53 | alutLoadWAVFile((ALbyte*)fileName, &format, &data, &this->size, &freq, &this->loop); |
---|
[4203] | 54 | if ((result = alGetError()) != AL_NO_ERROR) |
---|
| 55 | SoundEngine::PrintALErrorString(result); |
---|
| 56 | |
---|
| 57 | // send the loaded wav data to the buffer |
---|
[4196] | 58 | alBufferData(this->bufferID, format, data, this->size, freq); |
---|
[4203] | 59 | if ((result = alGetError()) != AL_NO_ERROR) |
---|
| 60 | SoundEngine::PrintALErrorString(result); |
---|
| 61 | |
---|
| 62 | // remove the wav data (redundant) |
---|
[4196] | 63 | alutUnloadWAV(format, data, this->size, freq); |
---|
[4203] | 64 | if ((result = alGetError()) != AL_NO_ERROR) |
---|
| 65 | SoundEngine::PrintALErrorString(result); |
---|
[4196] | 66 | } |
---|
| 67 | |
---|
| 68 | SoundBuffer::~SoundBuffer(void) |
---|
| 69 | { |
---|
| 70 | SoundEngine::getInstance()->removeBuffer(this); |
---|
[4198] | 71 | alDeleteBuffers(1, &this->bufferID); |
---|
[4196] | 72 | } |
---|
| 73 | |
---|
[4197] | 74 | ////////////////// |
---|
| 75 | /* SOUND-SOURCE */ |
---|
| 76 | ////////////////// |
---|
[4196] | 77 | /** |
---|
| 78 | \brief creates a SoundSource at position sourceNode with the SoundBuffer buffer |
---|
| 79 | */ |
---|
| 80 | SoundSource::SoundSource(SoundBuffer* buffer, PNode* sourceNode) |
---|
| 81 | { |
---|
[4203] | 82 | ALenum result; |
---|
| 83 | |
---|
| 84 | // adding the Source to the SourcesList of the SoundEngine |
---|
[4196] | 85 | SoundEngine::getInstance()->addSource(this); |
---|
| 86 | |
---|
| 87 | this->buffer = buffer; |
---|
| 88 | this->sourceNode = sourceNode; |
---|
[4197] | 89 | |
---|
| 90 | alGenSources(1, &this->sourceID); |
---|
[4203] | 91 | if ((result = alGetError()) != AL_NO_ERROR) |
---|
| 92 | SoundEngine::PrintALErrorString(result); |
---|
[4197] | 93 | alSourcei (this->sourceID, AL_BUFFER, this->buffer->getID()); |
---|
| 94 | alSourcef (this->sourceID, AL_PITCH, 1.0 ); |
---|
| 95 | alSourcef (this->sourceID, AL_GAIN, 1.0 ); |
---|
[4200] | 96 | alSourcei (sourceID, AL_LOOPING, true ); |
---|
[4196] | 97 | } |
---|
| 98 | |
---|
| 99 | SoundSource::~SoundSource(void) |
---|
| 100 | { |
---|
| 101 | SoundEngine::getInstance()->removeSource(this); |
---|
[4198] | 102 | alDeleteSources(1, &this->sourceID); |
---|
[4196] | 103 | } |
---|
| 104 | |
---|
[4197] | 105 | |
---|
| 106 | void SoundSource::play() |
---|
| 107 | { |
---|
| 108 | alSourcePlay(this->sourceID); |
---|
| 109 | } |
---|
| 110 | void SoundSource::stop() |
---|
| 111 | { |
---|
| 112 | alSourceStop(this->sourceID); |
---|
| 113 | } |
---|
| 114 | void SoundSource::pause() |
---|
| 115 | { |
---|
| 116 | alSourcePause(this->sourceID); |
---|
| 117 | } |
---|
| 118 | |
---|
[4200] | 119 | void SoundSource::setRolloffFactor(ALfloat rolloffFactor) |
---|
| 120 | { |
---|
| 121 | alSourcef(this->sourceID, AL_ROLLOFF_FACTOR, rolloffFactor); |
---|
| 122 | } |
---|
[4197] | 123 | |
---|
[4200] | 124 | |
---|
| 125 | |
---|
[4197] | 126 | ////////////////// |
---|
| 127 | /* SOUND-ENGINE */ |
---|
| 128 | ////////////////// |
---|
[4196] | 129 | /** |
---|
[3655] | 130 | \brief standard constructor |
---|
| 131 | */ |
---|
[4195] | 132 | SoundEngine::SoundEngine () |
---|
[3655] | 133 | { |
---|
[4196] | 134 | this->setClassName ("SoundEngine"); |
---|
| 135 | |
---|
| 136 | this->initAudio(); |
---|
[3655] | 137 | |
---|
[4196] | 138 | this->listener = NULL; |
---|
| 139 | this->bufferList = new tList<SoundBuffer>; |
---|
| 140 | this->sourceList = new tList<SoundSource>; |
---|
[3655] | 141 | } |
---|
| 142 | |
---|
| 143 | /** |
---|
| 144 | \brief the singleton reference to this class |
---|
| 145 | */ |
---|
[4195] | 146 | SoundEngine* SoundEngine::singletonRef = NULL; |
---|
[3655] | 147 | |
---|
| 148 | /** |
---|
| 149 | \returns a Pointer to this Class |
---|
| 150 | */ |
---|
[4195] | 151 | SoundEngine* SoundEngine::getInstance(void) |
---|
[3655] | 152 | { |
---|
[4195] | 153 | if (!SoundEngine::singletonRef) |
---|
| 154 | SoundEngine::singletonRef = new SoundEngine(); |
---|
| 155 | return SoundEngine::singletonRef; |
---|
[3655] | 156 | } |
---|
| 157 | |
---|
| 158 | /** |
---|
| 159 | \brief standard deconstructor |
---|
| 160 | |
---|
| 161 | */ |
---|
[4195] | 162 | SoundEngine::~SoundEngine () |
---|
[3655] | 163 | { |
---|
[4195] | 164 | SoundEngine::singletonRef = NULL; |
---|
[3655] | 165 | |
---|
[4204] | 166 | // deleting all the Resources |
---|
| 167 | tIterator<SoundSource>* sourceIterator = this->sourceList->getIterator(); |
---|
| 168 | SoundSource* enumSource = sourceIterator->nextElement(); |
---|
| 169 | while (enumSource) |
---|
| 170 | { |
---|
| 171 | delete enumSource; |
---|
| 172 | enumSource = sourceIterator->nextElement(); |
---|
| 173 | } |
---|
| 174 | delete sourceIterator; |
---|
| 175 | |
---|
| 176 | tIterator<SoundBuffer>* bufferIterator = this->bufferList->getIterator(); |
---|
| 177 | SoundBuffer* enumBuffer = bufferIterator->nextElement(); |
---|
| 178 | while (enumBuffer) |
---|
| 179 | { |
---|
| 180 | ResourceManager::getInstance()->unload(enumBuffer); |
---|
| 181 | enumBuffer = bufferIterator->nextElement(); |
---|
| 182 | } |
---|
| 183 | delete bufferIterator; |
---|
[3655] | 184 | } |
---|
[4196] | 185 | |
---|
| 186 | /** |
---|
[4204] | 187 | \brief creates a new SoundSource. |
---|
| 188 | \param fileName The Name to load the SoundBuffer from |
---|
| 189 | \param The sourceNode to bind this SoundSource to. |
---|
| 190 | \returns The newly created SoundSource |
---|
| 191 | |
---|
| 192 | acctualy this is nothing more than a wrapper around the ResourceManager. |
---|
| 193 | */ |
---|
| 194 | SoundSource* SoundEngine::createSource(const char* fileName, PNode* sourceNode) |
---|
| 195 | { |
---|
| 196 | return new SoundSource((SoundBuffer*)ResourceManager::getInstance()->load(fileName, WAV, RP_LEVEL), sourceNode); |
---|
| 197 | } |
---|
| 198 | |
---|
| 199 | |
---|
| 200 | /** |
---|
[4196] | 201 | \brief sets The listener (normaly the Camera) |
---|
| 202 | */ |
---|
| 203 | void SoundEngine::setListener(PNode* listener) |
---|
| 204 | { |
---|
| 205 | this->listener = listener; |
---|
| 206 | } |
---|
| 207 | |
---|
| 208 | |
---|
| 209 | void SoundEngine::addBuffer(SoundBuffer* buffer) |
---|
| 210 | { |
---|
| 211 | this->bufferList->add(buffer); |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | void SoundEngine::removeBuffer(SoundBuffer* buffer) |
---|
| 215 | { |
---|
| 216 | this->bufferList->remove(buffer); |
---|
| 217 | } |
---|
| 218 | |
---|
| 219 | void SoundEngine::addSource(SoundSource* source) |
---|
| 220 | { |
---|
| 221 | this->sourceList->add(source); |
---|
| 222 | } |
---|
| 223 | void SoundEngine::removeSource(SoundSource* source) |
---|
| 224 | { |
---|
| 225 | this->sourceList->remove(source); |
---|
| 226 | } |
---|
| 227 | |
---|
| 228 | |
---|
| 229 | /** |
---|
| 230 | \brief updates all The positions, Directions and Velocities of all Sounds |
---|
| 231 | */ |
---|
| 232 | void SoundEngine::update(void) |
---|
| 233 | { |
---|
| 234 | |
---|
| 235 | // updating the Listeners Position |
---|
[4205] | 236 | if (likely(this->listener != NULL)) |
---|
[4196] | 237 | { |
---|
| 238 | alListener3f(AL_POSITION, |
---|
| 239 | this->listener->getAbsCoor().x, |
---|
| 240 | this->listener->getAbsCoor().y, |
---|
| 241 | this->listener->getAbsCoor().z); |
---|
| 242 | alListener3f(AL_VELOCITY, |
---|
| 243 | this->listener->getVelocity().x, |
---|
| 244 | this->listener->getVelocity().y, |
---|
| 245 | this->listener->getVelocity().z); |
---|
| 246 | Vector absDirV = this->listener->getAbsDirV(); |
---|
[4198] | 247 | ALfloat orientation [6] = {1,0,0, absDirV.x, absDirV.y, absDirV.z}; |
---|
| 248 | alListenerfv(AL_ORIENTATION, orientation); |
---|
[4196] | 249 | } |
---|
[4197] | 250 | else |
---|
| 251 | PRINTF(2)("no listener defined\n"); |
---|
| 252 | |
---|
[4196] | 253 | // updating all the Sources positions |
---|
| 254 | tIterator<SoundSource>* iterator = this->sourceList->getIterator(); |
---|
| 255 | SoundSource* enumSource = iterator->nextElement(); |
---|
| 256 | while (enumSource) |
---|
| 257 | { |
---|
[4205] | 258 | if (likely(enumSource->getNode()!=NULL)) |
---|
| 259 | { |
---|
| 260 | alSource3f(enumSource->getID(), AL_POSITION, |
---|
| 261 | enumSource->getNode()->getAbsCoor().x, |
---|
| 262 | enumSource->getNode()->getAbsCoor().y, |
---|
| 263 | enumSource->getNode()->getAbsCoor().z); |
---|
| 264 | alSource3f(enumSource->getID(), AL_VELOCITY, |
---|
| 265 | enumSource->getNode()->getVelocity().x, |
---|
| 266 | enumSource->getNode()->getVelocity().y, |
---|
| 267 | enumSource->getNode()->getVelocity().z); |
---|
| 268 | } |
---|
[4196] | 269 | enumSource = iterator->nextElement(); |
---|
| 270 | } |
---|
| 271 | delete iterator; |
---|
| 272 | } |
---|
| 273 | |
---|
| 274 | /** |
---|
| 275 | \brief initializes Audio in general |
---|
| 276 | */ |
---|
| 277 | bool SoundEngine::initAudio(void) |
---|
| 278 | { |
---|
| 279 | alutInit(NULL, 0); |
---|
| 280 | alGetError(); |
---|
[4200] | 281 | |
---|
| 282 | alDopplerFactor(SOUND_DOPPLER_FACTOR); |
---|
| 283 | alDopplerVelocity(SOUND_DOPPLER_VELOCITY); |
---|
[4196] | 284 | } |
---|
| 285 | |
---|
[4203] | 286 | void SoundEngine::PrintALErrorString(ALenum err) |
---|
| 287 | { |
---|
| 288 | switch(err) |
---|
| 289 | { |
---|
| 290 | case AL_NO_ERROR: |
---|
| 291 | PRINTF(4)("AL_NO_ERROR\n"); |
---|
| 292 | break; |
---|
| 293 | |
---|
| 294 | case AL_INVALID_NAME: |
---|
| 295 | PRINTF(2)("AL_INVALID_NAME\n"); |
---|
| 296 | break; |
---|
| 297 | |
---|
| 298 | case AL_INVALID_ENUM: |
---|
| 299 | PRINTF(2)("AL_INVALID_ENUM\n"); |
---|
| 300 | break; |
---|
| 301 | |
---|
| 302 | case AL_INVALID_VALUE: |
---|
| 303 | PRINTF(2)("AL_INVALID_VALUE\n"); |
---|
| 304 | break; |
---|
| 305 | |
---|
| 306 | case AL_INVALID_OPERATION: |
---|
| 307 | PRINTF(2)("AL_INVALID_OPERATION\n"); |
---|
| 308 | break; |
---|
| 309 | |
---|
| 310 | case AL_OUT_OF_MEMORY: |
---|
| 311 | PRINTF(2)("AL_OUT_OF_MEMORY\n"); |
---|
| 312 | break; |
---|
| 313 | }; |
---|
| 314 | } |
---|
| 315 | |
---|
| 316 | |
---|
| 317 | void SoundEngine::PrintALCErrorString(ALenum err) |
---|
| 318 | { |
---|
| 319 | switch(err) |
---|
| 320 | { |
---|
| 321 | case ALC_NO_ERROR: |
---|
| 322 | PRINTF(4)("AL_NO_ERROR\n"); |
---|
| 323 | break; |
---|
| 324 | |
---|
| 325 | case ALC_INVALID_DEVICE: |
---|
| 326 | PRINTF(2)("ALC_INVALID_DEVICE\n"); |
---|
| 327 | break; |
---|
| 328 | |
---|
| 329 | case ALC_INVALID_CONTEXT: |
---|
| 330 | PRINTF(2)("ALC_INVALID_CONTEXT\n"); |
---|
| 331 | break; |
---|
| 332 | |
---|
| 333 | case ALC_INVALID_ENUM: |
---|
| 334 | PRINTF(2)("ALC_INVALID_ENUM\n"); |
---|
| 335 | break; |
---|
| 336 | |
---|
| 337 | case ALC_INVALID_VALUE: |
---|
| 338 | PRINTF(2)("ALC_INVALID_VALUE\n"); |
---|
| 339 | break; |
---|
| 340 | |
---|
| 341 | case ALC_OUT_OF_MEMORY: |
---|
| 342 | PRINTF(2)("ALC_OUT_OF_MEMORY\n"); |
---|
| 343 | break; |
---|
| 344 | }; |
---|
| 345 | } |
---|