Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6186 was 6186, checked in by dafrick, 14 years ago

Some cleanup in SoundManager and related classes. Overrall volume works now. Mute function has been implemented into the gui.
Once again you'll have to delete your orxonox.ini file to be trouble free.

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