Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation2/src/orxonox/sound/SoundBuffer.cc @ 6260

Last change on this file since 6260 was 6260, checked in by rgrieder, 14 years ago

Audio sources seem to be very limited resources. If we create more than available sources (usually more than 256), it will not result in a failed assert anymore. Instead, the sound will simply not load and play.

  • Property svn:eol-style set to native
File size: 5.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 *      Reto Grieder
24 *      Erwin 'vaiursch' Herrsche
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30#include "SoundBuffer.h"
31
32#include <AL/alut.h>
33#include <vorbis/vorbisfile.h>
34
35#include "util/Exception.h"
36#include "util/StringUtils.h"
37#include "core/Resource.h"
38#include "sound/SoundManager.h"
39
40namespace orxonox
41{
42    SoundBuffer::SoundBuffer(shared_ptr<ResourceInfo> fileInfo)
43        : fileInfo_(fileInfo)
44        , audioBuffer_(AL_NONE)
45    {
46        if (this->fileInfo_ == NULL)
47            ThrowException(General, "SoundBuffer construction: fileInfo was NULL");
48        DataStreamPtr dataStream = Resource::open(this->fileInfo_);
49
50        std::string extension(this->fileInfo_->basename.substr(this->fileInfo_->basename.find_last_of('.') + 1));
51        if (getLowercase(extension) == "ogg")
52        {
53            // Try ogg loader
54            this->loadOgg(dataStream);
55        }
56        else
57        {
58            // Try standard OpenAL loader
59            this->loadStandard(dataStream);
60        }
61    }
62
63    SoundBuffer::~SoundBuffer()
64    {
65        // Destroy buffer
66        alDeleteBuffers(1, &this->audioBuffer_);
67    }
68
69    unsigned int SoundBuffer::getSize() const
70    {
71        ALint size;
72        alGetBufferi(this->audioBuffer_, AL_SIZE, &size);
73        if (!alGetError())
74            return size;
75        else
76            return 0;
77    }
78
79    void SoundBuffer::loadStandard(DataStreamPtr dataStream)
80    {
81        // Read everything into a temporary buffer
82        char* buffer = new char[this->fileInfo_->size];
83        dataStream->read(buffer, this->fileInfo_->size);
84        dataStream->seek(0);
85
86        this->audioBuffer_ = alutCreateBufferFromFileImage(buffer, this->fileInfo_->size);
87        delete[] buffer;
88
89        if (!alIsBuffer(this->audioBuffer_))
90            ThrowException(General, "Sound Error: Standard file loader failed: " << alutGetErrorString(alutGetError()));
91    }
92
93    size_t readVorbis(void* ptr, size_t size, size_t nmemb, void* datasource)
94    {
95        return static_cast<Ogre::DataStream*>(datasource)->read(ptr, size * nmemb);
96    }
97
98    int seekVorbis(void* datasource, ogg_int64_t offset, int whence)
99    {
100        Ogre::DataStream* stream = static_cast<Ogre::DataStream*>(datasource);
101        int offset_beg = offset;
102        if (whence == SEEK_CUR)
103            offset_beg = stream->tell() + offset;
104        else if (whence == SEEK_END)
105            offset_beg = stream->size() + offset;
106        else if (whence != SEEK_SET)
107            return -1;
108        stream->seek(offset_beg);
109        return 0;
110    }
111
112    long tellVorbis(void* datasource)
113    {
114        return static_cast<long>(static_cast<Ogre::DataStream*>(datasource)->tell());
115    }
116
117    void SoundBuffer::loadOgg(DataStreamPtr dataStream)
118    {
119        char inbuffer[256*1024];
120        std::vector<char> outbuffer;
121        outbuffer.reserve(80*1024*1024);
122
123        // Open file with custom streaming
124        ov_callbacks vorbisCallbacks;
125        vorbisCallbacks.read_func  = &readVorbis;
126        vorbisCallbacks.seek_func  = &seekVorbis;
127        vorbisCallbacks.tell_func  = &tellVorbis;
128        vorbisCallbacks.close_func = NULL;
129
130        OggVorbis_File vf;
131        int ret = ov_open_callbacks(dataStream.get(), &vf, NULL, 0, vorbisCallbacks);
132        if (ret < 0)
133        {
134            COUT(2) << "Sound: libvorbisfile: File does not seem to be an Ogg Vorbis bitstream" << std::endl;
135            ov_clear(&vf);
136            ThrowException(General, "Sound Error: Ogg file loader failed when opening the bitstream");
137        }
138
139        int current_section;
140        int eof = false;
141        while (!eof)
142        {
143            long ret = ov_read(&vf, inbuffer, sizeof(inbuffer), 0, 2, 1, &current_section);
144            if (ret == 0)
145            {
146                eof = true;
147            }
148            else if (ret < 0)
149            {
150                COUT(2) << "Sound: libvorbisfile: error reading the file" << std::endl;
151                ov_clear(&vf);
152                ThrowException(General, "Sound Error: Ogg file loader failed when decoding the file");
153            }
154            else
155            {
156                outbuffer.insert(outbuffer.end(), inbuffer, inbuffer + ret);
157            }
158        }
159
160        vorbis_info* vorbisInfo;
161        vorbisInfo = ov_info(&vf, -1);
162        ALenum format;
163        if (vorbisInfo->channels == 1)
164            format = AL_FORMAT_MONO16;
165        else
166            format = AL_FORMAT_STEREO16;
167
168        alGenBuffers(1, &this->audioBuffer_);
169        alBufferData(this->audioBuffer_, format, &outbuffer[0], outbuffer.size(), vorbisInfo->rate);
170        ov_clear(&vf);
171
172        if (!alIsBuffer(this->audioBuffer_))
173            ThrowException(General, "Sound: Ogg file loader failed when creating the buffer.");
174    }
175}
Note: See TracBrowser for help on using the repository browser.