Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/cleanup/src/lib/sound/sound_engine.cc @ 10572

Last change on this file since 10572 was 10571, checked in by bensch, 18 years ago

cleaned out unused defs files, and moved glincl to grafics, alincl.h to sound

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.