Translated using Weblate (Chinese (Simplified))
[oweals/minetest.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         }
279
280         bool init()
281         {
282                 if (!(m_device = unique_ptr_alcdevice(alcOpenDevice(nullptr), delete_alcdevice))) {
283                         errorstream << "Audio: Global Initialization: Failed to open device" << std::endl;
284                         return false;
285                 }
286
287                 if (!(m_context = unique_ptr_alccontext(
288                                 alcCreateContext(m_device.get(), nullptr), delete_alccontext))) {
289                         errorstream << "Audio: Global Initialization: Failed to create context" << std::endl;
290                         return false;
291                 }
292
293                 if (!alcMakeContextCurrent(m_context.get())) {
294                         errorstream << "Audio: Global Initialization: Failed to make current context" << std::endl;
295                         return false;
296                 }
297
298                 alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
299
300                 if (alGetError() != AL_NO_ERROR) {
301                         errorstream << "Audio: Global Initialization: OpenAL Error " << alGetError() << std::endl;
302                         return false;
303                 }
304
305                 infostream << "Audio: Global Initialized: OpenAL " << alGetString(AL_VERSION)
306                         << ", using " << alcGetString(m_device.get(), ALC_DEVICE_SPECIFIER)
307                         << std::endl;
308
309                 return true;
310         }
311
312         ~SoundManagerSingleton()
313         {
314                 infostream << "Audio: Global Deinitialized." << std::endl;
315         }
316 };
317
318 class OpenALSoundManager: public ISoundManager
319 {
320 private:
321         OnDemandSoundFetcher *m_fetcher;
322         ALCdevice *m_device;
323         ALCcontext *m_context;
324         int m_next_id;
325         std::unordered_map<std::string, std::vector<SoundBuffer*>> m_buffers;
326         std::unordered_map<int, PlayingSound*> m_sounds_playing;
327         struct FadeState {
328                 FadeState() = default;
329
330                 FadeState(float step, float current_gain, float target_gain):
331                         step(step),
332                         current_gain(current_gain),
333                         target_gain(target_gain) {}
334                 float step;
335                 float current_gain;
336                 float target_gain;
337         };
338
339         std::unordered_map<int, FadeState> m_sounds_fading;
340         float m_fade_delay;
341 public:
342         OpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher):
343                 m_fetcher(fetcher),
344                 m_device(smg->m_device.get()),
345                 m_context(smg->m_context.get()),
346                 m_next_id(1),
347                 m_fade_delay(0)
348         {
349                 infostream << "Audio: Initialized: OpenAL " << std::endl;
350         }
351
352         ~OpenALSoundManager()
353         {
354                 infostream << "Audio: Deinitializing..." << std::endl;
355
356                 std::unordered_set<int> source_del_list;
357
358                 for (const auto &sp : m_sounds_playing)
359                         source_del_list.insert(sp.first);
360
361                 for (const auto &id : source_del_list)
362                         deleteSound(id);
363
364                 for (auto &buffer : m_buffers) {
365                         for (SoundBuffer *sb : buffer.second) {
366                                 delete sb;
367                         }
368                         buffer.second.clear();
369                 }
370                 m_buffers.clear();
371
372                 infostream << "Audio: Deinitialized." << std::endl;
373         }
374
375         void step(float dtime)
376         {
377                 doFades(dtime);
378         }
379
380         void addBuffer(const std::string &name, SoundBuffer *buf)
381         {
382                 std::unordered_map<std::string, std::vector<SoundBuffer*>>::iterator i =
383                                 m_buffers.find(name);
384                 if(i != m_buffers.end()){
385                         i->second.push_back(buf);
386                         return;
387                 }
388                 std::vector<SoundBuffer*> bufs;
389                 bufs.push_back(buf);
390                 m_buffers[name] = bufs;
391         }
392
393         SoundBuffer* getBuffer(const std::string &name)
394         {
395                 std::unordered_map<std::string, std::vector<SoundBuffer*>>::iterator i =
396                                 m_buffers.find(name);
397                 if(i == m_buffers.end())
398                         return nullptr;
399                 std::vector<SoundBuffer*> &bufs = i->second;
400                 int j = myrand() % bufs.size();
401                 return bufs[j];
402         }
403
404         PlayingSound* createPlayingSound(SoundBuffer *buf, bool loop,
405                         float volume, float pitch)
406         {
407                 infostream << "OpenALSoundManager: Creating playing sound" << std::endl;
408                 assert(buf);
409                 PlayingSound *sound = new PlayingSound;
410                 assert(sound);
411                 warn_if_error(alGetError(), "before createPlayingSound");
412                 alGenSources(1, &sound->source_id);
413                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
414                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, true);
415                 alSource3f(sound->source_id, AL_POSITION, 0, 0, 0);
416                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
417                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
418                 volume = std::fmax(0.0f, volume);
419                 alSourcef(sound->source_id, AL_GAIN, volume);
420                 alSourcef(sound->source_id, AL_PITCH, pitch);
421                 alSourcePlay(sound->source_id);
422                 warn_if_error(alGetError(), "createPlayingSound");
423                 return sound;
424         }
425
426         PlayingSound* createPlayingSoundAt(SoundBuffer *buf, bool loop,
427                         float volume, v3f pos, float pitch)
428         {
429                 infostream << "OpenALSoundManager: Creating positional playing sound"
430                                 << std::endl;
431                 assert(buf);
432                 PlayingSound *sound = new PlayingSound;
433                 assert(sound);
434                 warn_if_error(alGetError(), "before createPlayingSoundAt");
435                 alGenSources(1, &sound->source_id);
436                 alSourcei(sound->source_id, AL_BUFFER, buf->buffer_id);
437                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
438                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
439                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
440                 // Use alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED) and set reference
441                 // distance to clamp gain at <1 node distance, to avoid excessive
442                 // volume when closer
443                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 10.0f);
444                 alSourcei(sound->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
445                 // Multiply by 3 to compensate for reducing AL_REFERENCE_DISTANCE from
446                 // the previous value of 30 to the new value of 10
447                 volume = std::fmax(0.0f, volume * 3.0f);
448                 alSourcef(sound->source_id, AL_GAIN, volume);
449                 alSourcef(sound->source_id, AL_PITCH, pitch);
450                 alSourcePlay(sound->source_id);
451                 warn_if_error(alGetError(), "createPlayingSoundAt");
452                 return sound;
453         }
454
455         int playSoundRaw(SoundBuffer *buf, bool loop, float volume, float pitch)
456         {
457                 assert(buf);
458                 PlayingSound *sound = createPlayingSound(buf, loop, volume, pitch);
459                 if(!sound)
460                         return -1;
461                 int id = m_next_id++;
462                 m_sounds_playing[id] = sound;
463                 return id;
464         }
465
466         int playSoundRawAt(SoundBuffer *buf, bool loop, float volume, const v3f &pos,
467                         float pitch)
468         {
469                 assert(buf);
470                 PlayingSound *sound = createPlayingSoundAt(buf, loop, volume, pos, pitch);
471                 if(!sound)
472                         return -1;
473                 int id = m_next_id++;
474                 m_sounds_playing[id] = sound;
475                 return id;
476         }
477
478         void deleteSound(int id)
479         {
480                 std::unordered_map<int, PlayingSound*>::iterator i = m_sounds_playing.find(id);
481                 if(i == m_sounds_playing.end())
482                         return;
483                 PlayingSound *sound = i->second;
484
485                 alDeleteSources(1, &sound->source_id);
486
487                 delete sound;
488                 m_sounds_playing.erase(id);
489         }
490
491         /* If buffer does not exist, consult the fetcher */
492         SoundBuffer* getFetchBuffer(const std::string &name)
493         {
494                 SoundBuffer *buf = getBuffer(name);
495                 if(buf)
496                         return buf;
497                 if(!m_fetcher)
498                         return nullptr;
499                 std::set<std::string> paths;
500                 std::set<std::string> datas;
501                 m_fetcher->fetchSounds(name, paths, datas);
502                 for (const std::string &path : paths) {
503                         loadSoundFile(name, path);
504                 }
505                 for (const std::string &data : datas) {
506                         loadSoundData(name, data);
507                 }
508                 return getBuffer(name);
509         }
510
511         // Remove stopped sounds
512         void maintain()
513         {
514                 if (!m_sounds_playing.empty()) {
515                         verbosestream << "OpenALSoundManager::maintain(): "
516                                         << m_sounds_playing.size() <<" playing sounds, "
517                                         << m_buffers.size() <<" sound names loaded"<<std::endl;
518                 }
519                 std::unordered_set<int> del_list;
520                 for (const auto &sp : m_sounds_playing) {
521                         int id = sp.first;
522                         PlayingSound *sound = sp.second;
523                         // If not playing, remove it
524                         {
525                                 ALint state;
526                                 alGetSourcei(sound->source_id, AL_SOURCE_STATE, &state);
527                                 if(state != AL_PLAYING){
528                                         del_list.insert(id);
529                                 }
530                         }
531                 }
532                 if(!del_list.empty())
533                         verbosestream<<"OpenALSoundManager::maintain(): deleting "
534                                         <<del_list.size()<<" playing sounds"<<std::endl;
535                 for (int i : del_list) {
536                         deleteSound(i);
537                 }
538         }
539
540         /* Interface */
541
542         bool loadSoundFile(const std::string &name,
543                         const std::string &filepath)
544         {
545                 SoundBuffer *buf = load_ogg_from_file(filepath);
546                 if (buf)
547                         addBuffer(name, buf);
548                 return !!buf;
549         }
550
551         bool loadSoundData(const std::string &name,
552                         const std::string &filedata)
553         {
554                 SoundBuffer *buf = load_ogg_from_buffer(filedata, name);
555                 if (buf)
556                         addBuffer(name, buf);
557                 return !!buf;
558         }
559
560         void updateListener(const v3f &pos, const v3f &vel, const v3f &at, const v3f &up)
561         {
562                 alListener3f(AL_POSITION, pos.X, pos.Y, pos.Z);
563                 alListener3f(AL_VELOCITY, vel.X, vel.Y, vel.Z);
564                 ALfloat f[6];
565                 f3_set(f, at);
566                 f3_set(f+3, -up);
567                 alListenerfv(AL_ORIENTATION, f);
568                 warn_if_error(alGetError(), "updateListener");
569         }
570
571         void setListenerGain(float gain)
572         {
573                 alListenerf(AL_GAIN, gain);
574         }
575
576         int playSound(const std::string &name, bool loop, float volume, float fade, float pitch)
577         {
578                 maintain();
579                 if (name.empty())
580                         return 0;
581                 SoundBuffer *buf = getFetchBuffer(name);
582                 if(!buf){
583                         infostream << "OpenALSoundManager: \"" << name << "\" not found."
584                                         << std::endl;
585                         return -1;
586                 }
587                 int handle = -1;
588                 if (fade > 0) {
589                         handle = playSoundRaw(buf, loop, 0.0f, pitch);
590                         fadeSound(handle, fade, volume);
591                 } else {
592                         handle = playSoundRaw(buf, loop, volume, pitch);
593                 }
594                 return handle;
595         }
596
597         int playSoundAt(const std::string &name, bool loop, float volume, v3f pos, float pitch)
598         {
599                 maintain();
600                 if (name.empty())
601                         return 0;
602                 SoundBuffer *buf = getFetchBuffer(name);
603                 if(!buf){
604                         infostream << "OpenALSoundManager: \"" << name << "\" not found."
605                                         << std::endl;
606                         return -1;
607                 }
608                 return playSoundRawAt(buf, loop, volume, pos, pitch);
609         }
610
611         void stopSound(int sound)
612         {
613                 maintain();
614                 deleteSound(sound);
615         }
616
617         void fadeSound(int soundid, float step, float gain)
618         {
619                 m_sounds_fading[soundid] = FadeState(step, getSoundGain(soundid), gain);
620         }
621
622         void doFades(float dtime)
623         {
624                 m_fade_delay += dtime;
625
626                 if (m_fade_delay < 0.1f)
627                         return;
628
629                 float chkGain = 0;
630                 for (auto i = m_sounds_fading.begin();
631                                 i != m_sounds_fading.end();) {
632                         if (i->second.step < 0.f)
633                                 chkGain = -(i->second.current_gain);
634                         else
635                                 chkGain = i->second.current_gain;
636
637                         if (chkGain < i->second.target_gain) {
638                                 i->second.current_gain += (i->second.step * m_fade_delay);
639                                 i->second.current_gain = rangelim(i->second.current_gain, 0, 1);
640
641                                 updateSoundGain(i->first, i->second.current_gain);
642                                 ++i;
643                         } else {
644                                 if (i->second.target_gain <= 0.f)
645                                         stopSound(i->first);
646
647                                 m_sounds_fading.erase(i++);
648                         }
649                 }
650                 m_fade_delay = 0;
651         }
652
653         bool soundExists(int sound)
654         {
655                 maintain();
656                 return (m_sounds_playing.count(sound) != 0);
657         }
658
659         void updateSoundPosition(int id, v3f pos)
660         {
661                 auto i = m_sounds_playing.find(id);
662                 if (i == m_sounds_playing.end())
663                         return;
664                 PlayingSound *sound = i->second;
665
666                 alSourcei(sound->source_id, AL_SOURCE_RELATIVE, false);
667                 alSource3f(sound->source_id, AL_POSITION, pos.X, pos.Y, pos.Z);
668                 alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0);
669                 alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0);
670         }
671
672         bool updateSoundGain(int id, float gain)
673         {
674                 auto i = m_sounds_playing.find(id);
675                 if (i == m_sounds_playing.end())
676                         return false;
677
678                 PlayingSound *sound = i->second;
679                 alSourcef(sound->source_id, AL_GAIN, gain);
680                 return true;
681         }
682
683         float getSoundGain(int id)
684         {
685                 auto i = m_sounds_playing.find(id);
686                 if (i == m_sounds_playing.end())
687                         return 0;
688
689                 PlayingSound *sound = i->second;
690                 ALfloat gain;
691                 alGetSourcef(sound->source_id, AL_GAIN, &gain);
692                 return gain;
693         }
694 };
695
696 std::shared_ptr<SoundManagerSingleton> createSoundManagerSingleton()
697 {
698         auto smg = std::make_shared<SoundManagerSingleton>();
699         if (!smg->init()) {
700                 smg.reset();
701         }
702         return smg;
703 }
704
705 ISoundManager *createOpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher)
706 {
707         return new OpenALSoundManager(smg, fetcher);
708 };