Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/new_class_id/src/lib/sound/sound_engine.cc @ 9805

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

orxonox/new_class_id: SoundSource completely added as a Resource

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