Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: renamed all the \param → @param and so on in Doxygen tags.
Thanks a lot to the kDevelop team. this took since the last commit :)

File size: 11.8 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 *  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 *  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 *  deletes a SoundSource
116*/
117SoundSource::~SoundSource()
118{
119  SoundEngine::getInstance()->removeSource(this);
120  alDeleteSources(1, &this->sourceID);
121}
122
123
124/**
125 *  Plays back a SoundSource
126*/
127void SoundSource::play()
128{
129  alSourcePlay(this->sourceID);
130}
131
132/**
133 *  Stops playback of a SoundSource
134*/
135void SoundSource::stop()
136{
137  alSourceStop(this->sourceID);
138}
139
140/**
141 *  Pauses Playback of a SoundSource
142*/
143void SoundSource::pause()
144{
145  alSourcePause(this->sourceID);
146}
147
148/**
149 *  Rewinds Playback of a SoundSource
150*/
151void SoundSource::rewind()
152{
153  alSourceRewind(this->sourceID);
154}
155
156/**
157 *  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 *  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 *  the singleton reference to this class
187*/
188SoundEngine* SoundEngine::singletonRef = NULL;
189
190/**
191 *  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 *  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 *  sets The listener (normaly the Camera)
238*/
239void SoundEngine::setListener(PNode* listener)
240{
241  this->listener = listener;
242}
243
244/**
245 *  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 *  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 *  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 *  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 *  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 *  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 *  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 *  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  *  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 *  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 *  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.