Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: merged the SoundEngine into the Trunk.
merged file by file, but merged all the files in favor of the new trunk

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