Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/orxonox/sound/BaseSound.cc @ 10420

Last change on this file since 10420 was 10362, checked in by landauf, 10 years ago

use static identifier initializer to store the inheritance definition of abstract classes. this prevents that identifiers are used (via Class(Name)) before they are properly initialized.

  • Property svn:eol-style set to native
File size: 9.4 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 *   Co-authors:
25 *      Reto Grieder
26 *
27 */
28
29#include "BaseSound.h"
30
31#include <cassert>
32#include <vector>
33#include <al.h>
34
35#include "util/Math.h"
36#include "core/CoreIncludes.h"
37#include "core/GameMode.h"
38#include "core/Resource.h"
39#include "core/XMLPort.h"
40#include "SoundBuffer.h"
41#include "SoundManager.h"
42
43namespace orxonox
44{
45    RegisterAbstractClass(BaseSound).inheritsFrom<Listable>();
46
47    BaseSound::BaseSound()
48        : bPooling_(false)
49        , volume_(0.7)
50        , bLooping_(false)
51        , state_(Stopped)
52        , pitch_ (1.0)
53    {
54        RegisterObject(BaseSound);
55
56        // Initialise audioSource_ to a value that is not a source
57        // 0 is unfortunately not guaranteed to be no source ID.
58        // HACK!
59        this->audioSource_ = 0;
60        //while (alIsSource(++this->audioSource_));
61    }
62
63    BaseSound::~BaseSound()
64    {
65        if (this->state_ != Stopped)
66            this->stop();
67        // Release buffer
68        if (this->soundBuffer_ != NULL)
69        {
70            assert(GameMode::playsSound());
71            SoundManager::getInstance().releaseSoundBuffer(this->soundBuffer_, this->bPooling_);
72        }
73    }
74
75    void BaseSound::XMLPortExtern(Element& xmlelement, XMLPort::Mode mode)
76    {
77        XMLPortParam(BaseSound, "volume",  setVolume,  getVolume,  xmlelement, mode);
78        XMLPortParam(BaseSound, "looping", setLooping, getLooping, xmlelement, mode);
79        XMLPortParam(BaseSound, "pitch",   setPitch,   getPitch,   xmlelement, mode);
80        XMLPortParam(BaseSound, "source",  setSource,  getSource,  xmlelement, mode);
81    }
82
83    void BaseSound::doPlay()
84    {
85        this->state_ = Playing;
86        if (GameMode::playsSound() && this->getSourceState() != AL_PLAYING && this->soundBuffer_ != NULL)
87        {
88            if (!alIsSource(this->audioSource_))
89            {
90                this->audioSource_ = SoundManager::getInstance().getSoundSource(this);
91                if (!alIsSource(this->audioSource_))
92                    return;
93                this->initialiseSource();
94            }
95
96            alSourcePlay(this->audioSource_);
97            if (int error = alGetError())
98                orxout(internal_error, context::sound) << "Error playing sound: " << SoundManager::getALErrorString(error) << endl;
99        }
100    }
101
102    bool BaseSound::doStop()
103    {
104        this->state_ = Stopped;
105        if (alIsSource(this->audioSource_))
106        {
107            alSourceStop(this->audioSource_);
108            // Release buffer
109            alSourcei(this->audioSource_, AL_BUFFER, AL_NONE);
110            // Release source again
111            SoundManager::getInstance().releaseSoundSource(this->audioSource_);
112            // Get a no source ID
113            this->audioSource_ += 123455;
114            while (alIsSource(++this->audioSource_));
115
116            return true; // sound source destroyed - return true
117        }
118        return false; // nothing done - return false
119    }
120
121    void BaseSound::doPause()
122    {
123        if (this->isStopped())
124            return;
125        this->state_ = Paused;
126        if (alIsSource(this->audioSource_))
127            alSourcePause(this->audioSource_);
128    }
129
130    ALint BaseSound::getSourceState() const
131    {
132        if (alIsSource(this->audioSource_))
133        {
134            ALint state;
135            alGetSourcei(this->audioSource_, AL_SOURCE_STATE, &state);
136            return state;
137        }
138        else
139            return AL_INITIAL;
140    }
141
142    void BaseSound::initialiseSource()
143    {
144        this->updateVolume();
145        this->setPitch(this->getPitch());
146        this->setLooping(this->getLooping());
147        alSource3f(this->audioSource_, AL_POSITION,  0, 0, 0);
148        alSource3f(this->audioSource_, AL_VELOCITY,  0, 0, 0);
149        alSource3f(this->audioSource_, AL_DIRECTION, 0, 0, 0);
150        if (ALint error = alGetError())
151            orxout(internal_warning, context::sound) << "Setting source parameters to 0 failed: "
152                                                     << SoundManager::getALErrorString(error) << endl;
153        assert(this->soundBuffer_ != NULL);
154        alSourcei(this->audioSource_, AL_BUFFER, this->soundBuffer_->getBuffer());
155        if (ALuint error = alGetError())
156            orxout(internal_error, context::sound) << "Could not set buffer \"" << this->source_ << "\": " << SoundManager::getALErrorString(error) << endl;
157    }
158
159    void BaseSound::setVolume(float vol)
160    {
161        this->volume_ = clamp(vol, 0.0f, 1.0f);
162        if (this->volume_ != vol)
163            orxout(internal_warning, context::sound) << "Volume out of range, clamping value." << endl;
164        this->updateVolume();
165    }
166
167    void BaseSound::updateVolume()
168    {
169        if (alIsSource(this->audioSource_))
170        {
171            float volume = this->volume_ * this->getRealVolume();               
172            alSourcef(this->audioSource_, AL_GAIN, volume);
173            if (int error = alGetError())
174                orxout(internal_error, context::sound) << "Error setting volume to " << volume
175                                                       << ": " << SoundManager::getALErrorString(error) << endl;
176        }
177    }
178
179    void BaseSound::setLooping(bool val)
180    {
181        this->bLooping_ = val;
182        if (alIsSource(this->audioSource_))
183            alSourcei(this->audioSource_, AL_LOOPING, (val ? AL_TRUE : AL_FALSE));
184    }
185
186    void BaseSound::setPitch(float pitch)
187    {
188        if (pitch > 2 || pitch < 0.5f)
189        {
190            orxout(internal_warning, context::sound) << "Pitch out of range, cropping value." << endl;
191            pitch = pitch > 2.0f ? 2.0f : pitch;
192            pitch = pitch < 0.5f ? 0.5f : pitch;
193        }
194        this->pitch_ = pitch;
195        if (alIsSource(this->audioSource_))
196        {
197            alSourcef(this->audioSource_, AL_PITCH, pitch);
198            if (int error = alGetError())
199                orxout(internal_error, context::sound) << "Error setting pitch: " << SoundManager::getALErrorString(error) << endl;
200        }
201    }
202
203    void BaseSound::setSource(const std::string& source)
204    {
205        if (!GameMode::playsSound())
206        {
207            this->source_ = source;
208            return;
209        }
210
211        if (this->soundBuffer_ != NULL)
212        {
213            if (this->soundBuffer_->getFilename() == source)
214            {
215                assert(this->source_ == source_);
216                return;
217            }
218            // Stopping is imperative here!
219            if (alIsSource(this->audioSource_))
220            {
221                alSourceStop(this->audioSource_);
222                alSourcei(this->audioSource_, AL_BUFFER, AL_NONE);
223            }
224            SoundManager::getInstance().releaseSoundBuffer(this->soundBuffer_, this->bPooling_);
225            this->soundBuffer_.reset();
226        }
227
228        this->source_ = source;
229        // Don't load ""
230        if (source_.empty())
231            return;
232
233        // Get new sound buffer
234        this->soundBuffer_ = SoundManager::getInstance().getSoundBuffer(this->source_);
235        if (this->soundBuffer_ == NULL)
236            return;
237
238        if (alIsSource(this->audioSource_)) // already playing or paused
239        {
240            // Set new buffer
241            alSourcei(this->audioSource_, AL_BUFFER, this->soundBuffer_->getBuffer());
242            if (ALuint error = alGetError())
243            {
244                orxout(internal_error, context::sound) << "Could not set buffer \"" << source << "\": " << SoundManager::getALErrorString(error) << endl;
245                return;
246            }
247
248            // Sound was already playing or paused because there was a source acquired
249            assert(this->isPlaying() || this->isPaused());
250            alSourcePlay(this->audioSource_);
251            if (int error = alGetError())
252                orxout(internal_error, context::sound) << "Error playing sound: " << SoundManager::getALErrorString(error) << endl;
253            if (this->isPaused())
254                alSourcePause(this->audioSource_);
255        }
256        else // No source acquired so far, but might be set to playing or paused
257        {
258            State state = static_cast<State>(this->state_); // save
259            if (this->isPlaying() || this->isPaused())
260                doPlay();
261            if (state == Paused)
262            {
263                this->state_ = Paused;
264                doPause();
265            }
266        }
267    }
268
269    void BaseSound::stateChanged()
270    {
271        switch (this->state_)
272        {
273            case Playing:
274                this->play();
275                break;
276            case Paused:
277                this->pause();
278                break;
279            case Stopped:
280            default:
281                this->stop();
282                break;
283        }
284    }
285}
Note: See TracBrowser for help on using the repository browser.