Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10694 was 10618, checked in by bknecht, 18 years ago

merged cleanup into trunk (only improvements)

File size: 11.9 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_SOUND
20
21#include "sound_engine.h"
22
23#include "p_node.h"
24#include "debug.h"
25#include "parser/preferences/preferences.h"
26#include "orxonox_globals.h"
27#include "resource_sound_buffer.h"
28
29namespace OrxSound
30{
31  ObjectListDefinition(SoundEngine);
32  //////////////////
33  /* SOUND-ENGINE */
34  //////////////////
35  /**
36   * @brief standard constructor
37  */
38  SoundEngine::SoundEngine ()
39  {
40    this->registerObject(this, SoundEngine::_objectList);
41    this->setName("SoundEngine");
42
43    this->listener = NULL;
44
45    this->device = NULL;
46    this->context = NULL;
47
48    this->maxSourceCount = 32;
49
50    this->effectsVolume = .80;
51    this->musicVolume = .75;
52
53    this->sourceMutex = SDL_CreateMutex();
54  }
55
56  /**
57   * @brief the singleton reference to this class
58  */
59  SoundEngine* SoundEngine::singletonRef = NULL;
60
61  /**
62   * @brief standard destructor
63   */
64  SoundEngine::~SoundEngine ()
65  {
66    // deleting all the SoundSources
67    while (!SoundSource::objectList().empty())
68      delete (SoundSource::objectList().front());
69
70    while(!this->ALSources.empty())
71    {
72      if (alIsSource(this->ALSources.top()))
73      {
74        alDeleteSources(1, &this->ALSources.top());
75        SoundEngine::checkError("Deleting Source", __LINE__);
76      }
77      else
78        PRINTF(1)("%d is not a Source\n", this->ALSources.top());
79
80      this->ALSources.pop();
81    }
82
83    // deleting all the SoundBuffers
84    //    while(!SoundBuffer::objectList().empty())
85    //ResourceManager::getInstance()->unload(SoundBuffer::objectList().front());
86
87    // removing openAL from AudioResource
88    //! @todo this should be terminated through alc
89    //alutExit();
90
91    SDL_DestroyMutex(this->sourceMutex);
92
93    SoundEngine::singletonRef = NULL;
94  }
95
96  /**
97   * @brief loads the settings of the SoundEngine from an ini-file
98   */
99  void SoundEngine::loadSettings()
100  {
101    MultiType channels = Preferences::getInstance()->getString(CONFIG_SECTION_AUDIO, CONFIG_NAME_AUDIO_CHANNELS, "32");
102    this->maxSourceCount = channels.getInt();
103
104    MultiType effectsVolume = Preferences::getInstance()->getString(CONFIG_SECTION_AUDIO, CONFIG_NAME_EFFECTS_VOLUME, "80");
105    this->effectsVolume = effectsVolume.getFloat()/100.0;
106
107    MultiType musicVolume = Preferences::getInstance()->getString(CONFIG_SECTION_AUDIO, CONFIG_NAME_MUSIC_VOLUME, "75");
108    this->musicVolume = musicVolume.getFloat()/100.0;
109  }
110
111  /**
112   * @brief creates a new SoundSource.
113   * @param fileName The Name to load the SoundBuffer from
114   * @param sourceNode The sourceNode to bind this SoundSource to.
115   * @returns The newly created SoundSource
116   *
117   * acctualy this is nothing more than a wrapper around the ResourceManager.
118  */
119  SoundSource* SoundEngine::createSource(const std::string& fileName, PNode* sourceNode)
120  {
121    SoundBuffer buffer;
122    if (!fileName.empty())
123    {
124      buffer = ResourceSoundBuffer(fileName);
125      if (!buffer.loaded())
126        PRINTF(2)("Wav-Sound %s could not be loaded onto new Source\n", fileName.c_str());
127    }
128    return new SoundSource(sourceNode, buffer);
129  }
130
131  /**
132   * @brief Sets the doppler values of openAL
133   * @param dopplerFactor the extent of the doppler-effect
134   * @param dopplerVelocity the Speed the sound travels
135  */
136  void SoundEngine::setDopplerValues(ALfloat dopplerFactor, ALfloat dopplerVelocity)
137  {
138    alDopplerFactor(dopplerFactor);
139    this->checkError("Setting Doppler Factor", __LINE__);
140
141    alDopplerVelocity(dopplerVelocity);
142    this->checkError("Setting Doppler Velocity", __LINE__);
143  }
144
145
146  /**
147   * @brief retrieves an OpenAL Source from the availiable Sources.
148   * @param source the Source to fill with the Value.
149   */
150  void SoundEngine::popALSource(ALuint& source)
151  {
152    assert (source == 0);
153    /// @TODO try to create more sources if needed
154    if (!this->ALSources.empty())
155    {
156      SDL_mutexP(this->sourceMutex);
157      source = this->ALSources.top();
158      this->ALSources.pop();
159      SDL_mutexV(this->sourceMutex);
160    }
161  }
162
163
164  /**
165   * @brief Pushes an OpenAL Source back into the Stack of known sources
166   * @param source the Source to push onto the top of the SourceStack
167   */
168  void SoundEngine::pushALSource(ALuint& source)
169  {
170    if (source != 0)
171    {
172      SDL_mutexP(this->sourceMutex);
173      this->ALSources.push(source);
174      SDL_mutexV(this->sourceMutex);
175    }
176  };
177
178
179  /**
180   * @brief updates all The positions, Directions and Velocities of all Sounds
181   */
182  void SoundEngine::update()
183  {
184    // updating the Listeners Position
185    if (likely(this->listener != NULL))
186    {
187      alListener3f(AL_POSITION,
188                   this->listener->getAbsCoor().x,
189                   this->listener->getAbsCoor().y,
190                   this->listener->getAbsCoor().z);
191      alListener3f(AL_VELOCITY,
192                   this->listener->getVelocity().x,
193                   this->listener->getVelocity().y,
194                   this->listener->getVelocity().z);
195      Vector absDirV = this->listener->getAbsDirV();
196      ALfloat orientation [6] = {1,0,0, absDirV.x, absDirV.y, absDirV.z};
197      alListenerfv(AL_ORIENTATION, orientation);
198      SoundEngine::checkError("SoundEngine::update() - Listener Error", __LINE__);
199    }
200    else
201      PRINTF(2)("no listener defined\n");
202
203    // updating all the Sources positions
204    ObjectList<SoundSource>::const_iterator sourceIT;
205    for (sourceIT = SoundSource::objectList().begin();
206         sourceIT != SoundSource::objectList().end();
207         sourceIT++)
208    {
209      if ((*sourceIT)->isPlaying())
210      {
211        int play = 0x000;
212        alGetSourcei((*sourceIT)->getID(), AL_SOURCE_STATE, &play);
213        if (DEBUG_LEVEL > 2)
214          SoundEngine::checkError("SoundEngine::update() Play", __LINE__);
215        if(play == AL_PLAYING)
216        {
217          if (likely((*sourceIT)->getNode() != NULL))
218          {
219            alSource3f((*sourceIT)->getID(), AL_POSITION,
220                       (*sourceIT)->getNode()->getAbsCoor().x,
221                       (*sourceIT)->getNode()->getAbsCoor().y,
222                       (*sourceIT)->getNode()->getAbsCoor().z);
223            if (DEBUG_LEVEL > 2)
224              SoundEngine::checkError("SoundEngine::update() Set Source Position", __LINE__);
225            alSource3f((*sourceIT)->getID(), AL_VELOCITY,
226                       (*sourceIT)->getNode()->getVelocity().x,
227                       (*sourceIT)->getNode()->getVelocity().y,
228                       (*sourceIT)->getNode()->getVelocity().z);
229            if (DEBUG_LEVEL > 2)
230              SoundEngine::checkError("SoundEngine::update() Set Source Velocity", __LINE__);
231          }
232        }
233        else
234        {
235          (*sourceIT)->stop();
236        }
237      }
238    }
239    SoundEngine::checkError("SoundEngine::update()", __LINE__);
240  }
241
242
243  /**
244   *  initializes Audio in general
245  */
246  bool SoundEngine::initAudio()
247  {
248    //   ALenum result;
249    //   PRINTF(3)("Initialisazing openAL sound engine\n");
250    //   const char* defaultDevice =(const char*) alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
251    //   const char* deviceList = (const char*)alcGetString(NULL,ALC_DEVICE_SPECIFIER);
252    //   const char* devWalk = deviceList;
253    //   //  if (alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE)
254    //   { // try out enumeration extension
255    //     PRINTF(3)("Enumeration-extension found\n");
256    //
257    //     PRINTF(3)("Default device: %s\n", defaultDevice);
258    //     do
259    //     {
260    //       PRINTF(3)("%s\n", devWalk);
261    //       devWalk += strlen(devWalk)+1;
262    //     }
263    //     while (devWalk[0] != '\0');
264    //  }
265
266    // INITIALIZING THE DEVICE:
267    //   char deviceName[] =
268    //   #ifdef __WIN32__
269    //     "Direct3D";
270    //   #else
271    //     "'( ( devices '( native null ) ) )";
272    //   #endif
273
274    this->device = alcOpenDevice(NULL);
275    this->checkALCError("opening Device", __LINE__);
276
277    PRINTF(4)("Audio-Specifier: %s\n", (const char*)alcGetString(this->device, ALC_DEVICE_SPECIFIER));
278    PRINTF(4)("Audio-Extensions: %s\n", (const char*)alcGetString(this->device, ALC_EXTENSIONS));
279
280
281    this->context = alcCreateContext(this->device, NULL);
282    this->checkALCError("creating Context", __LINE__);
283
284    alcMakeContextCurrent(this->context);
285    this->checkALCError("making Context Current", __LINE__);
286    // #endif
287
288    this->setDopplerValues(SOUND_DOPPLER_FACTOR, SOUND_DOPPLER_VELOCITY);
289    this->allocateSources(this->maxSourceCount);
290    this->checkError("Allocating Sources", __LINE__);
291
292    return true;
293  }
294
295
296  /**
297   * Allocates openAL sources
298   * @param count how many sources to allocate
299   * @returns true on success, false if at least one source could not be allocated
300   */
301  bool SoundEngine::allocateSources(unsigned int count)
302  {
303    unsigned int failCount = 0;
304    for (unsigned int i = 0; i < count; i++)
305    {
306      ALuint source = 0;
307
308      alGenSources(1, &source);
309      this->checkError("allocate Source", __LINE__);
310      if (!alIsSource(source))
311      {
312        PRINTF(5)("not allocated Source\n");
313        failCount++;
314        continue;
315      }
316
317      alSourcef (source, AL_PITCH,    1.0      );
318      alSourcef (source, AL_GAIN,     this->getEffectsVolume() );
319      alSourcei (source, AL_LOOPING,  AL_FALSE );
320      this->ALSources.push(source);
321    }
322    if (failCount == 0)
323      return true;
324    else
325    {
326      PRINTF(2)("Failed to allocate %d of %d SoundSources\n", failCount, count);
327      return false;
328    }
329  }
330
331  /**
332   * @brief checks for an OpenAL error
333   * @param error the ErrorMessage to display
334   * @param line on what line did the error occure.
335   */
336  bool SoundEngine::checkError(const std::string& error, unsigned int line)
337  {
338    ALenum errorCode;
339    if ((errorCode = alGetError()) != AL_NO_ERROR)
340    {
341      //PRINTF(1)("Error %s (line:%d): '%s'\n", error.c_str(), line, SoundEngine::getALErrorString(errorCode));
342      return false;
343    }
344    else
345      return true;
346  }
347
348  /**
349   * @brief check for an ALC error.
350   * @brief error the Error-String to display
351   * @param line on that line, the error occured (debugging mode).
352   */
353  bool SoundEngine::checkALCError(const std::string& error, unsigned int line)
354  {
355    ALenum errorCode;
356    if ((errorCode = alcGetError(this->device)) != ALC_NO_ERROR)
357    {
358      PRINTF(1)("Error %s (line:%d): '%s'\n", error.c_str(), line, SoundEngine::getALCErrorString(errorCode));
359      return false;
360    }
361    else
362      return true;
363  }
364
365
366
367  void SoundEngine::listDevices()
368  {
369    printf("%s\n",(const char*)alcGetString(NULL, ALC_DEVICE_SPECIFIER));
370  }
371
372  /**
373   *  Transforms AL-errors into something readable
374   * @param err The error found
375  */
376  const char* SoundEngine::getALErrorString(ALenum err)
377  {
378    switch(err)
379    {
380      default:
381      case AL_NO_ERROR:
382      return ("AL_NO_ERROR");
383      case AL_INVALID_NAME:
384      return ("AL_INVALID_NAME");
385      case AL_INVALID_ENUM:
386      return ("AL_INVALID_ENUM");
387      case AL_INVALID_VALUE:
388      return ("AL_INVALID_VALUE");
389      case AL_INVALID_OPERATION:
390      return ("AL_INVALID_OPERATION");
391      case AL_OUT_OF_MEMORY:
392      return ("AL_OUT_OF_MEMORY");
393    };
394  }
395
396
397  const char* SoundEngine::getALCErrorString(ALenum err)
398  {
399    switch(err)
400    {
401      default:
402      case ALC_NO_ERROR:
403      return ("AL_NO_ERROR");
404      case ALC_INVALID_DEVICE:
405      return ("ALC_INVALID_DEVICE");
406      case ALC_INVALID_CONTEXT:
407      return("ALC_INVALID_CONTEXT");
408      case ALC_INVALID_ENUM:
409      return("ALC_INVALID_ENUM");
410      case ALC_INVALID_VALUE:
411      return ("ALC_INVALID_VALUE");
412      case ALC_OUT_OF_MEMORY:
413      return("ALC_OUT_OF_MEMORY");
414    };
415  }
416}
Note: See TracBrowser for help on using the repository browser.