Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: the SoundEngine now gets the SoundBuffer- and SoundSource - Lists directly from the ClassList, and therefor we have much less overhead in the process of alocating deleting them (/2)

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