]> git.lizzy.rs Git - minetest.git/blob - src/sound_openal.cpp
Camera: Higher frequency limit for view/hand bobbing and footsteps
[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                         delete snd;
148                         return NULL;
149                 }
150
151                 // Append to end of buffer
152                 snd->buffer.insert(snd->buffer.end(), array, array + bytes);
153         } while (bytes > 0);
154
155         alGenBuffers(1, &snd->buffer_id);
156         alBufferData(snd->buffer_id, snd->format,
157                         &(snd->buffer[0]), snd->buffer.size(),
158                         snd->freq);
159
160         ALenum error = alGetError();
161
162         if(error != AL_NO_ERROR){
163                 infostream<<"Audio: OpenAL error: "<<alErrorString(error)
164                                 <<"preparing sound buffer"<<std::endl;
165         }
166
167         infostream << "Audio file "
168                 << filename_for_logging << " loaded" << std::endl;
169
170         // Clean up!
171         ov_clear(oggFile);
172
173         return snd;
174 }
175
176 SoundBuffer *load_ogg_from_file(const std::string &path)
177 {
178         OggVorbis_File oggFile;
179
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;
186                 return NULL;
187         }
188
189         return load_opened_ogg_file(&oggFile, path);
190 }
191
192 struct BufferSource {
193         const char *buf;
194         size_t cur_offset;
195         size_t len;
196 };
197
198 size_t buffer_sound_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
199 {
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;
204         return copied_size;
205 }
206
207 int buffer_sound_seek_func(void *datasource, ogg_int64_t offset, int whence)
208 {
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
213                         return -1;
214                 }
215                 s->cur_offset = offset;
216                 return 0;
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
221                         return -1;
222                 }
223                 s->cur_offset += offset;
224                 return 0;
225         }
226         // invalid whence param (SEEK_END doesn't have to be supported)
227         return -1;
228 }
229
230 long BufferSourceell_func(void *datasource)
231 {
232         BufferSource *s = (BufferSource *)datasource;
233         return s->cur_offset;
234 }
235
236 static ov_callbacks g_buffer_ov_callbacks = {
237         &buffer_sound_read_func,
238         &buffer_sound_seek_func,
239         NULL,
240         &BufferSourceell_func
241 };
242
243 SoundBuffer *load_ogg_from_buffer(const std::string &buf, const std::string &id_for_log)
244 {
245         OggVorbis_File oggFile;
246
247         BufferSource s;
248         s.buf = buf.c_str();
249         s.cur_offset = 0;
250         s.len = buf.size();
251
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;
255                 return NULL;
256         }
257
258         return load_opened_ogg_file(&oggFile, id_for_log);
259 }
260
261 struct PlayingSound
262 {
263         ALuint source_id;
264         bool loop;
265 };
266
267 class OpenALSoundManager: public ISoundManager
268 {
269 private:
270         OnDemandSoundFetcher *m_fetcher;
271         ALCdevice *m_device;
272         ALCcontext *m_context;
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_next_id(1),
284                 m_is_initialized(false)
285         {
286                 ALCenum error = ALC_NO_ERROR;
287
288                 infostream<<"Audio: Initializing..."<<std::endl;
289
290                 m_device = alcOpenDevice(NULL);
291                 if(!m_device){
292                         infostream<<"Audio: No audio device available, audio system "
293                                 <<"not initialized"<<std::endl;
294                         return;
295                 }
296
297                 m_context = alcCreateContext(m_device, NULL);
298                 if(!m_context){
299                         error = alcGetError(m_device);
300                         infostream<<"Audio: Unable to initialize audio context, "
301                                         <<"aborting audio initialization ("<<alcErrorString(error)
302                                         <<")"<<std::endl;
303                         alcCloseDevice(m_device);
304                         m_device = NULL;
305                         return;
306                 }
307
308                 if(!alcMakeContextCurrent(m_context) ||
309                                 (error = alcGetError(m_device) != ALC_NO_ERROR))
310                 {
311                         infostream<<"Audio: Error setting audio context, aborting audio "
312                                         <<"initialization ("<<alcErrorString(error)<<")"<<std::endl;
313                         alcDestroyContext(m_context);
314                         m_context = NULL;
315                         alcCloseDevice(m_device);
316                         m_device = NULL;
317                         return;
318                 }
319
320                 alDistanceModel(AL_EXPONENT_DISTANCE);
321
322                 infostream<<"Audio: Initialized: OpenAL "<<alGetString(AL_VERSION)
323                                 <<", using "<<alcGetString(m_device, ALC_DEVICE_SPECIFIER)
324                                 <<std::endl;
325
326                 m_is_initialized = true;
327         }
328
329         ~OpenALSoundManager()
330         {
331                 infostream<<"Audio: Deinitializing..."<<std::endl;
332                 // KABOOM!
333                 // TODO: Clear SoundBuffers
334                 alcMakeContextCurrent(NULL);
335                 alcDestroyContext(m_context);
336                 m_context = NULL;
337                 alcCloseDevice(m_device);
338                 m_device = NULL;
339
340                 for (std::map<std::string, std::vector<SoundBuffer*> >::iterator i = m_buffers.begin();
341                                 i != m_buffers.end(); ++i) {
342                         for (std::vector<SoundBuffer*>::iterator iter = (*i).second.begin();
343                                         iter != (*i).second.end(); ++iter) {
344                                 delete *iter;
345                         }
346                         (*i).second.clear();
347                 }
348                 m_buffers.clear();
349                 infostream<<"Audio: Deinitialized."<<std::endl;
350         }
351
352         void addBuffer(const std::string &name, SoundBuffer *buf)
353         {
354                 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
355                                 m_buffers.find(name);
356                 if(i != m_buffers.end()){
357                         i->second.push_back(buf);
358                         return;
359                 }
360                 std::vector<SoundBuffer*> bufs;
361                 bufs.push_back(buf);
362                 m_buffers[name] = bufs;
363                 return;
364         }
365
366         SoundBuffer* getBuffer(const std::string &name)
367         {
368                 std::map<std::string, std::vector<SoundBuffer*> >::iterator i =
369                                 m_buffers.find(name);
370                 if(i == m_buffers.end())
371                         return NULL;
372                 std::vector<SoundBuffer*> &bufs = i->second;
373                 int j = myrand() % bufs.size();
374                 return bufs[j];
375         }
376
377         PlayingSound* createPlayingSound(SoundBuffer *buf, bool loop,
378                         float volume)
379         {
380                 infostream<<"OpenALSoundManager: Creating playing sound"<<std::endl;
381                 assert(buf);
382                 PlayingSound *sound = new PlayingSound;
383                 assert(sound);
384                 warn_if_error(alGetError(), "before createPlayingSound");
385                 alGenSources(1, &sound->source_id);
386                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
387                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, true);
388                 alSource3f(sound->source_id, AL_POSITION, 0, 0, 0);
389                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
390                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
391                 volume = MYMAX(0.0, volume);
392                 alSourcef(sound->source_id, AL_GAIN, volume);
393                 alSourcePlay(sound->source_id);
394                 warn_if_error(alGetError(), "createPlayingSound");
395                 return sound;
396         }
397
398         PlayingSound* createPlayingSoundAt(SoundBuffer *buf, bool loop,
399                         float volume, v3f pos)
400         {
401                 infostream<<"OpenALSoundManager: Creating positional playing sound"
402                                 <<std::endl;
403                 assert(buf);
404                 PlayingSound *sound = new PlayingSound;
405                 assert(sound);
406                 warn_if_error(alGetError(), "before createPlayingSoundAt");
407                 alGenSources(1, &sound->source_id);
408                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
409                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
410                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
411                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
412                 //alSourcef(sound->source_id, AL_ROLLOFF_FACTOR, 0.7);
413                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
414                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
415                 volume = MYMAX(0.0, volume);
416                 alSourcef(sound->source_id, AL_GAIN, volume);
417                 alSourcePlay(sound->source_id);
418                 warn_if_error(alGetError(), "createPlayingSoundAt");
419                 return sound;
420         }
421
422         int playSoundRaw(SoundBuffer *buf, bool loop, float volume)
423         {
424                 assert(buf);
425                 PlayingSound *sound = createPlayingSound(buf, loop, volume);
426                 if(!sound)
427                         return -1;
428                 int id = m_next_id++;
429                 m_sounds_playing[id] = sound;
430                 return id;
431         }
432
433         int playSoundRawAt(SoundBuffer *buf, bool loop, float volume, v3f pos)
434         {
435                 assert(buf);
436                 PlayingSound *sound = createPlayingSoundAt(buf, loop, volume, pos);
437                 if(!sound)
438                         return -1;
439                 int id = m_next_id++;
440                 m_sounds_playing[id] = sound;
441                 return id;
442         }
443
444         void deleteSound(int id)
445         {
446                 std::map<int, PlayingSound*>::iterator i =
447                                 m_sounds_playing.find(id);
448                 if(i == m_sounds_playing.end())
449                         return;
450                 PlayingSound *sound = i->second;
451
452                 alDeleteSources(1, &sound->source_id);
453
454                 delete sound;
455                 m_sounds_playing.erase(id);
456         }
457
458         /* If buffer does not exist, consult the fetcher */
459         SoundBuffer* getFetchBuffer(const std::string &name)
460         {
461                 SoundBuffer *buf = getBuffer(name);
462                 if(buf)
463                         return buf;
464                 if(!m_fetcher)
465                         return NULL;
466                 std::set<std::string> paths;
467                 std::set<std::string> datas;
468                 m_fetcher->fetchSounds(name, paths, datas);
469                 for(std::set<std::string>::iterator i = paths.begin();
470                                 i != paths.end(); ++i){
471                         loadSoundFile(name, *i);
472                 }
473                 for(std::set<std::string>::iterator i = datas.begin();
474                                 i != datas.end(); ++i){
475                         loadSoundData(name, *i);
476                 }
477                 return getBuffer(name);
478         }
479
480         // Remove stopped sounds
481         void maintain()
482         {
483                 verbosestream<<"OpenALSoundManager::maintain(): "
484                                 <<m_sounds_playing.size()<<" playing sounds, "
485                                 <<m_buffers.size()<<" sound names loaded"<<std::endl;
486                 std::set<int> del_list;
487                 for(std::map<int, PlayingSound*>::iterator
488                                 i = m_sounds_playing.begin();
489                                 i != m_sounds_playing.end(); ++i)
490                 {
491                         int id = i->first;
492                         PlayingSound *sound = i->second;
493                         // If not playing, remove it
494                         {
495                                 ALint state;
496                                 alGetSourcei(sound->source_id, AL_SOURCE_STATE, &state);
497                                 if(state != AL_PLAYING){
498                                         del_list.insert(id);
499                                 }
500                         }
501                 }
502                 if(!del_list.empty())
503                         verbosestream<<"OpenALSoundManager::maintain(): deleting "
504                                         <<del_list.size()<<" playing sounds"<<std::endl;
505                 for(std::set<int>::iterator i = del_list.begin();
506                                 i != del_list.end(); ++i)
507                 {
508                         deleteSound(*i);
509                 }
510         }
511
512         /* Interface */
513
514         bool loadSoundFile(const std::string &name,
515                         const std::string &filepath)
516         {
517                 SoundBuffer *buf = load_ogg_from_file(filepath);
518                 if (buf)
519                         addBuffer(name, buf);
520                 return false;
521         }
522         bool loadSoundData(const std::string &name,
523                         const std::string &filedata)
524         {
525                 SoundBuffer *buf = load_ogg_from_buffer(filedata, name);
526                 if (buf)
527                         addBuffer(name, buf);
528                 return false;
529         }
530
531         void updateListener(v3f pos, v3f vel, v3f at, v3f up)
532         {
533                 m_listener_pos = pos;
534                 alListener3f(AL_POSITION, pos.X, pos.Y, pos.Z);
535                 alListener3f(AL_VELOCITY, vel.X, vel.Y, vel.Z);
536                 ALfloat f[6];
537                 f3_set(f, at);
538                 f3_set(f+3, -up);
539                 alListenerfv(AL_ORIENTATION, f);
540                 warn_if_error(alGetError(), "updateListener");
541         }
542
543         void setListenerGain(float gain)
544         {
545                 alListenerf(AL_GAIN, gain);
546         }
547
548         int playSound(const std::string &name, bool loop, float volume)
549         {
550                 maintain();
551                 if(name == "")
552                         return 0;
553                 SoundBuffer *buf = getFetchBuffer(name);
554                 if(!buf){
555                         infostream<<"OpenALSoundManager: \""<<name<<"\" not found."
556                                         <<std::endl;
557                         return -1;
558                 }
559                 return playSoundRaw(buf, loop, volume);
560         }
561         int playSoundAt(const std::string &name, bool loop, float volume, v3f pos)
562         {
563                 maintain();
564                 if(name == "")
565                         return 0;
566                 SoundBuffer *buf = getFetchBuffer(name);
567                 if(!buf){
568                         infostream<<"OpenALSoundManager: \""<<name<<"\" not found."
569                                         <<std::endl;
570                         return -1;
571                 }
572                 return playSoundRawAt(buf, loop, volume, pos);
573         }
574         void stopSound(int sound)
575         {
576                 maintain();
577                 deleteSound(sound);
578         }
579         bool soundExists(int sound)
580         {
581                 maintain();
582                 return (m_sounds_playing.count(sound) != 0);
583         }
584         void updateSoundPosition(int id, v3f pos)
585         {
586                 std::map<int, PlayingSound*>::iterator i =
587                                 m_sounds_playing.find(id);
588                 if(i == m_sounds_playing.end())
589                         return;
590                 PlayingSound *sound = i->second;
591
592                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
593                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
594                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
595                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
596         }
597 };
598
599 ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher)
600 {
601         OpenALSoundManager *m = new OpenALSoundManager(fetcher);
602         if(m->m_is_initialized)
603                 return m;
604         delete m;
605         return NULL;
606 };
607