3 Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
4 OpenAL support based on work by:
5 Copyright (C) 2011 Sebastian 'Bahamada' Rühl
6 Copyright (C) 2011 Cyriaque 'Cisoun' Skrapits <cysoun@gmail.com>
7 Copyright (C) 2011 Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License along
20 with this program; ifnot, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "sound_openal.h"
30 #elif defined(__APPLE__)
31 #include <OpenAL/al.h>
32 #include <OpenAL/alc.h>
33 #include <OpenAL/alext.h>
39 #include <vorbis/vorbisfile.h>
43 #include "utility.h" // myrand()
45 #define BUFFER_SIZE 30000
47 static const char *alcErrorString(ALCenum err)
52 case ALC_INVALID_DEVICE:
53 return "invalid device";
54 case ALC_INVALID_CONTEXT:
55 return "invalid context";
56 case ALC_INVALID_ENUM:
57 return "invalid enum";
58 case ALC_INVALID_VALUE:
59 return "invalid value";
60 case ALC_OUT_OF_MEMORY:
61 return "out of memory";
63 return "<unknown OpenAL error>";
67 static const char *alErrorString(ALenum err)
73 return "invalid name";
75 return "invalid enum";
76 case AL_INVALID_VALUE:
77 return "invalid value";
78 case AL_INVALID_OPERATION:
79 return "invalid operation";
80 case AL_OUT_OF_MEMORY:
81 return "out of memory";
83 return "<unknown OpenAL error>";
87 void f3_set(ALfloat *f3, v3f v)
99 std::vector<char> buffer;
102 SoundBuffer* loadOggFile(const std::string &filepath)
104 int endian = 0; // 0 for Little-Endian, 1 for Big-Endian
107 char array[BUFFER_SIZE]; // Local fixed size array
109 OggVorbis_File oggFile;
111 // Try opening the given file
112 if(ov_fopen(filepath.c_str(), &oggFile) != 0)
114 infostream<<"Audio: Error opening "<<filepath<<" for decoding"<<std::endl;
118 SoundBuffer *snd = new SoundBuffer;
120 // Get some information about the OGG file
121 pInfo = ov_info(&oggFile, -1);
123 // Check the number of channels... always use 16-bit samples
124 if(pInfo->channels == 1)
125 snd->format = AL_FORMAT_MONO16;
127 snd->format = AL_FORMAT_STEREO16;
129 // The frequency of the sampling rate
130 snd->freq = pInfo->rate;
132 // Keep reading until all is read
135 // Read up to a buffer's worth of decoded sound data
136 bytes = ov_read(&oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream);
141 infostream<<"Audio: Error decoding "<<filepath<<std::endl;
145 // Append to end of buffer
146 snd->buffer.insert(snd->buffer.end(), array, array + bytes);
149 alGenBuffers(1, &snd->bufferID);
150 alBufferData(snd->bufferID, snd->format,
151 &(snd->buffer[0]), snd->buffer.size(),
154 ALenum error = alGetError();
156 if(error != AL_NO_ERROR){
157 infostream<<"Audio: OpenAL error: "<<alErrorString(error)
158 <<"preparing sound buffer"<<std::endl;
161 infostream<<"Audio file "<<filepath<<" loaded"<<std::endl;
173 class OpenALSoundManager: public ISoundManager
177 ALCcontext *m_context;
180 std::map<std::string, std::vector<SoundBuffer*> > m_buffers;
181 std::map<int, PlayingSound*> m_sounds_playing;
183 OpenALSoundManager():
189 ALCenum error = ALC_NO_ERROR;
191 infostream<<"Audio: Initializing..."<<std::endl;
193 m_device = alcOpenDevice(NULL);
195 infostream<<"Audio: No audio device available, audio system "
196 <<"not initialized"<<std::endl;
200 if(alcIsExtensionPresent(m_device, "EXT_vorbis")){
201 infostream<<"Audio: Vorbis extension present"<<std::endl;
204 infostream<<"Audio: Vorbis extension NOT present"<<std::endl;
205 m_can_vorbis = false;
208 m_context = alcCreateContext(m_device, NULL);
210 error = alcGetError(m_device);
211 infostream<<"Audio: Unable to initialize audio context, "
212 <<"aborting audio initialization ("<<alcErrorString(error)
214 alcCloseDevice(m_device);
219 if(!alcMakeContextCurrent(m_context) ||
220 (error = alcGetError(m_device) != ALC_NO_ERROR))
222 infostream<<"Audio: Error setting audio context, aborting audio "
223 <<"initialization ("<<alcErrorString(error)<<")"<<std::endl;
224 alcDestroyContext(m_context);
226 alcCloseDevice(m_device);
231 alDistanceModel(AL_EXPONENT_DISTANCE);
233 infostream<<"Audio: Initialized: OpenAL "<<alGetString(AL_VERSION)
234 <<", using "<<alcGetString(m_device, ALC_DEVICE_SPECIFIER)
238 ~OpenALSoundManager()
240 infostream<<"Audio: Deinitializing..."<<std::endl;
242 // TODO: Clear SoundBuffers
243 alcMakeContextCurrent(NULL);
244 alcDestroyContext(m_context);
246 alcCloseDevice(m_device);
248 infostream<<"Audio: Deinitialized."<<std::endl;
251 void addBuffer(const std::string &name, SoundBuffer *buf)
253 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
254 m_buffers.find(name);
255 if(i != m_buffers.end()){
256 i->second.push_back(buf);
259 std::vector<SoundBuffer*> bufs;
264 SoundBuffer* getBuffer(const std::string &name)
266 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
267 m_buffers.find(name);
268 if(i == m_buffers.end())
270 std::vector<SoundBuffer*> &bufs = i->second;
271 int j = myrand() % bufs.size();
275 void updateListener(v3f pos, v3f vel, v3f at, v3f up)
279 alListenerfv(AL_POSITION, f);
281 alListenerfv(AL_VELOCITY, f);
284 alListenerfv(AL_ORIENTATION, f);
287 bool loadSound(const std::string &name,
288 const std::string &filepath)
290 SoundBuffer *buf = loadOggFile(filepath);
292 addBuffer(name, buf);
295 bool loadSound(const std::string &name,
296 const std::vector<char> &filedata)
298 errorstream<<"OpenALSoundManager: Loading from filedata not"
299 " implemented"<<std::endl;
303 int playSound(const std::string &name, int loopcount,
308 int playSoundAt(const std::string &name, int loopcount,
309 v3f pos, float volume)
313 void stopSound(int sound)
318 ISoundManager *createSoundManager()
320 return new OpenALSoundManager();