Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

merged cleanup into trunk (only improvements)

File size: 11.9 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
23#include "p_node.h"
24#include "debug.h"
[9869]25#include "parser/preferences/preferences.h"
[10618]26#include "orxonox_globals.h"
[9869]27#include "resource_sound_buffer.h"
[4504]28
[7460]29namespace OrxSound
[4504]30{
[9869]31  ObjectListDefinition(SoundEngine);
[7460]32  //////////////////
33  /* SOUND-ENGINE */
34  //////////////////
35  /**
36   * @brief standard constructor
37  */
38  SoundEngine::SoundEngine ()
39  {
[9869]40    this->registerObject(this, SoundEngine::_objectList);
[7460]41    this->setName("SoundEngine");
[5930]42
[7460]43    this->listener = NULL;
[5930]44
[7460]45    this->device = NULL;
46    this->context = NULL;
[6829]47
[7460]48    this->maxSourceCount = 32;
[7298]49
[7460]50    this->effectsVolume = .80;
51    this->musicVolume = .75;
[4504]52
[7460]53    this->sourceMutex = SDL_CreateMutex();
[4960]54  }
[4504]55
[7460]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 ()
[5930]65  {
[7460]66    // deleting all the SoundSources
[9869]67    while (!SoundSource::objectList().empty())
68      delete (SoundSource::objectList().front());
[7291]69
[7460]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());
[5930]79
[7460]80      this->ALSources.pop();
81    }
[5293]82
[7460]83    // deleting all the SoundBuffers
[9869]84    //    while(!SoundBuffer::objectList().empty())
85    //ResourceManager::getInstance()->unload(SoundBuffer::objectList().front());
[5293]86
[7460]87    // removing openAL from AudioResource
88    //! @todo this should be terminated through alc
89    //alutExit();
[7298]90
[7460]91    SDL_DestroyMutex(this->sourceMutex);
[4504]92
[7460]93    SoundEngine::singletonRef = NULL;
94  }
[4985]95
[7460]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();
[6830]103
[7460]104    MultiType effectsVolume = Preferences::getInstance()->getString(CONFIG_SECTION_AUDIO, CONFIG_NAME_EFFECTS_VOLUME, "80");
105    this->effectsVolume = effectsVolume.getFloat()/100.0;
[4985]106
[7460]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)
[7318]120  {
[9869]121    SoundBuffer buffer;
[7460]122    if (!fileName.empty())
123    {
[9869]124      buffer = ResourceSoundBuffer(fileName);
125      if (!buffer.loaded())
[7460]126        PRINTF(2)("Wav-Sound %s could not be loaded onto new Source\n", fileName.c_str());
127    }
128    return new SoundSource(sourceNode, buffer);
[7318]129  }
[4504]130
[7460]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__);
[6840]140
[7460]141    alDopplerVelocity(dopplerVelocity);
142    this->checkError("Setting Doppler Velocity", __LINE__);
143  }
[4504]144
145
[7460]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)
[5930]151  {
[7460]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    }
[7284]161  }
[4504]162
[7299]163
[7460]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)
[7298]169  {
[7460]170    if (source != 0)
171    {
172      SDL_mutexP(this->sourceMutex);
173      this->ALSources.push(source);
174      SDL_mutexV(this->sourceMutex);
175    }
176  };
[4504]177
[7298]178
[7460]179  /**
180   * @brief updates all The positions, Directions and Velocities of all Sounds
181   */
182  void SoundEngine::update()
[6846]183  {
[7460]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");
[4504]202
[7460]203    // updating all the Sources positions
[9869]204    ObjectList<SoundSource>::const_iterator sourceIT;
205    for (sourceIT = SoundSource::objectList().begin();
206         sourceIT != SoundSource::objectList().end();
207         sourceIT++)
[4504]208    {
[9869]209      if ((*sourceIT)->isPlaying())
[4504]210      {
[9869]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)
[5930]216        {
[9869]217          if (likely((*sourceIT)->getNode() != NULL))
[5930]218          {
[9869]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__);
[5930]231          }
232        }
[9869]233        else
234        {
235          (*sourceIT)->stop();
236        }
[4504]237      }
238    }
[7460]239    SoundEngine::checkError("SoundEngine::update()", __LINE__);
[4960]240  }
[4504]241
242
[7460]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    //  }
[4504]265
[7460]266    // INITIALIZING THE DEVICE:
267    //   char deviceName[] =
268    //   #ifdef __WIN32__
269    //     "Direct3D";
270    //   #else
271    //     "'( ( devices '( native null ) ) )";
272    //   #endif
[5385]273
[7460]274    this->device = alcOpenDevice(NULL);
275    this->checkALCError("opening Device", __LINE__);
[5819]276
[7460]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));
[6849]279
[6856]280
[7460]281    this->context = alcCreateContext(this->device, NULL);
282    this->checkALCError("creating Context", __LINE__);
[6849]283
[7460]284    alcMakeContextCurrent(this->context);
285    this->checkALCError("making Context Current", __LINE__);
286    // #endif
[5819]287
[7460]288    this->setDopplerValues(SOUND_DOPPLER_FACTOR, SOUND_DOPPLER_VELOCITY);
289    this->allocateSources(this->maxSourceCount);
290    this->checkError("Allocating Sources", __LINE__);
[8350]291
292    return true;
[7460]293  }
[4504]294
[5917]295
[7460]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)
[5917]302  {
[7460]303    unsigned int failCount = 0;
304    for (unsigned int i = 0; i < count; i++)
305    {
306      ALuint source = 0;
[5917]307
[7460]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
[6842]325    {
[7460]326      PRINTF(2)("Failed to allocate %d of %d SoundSources\n", failCount, count);
[8350]327      return false;
[6842]328    }
[5917]329  }
330
[7460]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)
[6836]337  {
[7460]338    ALenum errorCode;
339    if ((errorCode = alGetError()) != AL_NO_ERROR)
340    {
[9235]341      //PRINTF(1)("Error %s (line:%d): '%s'\n", error.c_str(), line, SoundEngine::getALErrorString(errorCode));
[7460]342      return false;
343    }
344    else
345      return true;
[6836]346  }
347
[7460]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)
[6849]354  {
[7460]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;
[6849]363  }
364
365
366
[7460]367  void SoundEngine::listDevices()
368  {
369    printf("%s\n",(const char*)alcGetString(NULL, ALC_DEVICE_SPECIFIER));
370  }
[6849]371
[7460]372  /**
373   *  Transforms AL-errors into something readable
374   * @param err The error found
375  */
376  const char* SoundEngine::getALErrorString(ALenum err)
[6846]377  {
[7460]378    switch(err)
379    {
[8350]380      default:
381      case AL_NO_ERROR:
[9869]382      return ("AL_NO_ERROR");
[8350]383      case AL_INVALID_NAME:
[9869]384      return ("AL_INVALID_NAME");
[8350]385      case AL_INVALID_ENUM:
[9869]386      return ("AL_INVALID_ENUM");
[8350]387      case AL_INVALID_VALUE:
[9869]388      return ("AL_INVALID_VALUE");
[8350]389      case AL_INVALID_OPERATION:
[9869]390      return ("AL_INVALID_OPERATION");
[8350]391      case AL_OUT_OF_MEMORY:
[9869]392      return ("AL_OUT_OF_MEMORY");
[7460]393    };
394  }
[4504]395
[4959]396
[7460]397  const char* SoundEngine::getALCErrorString(ALenum err)
[7284]398  {
[7460]399    switch(err)
400    {
[8350]401      default:
402      case ALC_NO_ERROR:
[9869]403      return ("AL_NO_ERROR");
[8350]404      case ALC_INVALID_DEVICE:
[9869]405      return ("ALC_INVALID_DEVICE");
[8350]406      case ALC_INVALID_CONTEXT:
[9869]407      return("ALC_INVALID_CONTEXT");
[8350]408      case ALC_INVALID_ENUM:
[9869]409      return("ALC_INVALID_ENUM");
[8350]410      case ALC_INVALID_VALUE:
[9869]411      return ("ALC_INVALID_VALUE");
[8350]412      case ALC_OUT_OF_MEMORY:
[9869]413      return("ALC_OUT_OF_MEMORY");
[7460]414    };
415  }
[4504]416}
Note: See TracBrowser for help on using the repository browser.