Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Dec 25, 2009, 10:23:58 PM (14 years ago)
Author:
rgrieder
Message:

Merged presentation2 branch back to trunk.
Major new features:

  • Actual GUI with settings, etc.
  • Improved space ship steering (human interaction)
  • Rocket fire and more particle effects
  • Advanced sound framework
Location:
code/trunk
Files:
10 edited
4 copied

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/src/orxonox/sound/AmbientSound.cc

    r5929 r6417  
    3131#include "core/CoreIncludes.h"
    3232#include "core/EventIncludes.h"
     33#include "core/GameMode.h"
     34#include "core/Resource.h"
    3335#include "core/XMLPort.h"
     36#include "SoundManager.h"
    3437
    3538namespace orxonox
     
    3942    AmbientSound::AmbientSound(BaseObject* creator)
    4043        : BaseObject(creator)
     44        , Synchronisable(creator)
     45        , bPlayOnLoad_(false)
    4146    {
    4247        RegisterObject(AmbientSound);
     48
     49        // Ambient sounds always fade in
     50        this->setVolume(0);
     51        this->registerVariables();
    4352    }
    4453
    45     AmbientSound::~AmbientSound()
     54    void AmbientSound::preDestroy()
    4655    {
     56        if (GameMode::playsSound())
     57        {
     58            // Smoothly fade out by keeping a SmartPtr
     59            SoundManager::getInstance().unregisterAmbientSound(this);
     60        }
     61    }
     62
     63    void AmbientSound::registerVariables()
     64    {
     65        registerVariable(ambientSource_, ObjectDirection::ToClient, new NetworkCallback<AmbientSound>(this, &AmbientSound::ambientSourceChanged));
     66        registerVariable(bLooping_,      ObjectDirection::ToClient, new NetworkCallback<AmbientSound>(this, &AmbientSound::loopingChanged));
     67        registerVariable(pitch_,         ObjectDirection::ToClient, new NetworkCallback<AmbientSound>(this, &AmbientSound::pitchChanged));
     68        registerVariable(bPlayOnLoad_,   ObjectDirection::ToClient, new NetworkCallback<AmbientSound>(this, &AmbientSound::playOnLoadChanged));
    4769    }
    4870
     
    5072    {
    5173        SUPER(AmbientSound, XMLPort, xmlelement, mode);
    52         XMLPortParamExtern(AmbientSound, BaseSound, this, "source", setSource, getSource, xmlelement, mode);
    53         XMLPortParamExtern(AmbientSound, BaseSound, this, "loop", setLoop, getLoop, xmlelement, mode);
    54         XMLPortParamExtern(AmbientSound, BaseSound, this, "playOnLoad", setPlayOnLoad, getPlayOnLoad, xmlelement, mode);
     74        BaseSound::XMLPortExtern(xmlelement, mode);
     75        XMLPortParam(AmbientSound, "ambientSource", setAmbientSource, getAmbientSource, xmlelement, mode);
     76        XMLPortParam(AmbientSound, "playOnLoad", setPlayOnLoad, getPlayOnLoad, xmlelement, mode);
    5577    }
    5678
     
    6082        XMLPortEventState(AmbientSound, BaseObject, "play", play, xmlelement, mode);
    6183    }
     84
     85    void AmbientSound::play()
     86    {
     87        if (GameMode::playsSound())
     88            SoundManager::getInstance().registerAmbientSound(this);
     89    }
     90
     91    void AmbientSound::stop()
     92    {
     93        if (GameMode::playsSound())
     94            SoundManager::getInstance().unregisterAmbientSound(this);
     95    }
     96
     97    void AmbientSound::pause()
     98    {
     99        if (GameMode::playsSound())
     100            SoundManager::getInstance().pauseAmbientSound(this);
     101    }
     102
     103    float AmbientSound::getRealVolume()
     104    {
     105        assert(GameMode::playsSound());
     106        return SoundManager::getInstance().getRealVolume(SoundType::Music);
     107    }
     108
     109    void AmbientSound::setAmbientSource(const std::string& source)
     110    {
     111        this->ambientSource_ = source;
     112        this->moodChanged(this->getMood());
     113    }
     114
     115    void AmbientSound::moodChanged(const std::string& mood)
     116    {
     117        if (GameMode::playsSound())
     118        {
     119            const std::string& path = "ambient/" + MoodManager::getInstance().getMood() + '/' + this->ambientSource_;
     120            shared_ptr<ResourceInfo> fileInfo = Resource::getInfo(path);
     121            if (fileInfo != NULL)
     122                this->setSource(path);
     123            else
     124                COUT(3) << "Sound: " << this->ambientSource_ << ": Not a valid name! Ambient sound will not change." << std::endl;
     125        }
     126    }
     127
     128    void AmbientSound::setPlayOnLoad(bool val)
     129    {
     130        this->bPlayOnLoad_ = val;
     131        if (val)
     132            this->play();
     133    }
     134
     135    void AmbientSound::changedActivity()
     136    {
     137        SUPER(AmbientSound, changedActivity);
     138        if (this->isActive())
     139            this->play();
     140        else
     141            this->stop();
     142    }
    62143}
  • code/trunk/src/orxonox/sound/AmbientSound.h

    r5929 r6417  
    2222 *   Author:
    2323 *      Reto Grieder
     24 *      Kevin Young
    2425 *   Co-authors:
    2526 *      ...
    2627 *
    2728 */
     29
    2830#ifndef _AmbientSound_H__
    2931#define _AmbientSound_H__
     
    3234
    3335#include "core/BaseObject.h"
    34 #include "sound/BaseSound.h"
     36#include "network/synchronisable/Synchronisable.h"
     37#include "BaseSound.h"
     38#include "MoodManager.h"
    3539
    3640namespace orxonox
     
    4145     *
    4246     */
    43     class _OrxonoxExport AmbientSound : public BaseSound, public BaseObject
     47    class _OrxonoxExport AmbientSound : public BaseSound, public BaseObject, public Synchronisable, public MoodListener
    4448    {
     49        friend class SoundManager;
     50
    4551    public:
    4652        AmbientSound(BaseObject* creator);
    47         virtual ~AmbientSound();
    4853
    49         virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
    50         virtual void XMLEventPort(Element& xmlelement, XMLPort::Mode mode);
     54        void XMLPort(Element& xmlelement, XMLPort::Mode mode);
     55        void XMLEventPort(Element& xmlelement, XMLPort::Mode mode);
     56        void changedActivity();
     57
     58        void play();
     59        void stop();
     60        void pause();
     61
     62        void setAmbientSource(const std::string& source);
     63        inline const std::string& getAmbientSource() const
     64            { return this->ambientSource_; }
     65
     66        void setPlayOnLoad(bool val);
     67        bool getPlayOnLoad() const
     68            { return this->bPlayOnLoad_; }
     69
     70    protected:
     71        ~AmbientSound() { }
    5172
    5273    private:
     74        void preDestroy();
     75        void registerVariables();
     76        float getRealVolume();
     77        void moodChanged(const std::string& mood);
     78        inline void ambientSourceChanged()
     79            { this->setAmbientSource(this->ambientSource_); }
     80        inline void playOnLoadChanged()
     81            { this->setPlayOnLoad(this->bPlayOnLoad_); }
     82
     83        std::string ambientSource_; //!< Analogous to source_, but mood independent
     84        bool        bPlayOnLoad_;   //!< Play the sound immediately when loaded
    5385    };
    5486}
  • code/trunk/src/orxonox/sound/BaseSound.cc

    r5929 r6417  
    2929#include "BaseSound.h"
    3030
     31#include <cassert>
    3132#include <vector>
    32 #include <AL/alut.h>
    33 #include <vorbis/vorbisfile.h>
     33#include <al.h>
    3434
    3535#include "core/CoreIncludes.h"
    3636#include "core/GameMode.h"
    3737#include "core/Resource.h"
     38#include "core/XMLPort.h"
     39#include "SoundBuffer.h"
     40#include "SoundManager.h"
    3841
    3942namespace orxonox
    4043{
    4144    BaseSound::BaseSound()
    42         : audioSource_(0)
    43         , audioBuffer_(0)
    44         , bPlayOnLoad_(false)
    45         , bLoop_(false)
     45        : bPooling_(false)
     46        , volume_(1.0)
     47        , bLooping_(false)
     48        , state_(Stopped)
     49        , pitch_ (1.0)
    4650    {
    4751        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_));
    4857    }
    4958
    5059    BaseSound::~BaseSound()
    5160    {
    52         this->setSource("");
    53     }
    54 
    55     void BaseSound::play()
    56     {
    57         if (alIsSource(this->audioSource_))
    58         {
    59             if (this->bLoop_)
    60                 alSourcei(this->audioSource_, AL_LOOPING, AL_TRUE);
    61             else
    62                 alSourcei(this->audioSource_, AL_LOOPING, AL_FALSE);
     61        this->stop();
     62        // Release buffer
     63        if (this->soundBuffer_ != NULL)
     64        {
     65            assert(GameMode::playsSound());
     66            SoundManager::getInstance().releaseSoundBuffer(this->soundBuffer_, this->bPooling_);
     67        }
     68    }
     69
     70    void BaseSound::XMLPortExtern(Element& xmlelement, XMLPort::Mode mode)
     71    {
     72        XMLPortParam(BaseSound, "volume",  setVolume,  getVolume,  xmlelement, mode);
     73        XMLPortParam(BaseSound, "looping", setLooping, getLooping, xmlelement, mode);
     74        XMLPortParam(BaseSound, "pitch",   setPitch,   getPitch,   xmlelement, mode);
     75        XMLPortParam(BaseSound, "source",  setSource,  getSource,  xmlelement, mode);
     76    }
     77
     78    void BaseSound::doPlay()
     79    {
     80        this->state_ = Playing;
     81        if (GameMode::playsSound() && this->getSourceState() != AL_PLAYING && this->soundBuffer_ != NULL)
     82        {
     83            if (!alIsSource(this->audioSource_))
     84            {
     85                this->audioSource_ = SoundManager::getInstance().getSoundSource(this);
     86                if (!alIsSource(this->audioSource_))
     87                    return;
     88                this->initialiseSource();
     89            }
     90
    6391            alSourcePlay(this->audioSource_);
    64 
    65             if (alGetError() != AL_NO_ERROR)
    66             {
    67                  COUT(2) << "Sound: OpenAL: Error playin sound " << this->audioSource_ << std::endl;
    68             }
    69         }
    70     }
    71 
    72     void BaseSound::stop()
    73     {
    74         if (alIsSource(this->audioSource_))
     92            if (int error = alGetError())
     93                COUT(2) << "Sound: Error playing sound: " << SoundManager::getALErrorString(error) << std::endl;
     94        }
     95    }
     96
     97    void BaseSound::doStop()
     98    {
     99        this->state_ = Stopped;
     100        if (alIsSource(this->audioSource_))
     101        {
    75102            alSourceStop(this->audioSource_);
    76     }
    77 
    78     void BaseSound::pause()
    79     {
     103            // Release buffer
     104            alSourcei(this->audioSource_, AL_BUFFER, AL_NONE);
     105            // Release source again
     106            SoundManager::getInstance().releaseSoundSource(this->audioSource_);
     107            // Get a no source ID
     108            this->audioSource_ += 123455;
     109            while (alIsSource(++this->audioSource_));
     110        }
     111    }
     112
     113    void BaseSound::doPause()
     114    {
     115        if (this->isStopped())
     116            return;
     117        this->state_ = Paused;
    80118        if (alIsSource(this->audioSource_))
    81119            alSourcePause(this->audioSource_);
    82120    }
    83121
    84     bool BaseSound::isPlaying()
    85     {
    86         if (alIsSource(this->audioSource_))
    87             return getSourceState() == AL_PLAYING;
    88         return false;
    89     }
    90 
    91     bool BaseSound::isPaused()
    92     {
    93         if (alIsSource(this->audioSource_))
    94             return getSourceState() == AL_PAUSED;
    95         return true;
    96     }
    97 
    98     bool BaseSound::isStopped()
    99     {
    100         if (alIsSource(this->audioSource_))
    101             return getSourceState() == AL_INITIAL || getSourceState() == AL_STOPPED;
    102         return true;
    103     }
    104 
    105     void BaseSound::setPlayOnLoad(bool val)
    106     {
    107         this->bPlayOnLoad_ = true;
    108         this->play();
     122    ALint BaseSound::getSourceState() const
     123    {
     124        if (alIsSource(this->audioSource_))
     125        {
     126            ALint state;
     127            alGetSourcei(this->audioSource_, AL_SOURCE_STATE, &state);
     128            return state;
     129        }
     130        else
     131            return AL_INITIAL;
     132    }
     133
     134    void BaseSound::initialiseSource()
     135    {
     136        this->updateVolume();
     137        this->setPitch(this->getPitch());
     138        this->setLooping(this->getLooping());
     139        alSource3f(this->audioSource_, AL_POSITION,  0, 0, 0);
     140        alSource3f(this->audioSource_, AL_VELOCITY,  0, 0, 0);
     141        alSource3f(this->audioSource_, AL_DIRECTION, 0, 0, 0);
     142        if (ALint error = alGetError())
     143            COUT(2) << "Sound Warning: Setting source parameters to 0 failed: "
     144                    << SoundManager::getALErrorString(error) << std::endl;
     145        assert(this->soundBuffer_ != NULL);
     146        alSourcei(this->audioSource_, AL_BUFFER, this->soundBuffer_->getBuffer());
     147        if (ALuint error = alGetError())
     148            COUT(1) << "Sound Error: Could not set buffer \"" << this->source_ << "\": " << SoundManager::getALErrorString(error) << std::endl;
     149    }
     150
     151    void BaseSound::setVolume(float vol)
     152    {
     153        this->volume_ = clamp(vol, 0.0f, 1.0f);
     154        if (this->volume_ != vol)
     155            COUT(2) << "Sound warning: volume out of range, clamping value." << std::endl;
     156        this->updateVolume();
     157    }
     158
     159    void BaseSound::updateVolume()
     160    {
     161        if (alIsSource(this->audioSource_))
     162        {
     163            float volume = this->volume_ * this->getRealVolume();
     164            alSourcef(this->audioSource_, AL_GAIN, volume);
     165            if (int error = alGetError())
     166                COUT(2) << "Sound: Error setting volume to " << volume
     167                        << ": " << SoundManager::getALErrorString(error) << std::endl;
     168        }
     169    }
     170
     171    void BaseSound::setLooping(bool val)
     172    {
     173        this->bLooping_ = val;
     174        if (alIsSource(this->audioSource_))
     175            alSourcei(this->audioSource_, AL_LOOPING, (val ? AL_TRUE : AL_FALSE));
     176    }
     177
     178    void BaseSound::setPitch(float pitch)
     179    {
     180        if (pitch > 2 || pitch < 0.5)
     181        {
     182            COUT(2) << "Sound warning: pitch out of range, cropping value." << std::endl;
     183            pitch = pitch > 2 ? 2 : pitch;
     184            pitch = pitch < 0.5 ? 0.5 : pitch;
     185        }
     186        this->pitch_ = pitch;
     187        if (alIsSource(this->audioSource_))
     188        {
     189            alSourcef(this->audioSource_, AL_PITCH, pitch);
     190            if (int error = alGetError())
     191                COUT(2) << "Sound: Error setting pitch: " << SoundManager::getALErrorString(error) << std::endl;
     192        }
    109193    }
    110194
    111195    void BaseSound::setSource(const std::string& source)
    112196    {
     197        if (!GameMode::playsSound())
     198        {
     199            this->source_ = source;
     200            return;
     201        }
     202
     203        if (this->soundBuffer_ != NULL)
     204        {
     205            if (this->soundBuffer_->getFilename() == source)
     206            {
     207                assert(this->source_ == source_);
     208                return;
     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
    113220        this->source_ = source;
    114         if (!GameMode::playsSound())
    115             return;
    116 
    117         if (source.empty() && alIsSource(this->audioSource_))
    118         {
    119             // Unload sound
    120             alSourcei(this->audioSource_, AL_BUFFER, 0);
    121             alDeleteSources(1, &this->audioSource_);
    122             alDeleteBuffers(1, &this->audioBuffer_);
    123             return;
    124         }
    125 
    126         COUT(3) << "Sound: OpenAL ALUT: loading file " << source << std::endl;
    127         // Get DataStream from the resources
    128         shared_ptr<ResourceInfo> fileInfo = Resource::getInfo(source);
    129         if (fileInfo == NULL)
    130         {
    131             COUT(2) << "Warning: Sound file '" << source << "' not found" << std::endl;
    132             return;
    133         }
    134         dataStream_ = Resource::open(source);
    135         // Read everything into a temporary buffer
    136         char* buffer = new char[fileInfo->size];
    137         dataStream_->read(buffer, fileInfo->size);
    138         dataStream_->seek(0);
    139 
    140         this->audioBuffer_ = alutCreateBufferFromFileImage(buffer, fileInfo->size);
    141         delete[] buffer;
    142 
    143         if (this->audioBuffer_ == AL_NONE)
    144         {
    145             COUT(2) << "Sound: OpenAL ALUT: " << alutGetErrorString(alutGetError()) << std::endl;
    146             if (source.find("ogg", 0) != std::string::npos)
    147             {
    148                 COUT(2) << "Sound: Trying fallback ogg loader" << std::endl;
    149                 this->audioBuffer_ = loadOggFile();
    150             }
    151 
    152             if (this->audioBuffer_ == AL_NONE)
    153             {
    154                 COUT(2) << "Sound: fallback ogg loader failed: " << alutGetErrorString(alutGetError()) << std::endl;
     221        // Don't load ""
     222        if (source_.empty())
     223            return;
     224
     225        // Get new sound buffer
     226        this->soundBuffer_ = SoundManager::getInstance().getSoundBuffer(this->source_);
     227        if (this->soundBuffer_ == NULL)
     228            return;
     229
     230        if (alIsSource(this->audioSource_)) // already playing or paused
     231        {
     232            // Set new buffer
     233            alSourcei(this->audioSource_, AL_BUFFER, this->soundBuffer_->getBuffer());
     234            if (ALuint error = alGetError())
     235            {
     236                COUT(1) << "Sound Error: Could not set buffer \"" << source << "\": " << SoundManager::getALErrorString(error) << std::endl;
    155237                return;
    156238            }
    157         }
    158 
    159         alGenSources(1, &this->audioSource_);
    160         alSourcei(this->audioSource_, AL_BUFFER, this->audioBuffer_);
    161         if (alGetError() != AL_NO_ERROR)
    162         {
    163             COUT(2) << "Sound: OpenAL: Error loading sample file: " << source << std::endl;
    164             return;
    165         }
    166 
    167         alSource3f(this->audioSource_, AL_POSITION,  0, 0, 0);
    168 
    169         if (this->bPlayOnLoad_)
    170             this->play();
    171     }
    172 
    173     ALint BaseSound::getSourceState()
    174     {
    175         ALint state;
    176         alGetSourcei(this->audioSource_, AL_SOURCE_STATE, &state);
    177         return state;
    178     }
    179 
    180     size_t readVorbis(void* ptr, size_t size, size_t nmemb, void* datasource)
    181     {
    182         return static_cast<Ogre::DataStream*>(datasource)->read(ptr, size * nmemb);
    183     }
    184 
    185     int seekVorbis(void* datasource, ogg_int64_t offset, int whence)
    186     {
    187         Ogre::DataStream* stream = static_cast<Ogre::DataStream*>(datasource);
    188         int offset_beg = offset;
    189         if (whence == SEEK_CUR)
    190             offset_beg = stream->tell() + offset;
    191         else if (whence == SEEK_END)
    192             offset_beg = stream->size() + offset;
    193         else if (whence != SEEK_SET)
    194             return -1;
    195         stream->seek(offset_beg);
    196         return 0;
    197     }
    198 
    199     long tellVorbis(void* datasource)
    200     {
    201         return static_cast<long>(static_cast<Ogre::DataStream*>(datasource)->tell());
    202     }
    203 
    204     ALuint BaseSound::loadOggFile()
    205     {
    206         char inbuffer[4096];
    207         std::vector<char> outbuffer;
    208         OggVorbis_File vf;
    209         vorbis_info* vorbisInfo;
    210         int eof = false;
    211         int current_section;
    212         ALuint buffer;
    213         ALenum format;
    214 
    215         // Open file with custom streaming
    216         ov_callbacks vorbisCallbacks;
    217         vorbisCallbacks.read_func  = &readVorbis;
    218         vorbisCallbacks.seek_func  = &seekVorbis;
    219         vorbisCallbacks.tell_func  = &tellVorbis;
    220         vorbisCallbacks.close_func = NULL;
    221 
    222         int ret = ov_open_callbacks(dataStream_.get(), &vf, NULL, 0, vorbisCallbacks);
    223         if (ret < 0)
    224         {
    225             COUT(2) << "Sound: libvorbisfile: File does not seem to be an Ogg Vorbis bitstream" << std::endl;
    226             ov_clear(&vf);
    227             return AL_NONE;
    228         }
    229 
    230         while (!eof)
    231         {
    232             long ret = ov_read(&vf, inbuffer, sizeof(inbuffer), 0, 2, 1, &current_section);
    233             if (ret == 0)
    234             {
    235                 eof = true;
    236             }
    237             else if (ret < 0)
    238             {
    239                 COUT(2) << "Sound: libvorbisfile: error reading the file" << std::endl;
    240                 ov_clear(&vf);
    241                 return AL_NONE;
    242             }
    243             else
    244             {
    245                 outbuffer.insert(outbuffer.end(), inbuffer, inbuffer + sizeof(inbuffer));
    246             }
    247         }
    248 
    249         vorbisInfo = ov_info(&vf, -1);
    250         if (vorbisInfo->channels == 1)
    251             format = AL_FORMAT_MONO16;
    252         else
    253             format = AL_FORMAT_STEREO16;
    254 
    255         alGenBuffers(1, &buffer);
    256         alBufferData(buffer, format, &outbuffer[0], outbuffer.size(), vorbisInfo->rate);
    257         ov_clear(&vf);
    258 
    259         return buffer;
    260     }
    261 
    262 } // namespace: orxonox
     239
     240            // Sound was already playing or paused because there was a source acquired
     241            assert(this->isPlaying() || this->isPaused());
     242            alSourcePlay(this->audioSource_);
     243            if (int error = alGetError())
     244                COUT(2) << "Sound: Error playing sound: " << SoundManager::getALErrorString(error) << std::endl;
     245            if (this->isPaused())
     246                alSourcePause(this->audioSource_);
     247        }
     248        else // No source acquired so far, but might be set to playing or paused
     249        {
     250            State state = this->state_; // save
     251            if (this->isPlaying() || this->isPaused())
     252                doPlay();
     253            if (state == Paused)
     254            {
     255                this->state_ = Paused;
     256                doPause();
     257            }
     258        }
     259    }
     260
     261    void BaseSound::stateChanged()
     262    {
     263        switch (this->state_)
     264        {
     265            case Playing:
     266                this->play();
     267                break;
     268            case Paused:
     269                this->pause();
     270                break;
     271            case Stopped:
     272            default:
     273                this->stop();
     274                break;
     275        }
     276    }
     277}
  • code/trunk/src/orxonox/sound/BaseSound.h

    r5929 r6417  
    2626 *
    2727 */
     28
    2829#ifndef _BaseSound_H__
    2930#define _BaseSound_H__
     
    3233
    3334#include <string>
    34 #include <OgreSharedPtr.h>
     35#include <boost/shared_ptr.hpp>
    3536#include <OgreDataStream.h>
    3637#include "core/OrxonoxClass.h"
     
    4748    public:
    4849        BaseSound();
     50
     51        void XMLPortExtern(Element& xmlelement, XMLPort::Mode mode);
     52
     53        virtual void play()  { this->doPlay(); }
     54        virtual void stop()  { this->doStop(); }
     55        virtual void pause() { this->doPause(); }
     56
     57        bool isPlaying() const { return this->state_ == Playing; }
     58        bool isPaused()  const { return this->state_ == Paused; }
     59        bool isStopped() const { return this->state_ == Stopped; }
     60
     61        virtual void setSource(const std::string& source);
     62        virtual const std::string& getSource() const
     63            { return this->source_; }
     64
     65        void setVolume(float vol);
     66        float getVolume() const
     67            { return this->volume_; }
     68        void updateVolume();
     69
     70        bool getLooping() const
     71            { return this->bLooping_; }
     72        void setLooping(bool val);
     73
     74        float getPitch() const
     75            { return this->pitch_; }
     76        void setPitch(float pitch);
     77
     78    protected:
     79        enum State
     80        {
     81            Stopped,
     82            Playing,
     83            Paused
     84        };
     85
    4986        virtual ~BaseSound();
    5087
    51         void play();
    52         void stop();
    53         void pause();
     88        void doPlay();
     89        void doStop();
     90        void doPause();
    5491
    55         bool isPlaying();
    56         bool isPaused();
    57         bool isStopped();
     92        // network callbacks
     93        inline void pitchChanged()
     94            { this->setPitch(this->pitch_); }
     95        inline void loopingChanged()
     96            { this->setLooping(this->bLooping_); }
     97        inline void volumeChanged()
     98            { this->setVolume(this->volume_); }
     99        inline void sourceChanged()
     100            { this->setSource(this->source_); }
     101        void stateChanged();
    58102
    59         void setSource(const std::string& source);
    60         const std::string& getSource() { return this->source_; }
     103        virtual void initialiseSource();
     104        ALint getSourceState() const;
    61105
    62         bool getPlayOnLoad() { return this->bPlayOnLoad_; }
    63         void setPlayOnLoad(bool val);
     106        virtual float getRealVolume() = 0;
    64107
    65         bool getLoop() { return this->bLoop_; }
    66         void setLoop(bool val) { this->bLoop_ = val; }
    67 
    68     protected:
    69         ALuint loadOggFile();
    70         ALint getSourceState();
    71 
    72         ALuint audioSource_;
    73         ALuint audioBuffer_;
     108        ALuint          audioSource_;
     109        bool            bPooling_;
     110        shared_ptr<SoundBuffer> soundBuffer_;
     111        std::string     source_;
     112        float           volume_;
     113        bool            bLooping_;
     114        State           state_;
     115        float           pitch_;
    74116
    75117    private:
    76         std::string source_;
    77         bool bPlayOnLoad_;
    78         bool bLoop_;
    79         DataStreamPtr dataStream_;
     118        DataStreamPtr   dataStream_;
    80119    };
    81120}
  • code/trunk/src/orxonox/sound/CMakeLists.txt

    r5929 r6417  
    22    AmbientSound.cc
    33    BaseSound.cc
     4    SoundBuffer.cc
    45    SoundManager.cc
    56    WorldSound.cc
     7    SoundStreamer.cc
    68)
    79
  • code/trunk/src/orxonox/sound/SoundManager.cc

    r5929 r6417  
    2222 *   Author:
    2323 *       Erwin 'vaiursch' Herrsche
     24 *       Kevin Young
     25 *       Reto Grieder
    2426 *   Co-authors:
    2527 *      ...
     
    3032
    3133#include <AL/alut.h>
     34#include <utility>
    3235
    3336#include "util/Exception.h"
    3437#include "util/Math.h"
    3538#include "util/ScopeGuard.h"
     39#include "util/Clock.h"
     40#include "core/ConfigValueIncludes.h"
     41#include "core/CoreIncludes.h"
    3642#include "core/GameMode.h"
    3743#include "core/ScopedSingletonManager.h"
     44#include "core/Resource.h"
     45#include "SoundBuffer.h"
     46#include "BaseSound.h"
     47#include "AmbientSound.h"
     48#include "WorldSound.h"
    3849
    3950namespace orxonox
    4051{
    41     SoundManager* SoundManager::singletonPtr_s = NULL;
    4252    ManageScopedSingleton(SoundManager, ScopeID::Graphics, true);
    4353
     54    std::string SoundManager::getALErrorString(ALenum code)
     55    {
     56        switch (code)
     57        {
     58        case AL_NO_ERROR:          return "No error";
     59        case AL_INVALID_NAME:      return "Invalid AL parameter name";
     60        case AL_INVALID_ENUM:      return "Invalid AL enum";
     61        case AL_INVALID_VALUE:     return "Invalid AL value";
     62        case AL_INVALID_OPERATION: return "Invalid AL operation";
     63        case AL_OUT_OF_MEMORY:     return "AL reports out of memory";
     64        default:                   return "Unknown AL error";
     65        }
     66    }
     67
    4468    SoundManager::SoundManager()
    45     {
    46         if (!alutInitWithoutContext(NULL,NULL))
    47             ThrowException(InitialisationFailed, "OpenAL ALUT error: " << alutGetErrorString(alutGetError()));
     69        : effectsPoolSize_(0)
     70    {
     71        RegisterRootObject(SoundManager);
     72
     73        // See whether we even want to load
     74        bool bDisableSound_ = false;
     75        SetConfigValue(bDisableSound_, false);
     76        if (bDisableSound_)
     77            ThrowException(InitialisationAborted, "Sound: Not loading at all");
     78
     79        if (!alutInitWithoutContext(NULL, NULL))
     80            ThrowException(InitialisationFailed, "Sound Error: ALUT initialisation failed: " << alutGetErrorString(alutGetError()));
    4881        Loki::ScopeGuard alutExitGuard = Loki::MakeGuard(&alutExit);
    4982
    50         COUT(3) << "OpenAL: Opening sound device..." << std::endl;
     83/*
     84        // Get list of available sound devices and display them
     85        const char* devices = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
     86        char* device = new char[strlen(devices)+1];
     87        strcpy(device, devices);
     88        std::string renderDevice;
     89        SetConfigValue(renderDevice, std::string(device)).description("Sound device used for rendering");
     90        COUT(4) << "Sound: Available devices: ";
     91        while (true)
     92        {
     93            this->deviceNames_.push_back(devices);
     94            COUT(4) << '"' << devices << "\", ";
     95            devices += strlen(devices) + 1;
     96            if (*devices == '\0')
     97                break;
     98        }
     99        COUT(4) << std::endl;
     100
     101        // Open the selected device
     102        COUT(3) << "Sound: Opening device \"" << renderDevice << '\' << std::endl;
     103        this->device_ = alcOpenDevice(renderDevice.c_str());
     104*/
    51105        this->device_ = alcOpenDevice(NULL);
    52106        if (this->device_ == NULL)
    53107        {
    54             COUT(0) << "OpenaAL: Could not open sound device. Have you installed OpenAL?" << std::endl;
     108            COUT(1) << "Sound: Could not open sound device. Have you installed OpenAL?" << std::endl;
    55109#ifdef ORXONOX_PLATFORM_WINDOWS
    56             COUT(0) << "Just getting the DLL with the dependencies is not enough for Windows (esp. Windows 7)!" << std::endl;
     110            COUT(1) << "Sound: Just getting the DLL with the dependencies is not enough for Windows (esp. Windows 7)!" << std::endl;
    57111#endif
    58             ThrowException(InitialisationFailed, "OpenAL error: Could not open sound device.");
     112            ThrowException(InitialisationFailed, "Sound Error: Could not open sound device.");
    59113        }
    60114        Loki::ScopeGuard closeDeviceGuard = Loki::MakeGuard(&alcCloseDevice, this->device_);
    61115
    62         COUT(3) << "OpenAL: Sound device opened" << std::endl;
     116        // Create sound context and make it the currently used one
    63117        this->context_ = alcCreateContext(this->device_, NULL);
    64118        if (this->context_ == NULL)
    65             ThrowException(InitialisationFailed, "OpenAL error: Could not create sound context");
     119            ThrowException(InitialisationFailed, "Sound Error: Could not create ALC context");
    66120        Loki::ScopeGuard desroyContextGuard = Loki::MakeGuard(&alcDestroyContext, this->context_);
    67 
    68         if (alcMakeContextCurrent(this->context_) == AL_TRUE)
    69             COUT(3) << "OpenAL: Context " << this->context_ << " loaded" << std::endl;
    70 
    71         COUT(4) << "Sound: OpenAL ALUT version: " << alutGetMajorVersion() << "." << alutGetMinorVersion() << std::endl;
    72 
    73         const char* str = alutGetMIMETypes(ALUT_LOADER_BUFFER);
    74         if (str == NULL)
    75             COUT(2) << "OpenAL ALUT error: " << alutGetErrorString(alutGetError()) << std::endl;
     121        if (!alcMakeContextCurrent(this->context_))
     122            ThrowException(InitialisationFailed, "Sound Error: Could not use ALC context");
     123
     124        GameMode::setPlaysSound(true);
     125        Loki::ScopeGuard resetPlaysSoundGuard = Loki::MakeGuard(&GameMode::setPlaysSound, false);
     126
     127        // Get some information about the sound
     128        if (const char* version = alGetString(AL_VERSION))
     129            COUT(4) << "Sound: --- OpenAL Version: " << version << std::endl;
     130        if (const char* vendor = alGetString(AL_VENDOR))
     131            COUT(4) << "Sound: --- OpenAL Vendor : " << vendor << std::endl;
     132        if (const char* types = alutGetMIMETypes(ALUT_LOADER_BUFFER))
     133            COUT(4) << "Sound: --- Supported MIME Types: " << types << std::endl;
    76134        else
    77             COUT(4) << "OpenAL ALUT supported MIME types: " << str << std::endl;
    78 
    79         GameMode::setPlaysSound(true);
     135            COUT(2) << "Sound Warning: MIME Type retrieval failed: " << alutGetErrorString(alutGetError()) << std::endl;
     136
     137        this->mute_[SoundType::All]     = 1.0f;
     138        this->mute_[SoundType::Music]   = 1.0f;
     139        this->mute_[SoundType::Effects] = 1.0f;
     140
     141        this->setConfigValues();
     142
     143        // Try to get at least one source
     144        ALuint source;
     145        alGenSources(1, &source);
     146        if (!alGetError() && alIsSource(source))
     147            this->availableSoundSources_.push_back(source);
     148        else
     149            ThrowException(InitialisationFailed, "Sound Error: Could not create even a single source");
     150        // Create a few initial sources
     151        this->createSoundSources(this->minSources_ - 1);
     152
    80153        // Disarm guards
    81154        alutExitGuard.Dismiss();
    82155        closeDeviceGuard.Dismiss();
    83156        desroyContextGuard.Dismiss();
     157        resetPlaysSoundGuard.Dismiss();
     158
     159        COUT(4) << "Sound: Initialisation complete" << std::endl;
    84160    }
    85161
    86162    SoundManager::~SoundManager()
    87163    {
     164        // Erase fade lists because of the smart pointers
     165        this->fadeInList_.clear();
     166        this->fadeOutList_.clear();
     167
     168        // If there are still used buffers around, well, that's just very bad...
     169        if (this->soundBuffers_.size() != this->effectsPool_.size())
     170            COUT(1) << "Sound Error: Some sound buffers are still in use but OpenAL is about to shut down. Fix this!" << std::endl;
     171        // Empty buffer pool and buffer list
     172        this->effectsPool_.clear();
     173        this->soundBuffers_.clear();
     174
     175        // There should not be any sources in use anymore
     176        if (!this->usedSoundSources_.empty())
     177            COUT(1) << "Sound Error: Some sound sources are still in use but OpenAL is about to shut down. Fix this!" << std::endl;
     178        while (!this->availableSoundSources_.empty())
     179        {
     180            alDeleteSources(1, &this->availableSoundSources_.back());
     181            this->availableSoundSources_.pop_back();
     182        }
     183
    88184        GameMode::setPlaysSound(false);
     185
     186        // Relieve context to destroy it
     187        if (!alcMakeContextCurrent(NULL))
     188            COUT(1) << "Sound Error: Could not unset ALC context" << std::endl;
    89189        alcDestroyContext(this->context_);
     190        if (ALCenum error = alcGetError(this->device_))
     191        {
     192            if (error == AL_INVALID_OPERATION)
     193                COUT(1) << "Sound Error: Could not destroy ALC context because it is the current one" << std::endl;
     194            else
     195                COUT(1) << "Sound Error: Could not destroy ALC context because it is invalid" << std::endl;
     196        }
     197#ifdef AL_VERSION_1_1
     198        if (!alcCloseDevice(this->device_))
     199            COUT(1) << "Sound Error: Could not destroy ALC device. This might be because there are still buffers in use!" << std::endl;
     200#else
    90201        alcCloseDevice(this->device_);
    91         alutExit();
     202#endif
     203        if (!alutExit())
     204            COUT(1) << "Sound Error: Closing ALUT failed: " << alutGetErrorString(alutGetError()) << std::endl;
     205    }
     206
     207    void SoundManager::setConfigValues()
     208    {
     209        SetConfigValue(crossFadeStep_, 0.2f)
     210            .description("Determines how fast sounds should fade, per second.")
     211            .callback(this, &SoundManager::checkFadeStepValidity);
     212
     213        SetConfigValueAlias(volume_[SoundType::All], "soundVolume_", 1.0f)
     214            .description("Defines the overall volume.")
     215            .callback(this, &SoundManager::checkSoundVolumeValidity);
     216        SetConfigValueAlias(volume_[SoundType::Music], "ambientVolume_", 1.0f)
     217            .description("Defines the ambient volume.")
     218            .callback(this, &SoundManager::checkAmbientVolumeValidity);
     219        SetConfigValueAlias(volume_[SoundType::Effects], "effectsVolume_", 1.0f)
     220            .description("Defines the effects volume.")
     221            .callback(this, &SoundManager::checkEffectsVolumeValidity);
     222
     223        SetConfigValue(minSources_, 16)
     224            .description("Minimum number of sources being generated (if possible)");
     225        SetConfigValue(maxSources_, 1024)
     226            .description("Maximum number of sources to be made available");
     227    }
     228
     229    void SoundManager::preUpdate(const Clock& time)
     230    {
     231        this->processCrossFading(time.getDeltaTime());
     232
     233        // Check whether a sound object has stopped playing
     234        for (unsigned int i = 0; i < this->usedSoundSources_.size(); ++i)
     235        {
     236            ALint state;
     237            alGetSourcei(this->usedSoundSources_[i].first, AL_SOURCE_STATE, &state);
     238            if (state == AL_STOPPED)
     239            {
     240                this->usedSoundSources_[i].second->stop();
     241                --i;
     242            }
     243        }
     244    }
     245
     246    void SoundManager::checkFadeStepValidity()
     247    {
     248        if (crossFadeStep_ <= 0.0 || crossFadeStep_ >= 1.0 )
     249        {
     250            COUT(2) << "Sound warning: fade step out of range, ignoring change." << std::endl;
     251            ResetConfigValue(crossFadeStep_);
     252        }
     253    }
     254
     255    void SoundManager::checkVolumeValidity(SoundType::Value type)
     256    {
     257        float clampedVolume = clamp(this->volume_[type], 0.0f, 1.0f);
     258        if (clampedVolume != this->volume_[type])
     259            COUT(2) << "Sound warning: Volume setting (" << type << ") out of range, clamping." << std::endl;
     260        this->updateVolume(type);
     261    }
     262
     263    void SoundManager::setVolume(float vol, SoundType::Value type)
     264    {
     265        if (type < 0 || type > SoundType::Effects)
     266            return;
     267        this->volume_[type] = vol;
     268        this->checkVolumeValidity(type);
     269    }
     270
     271    float SoundManager::getVolume(SoundType::Value type)
     272    {
     273        if (type < 0 || type > SoundType::Effects)
     274            return 0.0f;
     275        return this->volume_[type];
     276    }
     277
     278    float SoundManager::getRealVolume(SoundType::Value type)
     279    {
     280        if (type != SoundType::Music && type != SoundType::Effects)
     281            return 0.0f;
     282        return this->volume_[SoundType::All] * this->mute_[SoundType::All] * this->volume_[type] * this->mute_[type];
     283    }
     284
     285    void SoundManager::updateVolume(SoundType::Value type)
     286    {
     287        switch(type)
     288        {
     289        case SoundType::All:
     290            for (ObjectList<BaseSound>::iterator it = ObjectList<BaseSound>::begin(); it != ObjectList<BaseSound>::end(); ++it)
     291                (*it)->updateVolume();
     292            break;
     293        case SoundType::Music:
     294            for (ObjectList<AmbientSound>::iterator it = ObjectList<AmbientSound>::begin(); it != ObjectList<AmbientSound>::end(); ++it)
     295                (*it)->updateVolume();
     296            break;
     297        case SoundType::Effects:
     298            for (ObjectList<WorldSound>::iterator it = ObjectList<WorldSound>::begin(); it != ObjectList<WorldSound>::end(); ++it)
     299                (*it)->updateVolume();
     300            break;
     301        default:
     302            assert(false);
     303        }
     304    }
     305
     306    void SoundManager::toggleMute(SoundType::Value type)
     307    {
     308        if (type < 0 || type > SoundType::Effects)
     309            return;
     310        this->mute_[type] = (this->mute_[type] == 0) ? 1.0f : 0.0f;
     311        this->updateVolume(type);
     312    }
     313
     314    bool SoundManager::getMute(SoundType::Value type)
     315    {
     316        if (type < 0 || type > SoundType::Effects)
     317            return true;
     318        return (this->mute_[type] == 0);
    92319    }
    93320
     
    103330    {
    104331        // update listener orientation
    105         Vector3 up = orientation.xAxis(); // just a wild guess
    106         Vector3 at = orientation.zAxis();
    107 
    108         ALfloat orient[6] = { at.x, at.y, at.z,
    109                               up.x, up.y, up.z };
    110 
    111         alListenerfv(AL_POSITION, orient);
     332        const Vector3& direction = -orientation.zAxis();
     333        const Vector3& up = orientation.yAxis();
     334
     335        ALfloat orient[6] = { direction.x, direction.y, direction.z, up.x, up.y, up.z };
     336
     337        alListenerfv(AL_ORIENTATION, orient);
    112338        ALenum error = alGetError();
    113339        if (error == AL_INVALID_VALUE)
    114340            COUT(2) << "Sound: OpenAL: Invalid listener orientation" << std::endl;
    115341    }
     342
     343    void SoundManager::registerAmbientSound(AmbientSound* newAmbient)
     344    {
     345        if (newAmbient != NULL)
     346        {
     347            for (AmbientList::const_iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
     348            {
     349                if (it->first == newAmbient)
     350                {
     351                    COUT(2) << "Sound warning: Will not play an AmbientSound twice." << std::endl;
     352                    return;
     353                }
     354            }
     355
     356            if (!this->ambientSounds_.empty())
     357            {
     358                this->fadeOut(ambientSounds_.front().first);
     359            }
     360            this->ambientSounds_.push_front(std::make_pair(newAmbient, false));
     361            newAmbient->doPlay();
     362            this->fadeIn(newAmbient);
     363        }
     364    }
     365
     366    void SoundManager::unregisterAmbientSound(AmbientSound* oldAmbient)
     367    {
     368        if (oldAmbient == NULL || ambientSounds_.empty())
     369            return;
     370
     371        if (this->ambientSounds_.front().first == oldAmbient)
     372        {
     373            this->fadeOut(oldAmbient);
     374            this->ambientSounds_.pop_front();
     375            if (!this->ambientSounds_.empty())
     376            {
     377                if (!this->ambientSounds_.front().second) // Not paused before
     378                {
     379                    this->ambientSounds_.front().first->doPlay();
     380                }
     381                this->fadeIn(this->ambientSounds_.front().first);
     382            }
     383        }
     384        else
     385        {
     386            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
     387            {
     388                if (it->first == oldAmbient)
     389                {
     390                    this->fadeOut(oldAmbient);
     391                    this->ambientSounds_.erase(it);
     392                    break;
     393                }
     394            }
     395        }
     396    }
     397
     398    void SoundManager::pauseAmbientSound(AmbientSound* ambient)
     399    {
     400        if (ambient != NULL)
     401        {
     402            for (AmbientList::iterator it = this->ambientSounds_.begin(); it != this->ambientSounds_.end(); ++it)
     403            {
     404                if (it->first == ambient)
     405                {
     406                    it->second = true;
     407                    this->fadeOut(it->first);
     408                    return;
     409                }
     410            }
     411        }
     412    }
     413
     414    void SoundManager::fadeIn(const SmartPtr<AmbientSound>& sound)
     415    {
     416        // If we're already fading out --> remove that
     417        for (std::list<SmartPtr<AmbientSound> >::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); it++)
     418        {
     419            if (*it == sound)
     420            {
     421                this->fadeOutList_.erase(it);
     422                break;
     423            }
     424        }
     425        // No duplicate entries
     426        if (std::find(this->fadeInList_.begin(), this->fadeInList_.end(), sound) == this->fadeInList_.end())
     427            this->fadeInList_.push_back(sound);
     428    }
     429
     430    void SoundManager::fadeOut(const SmartPtr<AmbientSound>& sound)
     431    {
     432        // If we're already fading in --> remove that
     433        for (std::list<SmartPtr<AmbientSound> >::iterator it = this->fadeInList_.begin(); it != this->fadeInList_.end(); it++)
     434        {
     435            if (*it == sound)
     436            {
     437                this->fadeInList_.erase(it);
     438                break;
     439            }
     440        }
     441        // No duplicate entries
     442        if (std::find(this->fadeOutList_.begin(), this->fadeOutList_.end(), sound) == this->fadeOutList_.end())
     443            this->fadeOutList_.push_back(sound);
     444    }
     445
     446    void SoundManager::processCrossFading(float dt)
     447    {
     448
     449        // Hacky solution to the fade delay while loading a level.
     450        if(dt > 0.2)
     451        {
     452            return;
     453        }
     454
     455        // FADE IN
     456        for (std::list<SmartPtr<AmbientSound> >::iterator it= this->fadeInList_.begin(); it != this->fadeInList_.end(); )
     457        {
     458            if ((*it)->getVolume() + this->crossFadeStep_*dt > 1.0f)
     459            {
     460                (*it)->setVolume(1.0f);
     461                this->fadeInList_.erase(it++);
     462            }
     463            else
     464            {
     465                (*it)->setVolume((*it)->getVolume() + this->crossFadeStep_*dt);
     466                ++it;
     467            }
     468        }
     469
     470        // FADE OUT
     471        for (std::list<SmartPtr<AmbientSound> >::iterator it = this->fadeOutList_.begin(); it != this->fadeOutList_.end(); )
     472        {
     473            if ((*it)->getVolume() - this->crossFadeStep_*dt < 0.0f)
     474            {
     475                (*it)->setVolume(0.0f);
     476
     477                // If sound is in the ambient list --> pause
     478                for (AmbientList::const_iterator it2 = this->ambientSounds_.begin(); it2 != this->ambientSounds_.end(); ++it2)
     479                {
     480                    if (it2->first == *it)
     481                    {
     482                        (*it)->doPause();
     483                        break;
     484                    }
     485                }
     486                // If not pause (by loop above for instance) --> stop
     487                if (!(*it)->isPaused())
     488                    (*it)->doStop();
     489
     490                this->fadeOutList_.erase(it++);
     491            }
     492            else
     493            {
     494                (*it)->setVolume((*it)->getVolume() - this->crossFadeStep_*dt);
     495                ++it;
     496            }
     497        }
     498    }
     499
     500    shared_ptr<SoundBuffer> SoundManager::getSoundBuffer(const std::string& filename)
     501    {
     502        shared_ptr<SoundBuffer> buffer;
     503        // Check active or pooled buffers
     504        SoundBufferMap::const_iterator it = this->soundBuffers_.find(filename);
     505        if (it != this->soundBuffers_.end())
     506        {
     507            buffer = it->second;
     508
     509            // Remove from effects pool if not active used before
     510            if (buffer->poolIterator_ != this->effectsPool_.end())
     511            {
     512                this->effectsPoolSize_ -= buffer->getSize();
     513                this->effectsPool_.erase(buffer->poolIterator_);
     514                buffer->poolIterator_ = this->effectsPool_.end();
     515            }
     516        }
     517        else
     518        {
     519            try
     520            {
     521                buffer.reset(new SoundBuffer(filename, this->effectsPool_.end()));
     522            }
     523            catch (...)
     524            {
     525                COUT(1) << Exception::handleMessage() << std::endl;
     526                return buffer;
     527            }
     528            this->soundBuffers_[filename] = buffer;
     529        }
     530        return buffer;
     531    }
     532
     533    void SoundManager::releaseSoundBuffer(const shared_ptr<SoundBuffer>& buffer, bool bPoolBuffer)
     534    {
     535        // Check if others are still using the buffer
     536        if (buffer.use_count() != 2)
     537            return;
     538        SoundBufferMap::iterator it = this->soundBuffers_.find(buffer->getFilename());
     539        if (it != this->soundBuffers_.end())
     540        {
     541            if (bPoolBuffer)
     542            {
     543                // Pool already too large?
     544                while (this->effectsPoolSize_ + it->second->getSize() > this->maxEffectsPoolSize_s && !this->effectsPool_.empty())
     545                {
     546                    shared_ptr<SoundBuffer> bufferDel = this->effectsPool_.back();
     547                    this->effectsPoolSize_ -= bufferDel->getSize();
     548                    bufferDel->poolIterator_ = this->effectsPool_.end();
     549                    this->effectsPool_.pop_back();
     550                    // Remove from buffer map too
     551                    SoundBufferMap::iterator itDel = this->soundBuffers_.find(bufferDel->getFilename());
     552                    if (itDel != this->soundBuffers_.end())
     553                        this->soundBuffers_.erase(itDel);
     554                }
     555                // Put buffer into the pool
     556                this->effectsPoolSize_ += it->second->getSize();
     557                this->effectsPool_.push_front(it->second);
     558                it->second->poolIterator_ = this->effectsPool_.begin();
     559            }
     560            else
     561                this->soundBuffers_.erase(it);
     562        }
     563    }
     564
     565    ALuint SoundManager::getSoundSource(BaseSound* object)
     566    {
     567        if (!this->availableSoundSources_.empty())
     568        {
     569            ALuint source = this->availableSoundSources_.back();
     570            this->availableSoundSources_.pop_back();
     571            this->usedSoundSources_.push_back(std::make_pair(source, object));
     572            return source;
     573        }
     574        else
     575        {
     576            if (this->usedSoundSources_.size() < this->maxSources_)
     577            {
     578                ALuint source;
     579                alGenSources(1, &source);
     580                // Try to create new sources (50% more, but at least one)
     581                if (alIsSource(source) && !alGetError())
     582                {
     583                    this->usedSoundSources_.push_back(std::make_pair(source, object));
     584                    return source;
     585                }
     586            }
     587            // Return no source ID
     588            ALuint source = 123456789;
     589            while (alIsSource(++source));
     590            return source;
     591        }
     592    }
     593
     594    void SoundManager::releaseSoundSource(ALuint source)
     595    {
     596#ifndef NDEBUG
     597        for (std::vector<ALuint>::const_iterator it = this->availableSoundSources_.begin(); it != this->availableSoundSources_.end(); ++it)
     598            assert((*it) != source);
     599#endif
     600        this->availableSoundSources_.push_back(source);
     601        for (std::vector<std::pair<ALuint, BaseSound*> >::iterator it = this->usedSoundSources_.begin();
     602            it != this->usedSoundSources_.end(); ++it)
     603        {
     604            if (it->first == source)
     605            {
     606                this->usedSoundSources_.erase(it);
     607                break;
     608            }
     609        }
     610        int used = std::max((unsigned int)(this->usedSoundSources_.size()), this->minSources_);
     611        // Subtract those we added in the statement above trough std::max
     612        int available = (int)this->availableSoundSources_.size() - (used - (int)this->usedSoundSources_.size());
     613        // Delete sources again to free resources if appropriate (more than 50% more available than used)
     614        int toDelete = available - used / 2;
     615        while (toDelete-- > 0)
     616        {
     617            alDeleteSources(1, &this->availableSoundSources_.back());
     618            if (alGetError())
     619                COUT(1) << "Sound Error: Failed to delete a source --> lost forever" << std::endl;
     620            this->availableSoundSources_.pop_back();
     621        }
     622    }
     623
     624    unsigned int SoundManager::createSoundSources(unsigned int n)
     625    {
     626        unsigned int count = this->availableSoundSources_.size() + this->usedSoundSources_.size();
     627        while (count < this->maxSources_ && count <= n)
     628        {
     629            ALuint source;
     630            alGenSources(1, &source);
     631            if (alIsSource(source) && !alGetError())
     632                this->availableSoundSources_.push_back(source);
     633            else
     634                break;
     635            ++count;
     636        }
     637        return count - this->availableSoundSources_.size() - this->usedSoundSources_.size();
     638    }
    116639}
  • code/trunk/src/orxonox/sound/SoundManager.h

    r5929 r6417  
    2222 *   Author:
    2323 *       Erwin 'vaiursch' Herrsche
     24 *       Kevin Young
     25 *       Reto Grieder
    2426 *   Co-authors:
    2527 *      ...
    2628 */
     29
    2730#ifndef _SoundManager_H__
    2831#define _SoundManager_H__
     
    3033#include "OrxonoxPrereqs.h"
    3134
    32 #include <cassert>
    3335#include <list>
     36#include <map>
     37#include <string>
     38#include <boost/shared_ptr.hpp>
     39
    3440#include "util/Singleton.h"
    35 #include "tools/interfaces/Tickable.h"
     41#include "core/OrxonoxClass.h"
     42#include "core/SmartPtr.h"
    3643
     44// tolua_begin
    3745namespace orxonox
    3846{
    39     /**
    40      * The SoundManager class manages the OpenAL device, context and listener
    41      * position. It is a singleton.
    42      *
    43      */
    44     class _OrxonoxExport SoundManager : public Singleton<SoundManager>
     47    //! Enum for the sound type.
     48    namespace SoundType
    4549    {
     50        enum Value
     51        {
     52            All     = 0,
     53            Music   = 1,
     54            Effects = 2
     55        };
     56    }
     57
     58    //! The SoundManager class manages the OpenAL device, context and listener position.
     59    class _OrxonoxExport SoundManager
     60    // tolua_end
     61        : public Singleton<SoundManager>, public OrxonoxClass
     62    { // tolua_export
    4663        friend class Singleton<SoundManager>;
     64
    4765    public:
    4866        SoundManager();
    4967        ~SoundManager();
    5068
     69        void preUpdate(const Clock& time);
     70        void setConfigValues();
     71
     72        // tolua_begin
     73        static SoundManager& getInstance() { return Singleton<SoundManager>::getInstance(); }
     74
     75        std::string getDeviceName(unsigned int index) const
     76            { return index < this->deviceNames_.size() ? this->deviceNames_[index] : std::string(); }
     77        // tolua_end
     78
    5179        void setListenerPosition(const Vector3& position);
    5280        void setListenerOrientation(const Quaternion& orientation);
    5381
     82        void registerAmbientSound(AmbientSound* newAmbient);
     83        void unregisterAmbientSound(AmbientSound* oldAmbient);
     84        void pauseAmbientSound(AmbientSound* ambient);
     85
     86        // tolua_begin
     87        void setVolume(float vol, SoundType::Value type);
     88        float getVolume(SoundType::Value type);
     89        float getRealVolume(SoundType::Value type);
     90
     91        void toggleMute(SoundType::Value type);
     92        bool getMute(SoundType::Value type);
     93        // tolua_end
     94
     95        shared_ptr<SoundBuffer> getSoundBuffer(const std::string& filename);
     96        void releaseSoundBuffer(const shared_ptr<SoundBuffer>& buffer, bool bPoolBuffer);
     97
     98        ALuint getSoundSource(BaseSound* object);
     99        void releaseSoundSource(ALuint source);
     100
     101        static std::string getALErrorString(ALenum error);
     102
    54103    private:
     104        void processCrossFading(float dt);
     105        void fadeIn(const SmartPtr<AmbientSound>& sound);
     106        void fadeOut(const SmartPtr<AmbientSound>& sound);
     107
     108        void checkFadeStepValidity();
     109
     110        void checkVolumeValidity(SoundType::Value type);
     111        void checkSoundVolumeValidity()   { this->checkVolumeValidity(SoundType::All); }
     112        void checkAmbientVolumeValidity() { this->checkVolumeValidity(SoundType::Music); }
     113        void checkEffectsVolumeValidity() { this->checkVolumeValidity(SoundType::Effects); }
     114        void updateVolume(SoundType::Value type);
     115
     116        unsigned int createSoundSources(unsigned int n);
     117
     118        // OpenAL device/context related
     119        std::vector<std::string> deviceNames_;
    55120        ALCdevice* device_;
    56121        ALCcontext* context_;
    57122
     123        // Ambient sound related
     124        typedef std::list<std::pair<AmbientSound*, bool> > AmbientList;
     125        AmbientList                        ambientSounds_;
     126        //! Absolute change per second (0.1 means 10% of the nominal volume) for cross fading
     127        float                              crossFadeStep_;
     128        std::list<SmartPtr<AmbientSound> > fadeInList_;
     129        std::list<SmartPtr<AmbientSound> > fadeOutList_;
     130
     131        // Volume related
     132        float volume_[3];
     133        float mute_[3];
     134
     135        // Sound buffer related
     136        static const unsigned int maxEffectsPoolSize_s = 40 * 1024 * 1024;
     137        unsigned int effectsPoolSize_;
     138        typedef std::list<shared_ptr<SoundBuffer> > EffectsPoolList;
     139        EffectsPoolList effectsPool_;
     140        typedef std::map<std::string, shared_ptr<SoundBuffer> > SoundBufferMap;
     141        SoundBufferMap soundBuffers_;
     142
     143        // Sound source related
     144        unsigned int minSources_;
     145        unsigned int maxSources_;
     146        std::vector<ALuint> availableSoundSources_;
     147        std::vector<std::pair<ALuint, BaseSound*> > usedSoundSources_;
     148
    58149        static SoundManager* singletonPtr_s;
    59     };
    60 }
     150    }; // tolua_export
     151} // tolua_export
    61152
    62153#endif /* _SoundManager_H__ */
  • code/trunk/src/orxonox/sound/WorldSound.cc

    r5929 r6417  
    3535#include "core/EventIncludes.h"
    3636#include "core/XMLPort.h"
     37#include "Scene.h"
     38#include "SoundManager.h"
     39#include <core/ConsoleCommandCompilation.h>
    3740
    3841namespace orxonox
     
    4447    {
    4548        RegisterObject(WorldSound);
     49        // WorldSound buffers should be pooled when they're not used anymore
     50        this->bPooling_ = true;
     51        this->registerVariables();
    4652    }
    4753
    48     WorldSound::~WorldSound()
     54    void WorldSound::registerVariables()
    4955    {
     56        registerVariable(volume_,   ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::volumeChanged));
     57        registerVariable(source_,   ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::sourceChanged));
     58        registerVariable(bLooping_, ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::loopingChanged));
     59        registerVariable(pitch_,    ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::pitchChanged));
     60        registerVariable((int&)(BaseSound::state_), ObjectDirection::ToClient, new NetworkCallback<WorldSound>(this, &WorldSound::stateChanged));
    5061    }
    5162
     
    5364    {
    5465        SUPER(WorldSound, XMLPort, xmlelement, mode);
    55         XMLPortParamExtern(WorldSound, BaseSound, this, "source", setSource, getSource, xmlelement, mode);
    56         XMLPortParamExtern(WorldSound, BaseSound, this, "loop", setLoop, getLoop, xmlelement, mode);
    57         XMLPortParamExtern(WorldSound, BaseSound, this, "playOnLoad", setPlayOnLoad, getPlayOnLoad, xmlelement, mode);
     66        BaseSound::XMLPortExtern(xmlelement, mode);
    5867    }
    5968
     
    6271        SUPER(WorldSound, XMLEventPort, xmlelement, mode);
    6372        XMLPortEventState(WorldSound, BaseObject, "play", play, xmlelement, mode);
     73    }
     74
     75    void WorldSound::initialiseSource()
     76    {
     77        BaseSound::initialiseSource();
     78        if (this->getScene())
     79        {
     80            float refDist = this->getScene()->getSoundReferenceDistance();
     81            alSourcef(this->audioSource_, AL_REFERENCE_DISTANCE, refDist);
     82            // TODO: 500 is very magical here. Derive something better
     83            alSourcef(this->audioSource_, AL_MAX_DISTANCE, refDist * 500);
     84        }
     85        this->tick(0); // update position, orientation and velocity
    6486    }
    6587
     
    80102                COUT(2) << "Sound: OpenAL: Invalid sound velocity" << std::endl;
    81103
    82             const Quaternion& orient = this->getWorldOrientation();
    83             Vector3 at = orient.zAxis();
    84             alSource3f(this->audioSource_, AL_DIRECTION, at.x, at.y, at.z);
     104            const Vector3& direction = -this->getWorldOrientation().zAxis();
     105            alSource3f(this->audioSource_, AL_DIRECTION, direction.x, direction.y, direction.z);
    85106            error = alGetError();
    86107            if (error == AL_INVALID_VALUE)
     
    89110    }
    90111
     112    void WorldSound::changedActivity()
     113    {
     114        SUPER(WorldSound, changedActivity);
     115        if (this->isActive())
     116            this->play();
     117        else
     118            this->stop();
     119    }
     120
     121    float WorldSound::getRealVolume()
     122    {
     123        assert(GameMode::playsSound());
     124        return SoundManager::getInstance().getRealVolume(SoundType::Effects);
     125    }
    91126}
  • code/trunk/src/orxonox/sound/WorldSound.h

    r5929 r6417  
    2626 *
    2727 */
     28
    2829#ifndef _WorldSound_H__
    2930#define _WorldSound_H__
     
    4546    public:
    4647        WorldSound(BaseObject* creator);
    47         virtual ~WorldSound();
    4848
    49         virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode);
    50         virtual void XMLEventPort(Element& xmlelement, XMLPort::Mode mode);
     49        void XMLPort(Element& xmlelement, XMLPort::Mode mode);
     50        void XMLEventPort(Element& xmlelement, XMLPort::Mode mode);
     51        void changedActivity();
    5152
    52         virtual void tick(float dt);
     53        void tick(float dt);
     54
     55    protected:
     56        ~WorldSound() {}
    5357
    5458    private:
     59        void registerVariables();
     60        void initialiseSource();
     61        float getRealVolume();
    5562    };
    5663}
Note: See TracChangeset for help on using the changeset viewer.