Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Dec 25, 2009, 1:18:03 PM (16 years ago)
Author:
dafrick
Message:

Merged presentation2 branch into pickup2 branch.

Location:
code/branches/pickup2
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/branches/pickup2

  • code/branches/pickup2/src/orxonox/sound/BaseSound.cc

    r5929 r6412  
    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}
Note: See TracChangeset for help on using the changeset viewer.