Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/trunk/src/lib/sound/sound_engine.cc @ 4959

Last change on this file since 4959 was 4959, checked in by bensch, 19 years ago

orxonox/trunk: orxonox runs again (the TrackManager produces speed)

File size: 12.3 KB
RevLine 
[4597]1/*
[4504]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:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
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.
17*/
18
19//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD_ENTITY
20
21#include "sound_engine.h"
22
23//#include <AL/alc.h> // maybe later
24
25#include "p_node.h"
26#include "list.h"
27#include "resource_manager.h"
28#include "debug.h"
29
30using namespace std;
31
32
33//////////////////
34/* SOUND-BUFFER */
35//////////////////
36/**
[4836]37 *  Creates a Soundbuffer out of an inputfile
38 * @param fileName The name of the File
[4504]39*/
40SoundBuffer::SoundBuffer(const char* fileName)
41{
[4597]42  this->setClassID(CL_SOUND_BUFFER, "SoundBuffer");
43  this->setName(fileName);
44
[4504]45  SoundEngine::getInstance()->addBuffer(this);
46
47  ALenum format;
48  ALvoid* data;
49  ALsizei freq;
[4597]50
[4504]51  ALenum result;
52
53  // generate a Buffer
54  alGenBuffers(1, &this->bufferID);
55  if ((result = alGetError()) != AL_NO_ERROR)
56    SoundEngine::PrintALErrorString(result);
57
58  // read in the wav data
[4601]59  /* according to http://www.edenwaith.com/products/pige/tutorials/openal.php the alutLoadWAVFile differs from platform to platform*/
[4605]60#ifdef __APPLE__
61  alutLoadWAVFile(fileName, &format, &data, &this->size, &freq);
[4601]62#elifdef __WIN32__
63  alutLoadWAVFile(fileName, &format, &data, &size, &freq, &this->loop);
[4605]64#else
65  alutLoadWAVFile((ALbyte*)fileName, &format, &data, &this->size, &freq, &this->loop);
[4601]66#endif
[4504]67  if ((result = alGetError()) != AL_NO_ERROR)
68    SoundEngine::PrintALErrorString(result);
[4597]69
[4504]70  // send the loaded wav data to the buffer
71  alBufferData(this->bufferID, format, data, this->size, freq);
72  if ((result = alGetError()) != AL_NO_ERROR)
73    SoundEngine::PrintALErrorString(result);
74
75  // remove the wav data (redundant)
76  alutUnloadWAV(format, data, this->size, freq);
77  if ((result = alGetError()) != AL_NO_ERROR)
78    SoundEngine::PrintALErrorString(result);
79}
80
[4746]81SoundBuffer::~SoundBuffer()
[4504]82{
83  SoundEngine::getInstance()->removeBuffer(this);
84  alDeleteBuffers(1, &this->bufferID);
85}
86
87//////////////////
88/* SOUND-SOURCE */
89//////////////////
90/**
[4836]91 *  creates a SoundSource at position sourceNode with the SoundBuffer buffer
[4504]92*/
[4885]93SoundSource::SoundSource(const PNode* sourceNode, const SoundBuffer* buffer)
[4504]94{
[4597]95  this->setClassID(CL_SOUND_SOURCE, "SoundSource");
96
[4504]97  ALenum result;
98
99  // adding the Source to the SourcesList of the SoundEngine
100  SoundEngine::getInstance()->addSource(this);
101
102  this->buffer = buffer;
103  this->sourceNode = sourceNode;
104
105  alGenSources(1, &this->sourceID);
106  if ((result = alGetError()) != AL_NO_ERROR)
107    SoundEngine::PrintALErrorString(result);
[4885]108  if (this->buffer != NULL)
109    alSourcei (this->sourceID, AL_BUFFER,   this->buffer->getID());
[4504]110  alSourcef (this->sourceID, AL_PITCH,    1.0      );
111  alSourcef (this->sourceID, AL_GAIN,     1.0      );
112  alSourcei (sourceID, AL_LOOPING,  AL_FALSE     );
113}
114
115/**
[4836]116 *  deletes a SoundSource
[4504]117*/
[4746]118SoundSource::~SoundSource()
[4504]119{
120  SoundEngine::getInstance()->removeSource(this);
121  alDeleteSources(1, &this->sourceID);
122}
123
124/**
[4836]125 *  Plays back a SoundSource
[4504]126*/
127void SoundSource::play()
128{
129  alSourcePlay(this->sourceID);
130}
131
132/**
[4885]133 * Plays back buffer on this Source
134 * @param buffer the buffer to play back on this Source
135 */
136void SoundSource::play(const SoundBuffer* buffer)
137{
138  alSourcei (this->sourceID, AL_BUFFER, buffer->getID());
139  alSourcePlay(this->sourceID);
140
141  if (unlikely(this->buffer != NULL))
142    alSourcei (this->sourceID, AL_BUFFER, this->buffer->getID());
143}
144
145/**
[4836]146 *  Stops playback of a SoundSource
[4504]147*/
148void SoundSource::stop()
149{
150  alSourceStop(this->sourceID);
151}
152
153/**
[4836]154 *  Pauses Playback of a SoundSource
[4504]155*/
156void SoundSource::pause()
157{
158  alSourcePause(this->sourceID);
159}
160
161/**
[4836]162 *  Rewinds Playback of a SoundSource
[4504]163*/
164void SoundSource::rewind()
165{
166  alSourceRewind(this->sourceID);
167}
168
169/**
[4836]170 *  sets the RolloffFactor of the Sound emitted from the SoundSource
171 * @param rolloffFactor The Factor described
[4504]172
173   this tells openAL how fast the Sounds decay outward from the Source
174*/
175void SoundSource::setRolloffFactor(ALfloat rolloffFactor)
176{
177  alSourcef(this->sourceID, AL_ROLLOFF_FACTOR, rolloffFactor);
178}
179
180
181
182//////////////////
183/* SOUND-ENGINE */
184//////////////////
185/**
[4836]186 *  standard constructor
[4504]187*/
[4597]188SoundEngine::SoundEngine ()
[4504]189{
[4597]190  this->setClassID(CL_SOUND_ENGINE, "SoundEngine");
191  this->setName("SoundEngine");
192
[4504]193  this->listener = NULL;
194  this->bufferList = new tList<SoundBuffer>;
195  this->sourceList = new tList<SoundSource>;
196}
197
198/**
[4836]199 *  the singleton reference to this class
[4504]200*/
201SoundEngine* SoundEngine::singletonRef = NULL;
202
203/**
[4836]204 *  standard deconstructor
[4504]205
206*/
[4597]207SoundEngine::~SoundEngine ()
[4504]208{
209  SoundEngine::singletonRef = NULL;
210
211  // deleting all the SoundSources
212  tIterator<SoundSource>* sourceIterator = this->sourceList->getIterator();
213  SoundSource* enumSource = sourceIterator->nextElement();
214  while (enumSource)
215    {
216      delete enumSource;
217      enumSource = sourceIterator->nextElement();
218    }
219  delete sourceIterator;
220
221  // deleting all the SoundBuffers
222  tIterator<SoundBuffer>* bufferIterator = this->bufferList->getIterator();
223  SoundBuffer* enumBuffer = bufferIterator->nextElement();
224  while (enumBuffer)
225    {
226      ResourceManager::getInstance()->unload(enumBuffer);
227      enumBuffer = bufferIterator->nextElement();
228    }
229  delete bufferIterator;
230
231  // removing openAL from AudioResource
232  alutExit();
233}
234
235/**
[4836]236 *  creates a new SoundSource.
237 * @param fileName The Name to load the SoundBuffer from
238 * @param sourceNode The sourceNode to bind this SoundSource to.
239 * @returns The newly created SoundSource
[4504]240
241   acctualy this is nothing more than a wrapper around the ResourceManager.
242*/
243SoundSource* SoundEngine::createSource(const char* fileName, PNode* sourceNode)
244{
[4885]245  return new SoundSource(sourceNode, (SoundBuffer*)ResourceManager::getInstance()->load(fileName, WAV, RP_LEVEL));
[4504]246}
247
248
249/**
[4836]250 *  sets The listener (normaly the Camera)
[4504]251*/
252void SoundEngine::setListener(PNode* listener)
253{
254  this->listener = listener;
255}
256
257/**
[4836]258 *  Sets the doppler values of openAL
259 * @param dopplerFactor the extent of the doppler-effect
260 * @param dopplerVelocity the Speed the sound travels
[4504]261*/
262void SoundEngine::setDopplerValues(ALfloat dopplerFactor, ALfloat dopplerVelocity)
263{
264  alDopplerFactor(dopplerFactor);
265  alDopplerVelocity(dopplerVelocity);
266}
267
268
269/**
[4836]270 *  adds a SoundBuffer to the bufferList of the SoundEngine
271 * @param buffer The buffer to add to the bufferList
[4504]272*/
273void SoundEngine::addBuffer(SoundBuffer* buffer)
274{
275  this->bufferList->add(buffer);
276}
277
278/**
[4836]279 *  removes a SoundBuffer from the bufferList of the SoundEngine
280 * @param buffer The buffer to delete from the SoundEngine
[4504]281*/
282void SoundEngine::removeBuffer(SoundBuffer* buffer)
283{
284  // look if there are any sources that have the buffer still loaded
285  tIterator<SoundSource>* sourceIterator = this->sourceList->getIterator();
286  SoundSource* enumSource = sourceIterator->nextElement();
287  while (enumSource)
288    {
289      if (buffer == enumSource->getBuffer())
[4597]290        delete enumSource;
[4504]291      enumSource = sourceIterator->nextElement();
292    }
293  delete sourceIterator;
294
295  // remove the Buffer
296  this->bufferList->remove(buffer);
297}
298
299/**
[4836]300 *  adds a SoundSource to the sourceList of the SoundEngine
301 * @param source The source to add to the sourceList
[4504]302*/
303void SoundEngine::addSource(SoundSource* source)
304{
305  this->sourceList->add(source);
306}
307
308/**
[4836]309 *  removes a SoundSource from the sourceList of the SoundEngine
310 * @param source The source to delete from the SoundEngine
[4504]311*/
312void SoundEngine::removeSource(SoundSource* source)
313{
314  this->sourceList->remove(source);
315}
316
317
318/**
[4836]319 *  updates all The positions, Directions and Velocities of all Sounds
[4504]320*/
[4746]321void SoundEngine::update()
[4504]322{
323
324  // updating the Listeners Position
325  if (likely(this->listener != NULL))
326    {
327      alListener3f(AL_POSITION,
[4597]328                   this->listener->getAbsCoor().x,
329                   this->listener->getAbsCoor().y,
330                   this->listener->getAbsCoor().z);
[4504]331      alListener3f(AL_VELOCITY,
[4597]332                   this->listener->getVelocity().x,
333                   this->listener->getVelocity().y,
334                   this->listener->getVelocity().z);
[4504]335      Vector absDirV = this->listener->getAbsDirV();
336      ALfloat orientation [6] = {1,0,0, absDirV.x, absDirV.y, absDirV.z};
337      alListenerfv(AL_ORIENTATION, orientation);
338    }
339  else
340    PRINTF(2)("no listener defined\n");
341
342  // updating all the Sources positions
343  tIterator<SoundSource>* iterator = this->sourceList->getIterator();
344  SoundSource* enumSource = iterator->nextElement();
345  while (enumSource)
346    {
347      if (likely(enumSource->getNode()!=NULL))
348      {
[4597]349        alSource3f(enumSource->getID(), AL_POSITION,
350                   enumSource->getNode()->getAbsCoor().x,
351                   enumSource->getNode()->getAbsCoor().y,
352                   enumSource->getNode()->getAbsCoor().z);
353        alSource3f(enumSource->getID(), AL_VELOCITY,
354                   enumSource->getNode()->getVelocity().x,
355                   enumSource->getNode()->getVelocity().y,
356                   enumSource->getNode()->getVelocity().z);
[4504]357      }
358      enumSource = iterator->nextElement();
359    }
360  delete iterator;
361}
362
363/**
[4836]364 *  Removes all the Buffers that are not anymore needed by any Sources
[4504]365*/
[4746]366void SoundEngine::flushUnusedBuffers()
[4504]367{
368  tIterator<SoundBuffer>* bufferIterator = this->bufferList->getIterator();
369  SoundBuffer* enumBuffer = bufferIterator->nextElement();
370  while (enumBuffer)
371    {
372      tIterator<SoundSource>* sourceIterator = this->sourceList->getIterator();
373      SoundSource* enumSource = sourceIterator->nextElement();
374      while (enumSource)
[4597]375        {
376          if (enumBuffer == enumSource->getBuffer())
377            break;
378          enumSource = sourceIterator->nextElement();
379        }
[4504]380      delete sourceIterator;
381      if (enumSource == NULL)
[4597]382        ResourceManager::getInstance()->unload(enumBuffer);
[4504]383      enumBuffer = bufferIterator->nextElement();
384    }
385  delete bufferIterator;
386}
387
388/**
[4836]389 *  SourceEngine::flushAllBuffers
[4504]390*/
[4746]391void SoundEngine::flushAllBuffers()
[4504]392{
[4830]393  tIterator<SoundBuffer>* bufferIterator = this->bufferList->getIterator();
[4504]394  SoundBuffer* enumBuffer = bufferIterator->nextElement();
395  while (enumBuffer)
396    {
397      ResourceManager::getInstance()->unload(enumBuffer, RP_LEVEL);
398      enumBuffer = bufferIterator->nextElement();
399    }
400  delete bufferIterator;
401}
402
403/**
[4836]404  *  SourceEngine::flushAllBuffers
[4830]405 */
406void SoundEngine::flushAllSources()
407{
408  tIterator<SoundSource>* Iterator = this->sourceList->getIterator();
409  SoundSource* enumSource = Iterator->nextElement();
410  while (enumSource)
411  {
412    delete enumSource;
413    enumSource = Iterator->nextElement();
414  }
415  delete Iterator;
416}
417
418
419/**
[4836]420 *  initializes Audio in general
[4504]421*/
[4746]422bool SoundEngine::initAudio()
[4504]423{
424  ALenum result;
425
426  PRINTF(3)("Initialisazing openAL sound library\n");
427
428  alutInit(NULL, 0);
429  if ((result = alGetError()) != AL_NO_ERROR)
430    SoundEngine::PrintALErrorString(result);
431
432  this->setDopplerValues(SOUND_DOPPLER_FACTOR, SOUND_DOPPLER_VELOCITY);
433}
434
435/**
[4836]436 *  Transforms AL-errors into something readable
437 * @param err The error found
[4504]438*/
439void SoundEngine::PrintALErrorString(ALenum err)
440{
441  switch(err)
442    {
443    case AL_NO_ERROR:
444      PRINTF(4)("AL_NO_ERROR\n");
445      break;
[4597]446
[4504]447    case AL_INVALID_NAME:
448      PRINTF(2)("AL_INVALID_NAME\n");
449      break;
450
451    case AL_INVALID_ENUM:
452      PRINTF(2)("AL_INVALID_ENUM\n");
453      break;
454
455    case AL_INVALID_VALUE:
456      PRINTF(2)("AL_INVALID_VALUE\n");
457      break;
458
459    case AL_INVALID_OPERATION:
460      PRINTF(2)("AL_INVALID_OPERATION\n");
461      break;
462
463    case AL_OUT_OF_MEMORY:
464      PRINTF(2)("AL_OUT_OF_MEMORY\n");
465      break;
466    };
467}
468
[4959]469void SoundEngine::listDevices()
470{
471
472  printf("%s\n",(const char*)alcGetString(NULL, ALC_DEVICE_SPECIFIER));
473}
474
[4504]475/*
476void SoundEngine::PrintALCErrorString(ALenum err)
477{
478  switch(err)
479    {
480    case ALC_NO_ERROR:
481      PRINTF(4)("AL_NO_ERROR\n");
482      break;
483
484    case ALC_INVALID_DEVICE:
485      PRINTF(2)("ALC_INVALID_DEVICE\n");
486      break;
487
488    case ALC_INVALID_CONTEXT:
489      PRINTF(2)("ALC_INVALID_CONTEXT\n");
490      break;
491
492    case ALC_INVALID_ENUM:
493      PRINTF(2)("ALC_INVALID_ENUM\n");
494      break;
495
496    case ALC_INVALID_VALUE:
497      PRINTF(2)("ALC_INVALID_VALUE\n");
498      break;
499
500    case ALC_OUT_OF_MEMORY:
501      PRINTF(2)("ALC_OUT_OF_MEMORY\n");
502      break;
503    };
504}
505*/
Note: See TracBrowser for help on using the repository browser.