1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2000 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
19 */
20
21 #include "config.h"
22
23 #include "version.h"
24
25 #include <atomic>
26 #include <cmath>
27 #include <cstdlib>
28 #include <cstring>
29 #include <mutex>
30
31 #include "AL/al.h"
32 #include "AL/alc.h"
33 #include "AL/alext.h"
34
35 #include "alcontext.h"
36 #include "almalloc.h"
37 #include "alnumeric.h"
38 #include "alspan.h"
39 #include "alu.h"
40 #include "atomic.h"
41 #include "core/except.h"
42 #include "event.h"
43 #include "inprogext.h"
44 #include "opthelpers.h"
45 #include "strutils.h"
46 #include "voice.h"
47
48
49 namespace {
50
51 constexpr ALchar alVendor[] = "OpenAL Community";
52 constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION;
53 constexpr ALchar alRenderer[] = "OpenAL Soft";
54
55 // Error Messages
56 constexpr ALchar alNoError[] = "No Error";
57 constexpr ALchar alErrInvalidName[] = "Invalid Name";
58 constexpr ALchar alErrInvalidEnum[] = "Invalid Enum";
59 constexpr ALchar alErrInvalidValue[] = "Invalid Value";
60 constexpr ALchar alErrInvalidOp[] = "Invalid Operation";
61 constexpr ALchar alErrOutOfMemory[] = "Out of Memory";
62
63 /* Resampler strings */
64 template<Resampler rtype> struct ResamplerName { };
65 template<> struct ResamplerName<Resampler::Point>
Get__anon5effb9350111::ResamplerName66 { static constexpr const ALchar *Get() noexcept { return "Nearest"; } };
67 template<> struct ResamplerName<Resampler::Linear>
Get__anon5effb9350111::ResamplerName68 { static constexpr const ALchar *Get() noexcept { return "Linear"; } };
69 template<> struct ResamplerName<Resampler::Cubic>
Get__anon5effb9350111::ResamplerName70 { static constexpr const ALchar *Get() noexcept { return "Cubic"; } };
71 template<> struct ResamplerName<Resampler::FastBSinc12>
Get__anon5effb9350111::ResamplerName72 { static constexpr const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } };
73 template<> struct ResamplerName<Resampler::BSinc12>
Get__anon5effb9350111::ResamplerName74 { static constexpr const ALchar *Get() noexcept { return "11th order Sinc"; } };
75 template<> struct ResamplerName<Resampler::FastBSinc24>
Get__anon5effb9350111::ResamplerName76 { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } };
77 template<> struct ResamplerName<Resampler::BSinc24>
Get__anon5effb9350111::ResamplerName78 { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc"; } };
79
GetResamplerName(const Resampler rtype)80 const ALchar *GetResamplerName(const Resampler rtype)
81 {
82 #define HANDLE_RESAMPLER(r) case r: return ResamplerName<r>::Get()
83 switch(rtype)
84 {
85 HANDLE_RESAMPLER(Resampler::Point);
86 HANDLE_RESAMPLER(Resampler::Linear);
87 HANDLE_RESAMPLER(Resampler::Cubic);
88 HANDLE_RESAMPLER(Resampler::FastBSinc12);
89 HANDLE_RESAMPLER(Resampler::BSinc12);
90 HANDLE_RESAMPLER(Resampler::FastBSinc24);
91 HANDLE_RESAMPLER(Resampler::BSinc24);
92 }
93 #undef HANDLE_RESAMPLER
94 /* Should never get here. */
95 throw std::runtime_error{"Unexpected resampler index"};
96 }
97
DistanceModelFromALenum(ALenum model)98 al::optional<DistanceModel> DistanceModelFromALenum(ALenum model)
99 {
100 switch(model)
101 {
102 case AL_NONE: return al::make_optional(DistanceModel::Disable);
103 case AL_INVERSE_DISTANCE: return al::make_optional(DistanceModel::Inverse);
104 case AL_INVERSE_DISTANCE_CLAMPED: return al::make_optional(DistanceModel::InverseClamped);
105 case AL_LINEAR_DISTANCE: return al::make_optional(DistanceModel::Linear);
106 case AL_LINEAR_DISTANCE_CLAMPED: return al::make_optional(DistanceModel::LinearClamped);
107 case AL_EXPONENT_DISTANCE: return al::make_optional(DistanceModel::Exponent);
108 case AL_EXPONENT_DISTANCE_CLAMPED: return al::make_optional(DistanceModel::ExponentClamped);
109 }
110 return al::nullopt;
111 }
ALenumFromDistanceModel(DistanceModel model)112 ALenum ALenumFromDistanceModel(DistanceModel model)
113 {
114 switch(model)
115 {
116 case DistanceModel::Disable: return AL_NONE;
117 case DistanceModel::Inverse: return AL_INVERSE_DISTANCE;
118 case DistanceModel::InverseClamped: return AL_INVERSE_DISTANCE_CLAMPED;
119 case DistanceModel::Linear: return AL_LINEAR_DISTANCE;
120 case DistanceModel::LinearClamped: return AL_LINEAR_DISTANCE_CLAMPED;
121 case DistanceModel::Exponent: return AL_EXPONENT_DISTANCE;
122 case DistanceModel::ExponentClamped: return AL_EXPONENT_DISTANCE_CLAMPED;
123 }
124 throw std::runtime_error{"Unexpected distance model "+std::to_string(static_cast<int>(model))};
125 }
126
127 } // namespace
128
129 /* WARNING: Non-standard export! Not part of any extension, or exposed in the
130 * alcFunctions list.
131 */
alsoft_get_version(void)132 extern "C" AL_API const ALchar* AL_APIENTRY alsoft_get_version(void)
133 START_API_FUNC
134 {
135 static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION");
136 if(spoof) return spoof->c_str();
137 return ALSOFT_VERSION;
138 }
139 END_API_FUNC
140
141 #define DO_UPDATEPROPS() do { \
142 if(!context->mDeferUpdates.load(std::memory_order_acquire)) \
143 UpdateContextProps(context.get()); \
144 else \
145 context->mPropsClean.clear(std::memory_order_release); \
146 } while(0)
147
148
alEnable(ALenum capability)149 AL_API void AL_APIENTRY alEnable(ALenum capability)
150 START_API_FUNC
151 {
152 ContextRef context{GetContextRef()};
153 if UNLIKELY(!context) return;
154
155 std::lock_guard<std::mutex> _{context->mPropLock};
156 switch(capability)
157 {
158 case AL_SOURCE_DISTANCE_MODEL:
159 context->mSourceDistanceModel = true;
160 DO_UPDATEPROPS();
161 break;
162
163 default:
164 context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability);
165 }
166 }
167 END_API_FUNC
168
alDisable(ALenum capability)169 AL_API void AL_APIENTRY alDisable(ALenum capability)
170 START_API_FUNC
171 {
172 ContextRef context{GetContextRef()};
173 if UNLIKELY(!context) return;
174
175 std::lock_guard<std::mutex> _{context->mPropLock};
176 switch(capability)
177 {
178 case AL_SOURCE_DISTANCE_MODEL:
179 context->mSourceDistanceModel = false;
180 DO_UPDATEPROPS();
181 break;
182
183 default:
184 context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
185 }
186 }
187 END_API_FUNC
188
alIsEnabled(ALenum capability)189 AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
190 START_API_FUNC
191 {
192 ContextRef context{GetContextRef()};
193 if UNLIKELY(!context) return AL_FALSE;
194
195 std::lock_guard<std::mutex> _{context->mPropLock};
196 ALboolean value{AL_FALSE};
197 switch(capability)
198 {
199 case AL_SOURCE_DISTANCE_MODEL:
200 value = context->mSourceDistanceModel ? AL_TRUE : AL_FALSE;
201 break;
202
203 default:
204 context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability);
205 }
206
207 return value;
208 }
209 END_API_FUNC
210
alGetBoolean(ALenum pname)211 AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
212 START_API_FUNC
213 {
214 ContextRef context{GetContextRef()};
215 if UNLIKELY(!context) return AL_FALSE;
216
217 std::lock_guard<std::mutex> _{context->mPropLock};
218 ALboolean value{AL_FALSE};
219 switch(pname)
220 {
221 case AL_DOPPLER_FACTOR:
222 if(context->mDopplerFactor != 0.0f)
223 value = AL_TRUE;
224 break;
225
226 case AL_DOPPLER_VELOCITY:
227 if(context->mDopplerVelocity != 0.0f)
228 value = AL_TRUE;
229 break;
230
231 case AL_DISTANCE_MODEL:
232 if(context->mDistanceModel == DistanceModel::Default)
233 value = AL_TRUE;
234 break;
235
236 case AL_SPEED_OF_SOUND:
237 if(context->mSpeedOfSound != 0.0f)
238 value = AL_TRUE;
239 break;
240
241 case AL_DEFERRED_UPDATES_SOFT:
242 if(context->mDeferUpdates.load(std::memory_order_acquire))
243 value = AL_TRUE;
244 break;
245
246 case AL_GAIN_LIMIT_SOFT:
247 if(GainMixMax/context->mGainBoost != 0.0f)
248 value = AL_TRUE;
249 break;
250
251 case AL_NUM_RESAMPLERS_SOFT:
252 /* Always non-0. */
253 value = AL_TRUE;
254 break;
255
256 case AL_DEFAULT_RESAMPLER_SOFT:
257 value = static_cast<int>(ResamplerDefault) ? AL_TRUE : AL_FALSE;
258 break;
259
260 default:
261 context->setError(AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname);
262 }
263
264 return value;
265 }
266 END_API_FUNC
267
alGetDouble(ALenum pname)268 AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
269 START_API_FUNC
270 {
271 ContextRef context{GetContextRef()};
272 if UNLIKELY(!context) return 0.0;
273
274 std::lock_guard<std::mutex> _{context->mPropLock};
275 ALdouble value{0.0};
276 switch(pname)
277 {
278 case AL_DOPPLER_FACTOR:
279 value = context->mDopplerFactor;
280 break;
281
282 case AL_DOPPLER_VELOCITY:
283 value = context->mDopplerVelocity;
284 break;
285
286 case AL_DISTANCE_MODEL:
287 value = static_cast<ALdouble>(ALenumFromDistanceModel(context->mDistanceModel));
288 break;
289
290 case AL_SPEED_OF_SOUND:
291 value = context->mSpeedOfSound;
292 break;
293
294 case AL_DEFERRED_UPDATES_SOFT:
295 if(context->mDeferUpdates.load(std::memory_order_acquire))
296 value = static_cast<ALdouble>(AL_TRUE);
297 break;
298
299 case AL_GAIN_LIMIT_SOFT:
300 value = ALdouble{GainMixMax}/context->mGainBoost;
301 break;
302
303 case AL_NUM_RESAMPLERS_SOFT:
304 value = static_cast<ALdouble>(Resampler::Max) + 1.0;
305 break;
306
307 case AL_DEFAULT_RESAMPLER_SOFT:
308 value = static_cast<ALdouble>(ResamplerDefault);
309 break;
310
311 default:
312 context->setError(AL_INVALID_VALUE, "Invalid double property 0x%04x", pname);
313 }
314
315 return value;
316 }
317 END_API_FUNC
318
alGetFloat(ALenum pname)319 AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
320 START_API_FUNC
321 {
322 ContextRef context{GetContextRef()};
323 if UNLIKELY(!context) return 0.0f;
324
325 std::lock_guard<std::mutex> _{context->mPropLock};
326 ALfloat value{0.0f};
327 switch(pname)
328 {
329 case AL_DOPPLER_FACTOR:
330 value = context->mDopplerFactor;
331 break;
332
333 case AL_DOPPLER_VELOCITY:
334 value = context->mDopplerVelocity;
335 break;
336
337 case AL_DISTANCE_MODEL:
338 value = static_cast<ALfloat>(ALenumFromDistanceModel(context->mDistanceModel));
339 break;
340
341 case AL_SPEED_OF_SOUND:
342 value = context->mSpeedOfSound;
343 break;
344
345 case AL_DEFERRED_UPDATES_SOFT:
346 if(context->mDeferUpdates.load(std::memory_order_acquire))
347 value = static_cast<ALfloat>(AL_TRUE);
348 break;
349
350 case AL_GAIN_LIMIT_SOFT:
351 value = GainMixMax/context->mGainBoost;
352 break;
353
354 case AL_NUM_RESAMPLERS_SOFT:
355 value = static_cast<ALfloat>(Resampler::Max) + 1.0f;
356 break;
357
358 case AL_DEFAULT_RESAMPLER_SOFT:
359 value = static_cast<ALfloat>(ResamplerDefault);
360 break;
361
362 default:
363 context->setError(AL_INVALID_VALUE, "Invalid float property 0x%04x", pname);
364 }
365
366 return value;
367 }
368 END_API_FUNC
369
alGetInteger(ALenum pname)370 AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
371 START_API_FUNC
372 {
373 ContextRef context{GetContextRef()};
374 if UNLIKELY(!context) return 0;
375
376 std::lock_guard<std::mutex> _{context->mPropLock};
377 ALint value{0};
378 switch(pname)
379 {
380 case AL_DOPPLER_FACTOR:
381 value = static_cast<ALint>(context->mDopplerFactor);
382 break;
383
384 case AL_DOPPLER_VELOCITY:
385 value = static_cast<ALint>(context->mDopplerVelocity);
386 break;
387
388 case AL_DISTANCE_MODEL:
389 value = ALenumFromDistanceModel(context->mDistanceModel);
390 break;
391
392 case AL_SPEED_OF_SOUND:
393 value = static_cast<ALint>(context->mSpeedOfSound);
394 break;
395
396 case AL_DEFERRED_UPDATES_SOFT:
397 if(context->mDeferUpdates.load(std::memory_order_acquire))
398 value = AL_TRUE;
399 break;
400
401 case AL_GAIN_LIMIT_SOFT:
402 value = static_cast<ALint>(GainMixMax/context->mGainBoost);
403 break;
404
405 case AL_NUM_RESAMPLERS_SOFT:
406 value = static_cast<int>(Resampler::Max) + 1;
407 break;
408
409 case AL_DEFAULT_RESAMPLER_SOFT:
410 value = static_cast<int>(ResamplerDefault);
411 break;
412
413 default:
414 context->setError(AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname);
415 }
416
417 return value;
418 }
419 END_API_FUNC
420
alGetInteger64SOFT(ALenum pname)421 extern "C" AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
422 START_API_FUNC
423 {
424 ContextRef context{GetContextRef()};
425 if UNLIKELY(!context) return 0_i64;
426
427 std::lock_guard<std::mutex> _{context->mPropLock};
428 ALint64SOFT value{0};
429 switch(pname)
430 {
431 case AL_DOPPLER_FACTOR:
432 value = static_cast<ALint64SOFT>(context->mDopplerFactor);
433 break;
434
435 case AL_DOPPLER_VELOCITY:
436 value = static_cast<ALint64SOFT>(context->mDopplerVelocity);
437 break;
438
439 case AL_DISTANCE_MODEL:
440 value = ALenumFromDistanceModel(context->mDistanceModel);
441 break;
442
443 case AL_SPEED_OF_SOUND:
444 value = static_cast<ALint64SOFT>(context->mSpeedOfSound);
445 break;
446
447 case AL_DEFERRED_UPDATES_SOFT:
448 if(context->mDeferUpdates.load(std::memory_order_acquire))
449 value = AL_TRUE;
450 break;
451
452 case AL_GAIN_LIMIT_SOFT:
453 value = static_cast<ALint64SOFT>(GainMixMax/context->mGainBoost);
454 break;
455
456 case AL_NUM_RESAMPLERS_SOFT:
457 value = static_cast<ALint64SOFT>(Resampler::Max) + 1;
458 break;
459
460 case AL_DEFAULT_RESAMPLER_SOFT:
461 value = static_cast<ALint64SOFT>(ResamplerDefault);
462 break;
463
464 default:
465 context->setError(AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname);
466 }
467
468 return value;
469 }
470 END_API_FUNC
471
alGetPointerSOFT(ALenum pname)472 AL_API ALvoid* AL_APIENTRY alGetPointerSOFT(ALenum pname)
473 START_API_FUNC
474 {
475 ContextRef context{GetContextRef()};
476 if UNLIKELY(!context) return nullptr;
477
478 std::lock_guard<std::mutex> _{context->mPropLock};
479 void *value{nullptr};
480 switch(pname)
481 {
482 case AL_EVENT_CALLBACK_FUNCTION_SOFT:
483 value = reinterpret_cast<void*>(context->mEventCb);
484 break;
485
486 case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
487 value = context->mEventParam;
488 break;
489
490 default:
491 context->setError(AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname);
492 }
493
494 return value;
495 }
496 END_API_FUNC
497
alGetBooleanv(ALenum pname,ALboolean * values)498 AL_API void AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
499 START_API_FUNC
500 {
501 if(values)
502 {
503 switch(pname)
504 {
505 case AL_DOPPLER_FACTOR:
506 case AL_DOPPLER_VELOCITY:
507 case AL_DISTANCE_MODEL:
508 case AL_SPEED_OF_SOUND:
509 case AL_DEFERRED_UPDATES_SOFT:
510 case AL_GAIN_LIMIT_SOFT:
511 case AL_NUM_RESAMPLERS_SOFT:
512 case AL_DEFAULT_RESAMPLER_SOFT:
513 values[0] = alGetBoolean(pname);
514 return;
515 }
516 }
517
518 ContextRef context{GetContextRef()};
519 if UNLIKELY(!context) return;
520
521 if(!values)
522 context->setError(AL_INVALID_VALUE, "NULL pointer");
523 else switch(pname)
524 {
525 default:
526 context->setError(AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname);
527 }
528 }
529 END_API_FUNC
530
alGetDoublev(ALenum pname,ALdouble * values)531 AL_API void AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
532 START_API_FUNC
533 {
534 if(values)
535 {
536 switch(pname)
537 {
538 case AL_DOPPLER_FACTOR:
539 case AL_DOPPLER_VELOCITY:
540 case AL_DISTANCE_MODEL:
541 case AL_SPEED_OF_SOUND:
542 case AL_DEFERRED_UPDATES_SOFT:
543 case AL_GAIN_LIMIT_SOFT:
544 case AL_NUM_RESAMPLERS_SOFT:
545 case AL_DEFAULT_RESAMPLER_SOFT:
546 values[0] = alGetDouble(pname);
547 return;
548 }
549 }
550
551 ContextRef context{GetContextRef()};
552 if UNLIKELY(!context) return;
553
554 if(!values)
555 context->setError(AL_INVALID_VALUE, "NULL pointer");
556 else switch(pname)
557 {
558 default:
559 context->setError(AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname);
560 }
561 }
562 END_API_FUNC
563
alGetFloatv(ALenum pname,ALfloat * values)564 AL_API void AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
565 START_API_FUNC
566 {
567 if(values)
568 {
569 switch(pname)
570 {
571 case AL_DOPPLER_FACTOR:
572 case AL_DOPPLER_VELOCITY:
573 case AL_DISTANCE_MODEL:
574 case AL_SPEED_OF_SOUND:
575 case AL_DEFERRED_UPDATES_SOFT:
576 case AL_GAIN_LIMIT_SOFT:
577 case AL_NUM_RESAMPLERS_SOFT:
578 case AL_DEFAULT_RESAMPLER_SOFT:
579 values[0] = alGetFloat(pname);
580 return;
581 }
582 }
583
584 ContextRef context{GetContextRef()};
585 if UNLIKELY(!context) return;
586
587 if(!values)
588 context->setError(AL_INVALID_VALUE, "NULL pointer");
589 else switch(pname)
590 {
591 default:
592 context->setError(AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname);
593 }
594 }
595 END_API_FUNC
596
alGetIntegerv(ALenum pname,ALint * values)597 AL_API void AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
598 START_API_FUNC
599 {
600 if(values)
601 {
602 switch(pname)
603 {
604 case AL_DOPPLER_FACTOR:
605 case AL_DOPPLER_VELOCITY:
606 case AL_DISTANCE_MODEL:
607 case AL_SPEED_OF_SOUND:
608 case AL_DEFERRED_UPDATES_SOFT:
609 case AL_GAIN_LIMIT_SOFT:
610 case AL_NUM_RESAMPLERS_SOFT:
611 case AL_DEFAULT_RESAMPLER_SOFT:
612 values[0] = alGetInteger(pname);
613 return;
614 }
615 }
616
617 ContextRef context{GetContextRef()};
618 if UNLIKELY(!context) return;
619
620 if(!values)
621 context->setError(AL_INVALID_VALUE, "NULL pointer");
622 else switch(pname)
623 {
624 default:
625 context->setError(AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname);
626 }
627 }
628 END_API_FUNC
629
alGetInteger64vSOFT(ALenum pname,ALint64SOFT * values)630 extern "C" AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
631 START_API_FUNC
632 {
633 if(values)
634 {
635 switch(pname)
636 {
637 case AL_DOPPLER_FACTOR:
638 case AL_DOPPLER_VELOCITY:
639 case AL_DISTANCE_MODEL:
640 case AL_SPEED_OF_SOUND:
641 case AL_DEFERRED_UPDATES_SOFT:
642 case AL_GAIN_LIMIT_SOFT:
643 case AL_NUM_RESAMPLERS_SOFT:
644 case AL_DEFAULT_RESAMPLER_SOFT:
645 values[0] = alGetInteger64SOFT(pname);
646 return;
647 }
648 }
649
650 ContextRef context{GetContextRef()};
651 if UNLIKELY(!context) return;
652
653 if(!values)
654 context->setError(AL_INVALID_VALUE, "NULL pointer");
655 else switch(pname)
656 {
657 default:
658 context->setError(AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname);
659 }
660 }
661 END_API_FUNC
662
alGetPointervSOFT(ALenum pname,ALvoid ** values)663 AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, ALvoid **values)
664 START_API_FUNC
665 {
666 if(values)
667 {
668 switch(pname)
669 {
670 case AL_EVENT_CALLBACK_FUNCTION_SOFT:
671 case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
672 values[0] = alGetPointerSOFT(pname);
673 return;
674 }
675 }
676
677 ContextRef context{GetContextRef()};
678 if UNLIKELY(!context) return;
679
680 if(!values)
681 context->setError(AL_INVALID_VALUE, "NULL pointer");
682 else switch(pname)
683 {
684 default:
685 context->setError(AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname);
686 }
687 }
688 END_API_FUNC
689
alGetString(ALenum pname)690 AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
691 START_API_FUNC
692 {
693 ContextRef context{GetContextRef()};
694 if UNLIKELY(!context) return nullptr;
695
696 const ALchar *value{nullptr};
697 switch(pname)
698 {
699 case AL_VENDOR:
700 value = alVendor;
701 break;
702
703 case AL_VERSION:
704 value = alVersion;
705 break;
706
707 case AL_RENDERER:
708 value = alRenderer;
709 break;
710
711 case AL_EXTENSIONS:
712 value = context->mExtensionList;
713 break;
714
715 case AL_NO_ERROR:
716 value = alNoError;
717 break;
718
719 case AL_INVALID_NAME:
720 value = alErrInvalidName;
721 break;
722
723 case AL_INVALID_ENUM:
724 value = alErrInvalidEnum;
725 break;
726
727 case AL_INVALID_VALUE:
728 value = alErrInvalidValue;
729 break;
730
731 case AL_INVALID_OPERATION:
732 value = alErrInvalidOp;
733 break;
734
735 case AL_OUT_OF_MEMORY:
736 value = alErrOutOfMemory;
737 break;
738
739 default:
740 context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
741 }
742 return value;
743 }
744 END_API_FUNC
745
alDopplerFactor(ALfloat value)746 AL_API void AL_APIENTRY alDopplerFactor(ALfloat value)
747 START_API_FUNC
748 {
749 ContextRef context{GetContextRef()};
750 if UNLIKELY(!context) return;
751
752 if(!(value >= 0.0f && std::isfinite(value)))
753 context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value);
754 else
755 {
756 std::lock_guard<std::mutex> _{context->mPropLock};
757 context->mDopplerFactor = value;
758 DO_UPDATEPROPS();
759 }
760 }
761 END_API_FUNC
762
alDopplerVelocity(ALfloat value)763 AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value)
764 START_API_FUNC
765 {
766 ContextRef context{GetContextRef()};
767 if UNLIKELY(!context) return;
768
769 if(!(value >= 0.0f && std::isfinite(value)))
770 context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
771 else
772 {
773 std::lock_guard<std::mutex> _{context->mPropLock};
774 context->mDopplerVelocity = value;
775 DO_UPDATEPROPS();
776 }
777 }
778 END_API_FUNC
779
alSpeedOfSound(ALfloat value)780 AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value)
781 START_API_FUNC
782 {
783 ContextRef context{GetContextRef()};
784 if UNLIKELY(!context) return;
785
786 if(!(value > 0.0f && std::isfinite(value)))
787 context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value);
788 else
789 {
790 std::lock_guard<std::mutex> _{context->mPropLock};
791 context->mSpeedOfSound = value;
792 DO_UPDATEPROPS();
793 }
794 }
795 END_API_FUNC
796
alDistanceModel(ALenum value)797 AL_API void AL_APIENTRY alDistanceModel(ALenum value)
798 START_API_FUNC
799 {
800 ContextRef context{GetContextRef()};
801 if UNLIKELY(!context) return;
802
803 if(auto model = DistanceModelFromALenum(value))
804 {
805 std::lock_guard<std::mutex> _{context->mPropLock};
806 context->mDistanceModel = *model;
807 if(!context->mSourceDistanceModel)
808 DO_UPDATEPROPS();
809 }
810 else
811 context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
812 }
813 END_API_FUNC
814
815
alDeferUpdatesSOFT(void)816 AL_API void AL_APIENTRY alDeferUpdatesSOFT(void)
817 START_API_FUNC
818 {
819 ContextRef context{GetContextRef()};
820 if UNLIKELY(!context) return;
821
822 context->deferUpdates();
823 }
824 END_API_FUNC
825
alProcessUpdatesSOFT(void)826 AL_API void AL_APIENTRY alProcessUpdatesSOFT(void)
827 START_API_FUNC
828 {
829 ContextRef context{GetContextRef()};
830 if UNLIKELY(!context) return;
831
832 context->processUpdates();
833 }
834 END_API_FUNC
835
836
alGetStringiSOFT(ALenum pname,ALsizei index)837 AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
838 START_API_FUNC
839 {
840 ContextRef context{GetContextRef()};
841 if UNLIKELY(!context) return nullptr;
842
843 const ALchar *value{nullptr};
844 switch(pname)
845 {
846 case AL_RESAMPLER_NAME_SOFT:
847 if(index < 0 || index > static_cast<ALint>(Resampler::Max))
848 context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index);
849 else
850 value = GetResamplerName(static_cast<Resampler>(index));
851 break;
852
853 default:
854 context->setError(AL_INVALID_VALUE, "Invalid string indexed property");
855 }
856 return value;
857 }
858 END_API_FUNC
859
860
UpdateContextProps(ALCcontext * context)861 void UpdateContextProps(ALCcontext *context)
862 {
863 /* Get an unused proprty container, or allocate a new one as needed. */
864 ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)};
865 if(!props)
866 props = new ContextProps{};
867 else
868 {
869 ContextProps *next;
870 do {
871 next = props->next.load(std::memory_order_relaxed);
872 } while(context->mFreeContextProps.compare_exchange_weak(props, next,
873 std::memory_order_seq_cst, std::memory_order_acquire) == 0);
874 }
875
876 /* Copy in current property values. */
877 props->DopplerFactor = context->mDopplerFactor;
878 props->DopplerVelocity = context->mDopplerVelocity;
879 props->SpeedOfSound = context->mSpeedOfSound;
880
881 props->SourceDistanceModel = context->mSourceDistanceModel;
882 props->mDistanceModel = context->mDistanceModel;
883
884 /* Set the new container for updating internal parameters. */
885 props = context->mParams.ContextUpdate.exchange(props, std::memory_order_acq_rel);
886 if(props)
887 {
888 /* If there was an unused update container, put it back in the
889 * freelist.
890 */
891 AtomicReplaceHead(context->mFreeContextProps, props);
892 }
893 }
894