1 #include <algorithm>
2 #include <cstring>
3 #include <vector>
4 #include <memory>
5 #include <array>
6 #include <atomic>
7 #include <condition_variable>
8 #include <thread>
9 #include <mutex>
10 #include <chrono>
11
12 #include <stdint.h>
13
14 #include <components/debug/debuglog.hpp>
15 #include <components/misc/constants.hpp>
16 #include <components/vfs/manager.hpp>
17
18 #include "openal_output.hpp"
19 #include "sound_decoder.hpp"
20 #include "sound.hpp"
21 #include "soundmanagerimp.hpp"
22 #include "loudness.hpp"
23
24 #include "efx-presets.h"
25
26 #ifndef ALC_ALL_DEVICES_SPECIFIER
27 #define ALC_ALL_DEVICES_SPECIFIER 0x1013
28 #endif
29
30
31 #define MAKE_PTRID(id) ((void*)(uintptr_t)id)
32 #define GET_PTRID(ptr) ((ALuint)(uintptr_t)ptr)
33
34 namespace
35 {
36
37 const int sLoudnessFPS = 20; // loudness values per second of audio
38
checkALCError(ALCdevice * device,const char * func,int line)39 ALCenum checkALCError(ALCdevice *device, const char *func, int line)
40 {
41 ALCenum err = alcGetError(device);
42 if(err != ALC_NO_ERROR)
43 Log(Debug::Error) << "ALC error "<< alcGetString(device, err) << " (" << err << ") @ " << func << ":" << line;
44 return err;
45 }
46 #define getALCError(d) checkALCError((d), __FUNCTION__, __LINE__)
47
checkALError(const char * func,int line)48 ALenum checkALError(const char *func, int line)
49 {
50 ALenum err = alGetError();
51 if(err != AL_NO_ERROR)
52 Log(Debug::Error) << "AL error " << alGetString(err) << " (" << err << ") @ " << func << ":" << line;
53 return err;
54 }
55 #define getALError() checkALError(__FUNCTION__, __LINE__)
56
57 // Helper to get an OpenAL extension function
58 template<typename T, typename R>
convertPointer(T & dest,R src)59 void convertPointer(T& dest, R src)
60 {
61 memcpy(&dest, &src, sizeof(src));
62 }
63
64 template<typename T>
getALCFunc(T & func,ALCdevice * device,const char * name)65 void getALCFunc(T& func, ALCdevice *device, const char *name)
66 {
67 void* funcPtr = alcGetProcAddress(device, name);
68 convertPointer(func, funcPtr);
69 }
70
71 template<typename T>
getALFunc(T & func,const char * name)72 void getALFunc(T& func, const char *name)
73 {
74 void* funcPtr = alGetProcAddress(name);
75 convertPointer(func, funcPtr);
76 }
77
78 // Effect objects
79 LPALGENEFFECTS alGenEffects;
80 LPALDELETEEFFECTS alDeleteEffects;
81 LPALISEFFECT alIsEffect;
82 LPALEFFECTI alEffecti;
83 LPALEFFECTIV alEffectiv;
84 LPALEFFECTF alEffectf;
85 LPALEFFECTFV alEffectfv;
86 LPALGETEFFECTI alGetEffecti;
87 LPALGETEFFECTIV alGetEffectiv;
88 LPALGETEFFECTF alGetEffectf;
89 LPALGETEFFECTFV alGetEffectfv;
90 // Filter objects
91 LPALGENFILTERS alGenFilters;
92 LPALDELETEFILTERS alDeleteFilters;
93 LPALISFILTER alIsFilter;
94 LPALFILTERI alFilteri;
95 LPALFILTERIV alFilteriv;
96 LPALFILTERF alFilterf;
97 LPALFILTERFV alFilterfv;
98 LPALGETFILTERI alGetFilteri;
99 LPALGETFILTERIV alGetFilteriv;
100 LPALGETFILTERF alGetFilterf;
101 LPALGETFILTERFV alGetFilterfv;
102 // Auxiliary slot objects
103 LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
104 LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
105 LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
106 LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
107 LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
108 LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
109 LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
110 LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
111 LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
112 LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
113 LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
114
115
LoadEffect(ALuint effect,const EFXEAXREVERBPROPERTIES & props)116 void LoadEffect(ALuint effect, const EFXEAXREVERBPROPERTIES &props)
117 {
118 ALint type = AL_NONE;
119 alGetEffecti(effect, AL_EFFECT_TYPE, &type);
120 if(type == AL_EFFECT_EAXREVERB)
121 {
122 alEffectf(effect, AL_EAXREVERB_DIFFUSION, props.flDiffusion);
123 alEffectf(effect, AL_EAXREVERB_DENSITY, props.flDensity);
124 alEffectf(effect, AL_EAXREVERB_GAIN, props.flGain);
125 alEffectf(effect, AL_EAXREVERB_GAINHF, props.flGainHF);
126 alEffectf(effect, AL_EAXREVERB_GAINLF, props.flGainLF);
127 alEffectf(effect, AL_EAXREVERB_DECAY_TIME, props.flDecayTime);
128 alEffectf(effect, AL_EAXREVERB_DECAY_HFRATIO, props.flDecayHFRatio);
129 alEffectf(effect, AL_EAXREVERB_DECAY_LFRATIO, props.flDecayLFRatio);
130 alEffectf(effect, AL_EAXREVERB_REFLECTIONS_GAIN, props.flReflectionsGain);
131 alEffectf(effect, AL_EAXREVERB_REFLECTIONS_DELAY, props.flReflectionsDelay);
132 alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, props.flReflectionsPan);
133 alEffectf(effect, AL_EAXREVERB_LATE_REVERB_GAIN, props.flLateReverbGain);
134 alEffectf(effect, AL_EAXREVERB_LATE_REVERB_DELAY, props.flLateReverbDelay);
135 alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, props.flLateReverbPan);
136 alEffectf(effect, AL_EAXREVERB_ECHO_TIME, props.flEchoTime);
137 alEffectf(effect, AL_EAXREVERB_ECHO_DEPTH, props.flEchoDepth);
138 alEffectf(effect, AL_EAXREVERB_MODULATION_TIME, props.flModulationTime);
139 alEffectf(effect, AL_EAXREVERB_MODULATION_DEPTH, props.flModulationDepth);
140 alEffectf(effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, props.flAirAbsorptionGainHF);
141 alEffectf(effect, AL_EAXREVERB_HFREFERENCE, props.flHFReference);
142 alEffectf(effect, AL_EAXREVERB_LFREFERENCE, props.flLFReference);
143 alEffectf(effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, props.flRoomRolloffFactor);
144 alEffecti(effect, AL_EAXREVERB_DECAY_HFLIMIT, props.iDecayHFLimit ? AL_TRUE : AL_FALSE);
145 }
146 else if(type == AL_EFFECT_REVERB)
147 {
148 alEffectf(effect, AL_REVERB_DIFFUSION, props.flDiffusion);
149 alEffectf(effect, AL_REVERB_DENSITY, props.flDensity);
150 alEffectf(effect, AL_REVERB_GAIN, props.flGain);
151 alEffectf(effect, AL_REVERB_GAINHF, props.flGainHF);
152 alEffectf(effect, AL_REVERB_DECAY_TIME, props.flDecayTime);
153 alEffectf(effect, AL_REVERB_DECAY_HFRATIO, props.flDecayHFRatio);
154 alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, props.flReflectionsGain);
155 alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, props.flReflectionsDelay);
156 alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, props.flLateReverbGain);
157 alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, props.flLateReverbDelay);
158 alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, props.flAirAbsorptionGainHF);
159 alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, props.flRoomRolloffFactor);
160 alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, props.iDecayHFLimit ? AL_TRUE : AL_FALSE);
161 }
162 getALError();
163 }
164
165 }
166
167 namespace MWSound
168 {
169
getALFormat(ChannelConfig chans,SampleType type)170 static ALenum getALFormat(ChannelConfig chans, SampleType type)
171 {
172 struct FormatEntry {
173 ALenum format;
174 ChannelConfig chans;
175 SampleType type;
176 };
177 struct FormatEntryExt {
178 const char name[32];
179 ChannelConfig chans;
180 SampleType type;
181 };
182 static const std::array<FormatEntry,4> fmtlist{{
183 { AL_FORMAT_MONO16, ChannelConfig_Mono, SampleType_Int16 },
184 { AL_FORMAT_MONO8, ChannelConfig_Mono, SampleType_UInt8 },
185 { AL_FORMAT_STEREO16, ChannelConfig_Stereo, SampleType_Int16 },
186 { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 },
187 }};
188
189 for(auto &fmt : fmtlist)
190 {
191 if(fmt.chans == chans && fmt.type == type)
192 return fmt.format;
193 }
194
195 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
196 {
197 static const std::array<FormatEntryExt,6> mcfmtlist{{
198 { "AL_FORMAT_QUAD16", ChannelConfig_Quad, SampleType_Int16 },
199 { "AL_FORMAT_QUAD8", ChannelConfig_Quad, SampleType_UInt8 },
200 { "AL_FORMAT_51CHN16", ChannelConfig_5point1, SampleType_Int16 },
201 { "AL_FORMAT_51CHN8", ChannelConfig_5point1, SampleType_UInt8 },
202 { "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 },
203 { "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 },
204 }};
205
206 for(auto &fmt : mcfmtlist)
207 {
208 if(fmt.chans == chans && fmt.type == type)
209 {
210 ALenum format = alGetEnumValue(fmt.name);
211 if(format != 0 && format != -1)
212 return format;
213 }
214 }
215 }
216 if(alIsExtensionPresent("AL_EXT_FLOAT32"))
217 {
218 static const std::array<FormatEntryExt,2> fltfmtlist{{
219 { "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 },
220 { "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 },
221 }};
222
223 for(auto &fmt : fltfmtlist)
224 {
225 if(fmt.chans == chans && fmt.type == type)
226 {
227 ALenum format = alGetEnumValue(fmt.name);
228 if(format != 0 && format != -1)
229 return format;
230 }
231 }
232
233 if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
234 {
235 static const std::array<FormatEntryExt,3> fltmcfmtlist{{
236 { "AL_FORMAT_QUAD32", ChannelConfig_Quad, SampleType_Float32 },
237 { "AL_FORMAT_51CHN32", ChannelConfig_5point1, SampleType_Float32 },
238 { "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 },
239 }};
240
241 for(auto &fmt : fltmcfmtlist)
242 {
243 if(fmt.chans == chans && fmt.type == type)
244 {
245 ALenum format = alGetEnumValue(fmt.name);
246 if(format != 0 && format != -1)
247 return format;
248 }
249 }
250 }
251 }
252
253 Log(Debug::Warning) << "Unsupported sound format (" << getChannelConfigName(chans) << ", " << getSampleTypeName(type) << ")";
254 return AL_NONE;
255 }
256
257
258 //
259 // A streaming OpenAL sound.
260 //
261 class OpenAL_SoundStream
262 {
263 static const ALfloat sBufferLength;
264
265 private:
266 ALuint mSource;
267
268 std::array<ALuint,6> mBuffers;
269 ALint mCurrentBufIdx;
270
271 ALenum mFormat;
272 ALsizei mSampleRate;
273 ALuint mBufferSize;
274 ALuint mFrameSize;
275 ALint mSilence;
276
277 DecoderPtr mDecoder;
278
279 std::unique_ptr<Sound_Loudness> mLoudnessAnalyzer;
280
281 std::atomic<bool> mIsFinished;
282
283 void updateAll(bool local);
284
285 OpenAL_SoundStream(const OpenAL_SoundStream &rhs);
286 OpenAL_SoundStream& operator=(const OpenAL_SoundStream &rhs);
287
288 friend class OpenAL_Output;
289
290 public:
291 OpenAL_SoundStream(ALuint src, DecoderPtr decoder);
292 ~OpenAL_SoundStream();
293
294 bool init(bool getLoudnessData=false);
295
296 bool isPlaying();
297 double getStreamDelay() const;
298 double getStreamOffset() const;
299
300 float getCurrentLoudness() const;
301
302 bool process();
303 ALint refillQueue();
304 };
305 const ALfloat OpenAL_SoundStream::sBufferLength = 0.125f;
306
307
308 //
309 // A background streaming thread (keeps active streams processed)
310 //
311 struct OpenAL_Output::StreamThread
312 {
313 typedef std::vector<OpenAL_SoundStream*> StreamVec;
314 StreamVec mStreams;
315
316 std::atomic<bool> mQuitNow;
317 std::mutex mMutex;
318 std::condition_variable mCondVar;
319 std::thread mThread;
320
StreamThreadMWSound::OpenAL_Output::StreamThread321 StreamThread()
322 : mQuitNow(false)
323 , mThread([this] { run(); })
324 {
325 }
~StreamThreadMWSound::OpenAL_Output::StreamThread326 ~StreamThread()
327 {
328 mQuitNow = true;
329 mMutex.lock(); mMutex.unlock();
330 mCondVar.notify_all();
331 mThread.join();
332 }
333
334 // thread entry point
runMWSound::OpenAL_Output::StreamThread335 void run()
336 {
337 std::unique_lock<std::mutex> lock(mMutex);
338 while(!mQuitNow)
339 {
340 StreamVec::iterator iter = mStreams.begin();
341 while(iter != mStreams.end())
342 {
343 if((*iter)->process() == false)
344 iter = mStreams.erase(iter);
345 else
346 ++iter;
347 }
348
349 mCondVar.wait_for(lock, std::chrono::milliseconds(50));
350 }
351 }
352
addMWSound::OpenAL_Output::StreamThread353 void add(OpenAL_SoundStream *stream)
354 {
355 std::lock_guard<std::mutex> lock(mMutex);
356 if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end())
357 {
358 mStreams.push_back(stream);
359 mCondVar.notify_all();
360 }
361 }
362
removeMWSound::OpenAL_Output::StreamThread363 void remove(OpenAL_SoundStream *stream)
364 {
365 std::lock_guard<std::mutex> lock(mMutex);
366 StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream);
367 if(iter != mStreams.end()) mStreams.erase(iter);
368 }
369
removeAllMWSound::OpenAL_Output::StreamThread370 void removeAll()
371 {
372 std::lock_guard<std::mutex> lock(mMutex);
373 mStreams.clear();
374 }
375
376 private:
377 StreamThread(const StreamThread &rhs);
378 StreamThread& operator=(const StreamThread &rhs);
379 };
380
381
OpenAL_SoundStream(ALuint src,DecoderPtr decoder)382 OpenAL_SoundStream::OpenAL_SoundStream(ALuint src, DecoderPtr decoder)
383 : mSource(src), mCurrentBufIdx(0), mFormat(AL_NONE), mSampleRate(0)
384 , mBufferSize(0), mFrameSize(0), mSilence(0), mDecoder(std::move(decoder))
385 , mLoudnessAnalyzer(nullptr), mIsFinished(true)
386 {
387 mBuffers.fill(0);
388 }
389
~OpenAL_SoundStream()390 OpenAL_SoundStream::~OpenAL_SoundStream()
391 {
392 if(mBuffers[0] && alIsBuffer(mBuffers[0]))
393 alDeleteBuffers(mBuffers.size(), mBuffers.data());
394 alGetError();
395
396 mDecoder->close();
397 }
398
init(bool getLoudnessData)399 bool OpenAL_SoundStream::init(bool getLoudnessData)
400 {
401 alGenBuffers(mBuffers.size(), mBuffers.data());
402 ALenum err = getALError();
403 if(err != AL_NO_ERROR)
404 return false;
405
406 ChannelConfig chans;
407 SampleType type;
408
409 try {
410 mDecoder->getInfo(&mSampleRate, &chans, &type);
411 mFormat = getALFormat(chans, type);
412 }
413 catch(std::exception &e)
414 {
415 Log(Debug::Error) << "Failed to get stream info: " << e.what();
416 return false;
417 }
418
419 switch(type)
420 {
421 case SampleType_UInt8: mSilence = 0x80; break;
422 case SampleType_Int16: mSilence = 0x00; break;
423 case SampleType_Float32: mSilence = 0x00; break;
424 }
425
426 mFrameSize = framesToBytes(1, chans, type);
427 mBufferSize = static_cast<ALuint>(sBufferLength*mSampleRate);
428 mBufferSize *= mFrameSize;
429
430 if (getLoudnessData)
431 mLoudnessAnalyzer.reset(new Sound_Loudness(sLoudnessFPS, mSampleRate, chans, type));
432
433 mIsFinished = false;
434 return true;
435 }
436
isPlaying()437 bool OpenAL_SoundStream::isPlaying()
438 {
439 ALint state;
440
441 alGetSourcei(mSource, AL_SOURCE_STATE, &state);
442 getALError();
443
444 if(state == AL_PLAYING || state == AL_PAUSED)
445 return true;
446 return !mIsFinished;
447 }
448
getStreamDelay() const449 double OpenAL_SoundStream::getStreamDelay() const
450 {
451 ALint state = AL_STOPPED;
452 double d = 0.0;
453 ALint offset;
454
455 alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset);
456 alGetSourcei(mSource, AL_SOURCE_STATE, &state);
457 if(state == AL_PLAYING || state == AL_PAUSED)
458 {
459 ALint queued;
460 alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
461 ALint inqueue = mBufferSize/mFrameSize*queued - offset;
462 d = (double)inqueue / (double)mSampleRate;
463 }
464
465 getALError();
466 return d;
467 }
468
getStreamOffset() const469 double OpenAL_SoundStream::getStreamOffset() const
470 {
471 ALint state = AL_STOPPED;
472 ALint offset;
473 double t;
474
475 alGetSourcei(mSource, AL_SAMPLE_OFFSET, &offset);
476 alGetSourcei(mSource, AL_SOURCE_STATE, &state);
477 if(state == AL_PLAYING || state == AL_PAUSED)
478 {
479 ALint queued;
480 alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
481 ALint inqueue = mBufferSize/mFrameSize*queued - offset;
482 t = (double)(mDecoder->getSampleOffset() - inqueue) / (double)mSampleRate;
483 }
484 else
485 {
486 /* Underrun, or not started yet. The decoder offset is where we'll play
487 * next. */
488 t = (double)mDecoder->getSampleOffset() / (double)mSampleRate;
489 }
490
491 getALError();
492 return t;
493 }
494
getCurrentLoudness() const495 float OpenAL_SoundStream::getCurrentLoudness() const
496 {
497 if (!mLoudnessAnalyzer.get())
498 return 0.f;
499
500 float time = getStreamOffset();
501 return mLoudnessAnalyzer->getLoudnessAtTime(time);
502 }
503
process()504 bool OpenAL_SoundStream::process()
505 {
506 try {
507 if(refillQueue() > 0)
508 {
509 ALint state;
510 alGetSourcei(mSource, AL_SOURCE_STATE, &state);
511 if(state != AL_PLAYING && state != AL_PAUSED)
512 {
513 // Ensure all processed buffers are removed so we don't replay them.
514 refillQueue();
515
516 alSourcePlay(mSource);
517 }
518 }
519 }
520 catch(std::exception&) {
521 Log(Debug::Error) << "Error updating stream \"" << mDecoder->getName() << "\"";
522 mIsFinished = true;
523 }
524 return !mIsFinished;
525 }
526
refillQueue()527 ALint OpenAL_SoundStream::refillQueue()
528 {
529 ALint processed;
530 alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed);
531 while(processed > 0)
532 {
533 ALuint buf;
534 alSourceUnqueueBuffers(mSource, 1, &buf);
535 --processed;
536 }
537
538 ALint queued;
539 alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued);
540 if(!mIsFinished && (ALuint)queued < mBuffers.size())
541 {
542 std::vector<char> data(mBufferSize);
543 for(;!mIsFinished && (ALuint)queued < mBuffers.size();++queued)
544 {
545 size_t got = mDecoder->read(data.data(), data.size());
546 if(got < data.size())
547 {
548 mIsFinished = true;
549 std::fill(data.begin()+got, data.end(), mSilence);
550 }
551 if(got > 0)
552 {
553 if (mLoudnessAnalyzer.get())
554 mLoudnessAnalyzer->analyzeLoudness(data);
555
556 ALuint bufid = mBuffers[mCurrentBufIdx];
557 alBufferData(bufid, mFormat, data.data(), data.size(), mSampleRate);
558 alSourceQueueBuffers(mSource, 1, &bufid);
559 mCurrentBufIdx = (mCurrentBufIdx+1) % mBuffers.size();
560 }
561 }
562 }
563
564 return queued;
565 }
566
567
568 //
569 // An OpenAL output device
570 //
enumerate()571 std::vector<std::string> OpenAL_Output::enumerate()
572 {
573 std::vector<std::string> devlist;
574 const ALCchar *devnames;
575
576 if(alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
577 devnames = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
578 else
579 devnames = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
580 while(devnames && *devnames)
581 {
582 devlist.emplace_back(devnames);
583 devnames += strlen(devnames)+1;
584 }
585 return devlist;
586 }
587
init(const std::string & devname,const std::string & hrtfname,HrtfMode hrtfmode)588 bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname, HrtfMode hrtfmode)
589 {
590 deinit();
591
592 Log(Debug::Info) << "Initializing OpenAL...";
593
594 mDevice = alcOpenDevice(devname.c_str());
595 if(!mDevice && !devname.empty())
596 {
597 Log(Debug::Warning) << "Failed to open \"" << devname << "\", trying default";
598 mDevice = alcOpenDevice(nullptr);
599 }
600
601 if(!mDevice)
602 {
603 Log(Debug::Error) << "Failed to open default audio device";
604 return false;
605 }
606
607 const ALCchar *name = nullptr;
608 if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT"))
609 name = alcGetString(mDevice, ALC_ALL_DEVICES_SPECIFIER);
610 if(alcGetError(mDevice) != AL_NO_ERROR || !name)
611 name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER);
612 Log(Debug::Info) << "Opened \"" << name << "\"";
613
614 ALCint major=0, minor=0;
615 alcGetIntegerv(mDevice, ALC_MAJOR_VERSION, 1, &major);
616 alcGetIntegerv(mDevice, ALC_MINOR_VERSION, 1, &minor);
617 Log(Debug::Info) << " ALC Version: " << major << "." << minor <<"\n" <<
618 " ALC Extensions: " << alcGetString(mDevice, ALC_EXTENSIONS);
619
620 ALC.EXT_EFX = alcIsExtensionPresent(mDevice, "ALC_EXT_EFX");
621 ALC.SOFT_HRTF = alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF");
622
623 std::vector<ALCint> attrs;
624 attrs.reserve(15);
625 if(ALC.SOFT_HRTF)
626 {
627 LPALCGETSTRINGISOFT alcGetStringiSOFT = nullptr;
628 getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT");
629
630 attrs.push_back(ALC_HRTF_SOFT);
631 attrs.push_back(hrtfmode == HrtfMode::Disable ? ALC_FALSE :
632 hrtfmode == HrtfMode::Enable ? ALC_TRUE :
633 /*hrtfmode == HrtfMode::Auto ?*/ ALC_DONT_CARE_SOFT);
634 if(!hrtfname.empty())
635 {
636 ALCint index = -1;
637 ALCint num_hrtf;
638 alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf);
639 for(ALCint i = 0;i < num_hrtf;++i)
640 {
641 const ALCchar *entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i);
642 if(hrtfname == entry)
643 {
644 index = i;
645 break;
646 }
647 }
648
649 if(index < 0)
650 Log(Debug::Warning) << "Failed to find HRTF \"" << hrtfname << "\", using default";
651 else
652 {
653 attrs.push_back(ALC_HRTF_ID_SOFT);
654 attrs.push_back(index);
655 }
656 }
657 }
658 attrs.push_back(0);
659
660 mContext = alcCreateContext(mDevice, attrs.data());
661 if(!mContext || alcMakeContextCurrent(mContext) == ALC_FALSE)
662 {
663 Log(Debug::Error) << "Failed to setup audio context: "<<alcGetString(mDevice, alcGetError(mDevice));
664 if(mContext)
665 alcDestroyContext(mContext);
666 mContext = nullptr;
667 alcCloseDevice(mDevice);
668 mDevice = nullptr;
669 return false;
670 }
671
672 Log(Debug::Info) << " Vendor: "<<alGetString(AL_VENDOR)<<"\n"<<
673 " Renderer: "<<alGetString(AL_RENDERER)<<"\n"<<
674 " Version: "<<alGetString(AL_VERSION)<<"\n"<<
675 " Extensions: "<<alGetString(AL_EXTENSIONS);
676
677 if(!ALC.SOFT_HRTF)
678 Log(Debug::Warning) << "HRTF status unavailable";
679 else
680 {
681 ALCint hrtf_state;
682 alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state);
683 if(!hrtf_state)
684 Log(Debug::Info) << "HRTF disabled";
685 else
686 {
687 const ALCchar *hrtf = alcGetString(mDevice, ALC_HRTF_SPECIFIER_SOFT);
688 Log(Debug::Info) << "Enabled HRTF " << hrtf;
689 }
690 }
691
692 AL.SOFT_source_spatialize = alIsExtensionPresent("AL_SOFT_source_spatialize");
693
694 ALCuint maxtotal;
695 ALCint maxmono = 0, maxstereo = 0;
696 alcGetIntegerv(mDevice, ALC_MONO_SOURCES, 1, &maxmono);
697 alcGetIntegerv(mDevice, ALC_STEREO_SOURCES, 1, &maxstereo);
698 if(getALCError(mDevice) != ALC_NO_ERROR)
699 maxtotal = 256;
700 else
701 {
702 maxtotal = std::min<ALCuint>(maxmono+maxstereo, 256);
703 if (maxtotal == 0) // workaround for broken implementations
704 maxtotal = 256;
705 }
706 for(size_t i = 0;i < maxtotal;i++)
707 {
708 ALuint src = 0;
709 alGenSources(1, &src);
710 if(alGetError() != AL_NO_ERROR)
711 break;
712 mFreeSources.push_back(src);
713 }
714 if(mFreeSources.empty())
715 {
716 Log(Debug::Warning) << "Could not allocate any sound sourcess";
717 alcMakeContextCurrent(nullptr);
718 alcDestroyContext(mContext);
719 mContext = nullptr;
720 alcCloseDevice(mDevice);
721 mDevice = nullptr;
722 return false;
723 }
724 Log(Debug::Info) << "Allocated " << mFreeSources.size() << " sound sources";
725
726 if(ALC.EXT_EFX)
727 {
728 #define LOAD_FUNC(x) getALFunc(x, #x)
729 LOAD_FUNC(alGenEffects);
730 LOAD_FUNC(alDeleteEffects);
731 LOAD_FUNC(alIsEffect);
732 LOAD_FUNC(alEffecti);
733 LOAD_FUNC(alEffectiv);
734 LOAD_FUNC(alEffectf);
735 LOAD_FUNC(alEffectfv);
736 LOAD_FUNC(alGetEffecti);
737 LOAD_FUNC(alGetEffectiv);
738 LOAD_FUNC(alGetEffectf);
739 LOAD_FUNC(alGetEffectfv);
740 LOAD_FUNC(alGenFilters);
741 LOAD_FUNC(alDeleteFilters);
742 LOAD_FUNC(alIsFilter);
743 LOAD_FUNC(alFilteri);
744 LOAD_FUNC(alFilteriv);
745 LOAD_FUNC(alFilterf);
746 LOAD_FUNC(alFilterfv);
747 LOAD_FUNC(alGetFilteri);
748 LOAD_FUNC(alGetFilteriv);
749 LOAD_FUNC(alGetFilterf);
750 LOAD_FUNC(alGetFilterfv);
751 LOAD_FUNC(alGenAuxiliaryEffectSlots);
752 LOAD_FUNC(alDeleteAuxiliaryEffectSlots);
753 LOAD_FUNC(alIsAuxiliaryEffectSlot);
754 LOAD_FUNC(alAuxiliaryEffectSloti);
755 LOAD_FUNC(alAuxiliaryEffectSlotiv);
756 LOAD_FUNC(alAuxiliaryEffectSlotf);
757 LOAD_FUNC(alAuxiliaryEffectSlotfv);
758 LOAD_FUNC(alGetAuxiliaryEffectSloti);
759 LOAD_FUNC(alGetAuxiliaryEffectSlotiv);
760 LOAD_FUNC(alGetAuxiliaryEffectSlotf);
761 LOAD_FUNC(alGetAuxiliaryEffectSlotfv);
762 #undef LOAD_FUNC
763 if(getALError() != AL_NO_ERROR)
764 {
765 ALC.EXT_EFX = false;
766 goto skip_efx;
767 }
768
769 alGenFilters(1, &mWaterFilter);
770 if(alGetError() == AL_NO_ERROR)
771 {
772 alFilteri(mWaterFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
773 if(alGetError() == AL_NO_ERROR)
774 {
775 Log(Debug::Info) << "Low-pass filter supported";
776 alFilterf(mWaterFilter, AL_LOWPASS_GAIN, 0.9f);
777 alFilterf(mWaterFilter, AL_LOWPASS_GAINHF, 0.125f);
778 }
779 else
780 {
781 alDeleteFilters(1, &mWaterFilter);
782 mWaterFilter = 0;
783 }
784 alGetError();
785 }
786
787 alGenAuxiliaryEffectSlots(1, &mEffectSlot);
788 alGetError();
789
790 alGenEffects(1, &mDefaultEffect);
791 if(alGetError() == AL_NO_ERROR)
792 {
793 alEffecti(mDefaultEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
794 if(alGetError() == AL_NO_ERROR)
795 Log(Debug::Info) << "EAX Reverb supported";
796 else
797 {
798 alEffecti(mDefaultEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
799 if(alGetError() == AL_NO_ERROR)
800 Log(Debug::Info) << "Standard Reverb supported";
801 }
802 EFXEAXREVERBPROPERTIES props = EFX_REVERB_PRESET_LIVINGROOM;
803 props.flGain = 0.0f;
804 LoadEffect(mDefaultEffect, props);
805 }
806
807 alGenEffects(1, &mWaterEffect);
808 if(alGetError() == AL_NO_ERROR)
809 {
810 alEffecti(mWaterEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
811 if(alGetError() != AL_NO_ERROR)
812 {
813 alEffecti(mWaterEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
814 alGetError();
815 }
816 LoadEffect(mWaterEffect, EFX_REVERB_PRESET_UNDERWATER);
817 }
818
819 alListenerf(AL_METERS_PER_UNIT, 1.0f / Constants::UnitsPerMeter);
820 }
821 skip_efx:
822 alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
823 // Speed of sound is in units per second. Take the sound speed in air (assumed
824 // meters per second), multiply by the units per meter to get the speed in u/s.
825 alSpeedOfSound(Constants::SoundSpeedInAir * Constants::UnitsPerMeter);
826 alGetError();
827
828 mInitialized = true;
829 return true;
830 }
831
deinit()832 void OpenAL_Output::deinit()
833 {
834 mStreamThread->removeAll();
835
836 for(ALuint source : mFreeSources)
837 alDeleteSources(1, &source);
838 mFreeSources.clear();
839
840 if(mEffectSlot)
841 alDeleteAuxiliaryEffectSlots(1, &mEffectSlot);
842 mEffectSlot = 0;
843 if(mDefaultEffect)
844 alDeleteEffects(1, &mDefaultEffect);
845 mDefaultEffect = 0;
846 if(mWaterEffect)
847 alDeleteEffects(1, &mWaterEffect);
848 mWaterEffect = 0;
849 if(mWaterFilter)
850 alDeleteFilters(1, &mWaterFilter);
851 mWaterFilter = 0;
852
853 alcMakeContextCurrent(nullptr);
854 if(mContext)
855 alcDestroyContext(mContext);
856 mContext = nullptr;
857 if(mDevice)
858 alcCloseDevice(mDevice);
859 mDevice = nullptr;
860
861 mInitialized = false;
862 }
863
864
enumerateHrtf()865 std::vector<std::string> OpenAL_Output::enumerateHrtf()
866 {
867 std::vector<std::string> ret;
868
869 if(!mDevice || !ALC.SOFT_HRTF)
870 return ret;
871
872 LPALCGETSTRINGISOFT alcGetStringiSOFT = nullptr;
873 getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT");
874
875 ALCint num_hrtf;
876 alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf);
877 ret.reserve(num_hrtf);
878 for(ALCint i = 0;i < num_hrtf;++i)
879 {
880 const ALCchar *entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i);
881 ret.emplace_back(entry);
882 }
883
884 return ret;
885 }
886
setHrtf(const std::string & hrtfname,HrtfMode hrtfmode)887 void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode)
888 {
889 if(!mDevice || !ALC.SOFT_HRTF)
890 {
891 Log(Debug::Info) << "HRTF extension not present";
892 return;
893 }
894
895 LPALCGETSTRINGISOFT alcGetStringiSOFT = nullptr;
896 getALCFunc(alcGetStringiSOFT, mDevice, "alcGetStringiSOFT");
897
898 LPALCRESETDEVICESOFT alcResetDeviceSOFT = nullptr;
899 getALCFunc(alcResetDeviceSOFT, mDevice, "alcResetDeviceSOFT");
900
901 std::vector<ALCint> attrs;
902 attrs.reserve(15);
903
904 attrs.push_back(ALC_HRTF_SOFT);
905 attrs.push_back(hrtfmode == HrtfMode::Disable ? ALC_FALSE :
906 hrtfmode == HrtfMode::Enable ? ALC_TRUE :
907 /*hrtfmode == HrtfMode::Auto ?*/ ALC_DONT_CARE_SOFT);
908 if(!hrtfname.empty())
909 {
910 ALCint index = -1;
911 ALCint num_hrtf;
912 alcGetIntegerv(mDevice, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf);
913 for(ALCint i = 0;i < num_hrtf;++i)
914 {
915 const ALCchar *entry = alcGetStringiSOFT(mDevice, ALC_HRTF_SPECIFIER_SOFT, i);
916 if(hrtfname == entry)
917 {
918 index = i;
919 break;
920 }
921 }
922
923 if(index < 0)
924 Log(Debug::Warning) << "Failed to find HRTF name \"" << hrtfname << "\", using default";
925 else
926 {
927 attrs.push_back(ALC_HRTF_ID_SOFT);
928 attrs.push_back(index);
929 }
930 }
931 attrs.push_back(0);
932 alcResetDeviceSOFT(mDevice, attrs.data());
933
934 ALCint hrtf_state;
935 alcGetIntegerv(mDevice, ALC_HRTF_SOFT, 1, &hrtf_state);
936 if(!hrtf_state)
937 Log(Debug::Info) << "HRTF disabled";
938 else
939 {
940 const ALCchar *hrtf = alcGetString(mDevice, ALC_HRTF_SPECIFIER_SOFT);
941 Log(Debug::Info) << "Enabled HRTF " << hrtf;
942 }
943 }
944
945
loadSound(const std::string & fname)946 std::pair<Sound_Handle,size_t> OpenAL_Output::loadSound(const std::string &fname)
947 {
948 getALError();
949
950 std::vector<char> data;
951 ALenum format = AL_NONE;
952 int srate = 0;
953
954 try
955 {
956 DecoderPtr decoder = mManager.getDecoder();
957 // Workaround: Bethesda at some point converted some of the files to mp3, but the references were kept as .wav.
958 if(decoder->mResourceMgr->exists(fname))
959 decoder->open(fname);
960 else
961 {
962 std::string file = fname;
963 std::string::size_type pos = file.rfind('.');
964 if(pos != std::string::npos)
965 file = file.substr(0, pos)+".mp3";
966 decoder->open(file);
967 }
968
969 ChannelConfig chans;
970 SampleType type;
971 decoder->getInfo(&srate, &chans, &type);
972 format = getALFormat(chans, type);
973 if(format) decoder->readAll(data);
974 }
975 catch(std::exception &e)
976 {
977 Log(Debug::Error) << "Failed to load audio from " << fname << ": " << e.what();
978 }
979
980 if(data.empty())
981 {
982 // If we failed to get any usable audio, substitute with silence.
983 format = AL_FORMAT_MONO8;
984 srate = 8000;
985 data.assign(8000, -128);
986 }
987
988 ALint size;
989 ALuint buf = 0;
990 alGenBuffers(1, &buf);
991 alBufferData(buf, format, data.data(), data.size(), srate);
992 alGetBufferi(buf, AL_SIZE, &size);
993 if(getALError() != AL_NO_ERROR)
994 {
995 if(buf && alIsBuffer(buf))
996 alDeleteBuffers(1, &buf);
997 getALError();
998 return std::make_pair(nullptr, 0);
999 }
1000 return std::make_pair(MAKE_PTRID(buf), size);
1001 }
1002
unloadSound(Sound_Handle data)1003 size_t OpenAL_Output::unloadSound(Sound_Handle data)
1004 {
1005 ALuint buffer = GET_PTRID(data);
1006 if(!buffer) return 0;
1007
1008 // Make sure no sources are playing this buffer before unloading it.
1009 SoundVec::const_iterator iter = mActiveSounds.begin();
1010 for(;iter != mActiveSounds.end();++iter)
1011 {
1012 if(!(*iter)->mHandle)
1013 continue;
1014
1015 ALuint source = GET_PTRID((*iter)->mHandle);
1016 ALint srcbuf;
1017 alGetSourcei(source, AL_BUFFER, &srcbuf);
1018 if((ALuint)srcbuf == buffer)
1019 {
1020 alSourceStop(source);
1021 alSourcei(source, AL_BUFFER, 0);
1022 }
1023 }
1024 ALint size = 0;
1025 alGetBufferi(buffer, AL_SIZE, &size);
1026 alDeleteBuffers(1, &buffer);
1027 getALError();
1028 return size;
1029 }
1030
1031
initCommon2D(ALuint source,const osg::Vec3f & pos,ALfloat gain,ALfloat pitch,bool loop,bool useenv)1032 void OpenAL_Output::initCommon2D(ALuint source, const osg::Vec3f &pos, ALfloat gain, ALfloat pitch, bool loop, bool useenv)
1033 {
1034 alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f);
1035 alSourcef(source, AL_MAX_DISTANCE, 1000.0f);
1036 alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f);
1037 alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
1038 alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
1039 if(AL.SOFT_source_spatialize)
1040 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_FALSE);
1041
1042 if(useenv)
1043 {
1044 if(mWaterFilter)
1045 alSourcei(source, AL_DIRECT_FILTER,
1046 (mListenerEnv == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL
1047 );
1048 else if(mListenerEnv == Env_Underwater)
1049 {
1050 gain *= 0.9f;
1051 pitch *= 0.7f;
1052 }
1053 if(mEffectSlot)
1054 alSource3i(source, AL_AUXILIARY_SEND_FILTER, mEffectSlot, 0, AL_FILTER_NULL);
1055 }
1056 else
1057 {
1058 if(mWaterFilter)
1059 alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
1060 if(mEffectSlot)
1061 alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
1062 }
1063
1064 alSourcef(source, AL_GAIN, gain);
1065 alSourcef(source, AL_PITCH, pitch);
1066 alSourcefv(source, AL_POSITION, pos.ptr());
1067 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1068 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1069 }
1070
initCommon3D(ALuint source,const osg::Vec3f & pos,ALfloat mindist,ALfloat maxdist,ALfloat gain,ALfloat pitch,bool loop,bool useenv)1071 void OpenAL_Output::initCommon3D(ALuint source, const osg::Vec3f &pos, ALfloat mindist, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool loop, bool useenv)
1072 {
1073 alSourcef(source, AL_REFERENCE_DISTANCE, mindist);
1074 alSourcef(source, AL_MAX_DISTANCE, maxdist);
1075 alSourcef(source, AL_ROLLOFF_FACTOR, 1.0f);
1076 alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE);
1077 alSourcei(source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
1078 if(AL.SOFT_source_spatialize)
1079 alSourcei(source, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE);
1080
1081 if((pos - mListenerPos).length2() > maxdist*maxdist)
1082 gain = 0.0f;
1083 if(useenv)
1084 {
1085 if(mWaterFilter)
1086 alSourcei(source, AL_DIRECT_FILTER,
1087 (mListenerEnv == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL
1088 );
1089 else if(mListenerEnv == Env_Underwater)
1090 {
1091 gain *= 0.9f;
1092 pitch *= 0.7f;
1093 }
1094 if(mEffectSlot)
1095 alSource3i(source, AL_AUXILIARY_SEND_FILTER, mEffectSlot, 0, AL_FILTER_NULL);
1096 }
1097 else
1098 {
1099 if(mWaterFilter)
1100 alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
1101 if(mEffectSlot)
1102 alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
1103 }
1104
1105 alSourcef(source, AL_GAIN, gain);
1106 alSourcef(source, AL_PITCH, pitch);
1107 alSourcefv(source, AL_POSITION, pos.ptr());
1108 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1109 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1110 }
1111
updateCommon(ALuint source,const osg::Vec3f & pos,ALfloat maxdist,ALfloat gain,ALfloat pitch,bool useenv,bool is3d)1112 void OpenAL_Output::updateCommon(ALuint source, const osg::Vec3f& pos, ALfloat maxdist, ALfloat gain, ALfloat pitch, bool useenv, bool is3d)
1113 {
1114 if(is3d)
1115 {
1116 if((pos - mListenerPos).length2() > maxdist*maxdist)
1117 gain = 0.0f;
1118 }
1119 if(useenv && mListenerEnv == Env_Underwater && !mWaterFilter)
1120 {
1121 gain *= 0.9f;
1122 pitch *= 0.7f;
1123 }
1124
1125 alSourcef(source, AL_GAIN, gain);
1126 alSourcef(source, AL_PITCH, pitch);
1127 alSourcefv(source, AL_POSITION, pos.ptr());
1128 alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
1129 alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
1130 }
1131
1132
playSound(Sound * sound,Sound_Handle data,float offset)1133 bool OpenAL_Output::playSound(Sound *sound, Sound_Handle data, float offset)
1134 {
1135 ALuint source;
1136
1137 if(mFreeSources.empty())
1138 {
1139 Log(Debug::Warning) << "No free sources!";
1140 return false;
1141 }
1142 source = mFreeSources.front();
1143
1144 initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(),
1145 sound->getIsLooping(), sound->getUseEnv());
1146 alSourcei(source, AL_BUFFER, GET_PTRID(data));
1147 alSourcef(source, AL_SEC_OFFSET, offset);
1148 if(getALError() != AL_NO_ERROR)
1149 {
1150 alSourceRewind(source);
1151 alSourcei(source, AL_BUFFER, 0);
1152 alGetError();
1153 return false;
1154 }
1155
1156 alSourcePlay(source);
1157 if(getALError() != AL_NO_ERROR)
1158 {
1159 alSourceRewind(source);
1160 alSourcei(source, AL_BUFFER, 0);
1161 alGetError();
1162 return false;
1163 }
1164
1165 mFreeSources.pop_front();
1166 sound->mHandle = MAKE_PTRID(source);
1167 mActiveSounds.push_back(sound);
1168
1169 return true;
1170 }
1171
playSound3D(Sound * sound,Sound_Handle data,float offset)1172 bool OpenAL_Output::playSound3D(Sound *sound, Sound_Handle data, float offset)
1173 {
1174 ALuint source;
1175
1176 if(mFreeSources.empty())
1177 {
1178 Log(Debug::Warning) << "No free sources!";
1179 return false;
1180 }
1181 source = mFreeSources.front();
1182
1183 initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(),
1184 sound->getRealVolume(), sound->getPitch(), sound->getIsLooping(),
1185 sound->getUseEnv());
1186 alSourcei(source, AL_BUFFER, GET_PTRID(data));
1187 alSourcef(source, AL_SEC_OFFSET, offset);
1188 if(getALError() != AL_NO_ERROR)
1189 {
1190 alSourceRewind(source);
1191 alSourcei(source, AL_BUFFER, 0);
1192 alGetError();
1193 return false;
1194 }
1195
1196 alSourcePlay(source);
1197 if(getALError() != AL_NO_ERROR)
1198 {
1199 alSourceRewind(source);
1200 alSourcei(source, AL_BUFFER, 0);
1201 alGetError();
1202 return false;
1203 }
1204
1205 mFreeSources.pop_front();
1206 sound->mHandle = MAKE_PTRID(source);
1207 mActiveSounds.push_back(sound);
1208
1209 return true;
1210 }
1211
finishSound(Sound * sound)1212 void OpenAL_Output::finishSound(Sound *sound)
1213 {
1214 if(!sound->mHandle) return;
1215 ALuint source = GET_PTRID(sound->mHandle);
1216 sound->mHandle = nullptr;
1217
1218 // Rewind the stream to put the source back into an AL_INITIAL state, for
1219 // the next time it's used.
1220 alSourceRewind(source);
1221 alSourcei(source, AL_BUFFER, 0);
1222 getALError();
1223
1224 mFreeSources.push_back(source);
1225 mActiveSounds.erase(std::find(mActiveSounds.begin(), mActiveSounds.end(), sound));
1226 }
1227
isSoundPlaying(Sound * sound)1228 bool OpenAL_Output::isSoundPlaying(Sound *sound)
1229 {
1230 if(!sound->mHandle) return false;
1231 ALuint source = GET_PTRID(sound->mHandle);
1232 ALint state = AL_STOPPED;
1233
1234 alGetSourcei(source, AL_SOURCE_STATE, &state);
1235 getALError();
1236
1237 return state == AL_PLAYING || state == AL_PAUSED;
1238 }
1239
updateSound(Sound * sound)1240 void OpenAL_Output::updateSound(Sound *sound)
1241 {
1242 if(!sound->mHandle) return;
1243 ALuint source = GET_PTRID(sound->mHandle);
1244
1245 updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(),
1246 sound->getPitch(), sound->getUseEnv(), sound->getIs3D());
1247 getALError();
1248 }
1249
1250
streamSound(DecoderPtr decoder,Stream * sound,bool getLoudnessData)1251 bool OpenAL_Output::streamSound(DecoderPtr decoder, Stream *sound, bool getLoudnessData)
1252 {
1253 if(mFreeSources.empty())
1254 {
1255 Log(Debug::Warning) << "No free sources!";
1256 return false;
1257 }
1258 ALuint source = mFreeSources.front();
1259
1260 if(sound->getIsLooping())
1261 Log(Debug::Warning) << "Warning: cannot loop stream \"" << decoder->getName() << "\"";
1262
1263 initCommon2D(source, sound->getPosition(), sound->getRealVolume(), sound->getPitch(),
1264 false, sound->getUseEnv());
1265 if(getALError() != AL_NO_ERROR)
1266 return false;
1267
1268 OpenAL_SoundStream *stream = new OpenAL_SoundStream(source, std::move(decoder));
1269 if(!stream->init(getLoudnessData))
1270 {
1271 delete stream;
1272 return false;
1273 }
1274 mStreamThread->add(stream);
1275
1276 mFreeSources.pop_front();
1277 sound->mHandle = stream;
1278 mActiveStreams.push_back(sound);
1279 return true;
1280 }
1281
streamSound3D(DecoderPtr decoder,Stream * sound,bool getLoudnessData)1282 bool OpenAL_Output::streamSound3D(DecoderPtr decoder, Stream *sound, bool getLoudnessData)
1283 {
1284 if(mFreeSources.empty())
1285 {
1286 Log(Debug::Warning) << "No free sources!";
1287 return false;
1288 }
1289 ALuint source = mFreeSources.front();
1290
1291 if(sound->getIsLooping())
1292 Log(Debug::Warning) << "Warning: cannot loop stream \"" << decoder->getName() << "\"";
1293
1294 initCommon3D(source, sound->getPosition(), sound->getMinDistance(), sound->getMaxDistance(),
1295 sound->getRealVolume(), sound->getPitch(), false, sound->getUseEnv());
1296 if(getALError() != AL_NO_ERROR)
1297 return false;
1298
1299 OpenAL_SoundStream *stream = new OpenAL_SoundStream(source, std::move(decoder));
1300 if(!stream->init(getLoudnessData))
1301 {
1302 delete stream;
1303 return false;
1304 }
1305 mStreamThread->add(stream);
1306
1307 mFreeSources.pop_front();
1308 sound->mHandle = stream;
1309 mActiveStreams.push_back(sound);
1310 return true;
1311 }
1312
finishStream(Stream * sound)1313 void OpenAL_Output::finishStream(Stream *sound)
1314 {
1315 if(!sound->mHandle) return;
1316 OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
1317 ALuint source = stream->mSource;
1318
1319 sound->mHandle = nullptr;
1320 mStreamThread->remove(stream);
1321
1322 // Rewind the stream to put the source back into an AL_INITIAL state, for
1323 // the next time it's used.
1324 alSourceRewind(source);
1325 alSourcei(source, AL_BUFFER, 0);
1326 getALError();
1327
1328 mFreeSources.push_back(source);
1329 mActiveStreams.erase(std::find(mActiveStreams.begin(), mActiveStreams.end(), sound));
1330
1331 delete stream;
1332 }
1333
getStreamDelay(Stream * sound)1334 double OpenAL_Output::getStreamDelay(Stream *sound)
1335 {
1336 if(!sound->mHandle) return 0.0;
1337 OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
1338 return stream->getStreamDelay();
1339 }
1340
getStreamOffset(Stream * sound)1341 double OpenAL_Output::getStreamOffset(Stream *sound)
1342 {
1343 if(!sound->mHandle) return 0.0;
1344 OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
1345 std::lock_guard<std::mutex> lock(mStreamThread->mMutex);
1346 return stream->getStreamOffset();
1347 }
1348
getStreamLoudness(Stream * sound)1349 float OpenAL_Output::getStreamLoudness(Stream *sound)
1350 {
1351 if(!sound->mHandle) return 0.0;
1352 OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
1353 std::lock_guard<std::mutex> lock(mStreamThread->mMutex);
1354 return stream->getCurrentLoudness();
1355 }
1356
isStreamPlaying(Stream * sound)1357 bool OpenAL_Output::isStreamPlaying(Stream *sound)
1358 {
1359 if(!sound->mHandle) return false;
1360 OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
1361 std::lock_guard<std::mutex> lock(mStreamThread->mMutex);
1362 return stream->isPlaying();
1363 }
1364
updateStream(Stream * sound)1365 void OpenAL_Output::updateStream(Stream *sound)
1366 {
1367 if(!sound->mHandle) return;
1368 OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
1369 ALuint source = stream->mSource;
1370
1371 updateCommon(source, sound->getPosition(), sound->getMaxDistance(), sound->getRealVolume(),
1372 sound->getPitch(), sound->getUseEnv(), sound->getIs3D());
1373 getALError();
1374 }
1375
1376
startUpdate()1377 void OpenAL_Output::startUpdate()
1378 {
1379 alcSuspendContext(alcGetCurrentContext());
1380 }
1381
finishUpdate()1382 void OpenAL_Output::finishUpdate()
1383 {
1384 alcProcessContext(alcGetCurrentContext());
1385 }
1386
1387
updateListener(const osg::Vec3f & pos,const osg::Vec3f & atdir,const osg::Vec3f & updir,Environment env)1388 void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdir, const osg::Vec3f &updir, Environment env)
1389 {
1390 if(mContext)
1391 {
1392 ALfloat orient[6] = {
1393 atdir.x(), atdir.y(), atdir.z(),
1394 updir.x(), updir.y(), updir.z()
1395 };
1396 alListenerfv(AL_POSITION, pos.ptr());
1397 alListenerfv(AL_ORIENTATION, orient);
1398
1399 if(env != mListenerEnv)
1400 {
1401 alSpeedOfSound(((env == Env_Underwater) ? Constants::SoundSpeedUnderwater : Constants::SoundSpeedInAir) * Constants::UnitsPerMeter);
1402
1403 // Update active sources with the environment's direct filter
1404 if(mWaterFilter)
1405 {
1406 ALuint filter = (env == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL;
1407 for(Sound *sound : mActiveSounds)
1408 {
1409 if(sound->getUseEnv())
1410 alSourcei(GET_PTRID(sound->mHandle), AL_DIRECT_FILTER, filter);
1411 }
1412 for(Stream *sound : mActiveStreams)
1413 {
1414 if(sound->getUseEnv())
1415 alSourcei(
1416 reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle)->mSource,
1417 AL_DIRECT_FILTER, filter
1418 );
1419 }
1420 }
1421 // Update the environment effect
1422 if(mEffectSlot)
1423 alAuxiliaryEffectSloti(mEffectSlot, AL_EFFECTSLOT_EFFECT,
1424 (env == Env_Underwater) ? mWaterEffect : mDefaultEffect
1425 );
1426 }
1427 getALError();
1428 }
1429
1430 mListenerPos = pos;
1431 mListenerEnv = env;
1432 }
1433
1434
pauseSounds(int types)1435 void OpenAL_Output::pauseSounds(int types)
1436 {
1437 std::vector<ALuint> sources;
1438 for(Sound *sound : mActiveSounds)
1439 {
1440 if((types&sound->getPlayType()))
1441 sources.push_back(GET_PTRID(sound->mHandle));
1442 }
1443 for(Stream *sound : mActiveStreams)
1444 {
1445 if((types&sound->getPlayType()))
1446 {
1447 OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
1448 sources.push_back(stream->mSource);
1449 }
1450 }
1451 if(!sources.empty())
1452 {
1453 alSourcePausev(sources.size(), sources.data());
1454 getALError();
1455 }
1456 }
1457
pauseActiveDevice()1458 void OpenAL_Output::pauseActiveDevice()
1459 {
1460 if (mDevice == nullptr)
1461 return;
1462
1463 if(alcIsExtensionPresent(mDevice, "ALC_SOFT_PAUSE_DEVICE"))
1464 {
1465 LPALCDEVICEPAUSESOFT alcDevicePauseSOFT = nullptr;
1466 getALCFunc(alcDevicePauseSOFT, mDevice, "alcDevicePauseSOFT");
1467 alcDevicePauseSOFT(mDevice);
1468 getALCError(mDevice);
1469 }
1470
1471 alListenerf(AL_GAIN, 0.0f);
1472 }
1473
resumeActiveDevice()1474 void OpenAL_Output::resumeActiveDevice()
1475 {
1476 if (mDevice == nullptr)
1477 return;
1478
1479 if(alcIsExtensionPresent(mDevice, "ALC_SOFT_PAUSE_DEVICE"))
1480 {
1481 LPALCDEVICERESUMESOFT alcDeviceResumeSOFT = nullptr;
1482 getALCFunc(alcDeviceResumeSOFT, mDevice, "alcDeviceResumeSOFT");
1483 alcDeviceResumeSOFT(mDevice);
1484 getALCError(mDevice);
1485 }
1486
1487 alListenerf(AL_GAIN, 1.0f);
1488 }
1489
resumeSounds(int types)1490 void OpenAL_Output::resumeSounds(int types)
1491 {
1492 std::vector<ALuint> sources;
1493 for(Sound *sound : mActiveSounds)
1494 {
1495 if((types&sound->getPlayType()))
1496 sources.push_back(GET_PTRID(sound->mHandle));
1497 }
1498 for(Stream *sound : mActiveStreams)
1499 {
1500 if((types&sound->getPlayType()))
1501 {
1502 OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
1503 sources.push_back(stream->mSource);
1504 }
1505 }
1506 if(!sources.empty())
1507 {
1508 alSourcePlayv(sources.size(), sources.data());
1509 getALError();
1510 }
1511 }
1512
1513
OpenAL_Output(SoundManager & mgr)1514 OpenAL_Output::OpenAL_Output(SoundManager &mgr)
1515 : Sound_Output(mgr)
1516 , mDevice(nullptr), mContext(nullptr)
1517 , mListenerPos(0.0f, 0.0f, 0.0f), mListenerEnv(Env_Normal)
1518 , mWaterFilter(0), mWaterEffect(0), mDefaultEffect(0), mEffectSlot(0)
1519 , mStreamThread(new StreamThread)
1520 {
1521 }
1522
~OpenAL_Output()1523 OpenAL_Output::~OpenAL_Output()
1524 {
1525 OpenAL_Output::deinit();
1526 }
1527
1528 }
1529