Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: orxonox runs again (the TrackManager produces speed)

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