Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/sound/BaseSound.cc @ 12338

Last change on this file since 12338 was 11071, checked in by landauf, 9 years ago

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 9.5 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_(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_ != State::Stopped)
66            this->stop();
67        // Release buffer
68        if (this->soundBuffer_ != nullptr)
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_ = State::Playing;
86        if (GameMode::playsSound() && this->getSourceState() != AL_PLAYING && this->soundBuffer_ != nullptr)
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_ = 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_ = 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_ != nullptr);
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_ != nullptr)
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_ == nullptr)
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 = this->state_; // save
259            if (this->isPlaying() || this->isPaused())
260                doPlay();
261            if (state == State::Paused)
262            {
263                this->state_ = State::Paused;
264                doPause();
265            }
266        }
267    }
268
269    void BaseSound::stateChanged()
270    {
271        switch (this->state_)
272        {
273            case State::Playing:
274                this->play();
275                break;
276            case State::Paused:
277                this->pause();
278                break;
279            case State::Stopped:
280            default:
281                this->stop();
282                break;
283        }
284    }
285}
Note: See TracBrowser for help on using the repository browser.