Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 6186 was 6186, checked in by dafrick, 14 years ago

Some cleanup in SoundManager and related classes. Overrall volume works now. Mute function has been implemented into the gui.
Once again you'll have to delete your orxonox.ini file to be trouble free.

  • Property svn:eol-style set to native
File size: 8.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 <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#include "SoundManager.h"
41
42namespace orxonox
43{
44    BaseSound::BaseSound()
45        : audioSource_(0)
46        , audioBuffer_(0)
47        , bLoop_(false)
48        , state_(Stopped)
49    {
50        RegisterRootObject(BaseSound);
51
52        if (GameMode::playsSound())
53        {
54            alGenSources(1, &this->audioSource_);
55            assert(this->audioSource_ != 0);
56        }
57       
58    }
59
60    BaseSound::~BaseSound()
61    {
62        this->setSource("");
63        if (GameMode::playsSound())
64            alDeleteSources(1, &this->audioSource_);
65    }
66
67    void BaseSound::XMLPortExtern(Element& xmlelement, XMLPort::Mode mode)
68    {
69        XMLPortParam(BaseSound, "volume", setVolume,  getVolume,  xmlelement, mode);
70        XMLPortParam(BaseSound, "loop",   setLooping, getLooping, xmlelement, mode);
71        XMLPortParam(BaseSound, "play",   play,       isPlaying,  xmlelement, mode);
72        XMLPortParam(BaseSound, "source", setSource,  getSource,  xmlelement, mode);
73    }
74
75    void BaseSound::play()
76    {
77        if (!this->isPlaying() && GameMode::showsGraphics())
78        {
79            this->state_ = Playing;
80            alSourcePlay(this->audioSource_);
81
82            if (alGetError() != AL_NO_ERROR)
83                 COUT(2) << "Sound: OpenAL: Error playing sound " << this->audioSource_ << std::endl;
84        }
85    }
86
87    void BaseSound::stop()
88    {
89        this->state_ = Stopped;
90        if (GameMode::playsSound())
91            alSourceStop(this->audioSource_);
92    }
93
94    void BaseSound::pause()
95    {
96        if (this->isStopped())
97            return;
98        this->state_ = Paused;
99        if (GameMode::playsSound())
100            alSourcePause(this->audioSource_);
101    }
102
103    void BaseSound::setVolume(float vol)
104    {
105        if (vol > 1 || vol < 0)
106        {
107            COUT(2) << "Sound warning: volume out of range, cropping value." << std::endl;
108            vol = vol > 1 ? 1 : vol;
109            vol = vol < 0 ? 0 : vol;
110        }
111        this->volume_ = vol;
112       
113        this->updateVolume();
114    }
115   
116    float BaseSound::getVolumeGain()
117    {
118        return SoundManager::getInstance().getVolume(SoundType::none);
119    }
120   
121    void BaseSound::updateVolume(void)
122    {
123        if (alIsSource(this->audioSource_))
124            alSourcef(this->audioSource_, AL_GAIN, this->volume_*this->getVolumeGain());
125    }
126
127    void BaseSound::setLooping(bool val)
128    {
129        this->bLoop_ = val;
130        if (GameMode::playsSound())
131            alSourcei(this->audioSource_, AL_LOOPING, (val ? AL_TRUE : AL_FALSE));
132    }
133
134    void BaseSound::setSource(const std::string& source)
135    {
136        if (!GameMode::playsSound() || source == this->source_) 
137        {
138            this->source_ = source;
139            return;
140        }
141
142        if (this->audioBuffer_ != 0 && alIsBuffer(this->audioBuffer_))
143        {
144            alSourceStop(this->audioSource_);
145            // Unload old sound first
146            alSourcei(this->audioSource_, AL_BUFFER, 0);
147            alDeleteBuffers(1, &this->audioBuffer_);
148            this->audioBuffer_ = 0;
149        }
150
151        this->source_ = source;
152        if (source_.empty()) 
153            return;
154
155        COUT(3) << "Sound: OpenAL ALUT: loading file " << source << std::endl;
156        // Get DataStream from the resources
157        shared_ptr<ResourceInfo> fileInfo = Resource::getInfo(source);
158        if (fileInfo == NULL)
159        {
160            COUT(2) << "Sound: Warning: Sound file '" << source << "' not found" << std::endl;
161            return;
162        }
163        dataStream_ = Resource::open(source);
164        // Read everything into a temporary buffer
165        char* buffer = new char[fileInfo->size];
166        dataStream_->read(buffer, fileInfo->size);
167        dataStream_->seek(0);
168
169        this->audioBuffer_ = alutCreateBufferFromFileImage(buffer, fileInfo->size);
170        delete[] buffer;
171
172        if (this->audioBuffer_ == AL_NONE)
173        {
174            COUT(2) << "Sound: OpenAL ALUT: " << alutGetErrorString(alutGetError()) << std::endl;
175            if (source.find("ogg", 0) != std::string::npos)
176            {
177                COUT(2) << "Sound: Trying fallback ogg loader" << std::endl;
178                this->audioBuffer_ = this->loadOggFile();
179            }
180
181            if (this->audioBuffer_ == AL_NONE)
182            {
183                COUT(2) << "Sound: fallback ogg loader failed: " << alutGetErrorString(alutGetError()) << std::endl;
184                return;
185            }
186        }
187
188        alSourcei(this->audioSource_, AL_BUFFER, this->audioBuffer_);
189        if (alGetError() != AL_NO_ERROR)
190        {
191            COUT(2) << "Sound: OpenAL: Error loading sample file: " << source << std::endl;
192            return;
193        }
194
195        alSource3f(this->audioSource_, AL_POSITION,  0, 0, 0);
196        this->updateVolume();
197        alSourcei (this->audioSource_, AL_LOOPING, (this->bLoop_ ? AL_TRUE : AL_FALSE));
198        if (this->isPlaying() || this->isPaused())
199            alSourcePlay(this->audioSource_);
200        if (this->isPaused())
201            alSourcePause(this->audioSource_);
202
203        if (alGetError() != AL_NO_ERROR)
204            COUT(2) << "Sound: OpenAL: Error playing sound " << this->audioSource_ << std::endl;
205    }
206
207    size_t readVorbis(void* ptr, size_t size, size_t nmemb, void* datasource)
208    {
209        return static_cast<Ogre::DataStream*>(datasource)->read(ptr, size * nmemb);
210    }
211
212    int seekVorbis(void* datasource, ogg_int64_t offset, int whence)
213    {
214        Ogre::DataStream* stream = static_cast<Ogre::DataStream*>(datasource);
215        int offset_beg = offset;
216        if (whence == SEEK_CUR)
217            offset_beg = stream->tell() + offset;
218        else if (whence == SEEK_END)
219            offset_beg = stream->size() + offset;
220        else if (whence != SEEK_SET)
221            return -1;
222        stream->seek(offset_beg);
223        return 0;
224    }
225
226    long tellVorbis(void* datasource)
227    {
228        return static_cast<long>(static_cast<Ogre::DataStream*>(datasource)->tell());
229    }
230
231    ALuint BaseSound::loadOggFile()
232    {
233        char inbuffer[256*1024];
234        std::vector<char> outbuffer;
235        outbuffer.reserve(80*1024*1024);
236        OggVorbis_File vf;
237        vorbis_info* vorbisInfo;
238        int eof = false;
239        int current_section;
240        ALuint buffer;
241        ALenum format;
242
243        // Open file with custom streaming
244        ov_callbacks vorbisCallbacks;
245        vorbisCallbacks.read_func  = &readVorbis;
246        vorbisCallbacks.seek_func  = &seekVorbis;
247        vorbisCallbacks.tell_func  = &tellVorbis;
248        vorbisCallbacks.close_func = NULL;
249
250        int ret = ov_open_callbacks(dataStream_.get(), &vf, NULL, 0, vorbisCallbacks);
251        if (ret < 0)
252        {
253            COUT(2) << "Sound: libvorbisfile: File does not seem to be an Ogg Vorbis bitstream" << std::endl;
254            ov_clear(&vf);
255            return AL_NONE;
256        }
257
258        while (!eof)
259        {
260            long ret = ov_read(&vf, inbuffer, sizeof(inbuffer), 0, 2, 1, &current_section);
261            if (ret == 0)
262            {
263                eof = true;
264            }
265            else if (ret < 0)
266            {
267                COUT(2) << "Sound: libvorbisfile: error reading the file" << std::endl;
268                ov_clear(&vf);
269                return AL_NONE;
270            }
271            else
272            {
273                outbuffer.insert(outbuffer.end(), inbuffer, inbuffer + ret);
274            }
275        }
276
277        vorbisInfo = ov_info(&vf, -1);
278        if (vorbisInfo->channels == 1)
279            format = AL_FORMAT_MONO16;
280        else
281            format = AL_FORMAT_STEREO16;
282
283        alGenBuffers(1, &buffer);
284        alBufferData(buffer, format, &outbuffer[0], outbuffer.size(), vorbisInfo->rate);
285        ov_clear(&vf);
286
287        return buffer;
288    }
289}
Note: See TracBrowser for help on using the repository browser.