]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/sound_openal.cpp
Fix UpdateBonePosition() breaking animations (#9577)
[dragonfireclient.git] / src / client / 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 <cmath>
40 #include <vorbis/vorbisfile.h>
41 #include <cassert>
42 #include "log.h"
43 #include "util/numeric.h" // myrand()
44 #include "porting.h"
45 #include <vector>
46 #include <fstream>
47 #include <unordered_map>
48 #include <unordered_set>
49
50 #define BUFFER_SIZE 30000
51
52 std::shared_ptr<SoundManagerSingleton> g_sound_manager_singleton;
53
54 typedef std::unique_ptr<ALCdevice, void (*)(ALCdevice *p)> unique_ptr_alcdevice;
55 typedef std::unique_ptr<ALCcontext, void(*)(ALCcontext *p)> unique_ptr_alccontext;
56
57 static void delete_alcdevice(ALCdevice *p)
58 {
59         if (p)
60                 alcCloseDevice(p);
61 }
62
63 static void delete_alccontext(ALCcontext *p)
64 {
65         if (p) {
66                 alcMakeContextCurrent(nullptr);
67                 alcDestroyContext(p);
68         }
69 }
70
71 static const char *alErrorString(ALenum err)
72 {
73         switch (err) {
74         case AL_NO_ERROR:
75                 return "no error";
76         case AL_INVALID_NAME:
77                 return "invalid name";
78         case AL_INVALID_ENUM:
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";
86         default:
87                 return "<unknown OpenAL error>";
88         }
89 }
90
91 static ALenum warn_if_error(ALenum err, const char *desc)
92 {
93         if(err == AL_NO_ERROR)
94                 return err;
95         warningstream<<desc<<": "<<alErrorString(err)<<std::endl;
96         return err;
97 }
98
99 void f3_set(ALfloat *f3, v3f v)
100 {
101         f3[0] = v.X;
102         f3[1] = v.Y;
103         f3[2] = v.Z;
104 }
105
106 struct SoundBuffer
107 {
108         ALenum format;
109         ALsizei freq;
110         ALuint buffer_id;
111         std::vector<char> buffer;
112 };
113
114 SoundBuffer *load_opened_ogg_file(OggVorbis_File *oggFile,
115                 const std::string &filename_for_logging)
116 {
117         int endian = 0; // 0 for Little-Endian, 1 for Big-Endian
118         int bitStream;
119         long bytes;
120         char array[BUFFER_SIZE]; // Local fixed size array
121         vorbis_info *pInfo;
122
123         SoundBuffer *snd = new SoundBuffer;
124
125         // Get some information about the OGG file
126         pInfo = ov_info(oggFile, -1);
127
128         // Check the number of channels... always use 16-bit samples
129         if(pInfo->channels == 1)
130                 snd->format = AL_FORMAT_MONO16;
131         else
132                 snd->format = AL_FORMAT_STEREO16;
133
134         // The frequency of the sampling rate
135         snd->freq = pInfo->rate;
136
137         // Keep reading until all is read
138         do
139         {
140                 // Read up to a buffer's worth of decoded sound data
141                 bytes = ov_read(oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream);
142
143                 if(bytes < 0)
144                 {
145                         ov_clear(oggFile);
146                         infostream << "Audio: Error decoding "
147                                 << filename_for_logging << std::endl;
148                         delete snd;
149                         return nullptr;
150                 }
151
152                 // Append to end of buffer
153                 snd->buffer.insert(snd->buffer.end(), array, array + bytes);
154         } while (bytes > 0);
155
156         alGenBuffers(1, &snd->buffer_id);
157         alBufferData(snd->buffer_id, snd->format,
158                         &(snd->buffer[0]), snd->buffer.size(),
159                         snd->freq);
160
161         ALenum error = alGetError();
162
163         if(error != AL_NO_ERROR){
164                 infostream << "Audio: OpenAL error: " << alErrorString(error)
165                                 << "preparing sound buffer" << std::endl;
166         }
167
168         //infostream << "Audio file "
169         //      << filename_for_logging << " loaded" << std::endl;
170
171         // Clean up!
172         ov_clear(oggFile);
173
174         return snd;
175 }
176
177 SoundBuffer *load_ogg_from_file(const std::string &path)
178 {
179         OggVorbis_File oggFile;
180
181         // Try opening the given file.
182         // This requires libvorbis >= 1.3.2, as
183         // previous versions expect a non-const char *
184         if (ov_fopen(path.c_str(), &oggFile) != 0) {
185                 infostream << "Audio: Error opening " << path
186                         << " for decoding" << std::endl;
187                 return nullptr;
188         }
189
190         return load_opened_ogg_file(&oggFile, path);
191 }
192
193 struct BufferSource {
194         const char *buf;
195         size_t cur_offset;
196         size_t len;
197 };
198
199 size_t buffer_sound_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
200 {
201         BufferSource *s = (BufferSource *)datasource;
202         size_t copied_size = MYMIN(s->len - s->cur_offset, size);
203         memcpy(ptr, s->buf + s->cur_offset, copied_size);
204         s->cur_offset += copied_size;
205         return copied_size;
206 }
207
208 int buffer_sound_seek_func(void *datasource, ogg_int64_t offset, int whence)
209 {
210         BufferSource *s = (BufferSource *)datasource;
211         if (whence == SEEK_SET) {
212                 if (offset < 0 || (size_t)MYMAX(offset, 0) >= s->len) {
213                         // offset out of bounds
214                         return -1;
215                 }
216                 s->cur_offset = offset;
217                 return 0;
218         } else if (whence == SEEK_CUR) {
219                 if ((size_t)MYMIN(-offset, 0) > s->cur_offset
220                                 || s->cur_offset + offset > s->len) {
221                         // offset out of bounds
222                         return -1;
223                 }
224                 s->cur_offset += offset;
225                 return 0;
226         }
227         // invalid whence param (SEEK_END doesn't have to be supported)
228         return -1;
229 }
230
231 long BufferSourceell_func(void *datasource)
232 {
233         BufferSource *s = (BufferSource *)datasource;
234         return s->cur_offset;
235 }
236
237 static ov_callbacks g_buffer_ov_callbacks = {
238         &buffer_sound_read_func,
239         &buffer_sound_seek_func,
240         nullptr,
241         &BufferSourceell_func
242 };
243
244 SoundBuffer *load_ogg_from_buffer(const std::string &buf, const std::string &id_for_log)
245 {
246         OggVorbis_File oggFile;
247
248         BufferSource s;
249         s.buf = buf.c_str();
250         s.cur_offset = 0;
251         s.len = buf.size();
252
253         if (ov_open_callbacks(&s, &oggFile, nullptr, 0, g_buffer_ov_callbacks) != 0) {
254                 infostream << "Audio: Error opening " << id_for_log
255                         << " for decoding" << std::endl;
256                 return nullptr;
257         }
258
259         return load_opened_ogg_file(&oggFile, id_for_log);
260 }
261
262 struct PlayingSound
263 {
264         ALuint source_id;
265         bool loop;
266 };
267
268 class SoundManagerSingleton
269 {
270 public:
271         unique_ptr_alcdevice  m_device;
272         unique_ptr_alccontext m_context;
273 public:
274         SoundManagerSingleton() :
275                 m_device(nullptr, delete_alcdevice),
276                 m_context(nullptr, delete_alccontext)
277         {
278                 if (!(m_device = unique_ptr_alcdevice(alcOpenDevice(nullptr), delete_alcdevice)))
279                         throw std::runtime_error("Audio: Global Initialization: Device Open");
280
281                 if (!(m_context = unique_ptr_alccontext(
282                                 alcCreateContext(m_device.get(), nullptr), delete_alccontext))) {
283                         throw std::runtime_error("Audio: Global Initialization: Context Create");
284                 }
285
286                 if (!alcMakeContextCurrent(m_context.get()))
287                         throw std::runtime_error("Audio: Global Initialization: Context Current");
288
289                 alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
290
291                 if (alGetError() != AL_NO_ERROR)
292                         throw std::runtime_error("Audio: Global Initialization: OpenAL Error");
293
294                 infostream << "Audio: Global Initialized: OpenAL " << alGetString(AL_VERSION)
295                         << ", using " << alcGetString(m_device.get(), ALC_DEVICE_SPECIFIER)
296                         << std::endl;
297         }
298
299         ~SoundManagerSingleton()
300         {
301                 infostream << "Audio: Global Deinitialized." << std::endl;
302         }
303 };
304
305 class OpenALSoundManager: public ISoundManager
306 {
307 private:
308         OnDemandSoundFetcher *m_fetcher;
309         ALCdevice *m_device;
310         ALCcontext *m_context;
311         int m_next_id;
312         std::unordered_map<std::string, std::vector<SoundBuffer*>> m_buffers;
313         std::unordered_map<int, PlayingSound*> m_sounds_playing;
314         struct FadeState {
315                 FadeState() = default;
316
317                 FadeState(float step, float current_gain, float target_gain):
318                         step(step),
319                         current_gain(current_gain),
320                         target_gain(target_gain) {}
321                 float step;
322                 float current_gain;
323                 float target_gain;
324         };
325
326         std::unordered_map<int, FadeState> m_sounds_fading;
327         float m_fade_delay;
328 public:
329         OpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher):
330                 m_fetcher(fetcher),
331                 m_device(smg->m_device.get()),
332                 m_context(smg->m_context.get()),
333                 m_next_id(1),
334                 m_fade_delay(0)
335         {
336                 infostream << "Audio: Initialized: OpenAL " << std::endl;
337         }
338
339         ~OpenALSoundManager()
340         {
341                 infostream << "Audio: Deinitializing..." << std::endl;
342
343                 std::unordered_set<int> source_del_list;
344
345                 for (const auto &sp : m_sounds_playing)
346                         source_del_list.insert(sp.first);
347
348                 for (const auto &id : source_del_list)
349                         deleteSound(id);
350
351                 for (auto &buffer : m_buffers) {
352                         for (SoundBuffer *sb : buffer.second) {
353                                 delete sb;
354                         }
355                         buffer.second.clear();
356                 }
357                 m_buffers.clear();
358
359                 infostream << "Audio: Deinitialized." << std::endl;
360         }
361
362         void step(float dtime)
363         {
364                 doFades(dtime);
365         }
366
367         void addBuffer(const std::string &name, SoundBuffer *buf)
368         {
369                 std::unordered_map<std::string, std::vector<SoundBuffer*>>::iterator i =
370                                 m_buffers.find(name);
371                 if(i != m_buffers.end()){
372                         i->second.push_back(buf);
373                         return;
374                 }
375                 std::vector<SoundBuffer*> bufs;
376                 bufs.push_back(buf);
377                 m_buffers[name] = bufs;
378         }
379
380         SoundBuffer* getBuffer(const std::string &name)
381         {
382                 std::unordered_map<std::string, std::vector<SoundBuffer*>>::iterator i =
383                                 m_buffers.find(name);
384                 if(i == m_buffers.end())
385                         return nullptr;
386                 std::vector<SoundBuffer*> &bufs = i->second;
387                 int j = myrand() % bufs.size();
388                 return bufs[j];
389         }
390
391         PlayingSound* createPlayingSound(SoundBuffer *buf, bool loop,
392                         float volume, float pitch)
393         {
394                 infostream << "OpenALSoundManager: Creating playing sound" << std::endl;
395                 assert(buf);
396                 PlayingSound *sound = new PlayingSound;
397                 assert(sound);
398                 warn_if_error(alGetError(), "before createPlayingSound");
399                 alGenSources(1, &sound->source_id);
400                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
401                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, true);
402                 alSource3f(sound->source_id, AL_POSITION, 0, 0, 0);
403                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
404                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
405                 volume = std::fmax(0.0f, volume);
406                 alSourcef(sound->source_id, AL_GAIN, volume);
407                 alSourcef(sound->source_id, AL_PITCH, pitch);
408                 alSourcePlay(sound->source_id);
409                 warn_if_error(alGetError(), "createPlayingSound");
410                 return sound;
411         }
412
413         PlayingSound* createPlayingSoundAt(SoundBuffer *buf, bool loop,
414                         float volume, v3f pos, float pitch)
415         {
416                 infostream << "OpenALSoundManager: Creating positional playing sound"
417                                 << std::endl;
418                 assert(buf);
419                 PlayingSound *sound = new PlayingSound;
420                 assert(sound);
421                 warn_if_error(alGetError(), "before createPlayingSoundAt");
422                 alGenSources(1, &sound->source_id);
423                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
424                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
425                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
426                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
427                 // Use alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED) and set reference
428                 // distance to clamp gain at <1 node distance, to avoid excessive
429                 // volume when closer
430                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 10.0f);
431                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
432                 // Multiply by 3 to compensate for reducing AL_REFERENCE_DISTANCE from
433                 // the previous value of 30 to the new value of 10
434                 volume = std::fmax(0.0f, volume * 3.0f);
435                 alSourcef(sound->source_id, AL_GAIN, volume);
436                 alSourcef(sound->source_id, AL_PITCH, pitch);
437                 alSourcePlay(sound->source_id);
438                 warn_if_error(alGetError(), "createPlayingSoundAt");
439                 return sound;
440         }
441
442         int playSoundRaw(SoundBuffer *buf, bool loop, float volume, float pitch)
443         {
444                 assert(buf);
445                 PlayingSound *sound = createPlayingSound(buf, loop, volume, pitch);
446                 if(!sound)
447                         return -1;
448                 int id = m_next_id++;
449                 m_sounds_playing[id] = sound;
450                 return id;
451         }
452
453         int playSoundRawAt(SoundBuffer *buf, bool loop, float volume, const v3f &pos,
454                         float pitch)
455         {
456                 assert(buf);
457                 PlayingSound *sound = createPlayingSoundAt(buf, loop, volume, pos, pitch);
458                 if(!sound)
459                         return -1;
460                 int id = m_next_id++;
461                 m_sounds_playing[id] = sound;
462                 return id;
463         }
464
465         void deleteSound(int id)
466         {
467                 std::unordered_map<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
468                 if(i == m_sounds_playing.end())
469                         return;
470                 PlayingSound *sound = i->second;
471
472                 alDeleteSources(1, &sound->source_id);
473
474                 delete sound;
475                 m_sounds_playing.erase(id);
476         }
477
478         /* If buffer does not exist, consult the fetcher */
479         SoundBuffer* getFetchBuffer(const std::string &name)
480         {
481                 SoundBuffer *buf = getBuffer(name);
482                 if(buf)
483                         return buf;
484                 if(!m_fetcher)
485                         return nullptr;
486                 std::set<std::string> paths;
487                 std::set<std::string> datas;
488                 m_fetcher->fetchSounds(name, paths, datas);
489                 for (const std::string &path : paths) {
490                         loadSoundFile(name, path);
491                 }
492                 for (const std::string &data : datas) {
493                         loadSoundData(name, data);
494                 }
495                 return getBuffer(name);
496         }
497
498         // Remove stopped sounds
499         void maintain()
500         {
501                 if (!m_sounds_playing.empty()) {
502                         verbosestream << "OpenALSoundManager::maintain(): "
503                                         << m_sounds_playing.size() <<" playing sounds, "
504                                         << m_buffers.size() <<" sound names loaded"<<std::endl;
505                 }
506                 std::unordered_set<int> del_list;
507                 for (const auto &sp : m_sounds_playing) {
508                         int id = sp.first;
509                         PlayingSound *sound = sp.second;
510                         // If not playing, remove it
511                         {
512                                 ALint state;
513                                 alGetSourcei(sound->source_id, AL_SOURCE_STATE, &state);
514                                 if(state != AL_PLAYING){
515                                         del_list.insert(id);
516                                 }
517                         }
518                 }
519                 if(!del_list.empty())
520                         verbosestream<<"OpenALSoundManager::maintain(): deleting "
521                                         <<del_list.size()<<" playing sounds"<<std::endl;
522                 for (int i : del_list) {
523                         deleteSound(i);
524                 }
525         }
526
527         /* Interface */
528
529         bool loadSoundFile(const std::string &name,
530                         const std::string &filepath)
531         {
532                 SoundBuffer *buf = load_ogg_from_file(filepath);
533                 if (buf)
534                         addBuffer(name, buf);
535                 return !!buf;
536         }
537
538         bool loadSoundData(const std::string &name,
539                         const std::string &filedata)
540         {
541                 SoundBuffer *buf = load_ogg_from_buffer(filedata, name);
542                 if (buf)
543                         addBuffer(name, buf);
544                 return !!buf;
545         }
546
547         void updateListener(const v3f &pos, const v3f &vel, const v3f &at, const v3f &up)
548         {
549                 alListener3f(AL_POSITION, pos.X, pos.Y, pos.Z);
550                 alListener3f(AL_VELOCITY, vel.X, vel.Y, vel.Z);
551                 ALfloat f[6];
552                 f3_set(f, at);
553                 f3_set(f+3, -up);
554                 alListenerfv(AL_ORIENTATION, f);
555                 warn_if_error(alGetError(), "updateListener");
556         }
557
558         void setListenerGain(float gain)
559         {
560                 alListenerf(AL_GAIN, gain);
561         }
562
563         int playSound(const std::string &name, bool loop, float volume, float fade, float pitch)
564         {
565                 maintain();
566                 if (name.empty())
567                         return 0;
568                 SoundBuffer *buf = getFetchBuffer(name);
569                 if(!buf){
570                         infostream << "OpenALSoundManager: \"" << name << "\" not found."
571                                         << std::endl;
572                         return -1;
573                 }
574                 int handle = -1;
575                 if (fade > 0) {
576                         handle = playSoundRaw(buf, loop, 0.0f, pitch);
577                         fadeSound(handle, fade, volume);
578                 } else {
579                         handle = playSoundRaw(buf, loop, volume, pitch);
580                 }
581                 return handle;
582         }
583
584         int playSoundAt(const std::string &name, bool loop, float volume, v3f pos, float pitch)
585         {
586                 maintain();
587                 if (name.empty())
588                         return 0;
589                 SoundBuffer *buf = getFetchBuffer(name);
590                 if(!buf){
591                         infostream << "OpenALSoundManager: \"" << name << "\" not found."
592                                         << std::endl;
593                         return -1;
594                 }
595                 return playSoundRawAt(buf, loop, volume, pos, pitch);
596         }
597
598         void stopSound(int sound)
599         {
600                 maintain();
601                 deleteSound(sound);
602         }
603
604         void fadeSound(int soundid, float step, float gain)
605         {
606                 m_sounds_fading[soundid] = FadeState(step, getSoundGain(soundid), gain);
607         }
608
609         void doFades(float dtime)
610         {
611                 m_fade_delay += dtime;
612
613                 if (m_fade_delay < 0.1f)
614                         return;
615
616                 float chkGain = 0;
617                 for (auto i = m_sounds_fading.begin();
618                                 i != m_sounds_fading.end();) {
619                         if (i->second.step < 0.f)
620                                 chkGain = -(i->second.current_gain);
621                         else
622                                 chkGain = i->second.current_gain;
623
624                         if (chkGain < i->second.target_gain) {
625                                 i->second.current_gain += (i->second.step * m_fade_delay);
626                                 i->second.current_gain = rangelim(i->second.current_gain, 0, 1);
627
628                                 updateSoundGain(i->first, i->second.current_gain);
629                                 ++i;
630                         } else {
631                                 if (i->second.target_gain <= 0.f)
632                                         stopSound(i->first);
633
634                                 m_sounds_fading.erase(i++);
635                         }
636                 }
637                 m_fade_delay = 0;
638         }
639
640         bool soundExists(int sound)
641         {
642                 maintain();
643                 return (m_sounds_playing.count(sound) != 0);
644         }
645
646         void updateSoundPosition(int id, v3f pos)
647         {
648                 auto i = m_sounds_playing.find(id);
649                 if (i == m_sounds_playing.end())
650                         return;
651                 PlayingSound *sound = i->second;
652
653                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
654                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
655                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
656                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
657         }
658
659         bool updateSoundGain(int id, float gain)
660         {
661                 auto i = m_sounds_playing.find(id);
662                 if (i == m_sounds_playing.end())
663                         return false;
664
665                 PlayingSound *sound = i->second;
666                 alSourcef(sound->source_id, AL_GAIN, gain);
667                 return true;
668         }
669
670         float getSoundGain(int id)
671         {
672                 auto i = m_sounds_playing.find(id);
673                 if (i == m_sounds_playing.end())
674                         return 0;
675
676                 PlayingSound *sound = i->second;
677                 ALfloat gain;
678                 alGetSourcef(sound->source_id, AL_GAIN, &gain);
679                 return gain;
680         }
681 };
682
683 std::shared_ptr<SoundManagerSingleton> createSoundManagerSingleton()
684 {
685         return std::shared_ptr<SoundManagerSingleton>(new SoundManagerSingleton());
686 }
687
688 ISoundManager *createOpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher)
689 {
690         return new OpenALSoundManager(smg, fetcher);
691 };