Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/openAL/src/lib/sound/sound_engine.cc @ 4225

Last change on this file since 4225 was 4219, checked in by bensch, 20 years ago

orxonox/branches/openAL: audio Buffers will be flushed at the End of the Level

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