Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

fixed out some warnings

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