Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/unity_build/src/orxonox/sound/BaseSound.cc @ 8639

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

Another hierarchy initialisation bug: BaseSound d'tor was always stopping a sound source. This one is a bit trickier because BaseSound is not a BaseObject and therefore does not have the isInitialized() method. However an instance is still being created through WorldSound.
This change also 'fixes' the POSIX IOConsole loosing lines between its construction and its first update because OpenAL sends output to STDOUT.

@Kevin: this could very well explain your mysterious error code.

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