Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/orxonox/branches/oggPlayer/src/lib/sound/sound_engine.cc @ 4629

Last change on this file since 4629 was 4601, checked in by patrick, 20 years ago

orxonox/trunk: made sound engine cross-platform compilable

File size: 11.7 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 __UNIX__
61  alutLoadWAVFile((ALbyte*)fileName, &format, &data, &this->size, &freq, &this->loop);
62#elifdef __APPLE__
63  alutLoadWAVFile(fileName, &format, &data, &size, &freq);
64#elifdef __WIN32__
65  alutLoadWAVFile(fileName, &format, &data, &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(void)
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(void)
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(void)
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(void)
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(void)
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 initializes Audio in general
392*/
393bool SoundEngine::initAudio(void)
394{
395  ALenum result;
396
397  PRINTF(3)("Initialisazing openAL sound library\n");
398
399  alutInit(NULL, 0);
400  if ((result = alGetError()) != AL_NO_ERROR)
401    SoundEngine::PrintALErrorString(result);
402
403  this->setDopplerValues(SOUND_DOPPLER_FACTOR, SOUND_DOPPLER_VELOCITY);
404}
405
406/**
407   \brief Transforms AL-errors into something readable
408   \param err The error found
409*/
410void SoundEngine::PrintALErrorString(ALenum err)
411{
412  switch(err)
413    {
414    case AL_NO_ERROR:
415      PRINTF(4)("AL_NO_ERROR\n");
416      break;
417
418    case AL_INVALID_NAME:
419      PRINTF(2)("AL_INVALID_NAME\n");
420      break;
421
422    case AL_INVALID_ENUM:
423      PRINTF(2)("AL_INVALID_ENUM\n");
424      break;
425
426    case AL_INVALID_VALUE:
427      PRINTF(2)("AL_INVALID_VALUE\n");
428      break;
429
430    case AL_INVALID_OPERATION:
431      PRINTF(2)("AL_INVALID_OPERATION\n");
432      break;
433
434    case AL_OUT_OF_MEMORY:
435      PRINTF(2)("AL_OUT_OF_MEMORY\n");
436      break;
437    };
438}
439
440/*
441void SoundEngine::PrintALCErrorString(ALenum err)
442{
443  switch(err)
444    {
445    case ALC_NO_ERROR:
446      PRINTF(4)("AL_NO_ERROR\n");
447      break;
448
449    case ALC_INVALID_DEVICE:
450      PRINTF(2)("ALC_INVALID_DEVICE\n");
451      break;
452
453    case ALC_INVALID_CONTEXT:
454      PRINTF(2)("ALC_INVALID_CONTEXT\n");
455      break;
456
457    case ALC_INVALID_ENUM:
458      PRINTF(2)("ALC_INVALID_ENUM\n");
459      break;
460
461    case ALC_INVALID_VALUE:
462      PRINTF(2)("ALC_INVALID_VALUE\n");
463      break;
464
465    case ALC_OUT_OF_MEMORY:
466      PRINTF(2)("ALC_OUT_OF_MEMORY\n");
467      break;
468    };
469}
470*/
Note: See TracBrowser for help on using the repository browser.