Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation2/src/orxonox/sound/SoundManager.cc @ 6241

Last change on this file since 6241 was 6241, checked in by youngk, 15 years ago

Changed COUT level from three to four, because showing volume change isn't really needed right now (at least in my opinion)

  • Property svn:eol-style set to native
File size: 17.0 KB
RevLine 
[3060]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *       Erwin 'vaiursch' Herrsche
[6117]24 *       Kevin Young
[3060]25 *   Co-authors:
26 *      ...
27 *
28 */
29
[3196]30#include "SoundManager.h"
31
[3060]32#include <AL/alut.h>
[6117]33#include <utility>
[3060]34
[5929]35#include "util/Exception.h"
[3196]36#include "util/Math.h"
[5929]37#include "util/ScopeGuard.h"
[6117]38#include "util/StringUtils.h"
39#include "util/Clock.h"
[6203]40#include "core/ConfigValueIncludes.h"
[5929]41#include "core/GameMode.h"
42#include "core/ScopedSingletonManager.h"
[6203]43#include "core/Resource.h"
44#include "SoundBuffer.h"
[6117]45#include "BaseSound.h"
46#include "AmbientSound.h"
[6184]47#include "WorldSound.h"
[3060]48
49namespace orxonox
50{
[5929]51    ManageScopedSingleton(SoundManager, ScopeID::Graphics, true);
[3060]52
53    SoundManager::SoundManager()
54    {
[6117]55        RegisterRootObject(SoundManager);
56
[6237]57/*
[6117]58        if (!alutInitWithoutContext(NULL, NULL))
[6237]59*/
60        if (!alutInit(NULL, NULL))
[6117]61            ThrowException(InitialisationFailed, "Sound: OpenAL ALUT error: " << alutGetErrorString(alutGetError()));
[5929]62        Loki::ScopeGuard alutExitGuard = Loki::MakeGuard(&alutExit);
63
[6237]64        // Note: Everything related to ALC has been commented because there seem to be
65        // very serious problems with the unloading sequence (complete freeze on Linux,
66        // sometimes really everything gone, including response to any signals).
67        // For the moment ALUT can do everything we need so far.
68/*
[6117]69        COUT(3) << "Sound: OpenAL: Opening sound device..." << std::endl;
[5929]70        this->device_ = alcOpenDevice(NULL);
71        if (this->device_ == NULL)
[3060]72        {
[6117]73            COUT(0) << "Sound: OpenaAL: Could not open sound device. Have you installed OpenAL?" << std::endl;
[5929]74#ifdef ORXONOX_PLATFORM_WINDOWS
[6117]75            COUT(0) << "Sound: Just getting the DLL with the dependencies is not enough for Windows (esp. Windows 7)!" << std::endl;
[5929]76#endif
[6117]77            ThrowException(InitialisationFailed, "Sound: OpenAL error: Could not open sound device.");
[3060]78        }
[5929]79        Loki::ScopeGuard closeDeviceGuard = Loki::MakeGuard(&alcCloseDevice, this->device_);
80
[6117]81        COUT(3) << "Sound: OpenAL: Sound device opened" << std::endl;
[5929]82        this->context_ = alcCreateContext(this->device_, NULL);
83        if (this->context_ == NULL)
[6117]84            ThrowException(InitialisationFailed, "Sound: OpenAL error: Could not create sound context");
[5929]85        Loki::ScopeGuard desroyContextGuard = Loki::MakeGuard(&alcDestroyContext, this->context_);
86
87        if (alcMakeContextCurrent(this->context_) == AL_TRUE)
[6117]88            COUT(3) << "Sound: OpenAL: Context " << this->context_ << " loaded" << std::endl;
[5929]89
90        COUT(4) << "Sound: OpenAL ALUT version: " << alutGetMajorVersion() << "." << alutGetMinorVersion() << std::endl;
91
92        const char* str = alutGetMIMETypes(ALUT_LOADER_BUFFER);
93        if (str == NULL)
[6117]94            COUT(2) << "Sound: OpenAL ALUT error: " << alutGetErrorString(alutGetError()) << std::endl;
[3060]95        else
[6117]96            COUT(4) << "Sound: OpenAL ALUT supported MIME types: " << str << std::endl;
[6237]97*/
[3060]98
[5929]99        GameMode::setPlaysSound(true);
100        // Disarm guards
101        alutExitGuard.Dismiss();
[6237]102/*
[5929]103        closeDeviceGuard.Dismiss();
104        desroyContextGuard.Dismiss();
[6237]105*/
[6184]106       
[6186]107        this->setVolumeInternal(1.0, SoundType::none);
108        this->setVolumeInternal(1.0, SoundType::ambient);
109        this->setVolumeInternal(1.0, SoundType::effects);
110       
111        this->mute_[SoundType::none] = false;
112        this->mute_[SoundType::ambient] = false;
113        this->mute_[SoundType::effects] = false;
[6117]114
115        this->setConfigValues();
[3060]116    }
117
118    SoundManager::~SoundManager()
119    {
[5929]120        GameMode::setPlaysSound(false);
[6237]121/*
[3060]122        alcDestroyContext(this->context_);
[3280]123        alcCloseDevice(this->device_);
[6237]124*/
[3060]125        alutExit();
126    }
127
[6183]128    void SoundManager::preUpdate(const Clock& time)
[6117]129    {
130        this->processCrossFading(time.getDeltaTime());
131    }
132
133    void SoundManager::setConfigValues()
134    {
135        SetConfigValue(crossFadeStep_, 0.2f)
136            .description("Determines how fast sounds should fade, per second.")
137            .callback(this, &SoundManager::checkFadeStepValidity);
[6184]138           
[6186]139        SetConfigValue(soundVolume_, 1.0f)
[6184]140            .description("Defines the overall volume.")
[6186]141            .callback(this, &SoundManager::checkSoundVolumeValidity);
[6184]142           
143        SetConfigValue(ambientVolume_, 1.0f)
144            .description("Defines the ambient volume.")
145            .callback(this, &SoundManager::checkAmbientVolumeValidity);
146           
147        SetConfigValue(effectsVolume_, 1.0f)
148            .description("Defines the effects volume.")
149            .callback(this, &SoundManager::checkEffectsVolumeValidity);
[6117]150    }
151
152    void SoundManager::checkFadeStepValidity()
153    {
154        if (crossFadeStep_ <= 0.0 || crossFadeStep_ >= 1.0 )
155        {
156            COUT(2) << "Sound warning: Sound step out of range, ignoring change." << std::endl;
157            ResetConfigValue(crossFadeStep_);
158        }
159        COUT(3) << "SoundManager: fade step set to " << crossFadeStep_ << std::endl;
160        return;
161    }
[6184]162   
[6186]163    bool SoundManager::checkVolumeValidity(SoundType::Value type)
[6184]164    {
[6186]165        bool valid = true;
166       
167        if(this->getVolumeInternal(type) < 0.0 || this->getVolumeInternal(type) > 1.0)
[6184]168        {
169            COUT(2) << "Sound warning: Sound volume out of range, ignoring change." << std::endl;
[6186]170            valid = false;
[6184]171        }
172       
[6186]173        this->updateVolume(type);
[6241]174        COUT(4) << "SoundManager: volume set to " << this->getVolumeInternal(type) << std::endl;
[6186]175        return valid;
[6184]176    }
177   
[6186]178    void SoundManager::checkSoundVolumeValidity()
179    {
[6197]180        if(!checkVolumeValidity(SoundType::none))
[6186]181        {
182            ResetConfigValue(soundVolume_);
183        }
184    }
185   
[6184]186    void SoundManager::checkAmbientVolumeValidity()
187    {
[6197]188        if(!checkVolumeValidity(SoundType::ambient))
[6184]189        {
190            ResetConfigValue(ambientVolume_);
191        }
192    }
193   
194    void SoundManager::checkEffectsVolumeValidity()
195    {
[6197]196        if(!checkVolumeValidity(SoundType::effects))
[6184]197        {
198            ResetConfigValue(effectsVolume_);
199        }
200    }
[6117]201
[5929]202    void SoundManager::setListenerPosition(const Vector3& position)
[3060]203    {
[5929]204        alListener3f(AL_POSITION, position.x, position.y, position.z);
205        ALenum error = alGetError();
206        if (error == AL_INVALID_VALUE)
207            COUT(2) << "Sound: OpenAL: Invalid listener position" << std::endl;
[3060]208    }
209
[5929]210    void SoundManager::setListenerOrientation(const Quaternion& orientation)
[3060]211    {
[5929]212        // update listener orientation
213        Vector3 up = orientation.xAxis(); // just a wild guess
214        Vector3 at = orientation.zAxis();
[3060]215
[5929]216        ALfloat orient[6] = { at.x, at.y, at.z,
217                              up.x, up.y, up.z };
[3060]218
[5929]219        alListenerfv(AL_POSITION, orient);
[3060]220        ALenum error = alGetError();
[5929]221        if (error == AL_INVALID_VALUE)
[3060]222            COUT(2) << "Sound: OpenAL: Invalid listener orientation" << std::endl;
223    }
[6117]224
225    void SoundManager::registerAmbientSound(AmbientSound* newAmbient)
226    {
227        if (newAmbient != NULL)
228        {
229            for (AmbientList::const_iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
230            {
231                if (it->first == newAmbient)
232                {
233                    COUT(2) << "Sound warning: Will not play an AmbientSound twice." << std::endl;
234                    return;
235                }
236            }
237
238            if (!this->ambientSounds_.empty()) 
239            {
240                this->fadeOut(ambientSounds_.front().first);
241            }
242            this->ambientSounds_.push_front(std::make_pair(newAmbient, false));
243            newAmbient->doPlay();
244            this->fadeIn(newAmbient);
245        }
246    }
247
248    void SoundManager::unregisterAmbientSound(AmbientSound* oldAmbient)
249    {
250        if (oldAmbient == NULL || ambientSounds_.empty())
251        {
252            return;
253        }
254        if (this->ambientSounds_.front().first == oldAmbient) 
255        {
256            this->fadeOut(oldAmbient);
257            this->ambientSounds_.pop_front();
258            if (!this->ambientSounds_.empty())
259            {
260                if (!this->ambientSounds_.front().second) // Not paused before
261                {
262                    this->ambientSounds_.front().first->doPlay();
263                }
264                this->fadeIn(this->ambientSounds_.front().first);
265            }
266        }
267        else
268        {
269            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
270            {
271                if (it->first == oldAmbient)
272                {
273                    this->fadeOut(oldAmbient);
274                    this->ambientSounds_.erase(it);
275                    break;
276                }
277            }
278        }
279    }
280
281    void SoundManager::pauseAmbientSound(AmbientSound* ambient)
282    {
283        if (ambient != NULL)
284        {
285            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
286            {
287                if (it->first == ambient)
288                {
289                    it->second = true;
290                    this->fadeOut(it->first);
291                    return;
292                }
293            }
294        }
295    }
[6184]296   
[6186]297   
298    void SoundManager::setVolume(float vol, SoundType::Value type)
[6184]299    {
[6186]300        vol = this->checkVolumeRange(vol);
301       
302        this->setVolumeInternal(vol, type);
303       
304        this->updateVolume(type);
305    }
306   
307    float SoundManager::checkVolumeRange(float vol)
308    {
309        if(vol < 0.0 || vol > 1.0)
[6184]310        {
311            COUT(2) << "Sound warning: volume out of range, cropping value." << std::endl;
312            vol = vol > 1 ? 1 : vol;
313            vol = vol < 0 ? 0 : vol;
314        }
315       
[6186]316        return vol;
[6184]317    }
318   
[6186]319    void SoundManager::updateVolume(SoundType::Value type)
[6184]320    {
[6186]321        switch(type)
[6184]322        {
[6186]323            case SoundType::none:
324                for (ObjectList<BaseSound>::iterator it = ObjectList<BaseSound>::begin(); it != ObjectList<BaseSound>::end(); ++it)
325                {
326                    (*it)->updateVolume();
327                }
328                break;
329            case SoundType::ambient:
330                for (ObjectList<AmbientSound>::iterator it = ObjectList<AmbientSound>::begin(); it != ObjectList<AmbientSound>::end(); ++it)
331                {
332                    (*it)->updateVolume();
333                }
334                break;
335            case SoundType::effects:
336                for (ObjectList<WorldSound>::iterator it = ObjectList<WorldSound>::begin(); it != ObjectList<WorldSound>::end(); ++it)
337                {
338                    (*it)->updateVolume();
339                }
340                break;
341            default:
342                COUT(2) << "Invalid SoundType in SoundManager::updateVolume() - Not updating!" << std::endl;
[6184]343        }
344    }
345   
[6186]346    void SoundManager::setVolumeInternal(float vol, SoundType::Value type)
[6184]347    {
[6186]348        switch(type)
[6184]349        {
[6186]350            case SoundType::none:
351                this->soundVolume_ = vol;
352                break;
353            case SoundType::ambient:
354                this->ambientVolume_ = vol;
355                break;
356            case SoundType::effects:
357                this->effectsVolume_ = vol;
358                break;
359            default:
360                COUT(2) << "Invalid SoundType in SoundManager::setVolumeInternal() - Not setting any volume!" << std::endl;
[6184]361        }
362    }
363   
[6186]364    float SoundManager::getVolumeInternal(SoundType::Value type)
[6184]365    {
[6186]366        switch(type)
367        {
368            case SoundType::none:
369                return this->soundVolume_;
370            case SoundType::ambient:
371                return this->ambientVolume_;
372            case SoundType::effects:
373                return this->effectsVolume_;
374            default:
375                COUT(2) << "Invalid SoundType in SoundManager::setVolumeInternal() - Returning 0.0!" << std::endl;
376                return 0.0;
377        }
[6184]378    }
379   
[6186]380    float SoundManager::getVolume(SoundType::Value type) 
[6184]381    {
[6186]382        if(this->mute_[SoundType::none] || this->mute_[type])
383            return 0.0;
384       
385        if(type == SoundType::none)
386            return this->getVolumeInternal(type);
387       
388        return this->getVolumeInternal(SoundType::none)*this->getVolumeInternal(type);
[6184]389    }
390   
[6186]391    void SoundManager::toggleMute(SoundType::Value type)
[6184]392    {
[6186]393        bool mute = !this->mute_[type];
394        this->mute_[type] = mute;
395       
396        this->updateVolume(type);
[6184]397    }
[6186]398   
399    bool SoundManager::getMute(SoundType::Value type)
400    {
401        return this->mute_[type];
402    }
403   
[6117]404
405    void SoundManager::fadeIn(AmbientSound* sound)
406    {
407        // If we're already fading out --> remove that
408        for (std::list<AmbientSound*>::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); it++)
409        {
410            if (*it == sound)
411            {
412                this->fadeOutList_.erase(it);
413                break;
414            }
415        }
416        // No duplicate entries
417        if (std::find(this->fadeInList_.begin(), this->fadeInList_.end(), sound) == this->fadeInList_.end())
418            this->fadeInList_.push_back(sound);
419    }
420
421    void SoundManager::fadeOut(AmbientSound* sound)
422    {
423        // If we're already fading in --> remove that
424        for (std::list<AmbientSound*>::iterator it = this->fadeInList_.begin(); it != this->fadeInList_.end(); it++)
425        {
426            if (*it == sound)
427            {
428                this->fadeInList_.erase(it);
429                break;
430            }
431        }
432        // No duplicate entries
433        if (std::find(this->fadeOutList_.begin(), this->fadeOutList_.end(), sound) == this->fadeOutList_.end())
434            this->fadeOutList_.push_back(sound);
435    }
436
437    void SoundManager::processCrossFading(float dt)
438    {
439       
440        // Hacky solution to the fade delay while loading a level.
441        if(dt > 0.2)
442        {
443            return;
444        }
445       
446        // FADE IN
[6138]447        for (std::list<AmbientSound*>::iterator it= this->fadeInList_.begin(); it != this->fadeInList_.end(); )
[6117]448        {
449            if ((*it)->getVolume() + this->crossFadeStep_*dt > 1.0f)
450            {
451                (*it)->setVolume(1.0f);
452                this->fadeInList_.erase(it++);
453            }
454            else
455            {
456                (*it)->setVolume((*it)->getVolume() + this->crossFadeStep_*dt);
457                ++it;
458            }
459        }
460
461        // FADE OUT
[6138]462        for (std::list<AmbientSound*>::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); )
[6117]463        {
464            if ((*it)->getVolume() - this->crossFadeStep_*dt < 0.0f)
465            {
466                (*it)->setVolume(0.0f);
467
468                // If sound is in the ambient list --> pause
469                for (AmbientList::const_iterator it2 = this->ambientSounds_.begin(); it2 != this->ambientSounds_.end(); ++it2)
470                {
471                    if (it2->first == *it)
472                    {
473                        (*it)->doPause();
474                        break;
475                    }
476                }
477                // If not pause (by loop above for instance) --> stop
478                if (!(*it)->isPaused())
479                    (*it)->doStop();
480
481                this->fadeOutList_.erase(it++);
482            }
483            else
484            {
485                (*it)->setVolume((*it)->getVolume() - this->crossFadeStep_*dt);
486                ++it;
487            }
488        }
489    }
[6203]490
491    shared_ptr<SoundBuffer> SoundManager::getSoundBuffer(shared_ptr<ResourceInfo> fileInfo)
492    {
493        std::map<std::string, weak_ptr<SoundBuffer> >::const_iterator it
494            = this->soundBuffers_.find(fileInfo->group + '/' + fileInfo->filename);
495        if (it != this->soundBuffers_.end())
496            return it->second.lock();
497        else
498        {
[6232]499            shared_ptr<SoundBuffer> buffer;
500            try
501            {
502                buffer.reset(new SoundBuffer(fileInfo));
503            }
504            catch (...)
505            {
506                COUT(1) << Exception::handleMessage() << std::endl;
507                return shared_ptr<SoundBuffer>();
508            }
[6203]509            this->soundBuffers_[fileInfo->group + '/' + fileInfo->filename] = buffer;
510            return buffer;
511        }
512    }
513
514    void SoundManager::removeBuffer(shared_ptr<ResourceInfo> fileInfo)
515    {
[6208]516        std::map<std::string, weak_ptr<SoundBuffer> >::iterator it
[6203]517            = this->soundBuffers_.find(fileInfo->group + '/' + fileInfo->filename);
[6232]518        if (it != this->soundBuffers_.end())
[6203]519            this->soundBuffers_.erase(it);
520    }
[3060]521}
Note: See TracBrowser for help on using the repository browser.