Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation2/src/orxonox/sound/BaseSound.cc @ 6322

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

Added audio source management. This should reduce the problems when loading too many sounds.
However if there are too many players shooting at the same time, some sounds may still not play.

  • Property svn:eol-style set to native
File size: 8.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 "core/CoreIncludes.h"
36#include "core/GameMode.h"
37#include "core/Resource.h"
38#include "core/XMLPort.h"
39#include "SoundBuffer.h"
40#include "SoundManager.h"
41
42namespace orxonox
43{
44    BaseSound::BaseSound()
45        : bPooling_(false)
46        , volume_(1.0)
47        , bLooping_(false)
48        , state_(Stopped)
49        , pitch_ (1.0)
50    {
51        RegisterRootObject(BaseSound);
52
53        // Initialise audioSource_ to a value that is not a source
54        // 0 is unfortunately not guaranteed to be no source ID.
55        this->audioSource_ = 123456789;
56        while (alIsSource(++this->audioSource_));
57    }
58
59    BaseSound::~BaseSound()
60    {
61        this->stop();
62    }
63
64    void BaseSound::XMLPortExtern(Element& xmlelement, XMLPort::Mode mode)
65    {
66        XMLPortParam(BaseSound, "volume", setVolume,  getVolume,  xmlelement, mode);
67        XMLPortParam(BaseSound, "loop",   setLooping, getLooping, xmlelement, mode);
68        XMLPortParam(BaseSound, "play",   setPlaying, isPlaying,  xmlelement, mode);
69        XMLPortParam(BaseSound, "source", setSource,  getSource,  xmlelement, mode);
70    }
71
72    void BaseSound::play()
73    {
74        this->state_ = Playing;
75        if (GameMode::playsSound() && this->getSourceState() != AL_PLAYING && this->soundBuffer_ != NULL)
76        {
77            if (!alIsSource(this->audioSource_))
78                this->audioSource_ = SoundManager::getInstance().getSoundSource();
79            if (!alIsSource(this->audioSource_))
80                return;
81            this->initialiseSource();
82
83            alSourcePlay(this->audioSource_);
84            if (int error = alGetError())
85                COUT(2) << "Sound: Error playing sound: " << SoundManager::getALErrorString(error) << std::endl;
86        }
87    }
88
89    void BaseSound::stop()
90    {
91        this->state_ = Stopped;
92        if (alIsSource(this->audioSource_))
93        {
94            alSourceStop(this->audioSource_);
95            // Release buffer
96            alSourcei(this->audioSource_, AL_BUFFER, AL_NONE);
97            // Release source again
98            SoundManager::getInstance().releaseSoundSource(this->audioSource_);
99            // Get a no source ID
100            this->audioSource_ += 123455;
101            while (alIsSource(++this->audioSource_));
102        }
103    }
104
105    void BaseSound::pause()
106    {
107        if (this->isStopped())
108            return;
109        this->state_ = Paused;
110        if (alIsSource(this->audioSource_))
111            alSourcePause(this->audioSource_);
112    }
113
114    ALint BaseSound::getSourceState() const
115    {
116        if (alIsSource(this->audioSource_))
117        {
118            ALint state;
119            alGetSourcei(this->audioSource_, AL_SOURCE_STATE, &state);
120            return state;
121        }
122        else
123            return AL_INITIAL;
124    }
125
126    void BaseSound::initialiseSource()
127    {
128        this->updateVolume();
129        this->setPitch(this->getPitch());
130        this->setLooping(this->getLooping());
131        alSource3f(this->audioSource_, AL_POSITION,  0, 0, 0);
132        alSource3f(this->audioSource_, AL_VELOCITY,  0, 0, 0);
133        alSource3f(this->audioSource_, AL_DIRECTION, 0, 0, 0);
134        alSourcei(this->audioSource_, AL_REFERENCE_DISTANCE, 20);
135        alSourcei(this->audioSource_, AL_MAX_DISTANCE, 10000);
136        if (ALint error = alGetError())
137            COUT(2) << "Sound Warning: Setting source parameters to 0 failed: "
138                    << SoundManager::getALErrorString(error) << std::endl;
139        assert(this->soundBuffer_ != NULL);
140        alSourcei(this->audioSource_, AL_BUFFER, this->soundBuffer_->getBuffer());
141        if (ALuint error = alGetError())
142            COUT(1) << "Sound Error: Could not set buffer \"" << this->source_ << "\": " << SoundManager::getALErrorString(error) << std::endl;
143    }
144
145    void BaseSound::setVolume(float vol)
146    {
147        if (vol > 1 || vol < 0)
148        {
149            COUT(2) << "Sound warning: volume out of range, cropping value." << std::endl;
150            vol = vol > 1 ? 1 : vol;
151            vol = vol < 0 ? 0 : vol;
152        }
153        this->volume_ = vol;
154       
155        this->updateVolume();
156    }
157   
158    float BaseSound::getVolumeGain()
159    {
160        assert(GameMode::playsSound());
161        return SoundManager::getInstance().getVolume(SoundType::none);
162    }
163   
164    void BaseSound::updateVolume(void)
165    {
166        if (alIsSource(this->audioSource_))
167        {
168            float volume = this->volume_ * this->getVolumeGain();
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.5)
186        {
187            COUT(2) << "Sound warning: pitch out of range, cropping value." << std::endl;
188            pitch = pitch > 2 ? 2 : pitch;
189            pitch = pitch < 0.5 ? 0.5 : pitch;
190        }       
191        this->pitch_ = pitch;
192        if (alIsSource(this->audioSource_))
193        {
194            if (int error = alGetError())
195                COUT(2) << "Sound: Error setting pitch: " << SoundManager::getALErrorString(error) << std::endl;
196            alSourcef(this->audioSource_, AL_PITCH, pitch);
197        }
198    }
199
200    void BaseSound::setSource(const std::string& source)
201    {
202        if (!GameMode::playsSound() || source == this->source_) 
203        {
204            this->source_ = source;
205            return;
206        }
207
208        if (this->soundBuffer_ != NULL)
209        {
210            // Stopping is imperative here!
211            if (alIsSource(this->audioSource_))
212            {
213                alSourceStop(this->audioSource_);
214                alSourcei(this->audioSource_, AL_BUFFER, AL_NONE);
215            }
216            SoundManager::getInstance().releaseSoundBuffer(this->soundBuffer_, this->bPooling_);
217            this->soundBuffer_.reset();
218        }
219
220        this->source_ = source;
221        if (source_.empty())
222            return;
223
224        this->soundBuffer_ = SoundManager::getInstance().getSoundBuffer(this->source_);
225        if (this->soundBuffer_ == NULL)
226            return;
227
228        if (alIsSource(this->audioSource_))
229        {
230            alSourcei(this->audioSource_, AL_BUFFER, this->soundBuffer_->getBuffer());
231            if (ALuint error = alGetError())
232            {
233                COUT(1) << "Sound Error: Could not set buffer \"" << source << "\": " << SoundManager::getALErrorString(error) << std::endl;
234                return;
235            }
236
237            if (this->isPlaying() || this->isPaused())
238            {
239                alSourcePlay(this->audioSource_);
240                if (int error = alGetError())
241                    COUT(2) << "Sound: Error playing sound: " << SoundManager::getALErrorString(error) << std::endl;
242            }
243            if (this->isPaused())
244                alSourcePause(this->audioSource_);
245        }
246    }
247   
248    void BaseSound::stateChanged()
249    {
250        CCOUT(0) << "changed state to " << this->state_ << endl;
251        switch( this->state_ )
252        {
253            case Playing:
254                this->play();
255                break;
256            case Paused:
257                this->pause();
258                break;
259            case Stopped:
260            default:
261                this->stop();
262                break;
263        }
264    }
265}
Note: See TracBrowser for help on using the repository browser.