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
35 #include "alcontext.h"
38 #include "alnumeric.h"
43 #include "inprogext.h"
44 #include "opthelpers.h"
50 constexpr ALchar alVendor
[] = "OpenAL Community";
51 constexpr ALchar alVersion
[] = "1.1 ALSOFT " ALSOFT_VERSION
;
52 constexpr ALchar alRenderer
[] = "OpenAL Soft";
55 constexpr ALchar alNoError
[] = "No Error";
56 constexpr ALchar alErrInvalidName
[] = "Invalid Name";
57 constexpr ALchar alErrInvalidEnum
[] = "Invalid Enum";
58 constexpr ALchar alErrInvalidValue
[] = "Invalid Value";
59 constexpr ALchar alErrInvalidOp
[] = "Invalid Operation";
60 constexpr ALchar alErrOutOfMemory
[] = "Out of Memory";
62 /* Resampler strings */
63 template<Resampler rtype
> struct ResamplerName
{ };
64 template<> struct ResamplerName
<Resampler::Point
>
65 { static constexpr const ALchar
*Get() noexcept
{ return "Nearest"; } };
66 template<> struct ResamplerName
<Resampler::Linear
>
67 { static constexpr const ALchar
*Get() noexcept
{ return "Linear"; } };
68 template<> struct ResamplerName
<Resampler::Cubic
>
69 { static constexpr const ALchar
*Get() noexcept
{ return "Cubic"; } };
70 template<> struct ResamplerName
<Resampler::FastBSinc12
>
71 { static constexpr const ALchar
*Get() noexcept
{ return "11th order Sinc (fast)"; } };
72 template<> struct ResamplerName
<Resampler::BSinc12
>
73 { static constexpr const ALchar
*Get() noexcept
{ return "11th order Sinc"; } };
74 template<> struct ResamplerName
<Resampler::FastBSinc24
>
75 { static constexpr const ALchar
*Get() noexcept
{ return "23rd order Sinc (fast)"; } };
76 template<> struct ResamplerName
<Resampler::BSinc24
>
77 { static constexpr const ALchar
*Get() noexcept
{ return "23rd order Sinc"; } };
79 const ALchar
*GetResamplerName(const Resampler rtype
)
81 #define HANDLE_RESAMPLER(r) case r: return ResamplerName<r>::Get()
84 HANDLE_RESAMPLER(Resampler::Point
);
85 HANDLE_RESAMPLER(Resampler::Linear
);
86 HANDLE_RESAMPLER(Resampler::Cubic
);
87 HANDLE_RESAMPLER(Resampler::FastBSinc12
);
88 HANDLE_RESAMPLER(Resampler::BSinc12
);
89 HANDLE_RESAMPLER(Resampler::FastBSinc24
);
90 HANDLE_RESAMPLER(Resampler::BSinc24
);
92 #undef HANDLE_RESAMPLER
93 /* Should never get here. */
94 throw std::runtime_error
{"Unexpected resampler index"};
99 /* WARNING: Non-standard export! Not part of any extension, or exposed in the
102 extern "C" AL_API
const ALchar
* AL_APIENTRY
alsoft_get_version(void)
105 static const auto spoof
= al::getenv("ALSOFT_SPOOF_VERSION");
106 if(spoof
) return spoof
->c_str();
107 return ALSOFT_VERSION
;
111 #define DO_UPDATEPROPS() do { \
112 if(!context->mDeferUpdates.load(std::memory_order_acquire)) \
113 UpdateContextProps(context.get()); \
115 context->mPropsClean.clear(std::memory_order_release); \
119 AL_API
void AL_APIENTRY
alEnable(ALenum capability
)
122 ContextRef context
{GetContextRef()};
123 if UNLIKELY(!context
) return;
125 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
128 case AL_SOURCE_DISTANCE_MODEL
:
129 context
->mSourceDistanceModel
= true;
134 context
->setError(AL_INVALID_VALUE
, "Invalid enable property 0x%04x", capability
);
139 AL_API
void AL_APIENTRY
alDisable(ALenum capability
)
142 ContextRef context
{GetContextRef()};
143 if UNLIKELY(!context
) return;
145 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
148 case AL_SOURCE_DISTANCE_MODEL
:
149 context
->mSourceDistanceModel
= false;
154 context
->setError(AL_INVALID_VALUE
, "Invalid disable property 0x%04x", capability
);
159 AL_API ALboolean AL_APIENTRY
alIsEnabled(ALenum capability
)
162 ContextRef context
{GetContextRef()};
163 if UNLIKELY(!context
) return AL_FALSE
;
165 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
166 ALboolean value
{AL_FALSE
};
169 case AL_SOURCE_DISTANCE_MODEL
:
170 value
= context
->mSourceDistanceModel
? AL_TRUE
: AL_FALSE
;
174 context
->setError(AL_INVALID_VALUE
, "Invalid is enabled property 0x%04x", capability
);
181 AL_API ALboolean AL_APIENTRY
alGetBoolean(ALenum pname
)
184 ContextRef context
{GetContextRef()};
185 if UNLIKELY(!context
) return AL_FALSE
;
187 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
188 ALboolean value
{AL_FALSE
};
191 case AL_DOPPLER_FACTOR
:
192 if(context
->mDopplerFactor
!= 0.0f
)
196 case AL_DOPPLER_VELOCITY
:
197 if(context
->mDopplerVelocity
!= 0.0f
)
201 case AL_DISTANCE_MODEL
:
202 if(context
->mDistanceModel
== DistanceModel::Default
)
206 case AL_SPEED_OF_SOUND
:
207 if(context
->mSpeedOfSound
!= 0.0f
)
211 case AL_DEFERRED_UPDATES_SOFT
:
212 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
216 case AL_GAIN_LIMIT_SOFT
:
217 if(GAIN_MIX_MAX
/context
->mGainBoost
!= 0.0f
)
221 case AL_NUM_RESAMPLERS_SOFT
:
226 case AL_DEFAULT_RESAMPLER_SOFT
:
227 value
= static_cast<int>(ResamplerDefault
) ? AL_TRUE
: AL_FALSE
;
231 context
->setError(AL_INVALID_VALUE
, "Invalid boolean property 0x%04x", pname
);
238 AL_API ALdouble AL_APIENTRY
alGetDouble(ALenum pname
)
241 ContextRef context
{GetContextRef()};
242 if UNLIKELY(!context
) return 0.0;
244 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
248 case AL_DOPPLER_FACTOR
:
249 value
= context
->mDopplerFactor
;
252 case AL_DOPPLER_VELOCITY
:
253 value
= context
->mDopplerVelocity
;
256 case AL_DISTANCE_MODEL
:
257 value
= static_cast<ALdouble
>(context
->mDistanceModel
);
260 case AL_SPEED_OF_SOUND
:
261 value
= context
->mSpeedOfSound
;
264 case AL_DEFERRED_UPDATES_SOFT
:
265 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
266 value
= static_cast<ALdouble
>(AL_TRUE
);
269 case AL_GAIN_LIMIT_SOFT
:
270 value
= ALdouble
{GAIN_MIX_MAX
}/context
->mGainBoost
;
273 case AL_NUM_RESAMPLERS_SOFT
:
274 value
= static_cast<ALdouble
>(Resampler::Max
) + 1.0;
277 case AL_DEFAULT_RESAMPLER_SOFT
:
278 value
= static_cast<ALdouble
>(ResamplerDefault
);
282 context
->setError(AL_INVALID_VALUE
, "Invalid double property 0x%04x", pname
);
289 AL_API ALfloat AL_APIENTRY
alGetFloat(ALenum pname
)
292 ContextRef context
{GetContextRef()};
293 if UNLIKELY(!context
) return 0.0f
;
295 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
299 case AL_DOPPLER_FACTOR
:
300 value
= context
->mDopplerFactor
;
303 case AL_DOPPLER_VELOCITY
:
304 value
= context
->mDopplerVelocity
;
307 case AL_DISTANCE_MODEL
:
308 value
= static_cast<ALfloat
>(context
->mDistanceModel
);
311 case AL_SPEED_OF_SOUND
:
312 value
= context
->mSpeedOfSound
;
315 case AL_DEFERRED_UPDATES_SOFT
:
316 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
317 value
= static_cast<ALfloat
>(AL_TRUE
);
320 case AL_GAIN_LIMIT_SOFT
:
321 value
= GAIN_MIX_MAX
/context
->mGainBoost
;
324 case AL_NUM_RESAMPLERS_SOFT
:
325 value
= static_cast<ALfloat
>(Resampler::Max
) + 1.0f
;
328 case AL_DEFAULT_RESAMPLER_SOFT
:
329 value
= static_cast<ALfloat
>(ResamplerDefault
);
333 context
->setError(AL_INVALID_VALUE
, "Invalid float property 0x%04x", pname
);
340 AL_API ALint AL_APIENTRY
alGetInteger(ALenum pname
)
343 ContextRef context
{GetContextRef()};
344 if UNLIKELY(!context
) return 0;
346 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
350 case AL_DOPPLER_FACTOR
:
351 value
= static_cast<ALint
>(context
->mDopplerFactor
);
354 case AL_DOPPLER_VELOCITY
:
355 value
= static_cast<ALint
>(context
->mDopplerVelocity
);
358 case AL_DISTANCE_MODEL
:
359 value
= static_cast<ALint
>(context
->mDistanceModel
);
362 case AL_SPEED_OF_SOUND
:
363 value
= static_cast<ALint
>(context
->mSpeedOfSound
);
366 case AL_DEFERRED_UPDATES_SOFT
:
367 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
371 case AL_GAIN_LIMIT_SOFT
:
372 value
= static_cast<ALint
>(GAIN_MIX_MAX
/context
->mGainBoost
);
375 case AL_NUM_RESAMPLERS_SOFT
:
376 value
= static_cast<int>(Resampler::Max
) + 1;
379 case AL_DEFAULT_RESAMPLER_SOFT
:
380 value
= static_cast<int>(ResamplerDefault
);
384 context
->setError(AL_INVALID_VALUE
, "Invalid integer property 0x%04x", pname
);
391 extern "C" AL_API ALint64SOFT AL_APIENTRY
alGetInteger64SOFT(ALenum pname
)
394 ContextRef context
{GetContextRef()};
395 if UNLIKELY(!context
) return 0_i64
;
397 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
398 ALint64SOFT value
{0};
401 case AL_DOPPLER_FACTOR
:
402 value
= static_cast<ALint64SOFT
>(context
->mDopplerFactor
);
405 case AL_DOPPLER_VELOCITY
:
406 value
= static_cast<ALint64SOFT
>(context
->mDopplerVelocity
);
409 case AL_DISTANCE_MODEL
:
410 value
= static_cast<ALint64SOFT
>(context
->mDistanceModel
);
413 case AL_SPEED_OF_SOUND
:
414 value
= static_cast<ALint64SOFT
>(context
->mSpeedOfSound
);
417 case AL_DEFERRED_UPDATES_SOFT
:
418 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
422 case AL_GAIN_LIMIT_SOFT
:
423 value
= static_cast<ALint64SOFT
>(GAIN_MIX_MAX
/context
->mGainBoost
);
426 case AL_NUM_RESAMPLERS_SOFT
:
427 value
= static_cast<ALint64SOFT
>(Resampler::Max
) + 1;
430 case AL_DEFAULT_RESAMPLER_SOFT
:
431 value
= static_cast<ALint64SOFT
>(ResamplerDefault
);
435 context
->setError(AL_INVALID_VALUE
, "Invalid integer64 property 0x%04x", pname
);
442 AL_API ALvoid
* AL_APIENTRY
alGetPointerSOFT(ALenum pname
)
445 ContextRef context
{GetContextRef()};
446 if UNLIKELY(!context
) return nullptr;
448 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
449 void *value
{nullptr};
452 case AL_EVENT_CALLBACK_FUNCTION_SOFT
:
453 value
= reinterpret_cast<void*>(context
->mEventCb
);
456 case AL_EVENT_CALLBACK_USER_PARAM_SOFT
:
457 value
= context
->mEventParam
;
461 context
->setError(AL_INVALID_VALUE
, "Invalid pointer property 0x%04x", pname
);
468 AL_API
void AL_APIENTRY
alGetBooleanv(ALenum pname
, ALboolean
*values
)
475 case AL_DOPPLER_FACTOR
:
476 case AL_DOPPLER_VELOCITY
:
477 case AL_DISTANCE_MODEL
:
478 case AL_SPEED_OF_SOUND
:
479 case AL_DEFERRED_UPDATES_SOFT
:
480 case AL_GAIN_LIMIT_SOFT
:
481 case AL_NUM_RESAMPLERS_SOFT
:
482 case AL_DEFAULT_RESAMPLER_SOFT
:
483 values
[0] = alGetBoolean(pname
);
488 ContextRef context
{GetContextRef()};
489 if UNLIKELY(!context
) return;
492 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
496 context
->setError(AL_INVALID_VALUE
, "Invalid boolean-vector property 0x%04x", pname
);
501 AL_API
void AL_APIENTRY
alGetDoublev(ALenum pname
, ALdouble
*values
)
508 case AL_DOPPLER_FACTOR
:
509 case AL_DOPPLER_VELOCITY
:
510 case AL_DISTANCE_MODEL
:
511 case AL_SPEED_OF_SOUND
:
512 case AL_DEFERRED_UPDATES_SOFT
:
513 case AL_GAIN_LIMIT_SOFT
:
514 case AL_NUM_RESAMPLERS_SOFT
:
515 case AL_DEFAULT_RESAMPLER_SOFT
:
516 values
[0] = alGetDouble(pname
);
521 ContextRef context
{GetContextRef()};
522 if UNLIKELY(!context
) return;
525 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
529 context
->setError(AL_INVALID_VALUE
, "Invalid double-vector property 0x%04x", pname
);
534 AL_API
void AL_APIENTRY
alGetFloatv(ALenum pname
, ALfloat
*values
)
541 case AL_DOPPLER_FACTOR
:
542 case AL_DOPPLER_VELOCITY
:
543 case AL_DISTANCE_MODEL
:
544 case AL_SPEED_OF_SOUND
:
545 case AL_DEFERRED_UPDATES_SOFT
:
546 case AL_GAIN_LIMIT_SOFT
:
547 case AL_NUM_RESAMPLERS_SOFT
:
548 case AL_DEFAULT_RESAMPLER_SOFT
:
549 values
[0] = alGetFloat(pname
);
554 ContextRef context
{GetContextRef()};
555 if UNLIKELY(!context
) return;
558 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
562 context
->setError(AL_INVALID_VALUE
, "Invalid float-vector property 0x%04x", pname
);
567 AL_API
void AL_APIENTRY
alGetIntegerv(ALenum pname
, ALint
*values
)
574 case AL_DOPPLER_FACTOR
:
575 case AL_DOPPLER_VELOCITY
:
576 case AL_DISTANCE_MODEL
:
577 case AL_SPEED_OF_SOUND
:
578 case AL_DEFERRED_UPDATES_SOFT
:
579 case AL_GAIN_LIMIT_SOFT
:
580 case AL_NUM_RESAMPLERS_SOFT
:
581 case AL_DEFAULT_RESAMPLER_SOFT
:
582 values
[0] = alGetInteger(pname
);
587 ContextRef context
{GetContextRef()};
588 if UNLIKELY(!context
) return;
591 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
595 context
->setError(AL_INVALID_VALUE
, "Invalid integer-vector property 0x%04x", pname
);
600 extern "C" AL_API
void AL_APIENTRY
alGetInteger64vSOFT(ALenum pname
, ALint64SOFT
*values
)
607 case AL_DOPPLER_FACTOR
:
608 case AL_DOPPLER_VELOCITY
:
609 case AL_DISTANCE_MODEL
:
610 case AL_SPEED_OF_SOUND
:
611 case AL_DEFERRED_UPDATES_SOFT
:
612 case AL_GAIN_LIMIT_SOFT
:
613 case AL_NUM_RESAMPLERS_SOFT
:
614 case AL_DEFAULT_RESAMPLER_SOFT
:
615 values
[0] = alGetInteger64SOFT(pname
);
620 ContextRef context
{GetContextRef()};
621 if UNLIKELY(!context
) return;
624 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
628 context
->setError(AL_INVALID_VALUE
, "Invalid integer64-vector property 0x%04x", pname
);
633 AL_API
void AL_APIENTRY
alGetPointervSOFT(ALenum pname
, ALvoid
**values
)
640 case AL_EVENT_CALLBACK_FUNCTION_SOFT
:
641 case AL_EVENT_CALLBACK_USER_PARAM_SOFT
:
642 values
[0] = alGetPointerSOFT(pname
);
647 ContextRef context
{GetContextRef()};
648 if UNLIKELY(!context
) return;
651 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
655 context
->setError(AL_INVALID_VALUE
, "Invalid pointer-vector property 0x%04x", pname
);
660 AL_API
const ALchar
* AL_APIENTRY
alGetString(ALenum pname
)
663 ContextRef context
{GetContextRef()};
664 if UNLIKELY(!context
) return nullptr;
666 const ALchar
*value
{nullptr};
682 value
= context
->mExtensionList
;
689 case AL_INVALID_NAME
:
690 value
= alErrInvalidName
;
693 case AL_INVALID_ENUM
:
694 value
= alErrInvalidEnum
;
697 case AL_INVALID_VALUE
:
698 value
= alErrInvalidValue
;
701 case AL_INVALID_OPERATION
:
702 value
= alErrInvalidOp
;
705 case AL_OUT_OF_MEMORY
:
706 value
= alErrOutOfMemory
;
710 context
->setError(AL_INVALID_VALUE
, "Invalid string property 0x%04x", pname
);
716 AL_API
void AL_APIENTRY
alDopplerFactor(ALfloat value
)
719 ContextRef context
{GetContextRef()};
720 if UNLIKELY(!context
) return;
722 if(!(value
>= 0.0f
&& std::isfinite(value
)))
723 context
->setError(AL_INVALID_VALUE
, "Doppler factor %f out of range", value
);
726 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
727 context
->mDopplerFactor
= value
;
733 AL_API
void AL_APIENTRY
alDopplerVelocity(ALfloat value
)
736 ContextRef context
{GetContextRef()};
737 if UNLIKELY(!context
) return;
739 if(!(value
>= 0.0f
&& std::isfinite(value
)))
740 context
->setError(AL_INVALID_VALUE
, "Doppler velocity %f out of range", value
);
743 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
744 context
->mDopplerVelocity
= value
;
750 AL_API
void AL_APIENTRY
alSpeedOfSound(ALfloat value
)
753 ContextRef context
{GetContextRef()};
754 if UNLIKELY(!context
) return;
756 if(!(value
> 0.0f
&& std::isfinite(value
)))
757 context
->setError(AL_INVALID_VALUE
, "Speed of sound %f out of range", value
);
760 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
761 context
->mSpeedOfSound
= value
;
767 AL_API
void AL_APIENTRY
alDistanceModel(ALenum value
)
770 ContextRef context
{GetContextRef()};
771 if UNLIKELY(!context
) return;
773 if(!(value
== AL_INVERSE_DISTANCE
|| value
== AL_INVERSE_DISTANCE_CLAMPED
||
774 value
== AL_LINEAR_DISTANCE
|| value
== AL_LINEAR_DISTANCE_CLAMPED
||
775 value
== AL_EXPONENT_DISTANCE
|| value
== AL_EXPONENT_DISTANCE_CLAMPED
||
777 context
->setError(AL_INVALID_VALUE
, "Distance model 0x%04x out of range", value
);
780 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
781 context
->mDistanceModel
= static_cast<DistanceModel
>(value
);
782 if(!context
->mSourceDistanceModel
)
789 AL_API
void AL_APIENTRY
alDeferUpdatesSOFT(void)
792 ContextRef context
{GetContextRef()};
793 if UNLIKELY(!context
) return;
795 context
->deferUpdates();
799 AL_API
void AL_APIENTRY
alProcessUpdatesSOFT(void)
802 ContextRef context
{GetContextRef()};
803 if UNLIKELY(!context
) return;
805 context
->processUpdates();
810 AL_API
const ALchar
* AL_APIENTRY
alGetStringiSOFT(ALenum pname
, ALsizei index
)
813 ContextRef context
{GetContextRef()};
814 if UNLIKELY(!context
) return nullptr;
816 const ALchar
*value
{nullptr};
819 case AL_RESAMPLER_NAME_SOFT
:
820 if(index
< 0 || index
> static_cast<ALint
>(Resampler::Max
))
821 context
->setError(AL_INVALID_VALUE
, "Resampler name index %d out of range", index
);
823 value
= GetResamplerName(static_cast<Resampler
>(index
));
827 context
->setError(AL_INVALID_VALUE
, "Invalid string indexed property");
834 void UpdateContextProps(ALCcontext
*context
)
836 /* Get an unused proprty container, or allocate a new one as needed. */
837 ALcontextProps
*props
{context
->mFreeContextProps
.load(std::memory_order_acquire
)};
839 props
= new ALcontextProps
{};
842 ALcontextProps
*next
;
844 next
= props
->next
.load(std::memory_order_relaxed
);
845 } while(context
->mFreeContextProps
.compare_exchange_weak(props
, next
,
846 std::memory_order_seq_cst
, std::memory_order_acquire
) == 0);
849 /* Copy in current property values. */
850 props
->DopplerFactor
= context
->mDopplerFactor
;
851 props
->DopplerVelocity
= context
->mDopplerVelocity
;
852 props
->SpeedOfSound
= context
->mSpeedOfSound
;
854 props
->SourceDistanceModel
= context
->mSourceDistanceModel
;
855 props
->mDistanceModel
= context
->mDistanceModel
;
857 /* Set the new container for updating internal parameters. */
858 props
= context
->mUpdate
.exchange(props
, std::memory_order_acq_rel
);
861 /* If there was an unused update container, put it back in the
864 AtomicReplaceHead(context
->mFreeContextProps
, props
);