Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/sound3/src/orxonox/sound/BaseSound.cc @ 5982

Last change on this file since 5982 was 5982, checked in by youngk, 15 years ago

Ambient Sounds are now locationally triggerable, i.e if the player comes close to an object, it's own ambient sound starts playing, while the sound of the outer object is paused. Upon leaving proximity of that object, the old sound is resumed. —> Triggerable by changing active state.

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Erwin 'vaiursch' Herrsche
24 *   Co-authors:
25 *      Reto Grieder
26 *
27 */
28
29#include "BaseSound.h"
30
31#include <vector>
32#include <AL/alut.h>
33#include <vorbis/vorbisfile.h>
34
35#include "core/CoreIncludes.h"
36#include "core/GameMode.h"
37#include "core/Resource.h"
38
39namespace orxonox
40{
41    BaseSound::BaseSound()
42        : audioSource_(0)
43        , audioBuffer_(0)
44        , bPlayOnLoad_(false)
45        , bLoop_(false)
46    {
47        RegisterRootObject(BaseSound);
48    }
49
50    BaseSound::~BaseSound()
51    {
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);
63            alSourcePlay(this->audioSource_);
64
65            if (alGetError() != AL_NO_ERROR)
66            {
67                 COUT(2) << "Sound: OpenAL: Error playing sound " << this->audioSource_ << std::endl;
68            }
69        }
70    }
71
72    void BaseSound::replay()
73    {
74        BaseSound::play();
75    }
76
77    void BaseSound::stop()
78    {
79        if (alIsSource(this->audioSource_))
80            alSourceStop(this->audioSource_);
81    }
82
83    void BaseSound::pause()
84    {
85        if (alIsSource(this->audioSource_))
86            alSourcePause(this->audioSource_);
87    }
88
89    bool BaseSound::isPlaying()
90    {
91        if (alIsSource(this->audioSource_))
92            return getSourceState() == AL_PLAYING;
93        return false;
94    }
95
96    bool BaseSound::isPaused()
97    {
98        if (alIsSource(this->audioSource_))
99            return getSourceState() == AL_PAUSED;
100        return true;
101    }
102
103    bool BaseSound::isStopped()
104    {
105        if (alIsSource(this->audioSource_))
106            return getSourceState() == AL_INITIAL || getSourceState() == AL_STOPPED;
107        return true;
108    }
109
110    void BaseSound::setPlayOnLoad(bool val)
111    {
112        this->bPlayOnLoad_ = val;
113        if(val)
114        {
115            this->play();
116        }
117    }
118
119    void BaseSound::setSource(const std::string& source)
120    {
121        if (!GameMode::playsSound() || source == this->source_) 
122        {
123            this->source_ = source;
124            return;
125        }
126       
127        if (alIsSource(this->audioSource_))
128        {
129            this->stop();
130            // Unload old sound first
131            alSourcei(this->audioSource_, AL_BUFFER, 0);
132            alDeleteSources(1, &this->audioSource_);
133            this->audioSource_ = 0;
134            alDeleteBuffers(1, &this->audioBuffer_);
135            this->audioBuffer_ = 0;
136        }
137
138        this->source_ = source;
139        if (source_.empty()) 
140            return;
141
142        COUT(3) << "Sound: OpenAL ALUT: loading file " << source << std::endl;
143        // Get DataStream from the resources
144        shared_ptr<ResourceInfo> fileInfo = Resource::getInfo(source);
145        if (fileInfo == NULL)
146        {
147            COUT(2) << "Sound: Warning: Sound file '" << source << "' not found" << std::endl;
148            return;
149        }
150        dataStream_ = Resource::open(source);
151        // Read everything into a temporary buffer
152        char* buffer = new char[fileInfo->size];
153        dataStream_->read(buffer, fileInfo->size);
154        dataStream_->seek(0);
155
156        this->audioBuffer_ = alutCreateBufferFromFileImage(buffer, fileInfo->size);
157        delete[] buffer;
158
159        if (this->audioBuffer_ == AL_NONE)
160        {
161            COUT(2) << "Sound: OpenAL ALUT: " << alutGetErrorString(alutGetError()) << std::endl;
162            if (source.find("ogg", 0) != std::string::npos)
163            {
164                COUT(2) << "Sound: Trying fallback ogg loader" << std::endl;
165                this->audioBuffer_ = this->loadOggFile();
166            }
167
168            if (this->audioBuffer_ == AL_NONE)
169            {
170                COUT(2) << "Sound: fallback ogg loader failed: " << alutGetErrorString(alutGetError()) << std::endl;
171                return;
172            }
173        }
174
175        alGenSources(1, &this->audioSource_);
176        alSourcei(this->audioSource_, AL_BUFFER, this->audioBuffer_);
177        if (alGetError() != AL_NO_ERROR)
178        {
179            COUT(2) << "Sound: OpenAL: Error loading sample file: " << source << std::endl;
180            return;
181        }
182
183        alSource3f(this->audioSource_, AL_POSITION,  0, 0, 0);
184
185        if (this->bPlayOnLoad_)
186            this->play();
187    }
188
189    ALint BaseSound::getSourceState()
190    {
191        ALint state;
192        alGetSourcei(this->audioSource_, AL_SOURCE_STATE, &state);
193        return state;
194    }
195
196    size_t readVorbis(void* ptr, size_t size, size_t nmemb, void* datasource)
197    {
198        return static_cast<Ogre::DataStream*>(datasource)->read(ptr, size * nmemb);
199    }
200
201    int seekVorbis(void* datasource, ogg_int64_t offset, int whence)
202    {
203        Ogre::DataStream* stream = static_cast<Ogre::DataStream*>(datasource);
204        int offset_beg = offset;
205        if (whence == SEEK_CUR)
206            offset_beg = stream->tell() + offset;
207        else if (whence == SEEK_END)
208            offset_beg = stream->size() + offset;
209        else if (whence != SEEK_SET)
210            return -1;
211        stream->seek(offset_beg);
212        return 0;
213    }
214
215    long tellVorbis(void* datasource)
216    {
217        return static_cast<long>(static_cast<Ogre::DataStream*>(datasource)->tell());
218    }
219
220    ALuint BaseSound::loadOggFile()
221    {
222        char inbuffer[4096];
223        std::vector<char> outbuffer;
224        OggVorbis_File vf;
225        vorbis_info* vorbisInfo;
226        int eof = false;
227        int current_section;
228        ALuint buffer;
229        ALenum format;
230
231        // Open file with custom streaming
232        ov_callbacks vorbisCallbacks;
233        vorbisCallbacks.read_func  = &readVorbis;
234        vorbisCallbacks.seek_func  = &seekVorbis;
235        vorbisCallbacks.tell_func  = &tellVorbis;
236        vorbisCallbacks.close_func = NULL;
237
238        int ret = ov_open_callbacks(dataStream_.get(), &vf, NULL, 0, vorbisCallbacks);
239        if (ret < 0)
240        {
241            COUT(2) << "Sound: libvorbisfile: File does not seem to be an Ogg Vorbis bitstream" << std::endl;
242            ov_clear(&vf);
243            return AL_NONE;
244        }
245
246        while (!eof)
247        {
248            long ret = ov_read(&vf, inbuffer, sizeof(inbuffer), 0, 2, 1, &current_section);
249            if (ret == 0)
250            {
251                eof = true;
252            }
253            else if (ret < 0)
254            {
255                COUT(2) << "Sound: libvorbisfile: error reading the file" << std::endl;
256                ov_clear(&vf);
257                return AL_NONE;
258            }
259            else
260            {
261                outbuffer.insert(outbuffer.end(), inbuffer, inbuffer + sizeof(inbuffer));
262            }
263        }
264
265        vorbisInfo = ov_info(&vf, -1);
266        if (vorbisInfo->channels == 1)
267            format = AL_FORMAT_MONO16;
268        else
269            format = AL_FORMAT_STEREO16;
270
271        alGenBuffers(1, &buffer);
272        alBufferData(buffer, format, &outbuffer[0], outbuffer.size(), vorbisInfo->rate);
273        ov_clear(&vf);
274
275        return buffer;
276    }
277
278} // namespace: orxonox
Note: See TracBrowser for help on using the repository browser.