3 Copyright (C) 2013 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 Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser 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 "util/numeric.h" // myrand()
49 #define BUFFER_SIZE 30000
51 static const char *alcErrorString(ALCenum err)
56 case ALC_INVALID_DEVICE:
57 return "invalid device";
58 case ALC_INVALID_CONTEXT:
59 return "invalid context";
60 case ALC_INVALID_ENUM:
61 return "invalid enum";
62 case ALC_INVALID_VALUE:
63 return "invalid value";
64 case ALC_OUT_OF_MEMORY:
65 return "out of memory";
67 return "<unknown OpenAL error>";
71 static const char *alErrorString(ALenum err)
77 return "invalid name";
79 return "invalid enum";
80 case AL_INVALID_VALUE:
81 return "invalid value";
82 case AL_INVALID_OPERATION:
83 return "invalid operation";
84 case AL_OUT_OF_MEMORY:
85 return "out of memory";
87 return "<unknown OpenAL error>";
91 static ALenum warn_if_error(ALenum err, const char *desc)
93 if(err == AL_NO_ERROR)
95 warningstream<<desc<<": "<<alErrorString(err)<<std::endl;
99 void f3_set(ALfloat *f3, v3f v)
111 std::vector<char> buffer;
114 SoundBuffer *load_opened_ogg_file(OggVorbis_File *oggFile,
115 const std::string &filename_for_logging)
117 int endian = 0; // 0 for Little-Endian, 1 for Big-Endian
120 char array[BUFFER_SIZE]; // Local fixed size array
123 SoundBuffer *snd = new SoundBuffer;
125 // Get some information about the OGG file
126 pInfo = ov_info(oggFile, -1);
128 // Check the number of channels... always use 16-bit samples
129 if(pInfo->channels == 1)
130 snd->format = AL_FORMAT_MONO16;
132 snd->format = AL_FORMAT_STEREO16;
134 // The frequency of the sampling rate
135 snd->freq = pInfo->rate;
137 // Keep reading until all is read
140 // Read up to a buffer's worth of decoded sound data
141 bytes = ov_read(oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream);
146 infostream << "Audio: Error decoding "
147 << filename_for_logging << std::endl;
151 // Append to end of buffer
152 snd->buffer.insert(snd->buffer.end(), array, array + bytes);
155 alGenBuffers(1, &snd->buffer_id);
156 alBufferData(snd->buffer_id, snd->format,
157 &(snd->buffer[0]), snd->buffer.size(),
160 ALenum error = alGetError();
162 if(error != AL_NO_ERROR){
163 infostream<<"Audio: OpenAL error: "<<alErrorString(error)
164 <<"preparing sound buffer"<<std::endl;
167 infostream << "Audio file "
168 << filename_for_logging << " loaded" << std::endl;
176 SoundBuffer *load_ogg_from_file(const std::string &path)
178 OggVorbis_File oggFile;
180 // Try opening the given file.
181 // This requires libvorbis >= 1.3.2, as
182 // previous versions expect a non-const char *
183 if (ov_fopen(path.c_str(), &oggFile) != 0) {
184 infostream << "Audio: Error opening " << path
185 << " for decoding" << std::endl;
189 return load_opened_ogg_file(&oggFile, path);
192 struct BufferSource {
198 size_t buffer_sound_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
200 BufferSource *s = (BufferSource *)datasource;
201 size_t copied_size = MYMIN(s->len - s->cur_offset, size);
202 memcpy(ptr, s->buf + s->cur_offset, copied_size);
203 s->cur_offset += copied_size;
207 int buffer_sound_seek_func(void *datasource, ogg_int64_t offset, int whence)
209 BufferSource *s = (BufferSource *)datasource;
210 if (whence == SEEK_SET) {
211 if (offset < 0 || (size_t)MYMAX(offset, 0) >= s->len) {
212 // offset out of bounds
215 s->cur_offset = offset;
217 } else if (whence == SEEK_CUR) {
218 if ((size_t)MYMIN(-offset, 0) > s->cur_offset
219 || s->cur_offset + offset > s->len) {
220 // offset out of bounds
223 s->cur_offset += offset;
226 // invalid whence param (SEEK_END doesn't have to be supported)
230 long BufferSourceell_func(void *datasource)
232 BufferSource *s = (BufferSource *)datasource;
233 return s->cur_offset;
236 static ov_callbacks g_buffer_ov_callbacks = {
237 &buffer_sound_read_func,
238 &buffer_sound_seek_func,
240 &BufferSourceell_func
243 SoundBuffer *load_ogg_from_buffer(const std::string &buf, const std::string &id_for_log)
245 OggVorbis_File oggFile;
252 if (ov_open_callbacks(&s, &oggFile, NULL, 0, g_buffer_ov_callbacks) != 0) {
253 infostream << "Audio: Error opening " << id_for_log
254 << " for decoding" << std::endl;
258 return load_opened_ogg_file(&oggFile, id_for_log);
267 class OpenALSoundManager: public ISoundManager
270 OnDemandSoundFetcher *m_fetcher;
272 ALCcontext *m_context;
275 std::map<std::string, std::vector<SoundBuffer*> > m_buffers;
276 std::map<int, PlayingSound*> m_sounds_playing;
279 bool m_is_initialized;
280 OpenALSoundManager(OnDemandSoundFetcher *fetcher):
286 m_is_initialized(false)
288 ALCenum error = ALC_NO_ERROR;
290 infostream<<"Audio: Initializing..."<<std::endl;
292 m_device = alcOpenDevice(NULL);
294 infostream<<"Audio: No audio device available, audio system "
295 <<"not initialized"<<std::endl;
299 if(alcIsExtensionPresent(m_device, "EXT_vorbis")){
300 infostream<<"Audio: Vorbis extension present"<<std::endl;
303 infostream<<"Audio: Vorbis extension NOT present"<<std::endl;
304 m_can_vorbis = false;
307 m_context = alcCreateContext(m_device, NULL);
309 error = alcGetError(m_device);
310 infostream<<"Audio: Unable to initialize audio context, "
311 <<"aborting audio initialization ("<<alcErrorString(error)
313 alcCloseDevice(m_device);
318 if(!alcMakeContextCurrent(m_context) ||
319 (error = alcGetError(m_device) != ALC_NO_ERROR))
321 infostream<<"Audio: Error setting audio context, aborting audio "
322 <<"initialization ("<<alcErrorString(error)<<")"<<std::endl;
323 alcDestroyContext(m_context);
325 alcCloseDevice(m_device);
330 alDistanceModel(AL_EXPONENT_DISTANCE);
332 infostream<<"Audio: Initialized: OpenAL "<<alGetString(AL_VERSION)
333 <<", using "<<alcGetString(m_device, ALC_DEVICE_SPECIFIER)
336 m_is_initialized = true;
339 ~OpenALSoundManager()
341 infostream<<"Audio: Deinitializing..."<<std::endl;
343 // TODO: Clear SoundBuffers
344 alcMakeContextCurrent(NULL);
345 alcDestroyContext(m_context);
347 alcCloseDevice(m_device);
350 for (std::map<std::string, std::vector<SoundBuffer*> >::iterator i = m_buffers.begin();
351 i != m_buffers.end(); ++i) {
352 for (std::vector<SoundBuffer*>::iterator iter = (*i).second.begin();
353 iter != (*i).second.end(); ++iter) {
359 infostream<<"Audio: Deinitialized."<<std::endl;
362 void addBuffer(const std::string &name, SoundBuffer *buf)
364 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
365 m_buffers.find(name);
366 if(i != m_buffers.end()){
367 i->second.push_back(buf);
370 std::vector<SoundBuffer*> bufs;
372 m_buffers[name] = bufs;
376 SoundBuffer* getBuffer(const std::string &name)
378 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
379 m_buffers.find(name);
380 if(i == m_buffers.end())
382 std::vector<SoundBuffer*> &bufs = i->second;
383 int j = myrand() % bufs.size();
387 PlayingSound* createPlayingSound(SoundBuffer *buf, bool loop,
390 infostream<<"OpenALSoundManager: Creating playing sound"<<std::endl;
392 PlayingSound *sound = new PlayingSound;
394 warn_if_error(alGetError(), "before createPlayingSound");
395 alGenSources(1, &sound->source_id);
396 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
397 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, true);
398 alSource3f(sound->source_id, AL_POSITION, 0, 0, 0);
399 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
400 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
401 volume = MYMAX(0.0, volume);
402 alSourcef(sound->source_id, AL_GAIN, volume);
403 alSourcePlay(sound->source_id);
404 warn_if_error(alGetError(), "createPlayingSound");
408 PlayingSound* createPlayingSoundAt(SoundBuffer *buf, bool loop,
409 float volume, v3f pos)
411 infostream<<"OpenALSoundManager: Creating positional playing sound"
414 PlayingSound *sound = new PlayingSound;
416 warn_if_error(alGetError(), "before createPlayingSoundAt");
417 alGenSources(1, &sound->source_id);
418 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
419 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
420 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
421 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
422 //alSourcef(sound->source_id, AL_ROLLOFF_FACTOR, 0.7);
423 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
424 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
425 volume = MYMAX(0.0, volume);
426 alSourcef(sound->source_id, AL_GAIN, volume);
427 alSourcePlay(sound->source_id);
428 warn_if_error(alGetError(), "createPlayingSoundAt");
432 int playSoundRaw(SoundBuffer *buf, bool loop, float volume)
435 PlayingSound *sound = createPlayingSound(buf, loop, volume);
438 int id = m_next_id++;
439 m_sounds_playing[id] = sound;
443 int playSoundRawAt(SoundBuffer *buf, bool loop, float volume, v3f pos)
446 PlayingSound *sound = createPlayingSoundAt(buf, loop, volume, pos);
449 int id = m_next_id++;
450 m_sounds_playing[id] = sound;
454 void deleteSound(int id)
456 std::map<int, PlayingSound*>::iterator i =
457 m_sounds_playing.find(id);
458 if(i == m_sounds_playing.end())
460 PlayingSound *sound = i->second;
462 alDeleteSources(1, &sound->source_id);
465 m_sounds_playing.erase(id);
468 /* If buffer does not exist, consult the fetcher */
469 SoundBuffer* getFetchBuffer(const std::string &name)
471 SoundBuffer *buf = getBuffer(name);
476 std::set<std::string> paths;
477 std::set<std::string> datas;
478 m_fetcher->fetchSounds(name, paths, datas);
479 for(std::set<std::string>::iterator i = paths.begin();
480 i != paths.end(); ++i){
481 loadSoundFile(name, *i);
483 for(std::set<std::string>::iterator i = datas.begin();
484 i != datas.end(); ++i){
485 loadSoundData(name, *i);
487 return getBuffer(name);
490 // Remove stopped sounds
493 verbosestream<<"OpenALSoundManager::maintain(): "
494 <<m_sounds_playing.size()<<" playing sounds, "
495 <<m_buffers.size()<<" sound names loaded"<<std::endl;
496 std::set<int> del_list;
497 for(std::map<int, PlayingSound*>::iterator
498 i = m_sounds_playing.begin();
499 i != m_sounds_playing.end(); ++i)
502 PlayingSound *sound = i->second;
503 // If not playing, remove it
506 alGetSourcei(sound->source_id, AL_SOURCE_STATE, &state);
507 if(state != AL_PLAYING){
512 if(!del_list.empty())
513 verbosestream<<"OpenALSoundManager::maintain(): deleting "
514 <<del_list.size()<<" playing sounds"<<std::endl;
515 for(std::set<int>::iterator i = del_list.begin();
516 i != del_list.end(); ++i)
524 bool loadSoundFile(const std::string &name,
525 const std::string &filepath)
527 SoundBuffer *buf = load_ogg_from_file(filepath);
529 addBuffer(name, buf);
532 bool loadSoundData(const std::string &name,
533 const std::string &filedata)
535 SoundBuffer *buf = load_ogg_from_buffer(filedata, name);
537 addBuffer(name, buf);
541 void updateListener(v3f pos, v3f vel, v3f at, v3f up)
543 m_listener_pos = pos;
544 alListener3f(AL_POSITION, pos.X, pos.Y, pos.Z);
545 alListener3f(AL_VELOCITY, vel.X, vel.Y, vel.Z);
549 alListenerfv(AL_ORIENTATION, f);
550 warn_if_error(alGetError(), "updateListener");
553 void setListenerGain(float gain)
555 alListenerf(AL_GAIN, gain);
558 int playSound(const std::string &name, bool loop, float volume)
563 SoundBuffer *buf = getFetchBuffer(name);
565 infostream<<"OpenALSoundManager: \""<<name<<"\" not found."
569 return playSoundRaw(buf, loop, volume);
571 int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
576 SoundBuffer *buf = getFetchBuffer(name);
578 infostream<<"OpenALSoundManager: \""<<name<<"\" not found."
582 return playSoundRawAt(buf, loop, volume, pos);
584 void stopSound(int sound)
589 bool soundExists(int sound)
592 return (m_sounds_playing.count(sound) != 0);
594 void updateSoundPosition(int id, v3f pos)
596 std::map<int, PlayingSound*>::iterator i =
597 m_sounds_playing.find(id);
598 if(i == m_sounds_playing.end())
600 PlayingSound *sound = i->second;
602 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
603 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
604 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
605 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
609 ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher)
611 OpenALSoundManager *m = new OpenALSoundManager(fetcher);
612 if(m->m_is_initialized)