sound_openal.cpp: remove unused header
[oweals/minetest.git] / src / sound_openal.cpp
1 /*
2 Minetest
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>
8
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.
13
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.
18
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.
22 */
23
24 #include "sound_openal.h"
25
26 #if defined(_WIN32)
27         #include <al.h>
28         #include <alc.h>
29         //#include <alext.h>
30 #elif defined(__APPLE__)
31         #include <OpenAL/al.h>
32         #include <OpenAL/alc.h>
33         //#include <OpenAL/alext.h>
34 #else
35         #include <AL/al.h>
36         #include <AL/alc.h>
37         #include <AL/alext.h>
38 #endif
39 #include <vorbis/vorbisfile.h>
40 #include <assert.h>
41 #include "log.h"
42 #include "util/numeric.h" // myrand()
43 #include "porting.h"
44 #include <map>
45 #include <vector>
46 #include <fstream>
47
48 #define BUFFER_SIZE 30000
49
50 static const char *alcErrorString(ALCenum err)
51 {
52         switch (err) {
53         case ALC_NO_ERROR:
54                 return "no error";
55         case ALC_INVALID_DEVICE:
56                 return "invalid device";
57         case ALC_INVALID_CONTEXT:
58                 return "invalid context";
59         case ALC_INVALID_ENUM:
60                 return "invalid enum";
61         case ALC_INVALID_VALUE:
62                 return "invalid value";
63         case ALC_OUT_OF_MEMORY:
64                 return "out of memory";
65         default:
66                 return "<unknown OpenAL error>";
67         }
68 }
69
70 static const char *alErrorString(ALenum err)
71 {
72         switch (err) {
73         case AL_NO_ERROR:
74                 return "no error";
75         case AL_INVALID_NAME:
76                 return "invalid name";
77         case AL_INVALID_ENUM:
78                 return "invalid enum";
79         case AL_INVALID_VALUE:
80                 return "invalid value";
81         case AL_INVALID_OPERATION:
82                 return "invalid operation";
83         case AL_OUT_OF_MEMORY:
84                 return "out of memory";
85         default:
86                 return "<unknown OpenAL error>";
87         }
88 }
89
90 static ALenum warn_if_error(ALenum err, const char *desc)
91 {
92         if(err == AL_NO_ERROR)
93                 return err;
94         warningstream<<desc<<": "<<alErrorString(err)<<std::endl;
95         return err;
96 }
97
98 void f3_set(ALfloat *f3, v3f v)
99 {
100         f3[0] = v.X;
101         f3[1] = v.Y;
102         f3[2] = v.Z;
103 }
104
105 struct SoundBuffer
106 {
107         ALenum format;
108         ALsizei freq;
109         ALuint buffer_id;
110         std::vector<char> buffer;
111 };
112
113 SoundBuffer *load_opened_ogg_file(OggVorbis_File *oggFile,
114                 const std::string &filename_for_logging)
115 {
116         int endian = 0; // 0 for Little-Endian, 1 for Big-Endian
117         int bitStream;
118         long bytes;
119         char array[BUFFER_SIZE]; // Local fixed size array
120         vorbis_info *pInfo;
121
122         SoundBuffer *snd = new SoundBuffer;
123
124         // Get some information about the OGG file
125         pInfo = ov_info(oggFile, -1);
126
127         // Check the number of channels... always use 16-bit samples
128         if(pInfo->channels == 1)
129                 snd->format = AL_FORMAT_MONO16;
130         else
131                 snd->format = AL_FORMAT_STEREO16;
132
133         // The frequency of the sampling rate
134         snd->freq = pInfo->rate;
135
136         // Keep reading until all is read
137         do
138         {
139                 // Read up to a buffer's worth of decoded sound data
140                 bytes = ov_read(oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream);
141
142                 if(bytes < 0)
143                 {
144                         ov_clear(oggFile);
145                         infostream << "Audio: Error decoding "
146                                 << filename_for_logging << std::endl;
147                         return NULL;
148                 }
149
150                 // Append to end of buffer
151                 snd->buffer.insert(snd->buffer.end(), array, array + bytes);
152         } while (bytes > 0);
153
154         alGenBuffers(1, &snd->buffer_id);
155         alBufferData(snd->buffer_id, snd->format,
156                         &(snd->buffer[0]), snd->buffer.size(),
157                         snd->freq);
158
159         ALenum error = alGetError();
160
161         if(error != AL_NO_ERROR){
162                 infostream<<"Audio: OpenAL error: "<<alErrorString(error)
163                                 <<"preparing sound buffer"<<std::endl;
164         }
165
166         infostream << "Audio file "
167                 << filename_for_logging << " loaded" << std::endl;
168
169         // Clean up!
170         ov_clear(oggFile);
171
172         return snd;
173 }
174
175 SoundBuffer *load_ogg_from_file(const std::string &path)
176 {
177         OggVorbis_File oggFile;
178
179         // Try opening the given file.
180         // This requires libvorbis >= 1.3.2, as
181         // previous versions expect a non-const char *
182         if (ov_fopen(path.c_str(), &oggFile) != 0) {
183                 infostream << "Audio: Error opening " << path
184                         << " for decoding" << std::endl;
185                 return NULL;
186         }
187
188         return load_opened_ogg_file(&oggFile, path);
189 }
190
191 struct BufferSource {
192         const char *buf;
193         size_t cur_offset;
194         size_t len;
195 };
196
197 size_t buffer_sound_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
198 {
199         BufferSource *s = (BufferSource *)datasource;
200         size_t copied_size = MYMIN(s->len - s->cur_offset, size);
201         memcpy(ptr, s->buf + s->cur_offset, copied_size);
202         s->cur_offset += copied_size;
203         return copied_size;
204 }
205
206 int buffer_sound_seek_func(void *datasource, ogg_int64_t offset, int whence)
207 {
208         BufferSource *s = (BufferSource *)datasource;
209         if (whence == SEEK_SET) {
210                 if (offset < 0 || (size_t)MYMAX(offset, 0) >= s->len) {
211                         // offset out of bounds
212                         return -1;
213                 }
214                 s->cur_offset = offset;
215                 return 0;
216         } else if (whence == SEEK_CUR) {
217                 if ((size_t)MYMIN(-offset, 0) > s->cur_offset
218                                 || s->cur_offset + offset > s->len) {
219                         // offset out of bounds
220                         return -1;
221                 }
222                 s->cur_offset += offset;
223                 return 0;
224         }
225         // invalid whence param (SEEK_END doesn't have to be supported)
226         return -1;
227 }
228
229 long BufferSourceell_func(void *datasource)
230 {
231         BufferSource *s = (BufferSource *)datasource;
232         return s->cur_offset;
233 }
234
235 static ov_callbacks g_buffer_ov_callbacks = {
236         &buffer_sound_read_func,
237         &buffer_sound_seek_func,
238         NULL,
239         &BufferSourceell_func
240 };
241
242 SoundBuffer *load_ogg_from_buffer(const std::string &buf, const std::string &id_for_log)
243 {
244         OggVorbis_File oggFile;
245
246         BufferSource s;
247         s.buf = buf.c_str();
248         s.cur_offset = 0;
249         s.len = buf.size();
250
251         if (ov_open_callbacks(&s, &oggFile, NULL, 0, g_buffer_ov_callbacks) != 0) {
252                 infostream << "Audio: Error opening " << id_for_log
253                         << " for decoding" << std::endl;
254                 return NULL;
255         }
256
257         return load_opened_ogg_file(&oggFile, id_for_log);
258 }
259
260 struct PlayingSound
261 {
262         ALuint source_id;
263         bool loop;
264 };
265
266 class OpenALSoundManager: public ISoundManager
267 {
268 private:
269         OnDemandSoundFetcher *m_fetcher;
270         ALCdevice *m_device;
271         ALCcontext *m_context;
272         bool m_can_vorbis;
273         int m_next_id;
274         std::map<std::string, std::vector<SoundBuffer*> > m_buffers;
275         std::map<int, PlayingSound*> m_sounds_playing;
276         v3f m_listener_pos;
277 public:
278         bool m_is_initialized;
279         OpenALSoundManager(OnDemandSoundFetcher *fetcher):
280                 m_fetcher(fetcher),
281                 m_device(NULL),
282                 m_context(NULL),
283                 m_can_vorbis(false),
284                 m_next_id(1),
285                 m_is_initialized(false)
286         {
287                 ALCenum error = ALC_NO_ERROR;
288
289                 infostream<<"Audio: Initializing..."<<std::endl;
290
291                 m_device = alcOpenDevice(NULL);
292                 if(!m_device){
293                         infostream<<"Audio: No audio device available, audio system "
294                                 <<"not initialized"<<std::endl;
295                         return;
296                 }
297
298                 if(alcIsExtensionPresent(m_device, "EXT_vorbis")){
299                         infostream<<"Audio: Vorbis extension present"<<std::endl;
300                         m_can_vorbis = true;
301                 } else{
302                         infostream<<"Audio: Vorbis extension NOT present"<<std::endl;
303                         m_can_vorbis = false;
304                 }
305
306                 m_context = alcCreateContext(m_device, NULL);
307                 if(!m_context){
308                         error = alcGetError(m_device);
309                         infostream<<"Audio: Unable to initialize audio context, "
310                                         <<"aborting audio initialization ("<<alcErrorString(error)
311                                         <<")"<<std::endl;
312                         alcCloseDevice(m_device);
313                         m_device = NULL;
314                         return;
315                 }
316
317                 if(!alcMakeContextCurrent(m_context) ||
318                                 (error = alcGetError(m_device) != ALC_NO_ERROR))
319                 {
320                         infostream<<"Audio: Error setting audio context, aborting audio "
321                                         <<"initialization ("<<alcErrorString(error)<<")"<<std::endl;
322                         alcDestroyContext(m_context);
323                         m_context = NULL;
324                         alcCloseDevice(m_device);
325                         m_device = NULL;
326                         return;
327                 }
328
329                 alDistanceModel(AL_EXPONENT_DISTANCE);
330
331                 infostream<<"Audio: Initialized: OpenAL "<<alGetString(AL_VERSION)
332                                 <<", using "<<alcGetString(m_device, ALC_DEVICE_SPECIFIER)
333                                 <<std::endl;
334
335                 m_is_initialized = true;
336         }
337
338         ~OpenALSoundManager()
339         {
340                 infostream<<"Audio: Deinitializing..."<<std::endl;
341                 // KABOOM!
342                 // TODO: Clear SoundBuffers
343                 alcMakeContextCurrent(NULL);
344                 alcDestroyContext(m_context);
345                 m_context = NULL;
346                 alcCloseDevice(m_device);
347                 m_device = NULL;
348
349                 for (std::map<std::string, std::vector<SoundBuffer*> >::iterator i = m_buffers.begin();
350                                 i != m_buffers.end(); ++i) {
351                         for (std::vector<SoundBuffer*>::iterator iter = (*i).second.begin();
352                                         iter != (*i).second.end(); ++iter) {
353                                 delete *iter;
354                         }
355                         (*i).second.clear();
356                 }
357                 m_buffers.clear();
358                 infostream<<"Audio: Deinitialized."<<std::endl;
359         }
360
361         void addBuffer(const std::string &name, SoundBuffer *buf)
362         {
363                 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
364                                 m_buffers.find(name);
365                 if(i != m_buffers.end()){
366                         i->second.push_back(buf);
367                         return;
368                 }
369                 std::vector<SoundBuffer*> bufs;
370                 bufs.push_back(buf);
371                 m_buffers[name] = bufs;
372                 return;
373         }
374
375         SoundBuffer* getBuffer(const std::string &name)
376         {
377                 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
378                                 m_buffers.find(name);
379                 if(i == m_buffers.end())
380                         return NULL;
381                 std::vector<SoundBuffer*> &bufs = i->second;
382                 int j = myrand() % bufs.size();
383                 return bufs[j];
384         }
385
386         PlayingSound* createPlayingSound(SoundBuffer *buf, bool loop,
387                         float volume)
388         {
389                 infostream<<"OpenALSoundManager: Creating playing sound"<<std::endl;
390                 assert(buf);
391                 PlayingSound *sound = new PlayingSound;
392                 assert(sound);
393                 warn_if_error(alGetError(), "before createPlayingSound");
394                 alGenSources(1, &sound->source_id);
395                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
396                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, true);
397                 alSource3f(sound->source_id, AL_POSITION, 0, 0, 0);
398                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
399                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
400                 volume = MYMAX(0.0, volume);
401                 alSourcef(sound->source_id, AL_GAIN, volume);
402                 alSourcePlay(sound->source_id);
403                 warn_if_error(alGetError(), "createPlayingSound");
404                 return sound;
405         }
406
407         PlayingSound* createPlayingSoundAt(SoundBuffer *buf, bool loop,
408                         float volume, v3f pos)
409         {
410                 infostream<<"OpenALSoundManager: Creating positional playing sound"
411                                 <<std::endl;
412                 assert(buf);
413                 PlayingSound *sound = new PlayingSound;
414                 assert(sound);
415                 warn_if_error(alGetError(), "before createPlayingSoundAt");
416                 alGenSources(1, &sound->source_id);
417                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
418                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
419                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
420                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
421                 //alSourcef(sound->source_id, AL_ROLLOFF_FACTOR, 0.7);
422                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
423                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
424                 volume = MYMAX(0.0, volume);
425                 alSourcef(sound->source_id, AL_GAIN, volume);
426                 alSourcePlay(sound->source_id);
427                 warn_if_error(alGetError(), "createPlayingSoundAt");
428                 return sound;
429         }
430
431         int playSoundRaw(SoundBuffer *buf, bool loop, float volume)
432         {
433                 assert(buf);
434                 PlayingSound *sound = createPlayingSound(buf, loop, volume);
435                 if(!sound)
436                         return -1;
437                 int id = m_next_id++;
438                 m_sounds_playing[id] = sound;
439                 return id;
440         }
441
442         int playSoundRawAt(SoundBuffer *buf, bool loop, float volume, v3f pos)
443         {
444                 assert(buf);
445                 PlayingSound *sound = createPlayingSoundAt(buf, loop, volume, pos);
446                 if(!sound)
447                         return -1;
448                 int id = m_next_id++;
449                 m_sounds_playing[id] = sound;
450                 return id;
451         }
452
453         void deleteSound(int id)
454         {
455                 std::map<int, PlayingSound*>::iterator i =
456                                 m_sounds_playing.find(id);
457                 if(i == m_sounds_playing.end())
458                         return;
459                 PlayingSound *sound = i->second;
460
461                 alDeleteSources(1, &sound->source_id);
462
463                 delete sound;
464                 m_sounds_playing.erase(id);
465         }
466
467         /* If buffer does not exist, consult the fetcher */
468         SoundBuffer* getFetchBuffer(const std::string &name)
469         {
470                 SoundBuffer *buf = getBuffer(name);
471                 if(buf)
472                         return buf;
473                 if(!m_fetcher)
474                         return NULL;
475                 std::set<std::string> paths;
476                 std::set<std::string> datas;
477                 m_fetcher->fetchSounds(name, paths, datas);
478                 for(std::set<std::string>::iterator i = paths.begin();
479                                 i != paths.end(); ++i){
480                         loadSoundFile(name, *i);
481                 }
482                 for(std::set<std::string>::iterator i = datas.begin();
483                                 i != datas.end(); ++i){
484                         loadSoundData(name, *i);
485                 }
486                 return getBuffer(name);
487         }
488
489         // Remove stopped sounds
490         void maintain()
491         {
492                 verbosestream<<"OpenALSoundManager::maintain(): "
493                                 <<m_sounds_playing.size()<<" playing sounds, "
494                                 <<m_buffers.size()<<" sound names loaded"<<std::endl;
495                 std::set<int> del_list;
496                 for(std::map<int, PlayingSound*>::iterator
497                                 i = m_sounds_playing.begin();
498                                 i != m_sounds_playing.end(); ++i)
499                 {
500                         int id = i->first;
501                         PlayingSound *sound = i->second;
502                         // If not playing, remove it
503                         {
504                                 ALint state;
505                                 alGetSourcei(sound->source_id, AL_SOURCE_STATE, &state);
506                                 if(state != AL_PLAYING){
507                                         del_list.insert(id);
508                                 }
509                         }
510                 }
511                 if(!del_list.empty())
512                         verbosestream<<"OpenALSoundManager::maintain(): deleting "
513                                         <<del_list.size()<<" playing sounds"<<std::endl;
514                 for(std::set<int>::iterator i = del_list.begin();
515                                 i != del_list.end(); ++i)
516                 {
517                         deleteSound(*i);
518                 }
519         }
520
521         /* Interface */
522
523         bool loadSoundFile(const std::string &name,
524                         const std::string &filepath)
525         {
526                 SoundBuffer *buf = load_ogg_from_file(filepath);
527                 if (buf)
528                         addBuffer(name, buf);
529                 return false;
530         }
531         bool loadSoundData(const std::string &name,
532                         const std::string &filedata)
533         {
534                 SoundBuffer *buf = load_ogg_from_buffer(filedata, name);
535                 if (buf)
536                         addBuffer(name, buf);
537                 return false;
538         }
539
540         void updateListener(v3f pos, v3f vel, v3f at, v3f up)
541         {
542                 m_listener_pos = pos;
543                 alListener3f(AL_POSITION, pos.X, pos.Y, pos.Z);
544                 alListener3f(AL_VELOCITY, vel.X, vel.Y, vel.Z);
545                 ALfloat f[6];
546                 f3_set(f, at);
547                 f3_set(f+3, -up);
548                 alListenerfv(AL_ORIENTATION, f);
549                 warn_if_error(alGetError(), "updateListener");
550         }
551
552         void setListenerGain(float gain)
553         {
554                 alListenerf(AL_GAIN, gain);
555         }
556
557         int playSound(const std::string &name, bool loop, float volume)
558         {
559                 maintain();
560                 if(name == "")
561                         return 0;
562                 SoundBuffer *buf = getFetchBuffer(name);
563                 if(!buf){
564                         infostream<<"OpenALSoundManager: \""<<name<<"\" not found."
565                                         <<std::endl;
566                         return -1;
567                 }
568                 return playSoundRaw(buf, loop, volume);
569         }
570         int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
571         {
572                 maintain();
573                 if(name == "")
574                         return 0;
575                 SoundBuffer *buf = getFetchBuffer(name);
576                 if(!buf){
577                         infostream<<"OpenALSoundManager: \""<<name<<"\" not found."
578                                         <<std::endl;
579                         return -1;
580                 }
581                 return playSoundRawAt(buf, loop, volume, pos);
582         }
583         void stopSound(int sound)
584         {
585                 maintain();
586                 deleteSound(sound);
587         }
588         bool soundExists(int sound)
589         {
590                 maintain();
591                 return (m_sounds_playing.count(sound) != 0);
592         }
593         void updateSoundPosition(int id, v3f pos)
594         {
595                 std::map<int, PlayingSound*>::iterator i =
596                                 m_sounds_playing.find(id);
597                 if(i == m_sounds_playing.end())
598                         return;
599                 PlayingSound *sound = i->second;
600
601                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
602                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
603                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
604                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
605         }
606 };
607
608 ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher)
609 {
610         OpenALSoundManager *m = new OpenALSoundManager(fetcher);
611         if(m->m_is_initialized)
612                 return m;
613         delete m;
614         return NULL;
615 };
616