Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6144 was 6127, checked in by rgrieder, 15 years ago

Fixed sound problem (annoying cracking) and increased buffers for faster loading (doesn't really make the difference though…).

  • Property svn:eol-style set to native
File size: 8.5 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Erwin 'vaiursch' Herrsche
24 *   Co-authors:
25 *      Reto Grieder
26 *
27 */
28
29#include "BaseSound.h"
30
31#include <cassert>
32#include <vector>
33#include <AL/alut.h>
34#include <vorbis/vorbisfile.h>
35
36#include "core/CoreIncludes.h"
37#include "core/GameMode.h"
38#include "core/Resource.h"
39#include "core/XMLPort.h"
40
41namespace orxonox
42{
43    BaseSound::BaseSound()
44        : audioSource_(0)
45        , audioBuffer_(0)
46        , bLoop_(false)
47        , state_(Stopped)
48    {
49        RegisterRootObject(BaseSound);
50
51        if (GameMode::playsSound())
52        {
53            alGenSources(1, &this->audioSource_);
54            assert(this->audioSource_ != 0);
55        }
56    }
57
58    BaseSound::~BaseSound()
59    {
60        this->setSource("");
61        if (GameMode::playsSound())
62            alDeleteSources(1, &this->audioSource_);
63    }
64
65    void BaseSound::XMLPortExtern(Element& xmlelement, XMLPort::Mode mode)
66    {
67        XMLPortParam(BaseSound, "volume", setVolume,  getVolume,  xmlelement, mode);
68        XMLPortParam(BaseSound, "loop",   setLooping, getLooping, xmlelement, mode);
69        XMLPortParam(BaseSound, "play",   play,       isPlaying,  xmlelement, mode);
70        XMLPortParam(BaseSound, "source", setSource,  getSource,  xmlelement, mode);
71    }
72
73    void BaseSound::play()
74    {
75        if (!this->isPlaying() && GameMode::showsGraphics())
76        {
77            this->state_ = Playing;
78            alSourcePlay(this->audioSource_);
79
80            if (alGetError() != AL_NO_ERROR)
81                 COUT(2) << "Sound: OpenAL: Error playing sound " << this->audioSource_ << std::endl;
82        }
83    }
84
85    void BaseSound::stop()
86    {
87        this->state_ = Stopped;
88        if (GameMode::playsSound())
89            alSourceStop(this->audioSource_);
90    }
91
92    void BaseSound::pause()
93    {
94        if (this->isStopped())
95            return;
96        this->state_ = Paused;
97        if (GameMode::playsSound())
98            alSourcePause(this->audioSource_);
99    }
100
101    void BaseSound::setVolume(float vol)
102    {
103        if (vol > 1 || vol < 0)
104        {
105            COUT(2) << "Sound warning: volume out of range, cropping value." << std::endl;
106            vol = vol > 1 ? 1 : vol;
107            vol = vol < 0 ? 0 : vol;
108        }
109        this->volume_ = vol;
110        if (alIsSource(this->audioSource_))
111            alSourcef(this->audioSource_, AL_GAIN, vol);
112    }
113
114    void BaseSound::setLooping(bool val)
115    {
116        this->bLoop_ = val;
117        if (GameMode::playsSound())
118            alSourcei(this->audioSource_, AL_LOOPING, (val ? AL_TRUE : AL_FALSE));
119    }
120
121    void BaseSound::setSource(const std::string& source)
122    {
123        if (!GameMode::playsSound() || source == this->source_) 
124        {
125            this->source_ = source;
126            return;
127        }
128
129        if (this->audioBuffer_ != 0 && alIsBuffer(this->audioBuffer_))
130        {
131            alSourceStop(this->audioSource_);
132            // Unload old sound first
133            alSourcei(this->audioSource_, AL_BUFFER, 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        alSourcei(this->audioSource_, AL_BUFFER, this->audioBuffer_);
176        if (alGetError() != AL_NO_ERROR)
177        {
178            COUT(2) << "Sound: OpenAL: Error loading sample file: " << source << std::endl;
179            return;
180        }
181
182        alSource3f(this->audioSource_, AL_POSITION,  0, 0, 0);
183        alSourcef (this->audioSource_, AL_GAIN, this->volume_);
184        alSourcei (this->audioSource_, AL_LOOPING, (this->bLoop_ ? AL_TRUE : AL_FALSE));
185        if (this->isPlaying() || this->isPaused())
186            alSourcePlay(this->audioSource_);
187        if (this->isPaused())
188            alSourcePause(this->audioSource_);
189
190        if (alGetError() != AL_NO_ERROR)
191            COUT(2) << "Sound: OpenAL: Error playing sound " << this->audioSource_ << std::endl;
192    }
193
194    size_t readVorbis(void* ptr, size_t size, size_t nmemb, void* datasource)
195    {
196        return static_cast<Ogre::DataStream*>(datasource)->read(ptr, size * nmemb);
197    }
198
199    int seekVorbis(void* datasource, ogg_int64_t offset, int whence)
200    {
201        Ogre::DataStream* stream = static_cast<Ogre::DataStream*>(datasource);
202        int offset_beg = offset;
203        if (whence == SEEK_CUR)
204            offset_beg = stream->tell() + offset;
205        else if (whence == SEEK_END)
206            offset_beg = stream->size() + offset;
207        else if (whence != SEEK_SET)
208            return -1;
209        stream->seek(offset_beg);
210        return 0;
211    }
212
213    long tellVorbis(void* datasource)
214    {
215        return static_cast<long>(static_cast<Ogre::DataStream*>(datasource)->tell());
216    }
217
218    ALuint BaseSound::loadOggFile()
219    {
220        char inbuffer[256*1024];
221        std::vector<char> outbuffer;
222        outbuffer.reserve(80*1024*1024);
223        OggVorbis_File vf;
224        vorbis_info* vorbisInfo;
225        int eof = false;
226        int current_section;
227        ALuint buffer;
228        ALenum format;
229
230        // Open file with custom streaming
231        ov_callbacks vorbisCallbacks;
232        vorbisCallbacks.read_func  = &readVorbis;
233        vorbisCallbacks.seek_func  = &seekVorbis;
234        vorbisCallbacks.tell_func  = &tellVorbis;
235        vorbisCallbacks.close_func = NULL;
236
237        int ret = ov_open_callbacks(dataStream_.get(), &vf, NULL, 0, vorbisCallbacks);
238        if (ret < 0)
239        {
240            COUT(2) << "Sound: libvorbisfile: File does not seem to be an Ogg Vorbis bitstream" << std::endl;
241            ov_clear(&vf);
242            return AL_NONE;
243        }
244
245        while (!eof)
246        {
247            long ret = ov_read(&vf, inbuffer, sizeof(inbuffer), 0, 2, 1, &current_section);
248            if (ret == 0)
249            {
250                eof = true;
251            }
252            else if (ret < 0)
253            {
254                COUT(2) << "Sound: libvorbisfile: error reading the file" << std::endl;
255                ov_clear(&vf);
256                return AL_NONE;
257            }
258            else
259            {
260                outbuffer.insert(outbuffer.end(), inbuffer, inbuffer + ret);
261            }
262        }
263
264        vorbisInfo = ov_info(&vf, -1);
265        if (vorbisInfo->channels == 1)
266            format = AL_FORMAT_MONO16;
267        else
268            format = AL_FORMAT_STEREO16;
269
270        alGenBuffers(1, &buffer);
271        alBufferData(buffer, format, &outbuffer[0], outbuffer.size(), vorbisInfo->rate);
272        ov_clear(&vf);
273
274        return buffer;
275    }
276}
Note: See TracBrowser for help on using the repository browser.