Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Detail changes in the sound classes.
Plus fixed the level sound problem (order of XML parameters was wrong).
There is still a large issue when changing an ambient sound source though.

  • Property svn:eol-style set to native
File size: 8.0 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::stop()
73    {
74        if (alIsSource(this->audioSource_))
75            alSourceStop(this->audioSource_);
76    }
77
78    void BaseSound::pause()
79    {
80        if (alIsSource(this->audioSource_))
81            alSourcePause(this->audioSource_);
82    }
83
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 false;
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::setVolume(float vol)
106    {
107        if (vol > 1 || vol < 0)
108        {
109            COUT(2) << "Sound warning: volume out of range, cropping value." << std::endl;
110            vol = vol > 1 ? 1 : vol;
111            vol = vol < 0 ? 0 : vol;
112        }
113        this->volume_ = vol;
114        if (alIsSource(this->audioSource_))
115            alSourcef(this->audioSource_, AL_GAIN, vol);
116    }
117
118    void BaseSound::setSource(const std::string& source)
119    {
120        if (!GameMode::playsSound() || source == this->source_) 
121        {
122            this->source_ = source;
123            return;
124        }
125       
126        if (alIsSource(this->audioSource_))
127        {
128            this->stop();
129            // Unload old sound first
130            alSourcei(this->audioSource_, AL_BUFFER, 0);
131            alDeleteSources(1, &this->audioSource_);
132            this->audioSource_ = 0;
133            alDeleteBuffers(1, &this->audioBuffer_);
134            this->audioBuffer_ = 0;
135        }
136
137        this->source_ = source;
138        if (source_.empty()) 
139            return;
140
141        COUT(3) << "Sound: OpenAL ALUT: loading file " << source << std::endl;
142        // Get DataStream from the resources
143        shared_ptr<ResourceInfo> fileInfo = Resource::getInfo(source);
144        if (fileInfo == NULL)
145        {
146            COUT(2) << "Sound: Warning: Sound file '" << source << "' not found" << std::endl;
147            return;
148        }
149        dataStream_ = Resource::open(source);
150        // Read everything into a temporary buffer
151        char* buffer = new char[fileInfo->size];
152        dataStream_->read(buffer, fileInfo->size);
153        dataStream_->seek(0);
154
155        this->audioBuffer_ = alutCreateBufferFromFileImage(buffer, fileInfo->size);
156        delete[] buffer;
157
158        if (this->audioBuffer_ == AL_NONE)
159        {
160            COUT(2) << "Sound: OpenAL ALUT: " << alutGetErrorString(alutGetError()) << std::endl;
161            if (source.find("ogg", 0) != std::string::npos)
162            {
163                COUT(2) << "Sound: Trying fallback ogg loader" << std::endl;
164                this->audioBuffer_ = this->loadOggFile();
165            }
166
167            if (this->audioBuffer_ == AL_NONE)
168            {
169                COUT(2) << "Sound: fallback ogg loader failed: " << alutGetErrorString(alutGetError()) << std::endl;
170                return;
171            }
172        }
173
174        alGenSources(1, &this->audioSource_);
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
184        this->setVolume(this->volume_);
185
186        if (this->bPlayOnLoad_)
187            this->play();
188    }
189
190    ALint BaseSound::getSourceState()
191    {
192        ALint state;
193        alGetSourcei(this->audioSource_, AL_SOURCE_STATE, &state);
194        return state;
195    }
196
197    size_t readVorbis(void* ptr, size_t size, size_t nmemb, void* datasource)
198    {
199        return static_cast<Ogre::DataStream*>(datasource)->read(ptr, size * nmemb);
200    }
201
202    int seekVorbis(void* datasource, ogg_int64_t offset, int whence)
203    {
204        Ogre::DataStream* stream = static_cast<Ogre::DataStream*>(datasource);
205        int offset_beg = offset;
206        if (whence == SEEK_CUR)
207            offset_beg = stream->tell() + offset;
208        else if (whence == SEEK_END)
209            offset_beg = stream->size() + offset;
210        else if (whence != SEEK_SET)
211            return -1;
212        stream->seek(offset_beg);
213        return 0;
214    }
215
216    long tellVorbis(void* datasource)
217    {
218        return static_cast<long>(static_cast<Ogre::DataStream*>(datasource)->tell());
219    }
220
221    ALuint BaseSound::loadOggFile()
222    {
223        char inbuffer[4096];
224        std::vector<char> outbuffer;
225        OggVorbis_File vf;
226        vorbis_info* vorbisInfo;
227        int eof = false;
228        int current_section;
229        ALuint buffer;
230        ALenum format;
231
232        // Open file with custom streaming
233        ov_callbacks vorbisCallbacks;
234        vorbisCallbacks.read_func  = &readVorbis;
235        vorbisCallbacks.seek_func  = &seekVorbis;
236        vorbisCallbacks.tell_func  = &tellVorbis;
237        vorbisCallbacks.close_func = NULL;
238
239        int ret = ov_open_callbacks(dataStream_.get(), &vf, NULL, 0, vorbisCallbacks);
240        if (ret < 0)
241        {
242            COUT(2) << "Sound: libvorbisfile: File does not seem to be an Ogg Vorbis bitstream" << std::endl;
243            ov_clear(&vf);
244            return AL_NONE;
245        }
246
247        while (!eof)
248        {
249            long ret = ov_read(&vf, inbuffer, sizeof(inbuffer), 0, 2, 1, &current_section);
250            if (ret == 0)
251            {
252                eof = true;
253            }
254            else if (ret < 0)
255            {
256                COUT(2) << "Sound: libvorbisfile: error reading the file" << std::endl;
257                ov_clear(&vf);
258                return AL_NONE;
259            }
260            else
261            {
262                outbuffer.insert(outbuffer.end(), inbuffer, inbuffer + sizeof(inbuffer));
263            }
264        }
265
266        vorbisInfo = ov_info(&vf, -1);
267        if (vorbisInfo->channels == 1)
268            format = AL_FORMAT_MONO16;
269        else
270            format = AL_FORMAT_STEREO16;
271
272        alGenBuffers(1, &buffer);
273        alBufferData(buffer, format, &outbuffer[0], outbuffer.size(), vorbisInfo->rate);
274        ov_clear(&vf);
275
276        return buffer;
277    }
278}
Note: See TracBrowser for help on using the repository browser.