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.
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.
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
29 #include "alcontext.h"
33 #include "backends/base.h"
38 constexpr ALchar alVendor
[] = "OpenAL Community";
39 constexpr ALchar alVersion
[] = "1.1 ALSOFT " ALSOFT_VERSION
;
40 constexpr ALchar alRenderer
[] = "OpenAL Soft";
43 constexpr ALchar alNoError
[] = "No Error";
44 constexpr ALchar alErrInvalidName
[] = "Invalid Name";
45 constexpr ALchar alErrInvalidEnum
[] = "Invalid Enum";
46 constexpr ALchar alErrInvalidValue
[] = "Invalid Value";
47 constexpr ALchar alErrInvalidOp
[] = "Invalid Operation";
48 constexpr ALchar alErrOutOfMemory
[] = "Out of Memory";
50 /* Resampler strings */
51 constexpr ALchar alPointResampler
[] = "Nearest";
52 constexpr ALchar alLinearResampler
[] = "Linear";
53 constexpr ALchar alCubicResampler
[] = "Cubic";
54 constexpr ALchar alBSinc12Resampler
[] = "11th order Sinc";
55 constexpr ALchar alBSinc24Resampler
[] = "23rd order Sinc";
59 /* WARNING: Non-standard export! Not part of any extension, or exposed in the
62 extern "C" AL_API
const ALchar
* AL_APIENTRY
alsoft_get_version(void)
64 const char *spoof
{getenv("ALSOFT_SPOOF_VERSION")};
65 if(spoof
&& spoof
[0] != '\0') return spoof
;
66 return ALSOFT_VERSION
;
69 #define DO_UPDATEPROPS() do { \
70 if(!context->DeferUpdates.load(std::memory_order_acquire)) \
71 UpdateContextProps(context.get()); \
73 context->PropsClean.clear(std::memory_order_release); \
77 AL_API ALvoid AL_APIENTRY
alEnable(ALenum capability
)
79 ContextRef context
{GetContextRef()};
80 if(UNLIKELY(!context
)) return;
82 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
85 case AL_SOURCE_DISTANCE_MODEL
:
86 context
->SourceDistanceModel
= AL_TRUE
;
91 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid enable property 0x%04x", capability
);
95 AL_API ALvoid AL_APIENTRY
alDisable(ALenum capability
)
97 ContextRef context
{GetContextRef()};
98 if(UNLIKELY(!context
)) return;
100 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
103 case AL_SOURCE_DISTANCE_MODEL
:
104 context
->SourceDistanceModel
= AL_FALSE
;
109 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid disable property 0x%04x", capability
);
113 AL_API ALboolean AL_APIENTRY
alIsEnabled(ALenum capability
)
115 ContextRef context
{GetContextRef()};
116 if(UNLIKELY(!context
)) return AL_FALSE
;
118 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
119 ALboolean value
{AL_FALSE
};
122 case AL_SOURCE_DISTANCE_MODEL
:
123 value
= context
->SourceDistanceModel
;
127 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid is enabled property 0x%04x", capability
);
133 AL_API ALboolean AL_APIENTRY
alGetBoolean(ALenum pname
)
135 ContextRef context
{GetContextRef()};
136 if(UNLIKELY(!context
)) return AL_FALSE
;
138 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
139 ALboolean value
{AL_FALSE
};
142 case AL_DOPPLER_FACTOR
:
143 if(context
->DopplerFactor
!= 0.0f
)
147 case AL_DOPPLER_VELOCITY
:
148 if(context
->DopplerVelocity
!= 0.0f
)
152 case AL_DISTANCE_MODEL
:
153 if(context
->mDistanceModel
== DistanceModel::Default
)
157 case AL_SPEED_OF_SOUND
:
158 if(context
->SpeedOfSound
!= 0.0f
)
162 case AL_DEFERRED_UPDATES_SOFT
:
163 if(context
->DeferUpdates
.load(std::memory_order_acquire
))
167 case AL_GAIN_LIMIT_SOFT
:
168 if(GAIN_MIX_MAX
/context
->GainBoost
!= 0.0f
)
172 case AL_NUM_RESAMPLERS_SOFT
:
177 case AL_DEFAULT_RESAMPLER_SOFT
:
178 value
= ResamplerDefault
? AL_TRUE
: AL_FALSE
;
182 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid boolean property 0x%04x", pname
);
188 AL_API ALdouble AL_APIENTRY
alGetDouble(ALenum pname
)
190 ContextRef context
{GetContextRef()};
191 if(UNLIKELY(!context
)) return 0.0;
193 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
197 case AL_DOPPLER_FACTOR
:
198 value
= (ALdouble
)context
->DopplerFactor
;
201 case AL_DOPPLER_VELOCITY
:
202 value
= (ALdouble
)context
->DopplerVelocity
;
205 case AL_DISTANCE_MODEL
:
206 value
= (ALdouble
)context
->mDistanceModel
;
209 case AL_SPEED_OF_SOUND
:
210 value
= (ALdouble
)context
->SpeedOfSound
;
213 case AL_DEFERRED_UPDATES_SOFT
:
214 if(context
->DeferUpdates
.load(std::memory_order_acquire
))
215 value
= (ALdouble
)AL_TRUE
;
218 case AL_GAIN_LIMIT_SOFT
:
219 value
= (ALdouble
)GAIN_MIX_MAX
/context
->GainBoost
;
222 case AL_NUM_RESAMPLERS_SOFT
:
223 value
= (ALdouble
)(ResamplerMax
+ 1);
226 case AL_DEFAULT_RESAMPLER_SOFT
:
227 value
= (ALdouble
)ResamplerDefault
;
231 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid double property 0x%04x", pname
);
237 AL_API ALfloat AL_APIENTRY
alGetFloat(ALenum pname
)
239 ContextRef context
{GetContextRef()};
240 if(UNLIKELY(!context
)) return 0.0f
;
242 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
246 case AL_DOPPLER_FACTOR
:
247 value
= context
->DopplerFactor
;
250 case AL_DOPPLER_VELOCITY
:
251 value
= context
->DopplerVelocity
;
254 case AL_DISTANCE_MODEL
:
255 value
= (ALfloat
)context
->mDistanceModel
;
258 case AL_SPEED_OF_SOUND
:
259 value
= context
->SpeedOfSound
;
262 case AL_DEFERRED_UPDATES_SOFT
:
263 if(context
->DeferUpdates
.load(std::memory_order_acquire
))
264 value
= (ALfloat
)AL_TRUE
;
267 case AL_GAIN_LIMIT_SOFT
:
268 value
= GAIN_MIX_MAX
/context
->GainBoost
;
271 case AL_NUM_RESAMPLERS_SOFT
:
272 value
= (ALfloat
)(ResamplerMax
+ 1);
275 case AL_DEFAULT_RESAMPLER_SOFT
:
276 value
= (ALfloat
)ResamplerDefault
;
280 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid float property 0x%04x", pname
);
286 AL_API ALint AL_APIENTRY
alGetInteger(ALenum pname
)
288 ContextRef context
{GetContextRef()};
289 if(UNLIKELY(!context
)) return 0;
291 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
295 case AL_DOPPLER_FACTOR
:
296 value
= (ALint
)context
->DopplerFactor
;
299 case AL_DOPPLER_VELOCITY
:
300 value
= (ALint
)context
->DopplerVelocity
;
303 case AL_DISTANCE_MODEL
:
304 value
= (ALint
)context
->mDistanceModel
;
307 case AL_SPEED_OF_SOUND
:
308 value
= (ALint
)context
->SpeedOfSound
;
311 case AL_DEFERRED_UPDATES_SOFT
:
312 if(context
->DeferUpdates
.load(std::memory_order_acquire
))
313 value
= (ALint
)AL_TRUE
;
316 case AL_GAIN_LIMIT_SOFT
:
317 value
= (ALint
)(GAIN_MIX_MAX
/context
->GainBoost
);
320 case AL_NUM_RESAMPLERS_SOFT
:
321 value
= ResamplerMax
+ 1;
324 case AL_DEFAULT_RESAMPLER_SOFT
:
325 value
= ResamplerDefault
;
329 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid integer property 0x%04x", pname
);
335 extern "C" AL_API ALint64SOFT AL_APIENTRY
alGetInteger64SOFT(ALenum pname
)
337 ContextRef context
{GetContextRef()};
338 if(UNLIKELY(!context
)) return 0;
340 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
341 ALint64SOFT value
{0};
344 case AL_DOPPLER_FACTOR
:
345 value
= (ALint64SOFT
)context
->DopplerFactor
;
348 case AL_DOPPLER_VELOCITY
:
349 value
= (ALint64SOFT
)context
->DopplerVelocity
;
352 case AL_DISTANCE_MODEL
:
353 value
= (ALint64SOFT
)context
->mDistanceModel
;
356 case AL_SPEED_OF_SOUND
:
357 value
= (ALint64SOFT
)context
->SpeedOfSound
;
360 case AL_DEFERRED_UPDATES_SOFT
:
361 if(context
->DeferUpdates
.load(std::memory_order_acquire
))
362 value
= (ALint64SOFT
)AL_TRUE
;
365 case AL_GAIN_LIMIT_SOFT
:
366 value
= (ALint64SOFT
)(GAIN_MIX_MAX
/context
->GainBoost
);
369 case AL_NUM_RESAMPLERS_SOFT
:
370 value
= (ALint64SOFT
)(ResamplerMax
+ 1);
373 case AL_DEFAULT_RESAMPLER_SOFT
:
374 value
= (ALint64SOFT
)ResamplerDefault
;
378 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid integer64 property 0x%04x", pname
);
384 AL_API
void* AL_APIENTRY
alGetPointerSOFT(ALenum pname
)
386 ContextRef context
{GetContextRef()};
387 if(UNLIKELY(!context
)) return nullptr;
389 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
390 void *value
{nullptr};
393 case AL_EVENT_CALLBACK_FUNCTION_SOFT
:
394 value
= reinterpret_cast<void*>(context
->EventCb
);
397 case AL_EVENT_CALLBACK_USER_PARAM_SOFT
:
398 value
= context
->EventParam
;
402 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid pointer property 0x%04x", pname
);
408 AL_API ALvoid AL_APIENTRY
alGetBooleanv(ALenum pname
, ALboolean
*values
)
414 case AL_DOPPLER_FACTOR
:
415 case AL_DOPPLER_VELOCITY
:
416 case AL_DISTANCE_MODEL
:
417 case AL_SPEED_OF_SOUND
:
418 case AL_DEFERRED_UPDATES_SOFT
:
419 case AL_GAIN_LIMIT_SOFT
:
420 case AL_NUM_RESAMPLERS_SOFT
:
421 case AL_DEFAULT_RESAMPLER_SOFT
:
422 values
[0] = alGetBoolean(pname
);
427 ContextRef context
{GetContextRef()};
428 if(UNLIKELY(!context
)) return;
431 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
435 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid boolean-vector property 0x%04x", pname
);
439 AL_API ALvoid AL_APIENTRY
alGetDoublev(ALenum pname
, ALdouble
*values
)
445 case AL_DOPPLER_FACTOR
:
446 case AL_DOPPLER_VELOCITY
:
447 case AL_DISTANCE_MODEL
:
448 case AL_SPEED_OF_SOUND
:
449 case AL_DEFERRED_UPDATES_SOFT
:
450 case AL_GAIN_LIMIT_SOFT
:
451 case AL_NUM_RESAMPLERS_SOFT
:
452 case AL_DEFAULT_RESAMPLER_SOFT
:
453 values
[0] = alGetDouble(pname
);
458 ContextRef context
{GetContextRef()};
459 if(UNLIKELY(!context
)) return;
462 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
466 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid double-vector property 0x%04x", pname
);
470 AL_API ALvoid AL_APIENTRY
alGetFloatv(ALenum pname
, ALfloat
*values
)
476 case AL_DOPPLER_FACTOR
:
477 case AL_DOPPLER_VELOCITY
:
478 case AL_DISTANCE_MODEL
:
479 case AL_SPEED_OF_SOUND
:
480 case AL_DEFERRED_UPDATES_SOFT
:
481 case AL_GAIN_LIMIT_SOFT
:
482 case AL_NUM_RESAMPLERS_SOFT
:
483 case AL_DEFAULT_RESAMPLER_SOFT
:
484 values
[0] = alGetFloat(pname
);
489 ContextRef context
{GetContextRef()};
490 if(UNLIKELY(!context
)) return;
493 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
497 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid float-vector property 0x%04x", pname
);
501 AL_API ALvoid AL_APIENTRY
alGetIntegerv(ALenum pname
, ALint
*values
)
507 case AL_DOPPLER_FACTOR
:
508 case AL_DOPPLER_VELOCITY
:
509 case AL_DISTANCE_MODEL
:
510 case AL_SPEED_OF_SOUND
:
511 case AL_DEFERRED_UPDATES_SOFT
:
512 case AL_GAIN_LIMIT_SOFT
:
513 case AL_NUM_RESAMPLERS_SOFT
:
514 case AL_DEFAULT_RESAMPLER_SOFT
:
515 values
[0] = alGetInteger(pname
);
520 ContextRef context
{GetContextRef()};
521 if(UNLIKELY(!context
)) return;
524 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
528 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid integer-vector property 0x%04x", pname
);
532 extern "C" AL_API
void AL_APIENTRY
alGetInteger64vSOFT(ALenum pname
, ALint64SOFT
*values
)
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] = alGetInteger64SOFT(pname
);
551 ContextRef context
{GetContextRef()};
552 if(UNLIKELY(!context
)) return;
555 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
559 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid integer64-vector property 0x%04x", pname
);
563 AL_API
void AL_APIENTRY
alGetPointervSOFT(ALenum pname
, void **values
)
569 case AL_EVENT_CALLBACK_FUNCTION_SOFT
:
570 case AL_EVENT_CALLBACK_USER_PARAM_SOFT
:
571 values
[0] = alGetPointerSOFT(pname
);
576 ContextRef context
{GetContextRef()};
577 if(UNLIKELY(!context
)) return;
580 alSetError(context
.get(), AL_INVALID_VALUE
, "NULL pointer");
584 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid pointer-vector property 0x%04x", pname
);
588 AL_API
const ALchar
* AL_APIENTRY
alGetString(ALenum pname
)
590 ContextRef context
{GetContextRef()};
591 if(UNLIKELY(!context
)) return nullptr;
593 const ALchar
*value
{nullptr};
609 value
= context
->ExtensionList
;
616 case AL_INVALID_NAME
:
617 value
= alErrInvalidName
;
620 case AL_INVALID_ENUM
:
621 value
= alErrInvalidEnum
;
624 case AL_INVALID_VALUE
:
625 value
= alErrInvalidValue
;
628 case AL_INVALID_OPERATION
:
629 value
= alErrInvalidOp
;
632 case AL_OUT_OF_MEMORY
:
633 value
= alErrOutOfMemory
;
637 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid string property 0x%04x", pname
);
642 AL_API ALvoid AL_APIENTRY
alDopplerFactor(ALfloat value
)
644 ContextRef context
{GetContextRef()};
645 if(UNLIKELY(!context
)) return;
647 if(!(value
>= 0.0f
&& std::isfinite(value
)))
648 alSetError(context
.get(), AL_INVALID_VALUE
, "Doppler factor %f out of range", value
);
651 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
652 context
->DopplerFactor
= value
;
657 AL_API ALvoid AL_APIENTRY
alDopplerVelocity(ALfloat value
)
659 ContextRef context
{GetContextRef()};
660 if(UNLIKELY(!context
)) return;
662 if((context
->EnabledEvts
.load(std::memory_order_relaxed
)&EventType_Deprecated
))
664 static constexpr ALCchar msg
[] =
665 "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound";
666 const ALsizei msglen
= (ALsizei
)strlen(msg
);
667 std::lock_guard
<std::mutex
> _
{context
->EventCbLock
};
668 ALbitfieldSOFT enabledevts
{context
->EnabledEvts
.load(std::memory_order_relaxed
)};
669 if((enabledevts
&EventType_Deprecated
) && context
->EventCb
)
670 (*context
->EventCb
)(AL_EVENT_TYPE_DEPRECATED_SOFT
, 0, 0, msglen
, msg
,
671 context
->EventParam
);
674 if(!(value
>= 0.0f
&& std::isfinite(value
)))
675 alSetError(context
.get(), AL_INVALID_VALUE
, "Doppler velocity %f out of range", value
);
678 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
679 context
->DopplerVelocity
= value
;
684 AL_API ALvoid AL_APIENTRY
alSpeedOfSound(ALfloat value
)
686 ContextRef context
{GetContextRef()};
687 if(UNLIKELY(!context
)) return;
689 if(!(value
> 0.0f
&& std::isfinite(value
)))
690 alSetError(context
.get(), AL_INVALID_VALUE
, "Speed of sound %f out of range", value
);
693 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
694 context
->SpeedOfSound
= value
;
699 AL_API ALvoid AL_APIENTRY
alDistanceModel(ALenum value
)
701 ContextRef context
{GetContextRef()};
702 if(UNLIKELY(!context
)) return;
704 if(!(value
== AL_INVERSE_DISTANCE
|| value
== AL_INVERSE_DISTANCE_CLAMPED
||
705 value
== AL_LINEAR_DISTANCE
|| value
== AL_LINEAR_DISTANCE_CLAMPED
||
706 value
== AL_EXPONENT_DISTANCE
|| value
== AL_EXPONENT_DISTANCE_CLAMPED
||
708 alSetError(context
.get(), AL_INVALID_VALUE
, "Distance model 0x%04x out of range", value
);
711 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
712 context
->mDistanceModel
= static_cast<DistanceModel
>(value
);
713 if(!context
->SourceDistanceModel
)
719 AL_API ALvoid AL_APIENTRY
alDeferUpdatesSOFT(void)
721 ContextRef context
{GetContextRef()};
722 if(UNLIKELY(!context
)) return;
724 ALCcontext_DeferUpdates(context
.get());
727 AL_API ALvoid AL_APIENTRY
alProcessUpdatesSOFT(void)
729 ContextRef context
{GetContextRef()};
730 if(UNLIKELY(!context
)) return;
732 ALCcontext_ProcessUpdates(context
.get());
736 AL_API
const ALchar
* AL_APIENTRY
alGetStringiSOFT(ALenum pname
, ALsizei index
)
738 const char *ResamplerNames
[] = {
739 alPointResampler
, alLinearResampler
,
740 alCubicResampler
, alBSinc12Resampler
,
743 static_assert(COUNTOF(ResamplerNames
) == ResamplerMax
+1, "Incorrect ResamplerNames list");
745 ContextRef context
{GetContextRef()};
746 if(UNLIKELY(!context
)) return nullptr;
748 const ALchar
*value
{nullptr};
751 case AL_RESAMPLER_NAME_SOFT
:
752 if(index
< 0 || (size_t)index
>= COUNTOF(ResamplerNames
))
753 alSetError(context
.get(), AL_INVALID_VALUE
, "Resampler name index %d out of range",
756 value
= ResamplerNames
[index
];
760 alSetError(context
.get(), AL_INVALID_VALUE
, "Invalid string indexed property");
766 void UpdateContextProps(ALCcontext
*context
)
768 /* Get an unused proprty container, or allocate a new one as needed. */
769 struct ALcontextProps
*props
{context
->FreeContextProps
.load(std::memory_order_acquire
)};
771 props
= static_cast<ALcontextProps
*>(al_calloc(16, sizeof(*props
)));
774 struct ALcontextProps
*next
;
776 next
= props
->next
.load(std::memory_order_relaxed
);
777 } while(context
->FreeContextProps
.compare_exchange_weak(props
, next
,
778 std::memory_order_seq_cst
, std::memory_order_acquire
) == 0);
781 /* Copy in current property values. */
782 props
->MetersPerUnit
= context
->MetersPerUnit
;
784 props
->DopplerFactor
= context
->DopplerFactor
;
785 props
->DopplerVelocity
= context
->DopplerVelocity
;
786 props
->SpeedOfSound
= context
->SpeedOfSound
;
788 props
->SourceDistanceModel
= context
->SourceDistanceModel
;
789 props
->mDistanceModel
= context
->mDistanceModel
;
791 /* Set the new container for updating internal parameters. */
792 props
= context
->Update
.exchange(props
, std::memory_order_acq_rel
);
795 /* If there was an unused update container, put it back in the
798 AtomicReplaceHead(context
->FreeContextProps
, props
);