Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/branches/openAL: added flush-function i talked of in the Wiki

File size: 9.9 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,  true     );
98}
99
100SoundSource::~SoundSource(void)
101{
102  SoundEngine::getInstance()->removeSource(this);
103  alDeleteSources(1, &this->sourceID);
104}
105
106
107/**
108   \brief Plays back a SoundSource
109*/
110void SoundSource::play()
111{
112  alSourcePlay(this->sourceID);
113}
114
115/**
116   \brief Stops playback of a SoundSource
117*/
118void SoundSource::stop()
119{
120  alSourceStop(this->sourceID);
121}
122
123/**
124   \brief Pauses Playback of a SoundSource
125*/
126void SoundSource::pause()
127{
128  alSourcePause(this->sourceID);
129}
130
131/**
132   \brief Rewinds Playback of a SoundSource
133*/
134void SoundSource::rewind()
135{
136  alSourceRewind(this->sourceID);
137}
138
139/**
140   \brief sets the RolloffFactor of the Sound emitted from the SoundSource
141   \param rolloffFactor The Factor described
142
143   this tells openAL how fast the Sounds decay outward from the Source
144*/
145void SoundSource::setRolloffFactor(ALfloat rolloffFactor)
146{
147  alSourcef(this->sourceID, AL_ROLLOFF_FACTOR, rolloffFactor);
148}
149
150
151
152//////////////////
153/* SOUND-ENGINE */
154//////////////////
155/**
156   \brief standard constructor
157*/
158SoundEngine::SoundEngine () 
159{
160  this->setClassName ("SoundEngine");
161   
162   this->initAudio();
163
164   this->listener = NULL;
165   this->bufferList = new tList<SoundBuffer>;
166   this->sourceList = new tList<SoundSource>;
167}
168
169/**
170   \brief the singleton reference to this class
171*/
172SoundEngine* SoundEngine::singletonRef = NULL;
173
174/**
175   \returns a Pointer to this Class
176*/
177SoundEngine* SoundEngine::getInstance(void)
178{
179  if (!SoundEngine::singletonRef)
180    SoundEngine::singletonRef = new SoundEngine();
181  return SoundEngine::singletonRef;
182}
183
184/**
185   \brief standard deconstructor
186
187*/
188SoundEngine::~SoundEngine () 
189{
190  SoundEngine::singletonRef = NULL;
191
192  // deleting all the SoundSources
193  tIterator<SoundSource>* sourceIterator = this->sourceList->getIterator();
194  SoundSource* enumSource = sourceIterator->nextElement();
195  while (enumSource)
196    {
197      delete enumSource;
198      enumSource = sourceIterator->nextElement();
199    }
200  delete sourceIterator;
201
202  // deleting all the SoundBuffers
203  tIterator<SoundBuffer>* bufferIterator = this->bufferList->getIterator();
204  SoundBuffer* enumBuffer = bufferIterator->nextElement();
205  while (enumBuffer)
206    {
207      ResourceManager::getInstance()->unload(enumBuffer);
208      enumBuffer = bufferIterator->nextElement();
209    }
210  delete bufferIterator;
211}
212
213/**
214   \brief creates a new SoundSource.
215   \param fileName The Name to load the SoundBuffer from
216   \param sourceNode The sourceNode to bind this SoundSource to.
217   \returns The newly created SoundSource
218
219   acctualy this is nothing more than a wrapper around the ResourceManager.
220*/
221SoundSource* SoundEngine::createSource(const char* fileName, PNode* sourceNode)
222{
223  return new SoundSource((SoundBuffer*)ResourceManager::getInstance()->load(fileName, WAV, RP_LEVEL), sourceNode);
224}
225
226
227/**
228   \brief sets The listener (normaly the Camera)
229*/
230void SoundEngine::setListener(PNode* listener)
231{
232  this->listener = listener;
233}
234
235/**
236   \brief adds a SoundBuffer to the bufferList of the SoundEngine
237   \param buffer The buffer to add to the bufferList
238*/
239void SoundEngine::addBuffer(SoundBuffer* buffer)
240{
241  this->bufferList->add(buffer);
242}
243
244/**
245   \brief removes a SoundBuffer from the bufferList of the SoundEngine
246   \param buffer The buffer to delete from the SoundEngine
247*/
248void SoundEngine::removeBuffer(SoundBuffer* buffer)
249{
250  this->bufferList->remove(buffer);
251}
252
253/**
254   \brief adds a SoundSource to the sourceList of the SoundEngine
255   \param source The source to add to the sourceList
256*/
257void SoundEngine::addSource(SoundSource* source)
258{
259  this->sourceList->add(source);
260}
261
262/**
263   \brief removes a SoundSource from the sourceList of the SoundEngine
264   \param source The source to delete from the SoundEngine
265*/
266void SoundEngine::removeSource(SoundSource* source)
267{
268  this->sourceList->remove(source);
269}
270
271
272/**
273   \brief updates all The positions, Directions and Velocities of all Sounds
274*/
275void SoundEngine::update(void)
276{
277
278  // updating the Listeners Position
279  if (likely(this->listener != NULL))
280    {
281      alListener3f(AL_POSITION,
282                   this->listener->getAbsCoor().x,
283                   this->listener->getAbsCoor().y,
284                   this->listener->getAbsCoor().z);
285      alListener3f(AL_VELOCITY,
286                   this->listener->getVelocity().x,
287                   this->listener->getVelocity().y,
288                   this->listener->getVelocity().z);
289      Vector absDirV = this->listener->getAbsDirV();
290      ALfloat orientation [6] = {1,0,0, absDirV.x, absDirV.y, absDirV.z};
291      alListenerfv(AL_ORIENTATION, orientation);
292    }
293  else
294    PRINTF(2)("no listener defined\n");
295
296  // updating all the Sources positions
297  tIterator<SoundSource>* iterator = this->sourceList->getIterator();
298  SoundSource* enumSource = iterator->nextElement();
299  while (enumSource)
300    {
301      if (likely(enumSource->getNode()!=NULL))
302      {
303        alSource3f(enumSource->getID(), AL_POSITION,
304                   enumSource->getNode()->getAbsCoor().x,
305                   enumSource->getNode()->getAbsCoor().y,
306                   enumSource->getNode()->getAbsCoor().z);
307        alSource3f(enumSource->getID(), AL_VELOCITY,
308                   enumSource->getNode()->getVelocity().x,
309                   enumSource->getNode()->getVelocity().y,
310                   enumSource->getNode()->getVelocity().z);
311      }
312      enumSource = iterator->nextElement();
313    }
314  delete iterator;
315}
316
317/**
318   \brief Removes all the Buffers that are not anymore needed by any Sources
319*/
320void SoundEngine::flushUnusedBuffers(void)
321{
322  tIterator<SoundBuffer>* bufferIterator = this->bufferList->getIterator();
323  SoundBuffer* enumBuffer = bufferIterator->nextElement();
324  while (enumBuffer)
325    {
326      tIterator<SoundSource>* sourceIterator = this->sourceList->getIterator();
327      SoundSource* enumSource = sourceIterator->nextElement();
328      while (enumSource)
329        {
330          if (enumBuffer == enumSource->getBuffer())
331            break;
332          enumSource = sourceIterator->nextElement();
333        }
334      delete sourceIterator;
335      if (enumSource == NULL)
336        ResourceManager::getInstance()->unload(enumBuffer);
337      enumBuffer = bufferIterator->nextElement();
338    }
339  delete bufferIterator;
340}
341
342/**
343   \brief initializes Audio in general
344*/
345bool SoundEngine::initAudio(void)
346{
347  alutInit(NULL, 0);
348  alGetError();
349
350  alDopplerFactor(SOUND_DOPPLER_FACTOR);
351  alDopplerVelocity(SOUND_DOPPLER_VELOCITY);
352}
353
354/**
355   \brief Transforms AL-errors into something readable
356   \param err The error found
357*/
358void SoundEngine::PrintALErrorString(ALenum err)
359{
360  switch(err)
361    {
362    case AL_NO_ERROR:
363      PRINTF(4)("AL_NO_ERROR\n");
364      break;
365     
366    case AL_INVALID_NAME:
367      PRINTF(2)("AL_INVALID_NAME\n");
368      break;
369
370    case AL_INVALID_ENUM:
371      PRINTF(2)("AL_INVALID_ENUM\n");
372      break;
373
374    case AL_INVALID_VALUE:
375      PRINTF(2)("AL_INVALID_VALUE\n");
376      break;
377
378    case AL_INVALID_OPERATION:
379      PRINTF(2)("AL_INVALID_OPERATION\n");
380      break;
381
382    case AL_OUT_OF_MEMORY:
383      PRINTF(2)("AL_OUT_OF_MEMORY\n");
384      break;
385    };
386}
387
388/*
389void SoundEngine::PrintALCErrorString(ALenum err)
390{
391  switch(err)
392    {
393    case ALC_NO_ERROR:
394      PRINTF(4)("AL_NO_ERROR\n");
395      break;
396
397    case ALC_INVALID_DEVICE:
398      PRINTF(2)("ALC_INVALID_DEVICE\n");
399      break;
400
401    case ALC_INVALID_CONTEXT:
402      PRINTF(2)("ALC_INVALID_CONTEXT\n");
403      break;
404
405    case ALC_INVALID_ENUM:
406      PRINTF(2)("ALC_INVALID_ENUM\n");
407      break;
408
409    case ALC_INVALID_VALUE:
410      PRINTF(2)("ALC_INVALID_VALUE\n");
411      break;
412
413    case ALC_OUT_OF_MEMORY:
414      PRINTF(2)("ALC_OUT_OF_MEMORY\n");
415      break;
416    };
417}
418*/
Note: See TracBrowser for help on using the repository browser.