29 #include "inprogext.h"
31 #include "polymorphism.h"
38 template<typename T
, size_t N
>
39 constexpr inline size_t countof(const T(&)[N
]) noexcept
41 #define COUNTOF countof
52 #define HAS_BUILTIN __has_builtin
54 #define HAS_BUILTIN(x) (0)
58 /* LIKELY optimizes the case where the condition is true. The condition is not
59 * required to be true, but it can result in more optimal code for the true
60 * path at the expense of a less optimal false path.
62 #define LIKELY(x) __builtin_expect(!!(x), !0)
63 /* The opposite of LIKELY, optimizing the case where the condition is false. */
64 #define UNLIKELY(x) __builtin_expect(!!(x), 0)
65 /* Unlike LIKELY, ASSUME requires the condition to be true or else it invokes
66 * undefined behavior. It's essentially an assert without actually checking the
67 * condition at run-time, allowing for stronger optimizations than LIKELY.
69 #if HAS_BUILTIN(__builtin_assume)
70 #define ASSUME __builtin_assume
72 #define ASSUME(x) do { if(!(x)) __builtin_unreachable(); } while(0)
77 #define LIKELY(x) (!!(x))
78 #define UNLIKELY(x) (!!(x))
80 #define ASSUME __assume
82 #define ASSUME(x) ((void)0)
87 #define UINT64_MAX U64(18446744073709551615)
91 #if defined(__cplusplus)
93 #elif defined(__GNUC__)
94 #define UNUSED(x) UNUSED_##x __attribute__((unused))
95 #elif defined(__LCLINT__)
96 #define UNUSED(x) /*@unused@*/ x
102 /* Calculates the size of a struct with N elements of a flexible array member.
103 * GCC and Clang allow offsetof(Type, fam[N]) for this, but MSVC seems to have
104 * trouble, so a bit more verbose workaround is needed.
106 #define FAM_SIZE(T, M, N) (offsetof(T, M) + sizeof(((T*)NULL)->M[0])*(N))
109 typedef ALint64SOFT ALint64
;
110 typedef ALuint64SOFT ALuint64
;
113 #if defined(_MSC_VER)
114 #define U64(x) ((ALuint64)(x##ui64))
115 #elif SIZEOF_LONG == 8
116 #define U64(x) ((ALuint64)(x##ul))
117 #elif SIZEOF_LONG_LONG == 8
118 #define U64(x) ((ALuint64)(x##ull))
123 #if defined(_MSC_VER)
124 #define I64(x) ((ALint64)(x##i64))
125 #elif SIZEOF_LONG == 8
126 #define I64(x) ((ALint64)(x##l))
127 #elif SIZEOF_LONG_LONG == 8
128 #define I64(x) ((ALint64)(x##ll))
132 /* Define a CTZ64 macro (count trailing zeros, for 64-bit integers). The result
133 * is *UNDEFINED* if the value is 0.
138 #define POPCNT64 __builtin_popcountl
139 #define CTZ64 __builtin_ctzl
141 #define POPCNT64 __builtin_popcountll
142 #define CTZ64 __builtin_ctzll
145 #elif defined(HAVE_BITSCANFORWARD64_INTRINSIC)
147 inline int msvc64_popcnt64(ALuint64 v
)
149 return __popcnt64(v
);
151 #define POPCNT64 msvc64_popcnt64
153 inline int msvc64_ctz64(ALuint64 v
)
155 unsigned long idx
= 64;
156 _BitScanForward64(&idx
, v
);
159 #define CTZ64 msvc64_ctz64
161 #elif defined(HAVE_BITSCANFORWARD_INTRINSIC)
163 inline int msvc_popcnt64(ALuint64 v
)
165 return __popcnt((ALuint
)v
) + __popcnt((ALuint
)(v
>>32));
167 #define POPCNT64 msvc_popcnt64
169 inline int msvc_ctz64(ALuint64 v
)
171 unsigned long idx
= 64;
172 if(!_BitScanForward(&idx
, v
&0xffffffff))
174 if(_BitScanForward(&idx
, v
>>32))
179 #define CTZ64 msvc_ctz64
183 /* There be black magics here. The popcnt64 method is derived from
184 * https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
185 * while the ctz-utilizing-popcnt algorithm is shown here
186 * http://www.hackersdelight.org/hdcodetxt/ntz.c.txt
187 * as the ntz2 variant. These likely aren't the most efficient methods, but
188 * they're good enough if the GCC or MSVC intrinsics aren't available.
190 inline int fallback_popcnt64(ALuint64 v
)
192 v
= v
- ((v
>> 1) & U64(0x5555555555555555));
193 v
= (v
& U64(0x3333333333333333)) + ((v
>> 2) & U64(0x3333333333333333));
194 v
= (v
+ (v
>> 4)) & U64(0x0f0f0f0f0f0f0f0f);
195 return (int)((v
* U64(0x0101010101010101)) >> 56);
197 #define POPCNT64 fallback_popcnt64
199 inline int fallback_ctz64(ALuint64 value
)
201 return fallback_popcnt64(~value
& (value
- 1));
203 #define CTZ64 fallback_ctz64
206 #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
207 #define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
211 ALubyte b
[sizeof(ALuint
)];
212 } EndianTest
= { 1 };
213 #define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1)
219 struct DirectHrtfState
;
220 struct FrontStablizer
;
229 struct AmbiUpsampler
;
233 #define DEFAULT_OUTPUT_RATE (44100)
234 #define MIN_OUTPUT_RATE (8000)
237 /* Find the next power-of-2 for non-power-of-2 numbers. */
238 inline ALuint
NextPowerOf2(ALuint value
) noexcept
252 /** Round up a value to the next multiple. */
253 inline size_t RoundUp(size_t value
, size_t r
) noexcept
256 return value
- (value
%r
);
259 /* Fast float-to-int conversion. No particular rounding mode is assumed; the
260 * IEEE-754 default is round-to-nearest with ties-to-even, though an app could
261 * change it on its own threads. On some systems, a truncating conversion may
262 * always be the fastest method.
264 inline ALint
fastf2i(ALfloat f
) noexcept
266 #if defined(HAVE_INTRIN_H) && ((defined(_M_IX86_FP) && (_M_IX86_FP > 0)) || defined(_M_X64))
267 return _mm_cvt_ss2si(_mm_set1_ps(f
));
269 #elif defined(_MSC_VER) && defined(_M_IX86_FP)
276 #elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
280 __asm__("cvtss2si %1, %0" : "=r"(i
) : "x"(f
));
282 __asm__
__volatile__("fistpl %0" : "=m"(i
) : "t"(f
) : "st");
286 /* On GCC when compiling with -fno-math-errno, lrintf can be inlined to
287 * some simple instructions. Clang does not inline it, always generating a
288 * libc call, while MSVC's implementation is horribly slow, so always fall
289 * back to a normal integer conversion for them.
291 #elif !defined(_MSC_VER) && !defined(__clang__)
301 /* Converts float-to-int using standard behavior (truncation). */
302 inline int float2int(float f
) noexcept
304 #if ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \
305 !defined(__SSE_MATH__)) || (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 0)
306 ALint sign
, shift
, mant
;
313 sign
= (conv
.i
>>31) | 1;
314 shift
= ((conv
.i
>>23)&0xff) - (127+23);
317 if(UNLIKELY(shift
>= 31 || shift
< -23))
320 mant
= (conv
.i
&0x7fffff) | 0x800000;
321 if(LIKELY(shift
< 0))
322 return (mant
>> -shift
) * sign
;
323 return (mant
<< shift
) * sign
;
331 /* Rounds a float to the nearest integral value, according to the current
332 * rounding mode. This is essentially an inlined version of rintf, although
333 * makes fewer promises (e.g. -0 or -0.25 rounded to 0 may result in +0).
335 inline float fast_roundf(float f
) noexcept
337 #if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && \
338 !defined(__SSE_MATH__)
341 __asm__
__volatile__("frndint" : "=t"(out
) : "0"(f
));
346 /* Integral limit, where sub-integral precision is not available for
349 static const float ilim
[2] = {
350 8388608.0f
/* 0x1.0p+23 */,
351 -8388608.0f
/* -0x1.0p+23 */
360 sign
= (conv
.i
>>31)&0x01;
361 expo
= (conv
.i
>>23)&0xff;
363 if(UNLIKELY(expo
>= 150/*+23*/))
365 /* An exponent (base-2) of 23 or higher is incapable of sub-integral
366 * precision, so it's already an integral value. We don't need to worry
367 * about infinity or NaN here.
371 /* Adding the integral limit to the value (with a matching sign) forces a
372 * result that has no sub-integral precision, and is consequently forced to
373 * round to an integral value. Removing the integral limit then restores
374 * the initial value rounded to the integral. The compiler should not
375 * optimize this out because of non-associative rules on floating-point
376 * math (as long as you don't use -fassociative-math,
377 * -funsafe-math-optimizations, -ffast-math, or -Ofast, in which case this
381 return f
- ilim
[sign
];
435 DevFmtByte
= ALC_BYTE_SOFT
,
436 DevFmtUByte
= ALC_UNSIGNED_BYTE_SOFT
,
437 DevFmtShort
= ALC_SHORT_SOFT
,
438 DevFmtUShort
= ALC_UNSIGNED_SHORT_SOFT
,
439 DevFmtInt
= ALC_INT_SOFT
,
440 DevFmtUInt
= ALC_UNSIGNED_INT_SOFT
,
441 DevFmtFloat
= ALC_FLOAT_SOFT
,
443 DevFmtTypeDefault
= DevFmtFloat
445 enum DevFmtChannels
{
446 DevFmtMono
= ALC_MONO_SOFT
,
447 DevFmtStereo
= ALC_STEREO_SOFT
,
448 DevFmtQuad
= ALC_QUAD_SOFT
,
449 DevFmtX51
= ALC_5POINT1_SOFT
,
450 DevFmtX61
= ALC_6POINT1_SOFT
,
451 DevFmtX71
= ALC_7POINT1_SOFT
,
452 DevFmtAmbi3D
= ALC_BFORMAT3D_SOFT
,
454 /* Similar to 5.1, except using rear channels instead of sides */
455 DevFmtX51Rear
= 0x80000000,
457 DevFmtChannelsDefault
= DevFmtStereo
459 #define MAX_OUTPUT_CHANNELS (16)
461 /* DevFmtType traits, providing the type, etc given a DevFmtType. */
462 template<DevFmtType T
>
463 struct DevFmtTypeTraits
{ };
466 struct DevFmtTypeTraits
<DevFmtByte
> { using Type
= ALbyte
; };
468 struct DevFmtTypeTraits
<DevFmtUByte
> { using Type
= ALubyte
; };
470 struct DevFmtTypeTraits
<DevFmtShort
> { using Type
= ALshort
; };
472 struct DevFmtTypeTraits
<DevFmtUShort
> { using Type
= ALushort
; };
474 struct DevFmtTypeTraits
<DevFmtInt
> { using Type
= ALint
; };
476 struct DevFmtTypeTraits
<DevFmtUInt
> { using Type
= ALuint
; };
478 struct DevFmtTypeTraits
<DevFmtFloat
> { using Type
= ALfloat
; };
481 ALsizei
BytesFromDevFmt(enum DevFmtType type
);
482 ALsizei
ChannelsFromDevFmt(enum DevFmtChannels chans
, ALsizei ambiorder
);
483 inline ALsizei
FrameSizeFromDevFmt(enum DevFmtChannels chans
, enum DevFmtType type
, ALsizei ambiorder
)
485 return ChannelsFromDevFmt(chans
, ambiorder
) * BytesFromDevFmt(type
);
488 enum class AmbiLayout
{
489 FuMa
= ALC_FUMA_SOFT
, /* FuMa channel order */
490 ACN
= ALC_ACN_SOFT
, /* ACN channel order */
495 enum class AmbiNorm
{
496 FuMa
= ALC_FUMA_SOFT
, /* FuMa normalization */
497 SN3D
= ALC_SN3D_SOFT
, /* SN3D normalization */
498 N3D
= ALC_N3D_SOFT
, /* N3D normalization */
518 /* The maximum number of Ambisonics coefficients. For a given order (o), the
519 * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4,
520 * second-order has 9, third-order has 16, and fourth-order has 25.
522 #define MAX_AMBI_ORDER 3
523 #define MAX_AMBI_COEFFS ((MAX_AMBI_ORDER+1) * (MAX_AMBI_ORDER+1))
525 /* A bitmask of ambisonic channels with height information. If none of these
526 * channels are used/needed, there's no height (e.g. with most surround sound
527 * speaker setups). This only specifies up to 4th order, which is the highest
528 * order a 32-bit mask value can specify (a 64-bit mask could handle up to 7th
529 * order). This is ACN ordering, with bit 0 being ACN 0, etc.
531 #define AMBI_PERIPHONIC_MASK (0xfe7ce4)
533 /* The maximum number of Ambisonic coefficients for 2D (non-periphonic)
534 * representation. This is 2 per each order above zero-order, plus 1 for zero-
535 * order. Or simply, o*2 + 1.
537 #define MAX_AMBI2D_COEFFS (MAX_AMBI_ORDER*2 + 1)
540 typedef ALfloat ChannelConfig
[MAX_AMBI_COEFFS
];
541 typedef struct BFChannelConfig
{
546 typedef union AmbiConfig
{
547 /* Ambisonic coefficients for mixing to the dry buffer. */
548 ChannelConfig Coeffs
[MAX_OUTPUT_CHANNELS
];
549 /* Coefficient channel mapping for mixing to the dry buffer. */
550 BFChannelConfig Map
[MAX_OUTPUT_CHANNELS
];
554 struct BufferSubList
{
555 uint64_t FreeMask
{~uint64_t{}};
556 struct ALbuffer
*Buffers
{nullptr}; /* 64 */
558 BufferSubList() noexcept
= default;
559 BufferSubList(const BufferSubList
&) = delete;
560 BufferSubList(BufferSubList
&& rhs
) noexcept
: FreeMask
{rhs
.FreeMask
}, Buffers
{rhs
.Buffers
}
561 { rhs
.FreeMask
= ~uint64_t{}; rhs
.Buffers
= nullptr; }
564 BufferSubList
& operator=(const BufferSubList
&) = delete;
565 BufferSubList
& operator=(BufferSubList
&& rhs
) noexcept
566 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(Buffers
, rhs
.Buffers
); return *this; }
569 struct EffectSubList
{
570 uint64_t FreeMask
{~uint64_t{}};
571 struct ALeffect
*Effects
{nullptr}; /* 64 */
573 EffectSubList() noexcept
= default;
574 EffectSubList(const EffectSubList
&) = delete;
575 EffectSubList(EffectSubList
&& rhs
) noexcept
: FreeMask
{rhs
.FreeMask
}, Effects
{rhs
.Effects
}
576 { rhs
.FreeMask
= ~uint64_t{}; rhs
.Effects
= nullptr; }
579 EffectSubList
& operator=(const EffectSubList
&) = delete;
580 EffectSubList
& operator=(EffectSubList
&& rhs
) noexcept
581 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(Effects
, rhs
.Effects
); return *this; }
584 struct FilterSubList
{
585 uint64_t FreeMask
{~uint64_t{}};
586 struct ALfilter
*Filters
{nullptr}; /* 64 */
588 FilterSubList() noexcept
= default;
589 FilterSubList(const FilterSubList
&) = delete;
590 FilterSubList(FilterSubList
&& rhs
) noexcept
: FreeMask
{rhs
.FreeMask
}, Filters
{rhs
.Filters
}
591 { rhs
.FreeMask
= ~uint64_t{}; rhs
.Filters
= nullptr; }
594 FilterSubList
& operator=(const FilterSubList
&) = delete;
595 FilterSubList
& operator=(FilterSubList
&& rhs
) noexcept
596 { std::swap(FreeMask
, rhs
.FreeMask
); std::swap(Filters
, rhs
.Filters
); return *this; }
600 typedef struct EnumeratedHrtf
{
603 struct HrtfEntry
*hrtf
;
607 /* Maximum delay in samples for speaker distance compensation. */
608 #define MAX_DELAY_LENGTH 1024
613 ALsizei Length
{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */
614 ALfloat
*Buffer
{nullptr};
615 } mChannel
[MAX_OUTPUT_CHANNELS
];
616 al::vector
<ALfloat
,16> mSamples
;
619 void resize(size_t amt
) { mSamples
.resize(amt
); }
620 void shrink_to_fit() { mSamples
.shrink_to_fit(); }
621 void clear() noexcept
623 for(auto &chan
: mChannel
)
627 chan
.Buffer
= nullptr;
632 ALfloat
*data() noexcept
{ return mSamples
.data(); }
633 const ALfloat
*data() const noexcept
{ return mSamples
.data(); }
635 DistData
& operator[](size_t o
) noexcept
{ return mChannel
[o
]; }
636 const DistData
& operator[](size_t o
) const noexcept
{ return mChannel
[o
]; }
639 /* Size for temporary storage of buffer data, in ALfloats. Larger values need
640 * more memory, while smaller values may need more iterations. The value needs
641 * to be a sensible size, however, as it constrains the max stepping value used
642 * for mixing, as well as the maximum number of samples per mixing iteration.
644 #define BUFFERSIZE 2048
646 typedef struct MixParams
{
648 /* Number of coefficients in each Ambi.Coeffs to mix together (4 for first-
649 * order, 9 for second-order, etc). If the count is 0, Ambi.Map is used
650 * instead to map each output to a coefficient index.
652 ALsizei CoeffCount
{0};
654 ALfloat (*Buffer
)[BUFFERSIZE
]{nullptr};
655 ALsizei NumChannels
{0};
658 typedef struct RealMixParams
{
659 enum Channel ChannelName
[MAX_OUTPUT_CHANNELS
]{};
661 ALfloat (*Buffer
)[BUFFERSIZE
]{nullptr};
662 ALsizei NumChannels
{0};
665 typedef void (*POSTPROCESS
)(ALCdevice
*device
, ALsizei SamplesToDo
);
667 struct ALCdevice_struct
{
670 std::atomic
<ALenum
> Connected
{AL_TRUE
};
676 DevFmtChannels FmtChans
{};
677 DevFmtType FmtType
{};
678 ALboolean IsHeadphones
{AL_FALSE
};
679 ALsizei mAmbiOrder
{0};
680 /* For DevFmtAmbi* output only, specifies the channel order and
683 AmbiLayout mAmbiLayout
{AmbiLayout::Default
};
684 AmbiNorm mAmbiScale
{AmbiNorm::Default
};
686 ALCenum LimiterState
{ALC_DONT_CARE_SOFT
};
688 std::string DeviceName
;
693 std::string HrtfName
;
694 al::vector
<EnumeratedHrtf
> HrtfList
;
695 ALCenum HrtfStatus
{ALC_FALSE
};
697 std::atomic
<ALCenum
> LastError
{ALC_NO_ERROR
};
699 // Maximum number of sources that can be created
701 // Maximum number of slots that can be created
702 ALuint AuxiliaryEffectSlotMax
{};
704 ALCuint NumMonoSources
{};
705 ALCuint NumStereoSources
{};
706 ALsizei NumAuxSends
{};
708 // Map of Buffers for this device
709 al::vector
<BufferSubList
> BufferList
;
710 std::mutex BufferLock
;
712 // Map of Effects for this device
713 al::vector
<EffectSubList
> EffectList
;
714 std::mutex EffectLock
;
716 // Map of Filters for this device
717 al::vector
<FilterSubList
> FilterList
;
718 std::mutex FilterLock
;
720 /* Rendering mode. */
721 RenderMode Render_Mode
{NormalRender
};
723 /* The average speaker distance as determined by the ambdec configuration
724 * (or alternatively, by the NFC-HOA reference delay). Only used for NFC.
726 ALfloat AvgSpeakerDist
{0.0f
};
728 ALuint SamplesDone
{0u};
729 std::chrono::nanoseconds ClockBase
{0};
730 std::chrono::nanoseconds FixedLatency
{0};
732 /* Temp storage used for mixer processing. */
733 alignas(16) ALfloat TempBuffer
[4][BUFFERSIZE
];
735 /* Mixing buffer used by the Dry mix, FOAOut, and Real out. */
736 al::vector
<std::array
<ALfloat
,BUFFERSIZE
>, 16> MixBuffer
;
738 /* The "dry" path corresponds to the main output. */
740 ALsizei NumChannelsPerOrder
[MAX_AMBI_ORDER
+1]{};
742 /* First-order ambisonics output, to be upsampled to the dry buffer if different. */
745 /* "Real" output, which will be written to the device buffer. May alias the
748 RealMixParams RealOut
;
750 /* HRTF state and info */
751 std::unique_ptr
<DirectHrtfState
> mHrtfState
;
752 Hrtf
*HrtfHandle
{nullptr};
754 /* UHJ encoder state */
755 std::unique_ptr
<Uhj2Encoder
> Uhj_Encoder
;
757 /* High quality Ambisonic decoder */
758 std::unique_ptr
<BFormatDec
> AmbiDecoder
;
760 /* Stereo-to-binaural filter */
761 std::unique_ptr
<bs2b
> Bs2b
;
763 /* First-order ambisonic upsampler for higher-order output */
764 std::unique_ptr
<AmbiUpsampler
> AmbiUp
;
766 POSTPROCESS PostProcess
{};
768 std::unique_ptr
<FrontStablizer
> Stablizer
;
770 /* Delay buffers used to compensate for speaker distances. */
771 DistanceComp ChannelDelay
;
773 std::unique_ptr
<Compressor
> Limiter
;
775 /* Dithering control. */
776 ALfloat DitherDepth
{0.0f
};
777 ALuint DitherSeed
{0u};
779 /* Running count of the mixer invocations, in 31.1 fixed point. This
780 * actually increments *twice* when mixing, first at the start and then at
781 * the end, so the bottom bit indicates if the device is currently mixing
782 * and the upper bits indicates how many mixes have been done.
784 RefCount MixCount
{0u};
786 // Contexts created on this device
787 std::atomic
<ALCcontext
*> ContextList
{nullptr};
789 std::mutex BackendLock
;
790 ALCbackend
*Backend
{nullptr};
792 std::atomic
<ALCdevice
*> next
{nullptr};
795 ALCdevice_struct(DeviceType type
);
796 ALCdevice_struct(const ALCdevice_struct
&) = delete;
797 ALCdevice_struct
& operator=(const ALCdevice_struct
&) = delete;
800 DEF_NEWDEL(ALCdevice
)
803 // Frequency was requested by the app or config file
804 #define DEVICE_FREQUENCY_REQUEST (1u<<1)
805 // Channel configuration was requested by the config file
806 #define DEVICE_CHANNELS_REQUEST (1u<<2)
807 // Sample type was requested by the config file
808 #define DEVICE_SAMPLE_TYPE_REQUEST (1u<<3)
810 // Specifies if the DSP is paused at user request
811 #define DEVICE_PAUSED (1u<<30)
813 // Specifies if the device is currently running
814 #define DEVICE_RUNNING (1u<<31)
817 /* Nanosecond resolution for the device clock time. */
818 #define DEVICE_CLOCK_RES U64(1000000000)
821 /* Must be less than 15 characters (16 including terminating null) for
822 * compatibility with pthread_setname_np limitations. */
823 #define MIXER_THREAD_NAME "alsoft-mixer"
825 #define RECORD_THREAD_NAME "alsoft-record"
829 /* End event thread processing. */
830 EventType_KillThread
= 0,
832 /* User event types. */
833 EventType_SourceStateChange
= 1<<0,
834 EventType_BufferCompleted
= 1<<1,
835 EventType_Error
= 1<<2,
836 EventType_Performance
= 1<<3,
837 EventType_Deprecated
= 1<<4,
838 EventType_Disconnected
= 1<<5,
840 /* Internal events. */
841 EventType_ReleaseEffectState
= 65536,
845 unsigned int EnumType
;
862 EffectState
*mEffectState
;
865 #define ASYNC_EVENT(t) AsyncEvent{ t, { 0 } }
868 void AllocateVoices(ALCcontext
*context
, ALsizei num_voices
, ALsizei old_sends
);
871 extern ALint RTPrioLevel
;
872 void SetRTPriority(void);
874 void SetDefaultChannelOrder(ALCdevice
*device
);
875 void SetDefaultWFXChannelOrder(ALCdevice
*device
);
877 const ALCchar
*DevFmtTypeString(enum DevFmtType type
);
878 const ALCchar
*DevFmtChannelsString(enum DevFmtChannels chans
);
880 inline ALint
GetChannelIndex(const enum Channel (&names
)[MAX_OUTPUT_CHANNELS
], enum Channel chan
)
882 auto iter
= std::find(std::begin(names
), std::end(names
), chan
);
883 if(iter
== std::end(names
)) return -1;
884 return std::distance(std::begin(names
), iter
);
887 * GetChannelIdxByName
889 * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it
892 inline ALint
GetChannelIdxByName(const RealMixParams
*real
, enum Channel chan
)
893 { return GetChannelIndex(real
->ChannelName
, chan
); }
896 void StartEventThrd(ALCcontext
*ctx
);
897 void StopEventThrd(ALCcontext
*ctx
);
900 al::vector
<std::string
> SearchDataFiles(const char *match
, const char *subdir
);