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