Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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