Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6183 was 6183, checked in by rgrieder, 14 years ago

Added preUpdate and postUpdate methods for all classes inheriting Singleton. Replaced update() with preUpdate except for the GraphicsManager (postUpdate).
However this does not apply to the Client and Server singletons in the network library. We should think about putting them in a scope as well.

  • Property svn:eol-style set to native
File size: 10.3 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
46namespace orxonox
47{
48    ManageScopedSingleton(SoundManager, ScopeID::Graphics, true);
49
50    SoundManager::SoundManager()
51    {
52        RegisterRootObject(SoundManager);
53
54        if (!alutInitWithoutContext(NULL, NULL))
55            ThrowException(InitialisationFailed, "Sound: OpenAL ALUT error: " << alutGetErrorString(alutGetError()));
56        Loki::ScopeGuard alutExitGuard = Loki::MakeGuard(&alutExit);
57
58        COUT(3) << "Sound: OpenAL: Opening sound device..." << std::endl;
59        this->device_ = alcOpenDevice(NULL);
60        if (this->device_ == NULL)
61        {
62            COUT(0) << "Sound: OpenaAL: Could not open sound device. Have you installed OpenAL?" << std::endl;
63#ifdef ORXONOX_PLATFORM_WINDOWS
64            COUT(0) << "Sound: Just getting the DLL with the dependencies is not enough for Windows (esp. Windows 7)!" << std::endl;
65#endif
66            ThrowException(InitialisationFailed, "Sound: OpenAL error: Could not open sound device.");
67        }
68        Loki::ScopeGuard closeDeviceGuard = Loki::MakeGuard(&alcCloseDevice, this->device_);
69
70        COUT(3) << "Sound: OpenAL: Sound device opened" << std::endl;
71        this->context_ = alcCreateContext(this->device_, NULL);
72        if (this->context_ == NULL)
73            ThrowException(InitialisationFailed, "Sound: OpenAL error: Could not create sound context");
74        Loki::ScopeGuard desroyContextGuard = Loki::MakeGuard(&alcDestroyContext, this->context_);
75
76        if (alcMakeContextCurrent(this->context_) == AL_TRUE)
77            COUT(3) << "Sound: OpenAL: Context " << this->context_ << " loaded" << std::endl;
78
79        COUT(4) << "Sound: OpenAL ALUT version: " << alutGetMajorVersion() << "." << alutGetMinorVersion() << std::endl;
80
81        const char* str = alutGetMIMETypes(ALUT_LOADER_BUFFER);
82        if (str == NULL)
83            COUT(2) << "Sound: OpenAL ALUT error: " << alutGetErrorString(alutGetError()) << std::endl;
84        else
85            COUT(4) << "Sound: OpenAL ALUT supported MIME types: " << str << std::endl;
86
87        GameMode::setPlaysSound(true);
88        // Disarm guards
89        alutExitGuard.Dismiss();
90        closeDeviceGuard.Dismiss();
91        desroyContextGuard.Dismiss();
92
93        this->setConfigValues();
94    }
95
96    SoundManager::~SoundManager()
97    {
98        GameMode::setPlaysSound(false);
99        alcDestroyContext(this->context_);
100        alcCloseDevice(this->device_);
101        alutExit();
102    }
103
104    void SoundManager::preUpdate(const Clock& time)
105    {
106        this->processCrossFading(time.getDeltaTime());
107    }
108
109    void SoundManager::setConfigValues()
110    {
111        SetConfigValue(crossFadeStep_, 0.2f)
112            .description("Determines how fast sounds should fade, per second.")
113            .callback(this, &SoundManager::checkFadeStepValidity);
114    }
115
116    void SoundManager::checkFadeStepValidity()
117    {
118        if (crossFadeStep_ <= 0.0 || crossFadeStep_ >= 1.0 )
119        {
120            COUT(2) << "Sound warning: Sound step out of range, ignoring change." << std::endl;
121            ResetConfigValue(crossFadeStep_);
122        }
123        COUT(3) << "SoundManager: fade step set to " << crossFadeStep_ << std::endl;
124        return;
125    }
126
127    void SoundManager::setListenerPosition(const Vector3& position)
128    {
129        alListener3f(AL_POSITION, position.x, position.y, position.z);
130        ALenum error = alGetError();
131        if (error == AL_INVALID_VALUE)
132            COUT(2) << "Sound: OpenAL: Invalid listener position" << std::endl;
133    }
134
135    void SoundManager::setListenerOrientation(const Quaternion& orientation)
136    {
137        // update listener orientation
138        Vector3 up = orientation.xAxis(); // just a wild guess
139        Vector3 at = orientation.zAxis();
140
141        ALfloat orient[6] = { at.x, at.y, at.z,
142                              up.x, up.y, up.z };
143
144        alListenerfv(AL_POSITION, orient);
145        ALenum error = alGetError();
146        if (error == AL_INVALID_VALUE)
147            COUT(2) << "Sound: OpenAL: Invalid listener orientation" << std::endl;
148    }
149
150    void SoundManager::registerAmbientSound(AmbientSound* newAmbient)
151    {
152        if (newAmbient != NULL)
153        {
154            for (AmbientList::const_iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
155            {
156                if (it->first == newAmbient)
157                {
158                    COUT(2) << "Sound warning: Will not play an AmbientSound twice." << std::endl;
159                    return;
160                }
161            }
162
163            if (!this->ambientSounds_.empty()) 
164            {
165                this->fadeOut(ambientSounds_.front().first);
166            }
167            this->ambientSounds_.push_front(std::make_pair(newAmbient, false));
168            newAmbient->doPlay();
169            this->fadeIn(newAmbient);
170        }
171    }
172
173    void SoundManager::unregisterAmbientSound(AmbientSound* oldAmbient)
174    {
175        if (oldAmbient == NULL || ambientSounds_.empty())
176        {
177            return;
178        }
179        if (this->ambientSounds_.front().first == oldAmbient) 
180        {
181            this->fadeOut(oldAmbient);
182            this->ambientSounds_.pop_front();
183            if (!this->ambientSounds_.empty())
184            {
185                if (!this->ambientSounds_.front().second) // Not paused before
186                {
187                    this->ambientSounds_.front().first->doPlay();
188                }
189                this->fadeIn(this->ambientSounds_.front().first);
190            }
191        }
192        else
193        {
194            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
195            {
196                if (it->first == oldAmbient)
197                {
198                    this->fadeOut(oldAmbient);
199                    this->ambientSounds_.erase(it);
200                    break;
201                }
202            }
203        }
204    }
205
206    void SoundManager::pauseAmbientSound(AmbientSound* ambient)
207    {
208        if (ambient != NULL)
209        {
210            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
211            {
212                if (it->first == ambient)
213                {
214                    it->second = true;
215                    this->fadeOut(it->first);
216                    return;
217                }
218            }
219        }
220    }
221
222    void SoundManager::fadeIn(AmbientSound* sound)
223    {
224        // If we're already fading out --> remove that
225        for (std::list<AmbientSound*>::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); it++)
226        {
227            if (*it == sound)
228            {
229                this->fadeOutList_.erase(it);
230                break;
231            }
232        }
233        // No duplicate entries
234        if (std::find(this->fadeInList_.begin(), this->fadeInList_.end(), sound) == this->fadeInList_.end())
235            this->fadeInList_.push_back(sound);
236    }
237
238    void SoundManager::fadeOut(AmbientSound* sound)
239    {
240        // If we're already fading in --> remove that
241        for (std::list<AmbientSound*>::iterator it = this->fadeInList_.begin(); it != this->fadeInList_.end(); it++)
242        {
243            if (*it == sound)
244            {
245                this->fadeInList_.erase(it);
246                break;
247            }
248        }
249        // No duplicate entries
250        if (std::find(this->fadeOutList_.begin(), this->fadeOutList_.end(), sound) == this->fadeOutList_.end())
251            this->fadeOutList_.push_back(sound);
252    }
253
254    void SoundManager::processCrossFading(float dt)
255    {
256       
257        // Hacky solution to the fade delay while loading a level.
258        if(dt > 0.2)
259        {
260            return;
261        }
262       
263        // FADE IN
264        for (std::list<AmbientSound*>::iterator it= this->fadeInList_.begin(); it != this->fadeInList_.end(); )
265        {
266            if ((*it)->getVolume() + this->crossFadeStep_*dt > 1.0f)
267            {
268                (*it)->setVolume(1.0f);
269                this->fadeInList_.erase(it++);
270            }
271            else
272            {
273                (*it)->setVolume((*it)->getVolume() + this->crossFadeStep_*dt);
274                ++it;
275            }
276        }
277
278        // FADE OUT
279        for (std::list<AmbientSound*>::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); )
280        {
281            if ((*it)->getVolume() - this->crossFadeStep_*dt < 0.0f)
282            {
283                (*it)->setVolume(0.0f);
284
285                // If sound is in the ambient list --> pause
286                for (AmbientList::const_iterator it2 = this->ambientSounds_.begin(); it2 != this->ambientSounds_.end(); ++it2)
287                {
288                    if (it2->first == *it)
289                    {
290                        (*it)->doPause();
291                        break;
292                    }
293                }
294                // If not pause (by loop above for instance) --> stop
295                if (!(*it)->isPaused())
296                    (*it)->doStop();
297
298                this->fadeOutList_.erase(it++);
299            }
300            else
301            {
302                (*it)->setVolume((*it)->getVolume() - this->crossFadeStep_*dt);
303                ++it;
304            }
305        }
306    }
307}
Note: See TracBrowser for help on using the repository browser.