Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Created capability in SoundManager to set an overall volume, and to also adjust general ambient and effects volumes.
For this to work, you need to delete your config-file (orxonox.ini) so that it can be reset.
It has still som quirks, though.

  • Property svn:eol-style set to native
File size: 14.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->volume_ = 1.0;
95        this->ambientVolume_ = 1.0;
96        this->effectsVolume_ = 1.0;
97
98        this->setConfigValues();
99    }
100
101    SoundManager::~SoundManager()
102    {
103        GameMode::setPlaysSound(false);
104        alcDestroyContext(this->context_);
105        alcCloseDevice(this->device_);
106        alutExit();
107    }
108
109    void SoundManager::preUpdate(const Clock& time)
110    {
111        this->processCrossFading(time.getDeltaTime());
112    }
113
114    void SoundManager::setConfigValues()
115    {
116        SetConfigValue(crossFadeStep_, 0.2f)
117            .description("Determines how fast sounds should fade, per second.")
118            .callback(this, &SoundManager::checkFadeStepValidity);
119           
120        SetConfigValue(volume_, 1.0f)
121            .description("Defines the overall volume.")
122            .callback(this, &SoundManager::checkVolumeValidity);
123           
124        SetConfigValue(ambientVolume_, 1.0f)
125            .description("Defines the ambient volume.")
126            .callback(this, &SoundManager::checkAmbientVolumeValidity);
127           
128        SetConfigValue(effectsVolume_, 1.0f)
129            .description("Defines the effects volume.")
130            .callback(this, &SoundManager::checkEffectsVolumeValidity);
131    }
132
133    void SoundManager::checkFadeStepValidity()
134    {
135        if (crossFadeStep_ <= 0.0 || crossFadeStep_ >= 1.0 )
136        {
137            COUT(2) << "Sound warning: Sound step out of range, ignoring change." << std::endl;
138            ResetConfigValue(crossFadeStep_);
139        }
140        COUT(3) << "SoundManager: fade step set to " << crossFadeStep_ << std::endl;
141        return;
142    }
143   
144    void SoundManager::checkVolumeValidity()
145    {
146        if(volume_ < 0.0 || volume_ > 1.0)
147        {
148            COUT(2) << "Sound warning: Sound volume out of range, ignoring change." << std::endl;
149            ResetConfigValue(volume_);
150        }
151       
152        this->updateVolume();
153        COUT(3) << "SoundManager: Overall volume set to " << volume_ << std::endl;
154        return;
155    }
156   
157    void SoundManager::checkAmbientVolumeValidity()
158    {
159        if(this->ambientVolume_ < 0.0 || this->ambientVolume_ > 1.0)
160        {
161            COUT(2) << "Sound warning: Ambient volume out of range, ignoring change." << std::endl;
162            ResetConfigValue(ambientVolume_);
163        }
164       
165        this->updateAmbientVolume();
166        COUT(3) << "SoundManager: Ambient volume set to " << this->ambientVolume_ << std::endl;
167        return;
168    }
169   
170    void SoundManager::checkEffectsVolumeValidity()
171    {
172        if(this->effectsVolume_ < 0.0 || this->effectsVolume_ > 1.0)
173        {
174            COUT(2) << "Sound warning: effects volume out of range, ignoring change." << std::endl;
175            ResetConfigValue(effectsVolume_);
176        }
177       
178        this->updateEffectsVolume();
179        COUT(3) << "SoundManager: Effects volume set to " << this->effectsVolume_ << std::endl;
180        return;
181    }
182
183    void SoundManager::setListenerPosition(const Vector3& position)
184    {
185        alListener3f(AL_POSITION, position.x, position.y, position.z);
186        ALenum error = alGetError();
187        if (error == AL_INVALID_VALUE)
188            COUT(2) << "Sound: OpenAL: Invalid listener position" << std::endl;
189    }
190
191    void SoundManager::setListenerOrientation(const Quaternion& orientation)
192    {
193        // update listener orientation
194        Vector3 up = orientation.xAxis(); // just a wild guess
195        Vector3 at = orientation.zAxis();
196
197        ALfloat orient[6] = { at.x, at.y, at.z,
198                              up.x, up.y, up.z };
199
200        alListenerfv(AL_POSITION, orient);
201        ALenum error = alGetError();
202        if (error == AL_INVALID_VALUE)
203            COUT(2) << "Sound: OpenAL: Invalid listener orientation" << std::endl;
204    }
205
206    void SoundManager::registerAmbientSound(AmbientSound* newAmbient)
207    {
208        if (newAmbient != NULL)
209        {
210            for (AmbientList::const_iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
211            {
212                if (it->first == newAmbient)
213                {
214                    COUT(2) << "Sound warning: Will not play an AmbientSound twice." << std::endl;
215                    return;
216                }
217            }
218
219            if (!this->ambientSounds_.empty()) 
220            {
221                this->fadeOut(ambientSounds_.front().first);
222            }
223            this->ambientSounds_.push_front(std::make_pair(newAmbient, false));
224            newAmbient->doPlay();
225            this->fadeIn(newAmbient);
226        }
227    }
228
229    void SoundManager::unregisterAmbientSound(AmbientSound* oldAmbient)
230    {
231        if (oldAmbient == NULL || ambientSounds_.empty())
232        {
233            return;
234        }
235        if (this->ambientSounds_.front().first == oldAmbient) 
236        {
237            this->fadeOut(oldAmbient);
238            this->ambientSounds_.pop_front();
239            if (!this->ambientSounds_.empty())
240            {
241                if (!this->ambientSounds_.front().second) // Not paused before
242                {
243                    this->ambientSounds_.front().first->doPlay();
244                }
245                this->fadeIn(this->ambientSounds_.front().first);
246            }
247        }
248        else
249        {
250            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
251            {
252                if (it->first == oldAmbient)
253                {
254                    this->fadeOut(oldAmbient);
255                    this->ambientSounds_.erase(it);
256                    break;
257                }
258            }
259        }
260    }
261
262    void SoundManager::pauseAmbientSound(AmbientSound* ambient)
263    {
264        if (ambient != NULL)
265        {
266            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
267            {
268                if (it->first == ambient)
269                {
270                    it->second = true;
271                    this->fadeOut(it->first);
272                    return;
273                }
274            }
275        }
276    }
277   
278    void SoundManager::setAmbientVolume(float vol)
279    {
280        if (vol > 1 || vol < 0)
281        {
282            COUT(2) << "Sound warning: volume out of range, cropping value." << std::endl;
283            vol = vol > 1 ? 1 : vol;
284            vol = vol < 0 ? 0 : vol;
285        }
286        this->ambientVolume_ = vol;
287       
288        this->updateAmbientVolume();
289    }
290   
291    void SoundManager::setEffectsVolume(float vol)
292    {
293        if (vol > 1 || vol < 0)
294        {
295            COUT(2) << "Sound warning: volume out of range, cropping value." << std::endl;
296            vol = vol > 1 ? 1 : vol;
297            vol = vol < 0 ? 0 : vol;
298        }
299        this->effectsVolume_ = vol;
300       
301        this->updateEffectsVolume();
302    }
303   
304    void SoundManager::setVolume(float vol)
305    {
306        if (vol > 1 || vol < 0)
307        {
308            COUT(2) << "Sound warning: volume out of range, cropping value." << std::endl;
309            vol = vol > 1 ? 1 : vol;
310            vol = vol < 0 ? 0 : vol;
311        }
312        this->volume_ = vol;
313       
314        this->updateVolume();
315    }
316   
317    float SoundManager::getAmbientVolume(void)
318    {
319        return this->ambientVolume_;
320    }
321   
322    float SoundManager::getEffectsVolume(void)
323    {
324        return this->effectsVolume_;
325    }
326   
327    float SoundManager::getVolume(void) 
328    {
329        return this->volume_;
330    }
331
332    void SoundManager::fadeIn(AmbientSound* sound)
333    {
334        // If we're already fading out --> remove that
335        for (std::list<AmbientSound*>::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); it++)
336        {
337            if (*it == sound)
338            {
339                this->fadeOutList_.erase(it);
340                break;
341            }
342        }
343        // No duplicate entries
344        if (std::find(this->fadeInList_.begin(), this->fadeInList_.end(), sound) == this->fadeInList_.end())
345            this->fadeInList_.push_back(sound);
346    }
347
348    void SoundManager::fadeOut(AmbientSound* sound)
349    {
350        // If we're already fading in --> remove that
351        for (std::list<AmbientSound*>::iterator it = this->fadeInList_.begin(); it != this->fadeInList_.end(); it++)
352        {
353            if (*it == sound)
354            {
355                this->fadeInList_.erase(it);
356                break;
357            }
358        }
359        // No duplicate entries
360        if (std::find(this->fadeOutList_.begin(), this->fadeOutList_.end(), sound) == this->fadeOutList_.end())
361            this->fadeOutList_.push_back(sound);
362    }
363
364    void SoundManager::processCrossFading(float dt)
365    {
366       
367        // Hacky solution to the fade delay while loading a level.
368        if(dt > 0.2)
369        {
370            return;
371        }
372       
373        // FADE IN
374        for (std::list<AmbientSound*>::iterator it= this->fadeInList_.begin(); it != this->fadeInList_.end(); )
375        {
376            if ((*it)->getVolume() + this->crossFadeStep_*dt > 1.0f)
377            {
378                (*it)->setVolume(1.0f);
379                this->fadeInList_.erase(it++);
380            }
381            else
382            {
383                (*it)->setVolume((*it)->getVolume() + this->crossFadeStep_*dt);
384                ++it;
385            }
386        }
387
388        // FADE OUT
389        for (std::list<AmbientSound*>::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); )
390        {
391            if ((*it)->getVolume() - this->crossFadeStep_*dt < 0.0f)
392            {
393                (*it)->setVolume(0.0f);
394
395                // If sound is in the ambient list --> pause
396                for (AmbientList::const_iterator it2 = this->ambientSounds_.begin(); it2 != this->ambientSounds_.end(); ++it2)
397                {
398                    if (it2->first == *it)
399                    {
400                        (*it)->doPause();
401                        break;
402                    }
403                }
404                // If not pause (by loop above for instance) --> stop
405                if (!(*it)->isPaused())
406                    (*it)->doStop();
407
408                this->fadeOutList_.erase(it++);
409            }
410            else
411            {
412                (*it)->setVolume((*it)->getVolume() - this->crossFadeStep_*dt);
413                ++it;
414            }
415        }
416    }
417   
418    void SoundManager::updateAmbientVolume(void)
419    {
420        for(ObjectList<AmbientSound>::iterator it = ObjectList<AmbientSound>::begin(); it != ObjectList<AmbientSound>::end(); ++it)
421        {
422            (*it)->setVolumeGain(this->volume_*this->ambientVolume_);
423        }
424    }
425   
426    void SoundManager::updateEffectsVolume(void)
427    {
428        for (ObjectList<WorldSound>::iterator it = ObjectList<WorldSound>::begin(); it != ObjectList<WorldSound>::end(); ++it)
429        {
430            (*it)->setVolumeGain(this->volume_*this->effectsVolume_);
431        }
432    }
433   
434    void SoundManager::updateVolume(void)
435    {
436        for (ObjectList<BaseSound>::iterator it = ObjectList<BaseSound>::begin(); it != ObjectList<BaseSound>::end(); ++it)
437        {
438            AmbientSound* ambient = dynamic_cast<AmbientSound*>(*it);
439            WorldSound* world = dynamic_cast<WorldSound*>(*it);
440            if(ambient != NULL)
441            {
442                ambient->setVolumeGain(this->volume_*this->ambientVolume_);
443            }
444            else if(world != NULL)
445            {
446                world->setVolumeGain(this->volume_*this->effectsVolume_);
447            }
448            else
449            {
450                (*it)->setVolumeGain(this->volume_);
451            }
452        }
453    }
454}
Note: See TracBrowser for help on using the repository browser.