Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 4834 was 4830, checked in by bensch, 20 years ago

orxonox/trunk: implemented aim

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