|
|
- #ifndef AL_MAIN_H
- #define AL_MAIN_H
-
- #include <string.h>
- #include <stdio.h>
- #include <stddef.h>
- #include <stdarg.h>
- #include <assert.h>
- #include <math.h>
- #include <limits.h>
-
- #ifdef HAVE_STRINGS_H
- #include <strings.h>
- #endif
-
- #include <array>
- #include <vector>
- #include <string>
- #include <chrono>
- #include <algorithm>
-
- #include "AL/al.h"
- #include "AL/alc.h"
- #include "AL/alext.h"
-
- #include "inprogext.h"
- #include "atomic.h"
- #include "vector.h"
- #include "almalloc.h"
- #include "alnumeric.h"
- #include "threads.h"
- #include "ambidefs.h"
- #include "hrtf.h"
-
-
- template<typename T, size_t N>
- constexpr inline size_t countof(const T(&)[N]) noexcept
- { return N; }
- #define COUNTOF countof
-
-
- #ifndef UNUSED
- #if defined(__cplusplus)
- #define UNUSED(x)
- #elif defined(__GNUC__)
- #define UNUSED(x) UNUSED_##x __attribute__((unused))
- #elif defined(__LCLINT__)
- #define UNUSED(x) /*@unused@*/ x
- #else
- #define UNUSED(x) x
- #endif
- #endif
-
-
- #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
- #define IS_LITTLE_ENDIAN (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
- #else
- static const union {
- ALuint u;
- ALubyte b[sizeof(ALuint)];
- } EndianTest = { 1 };
- #define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1)
- #endif
-
-
- struct HrtfEntry;
- struct HrtfHandle;
- struct EnumeratedHrtf;
- struct DirectHrtfState;
- struct FrontStablizer;
- struct Compressor;
- struct BackendBase;
- struct ALbuffer;
- struct ALeffect;
- struct ALfilter;
- struct EffectState;
- struct Uhj2Encoder;
- class BFormatDec;
- class AmbiUpsampler;
- struct bs2b;
-
-
- #define MIN_OUTPUT_RATE 8000
- #define DEFAULT_OUTPUT_RATE 44100
- #define DEFAULT_UPDATE_SIZE 882 /* 20ms */
- #define DEFAULT_NUM_UPDATES 3
-
-
- enum Channel {
- FrontLeft = 0,
- FrontRight,
- FrontCenter,
- LFE,
- BackLeft,
- BackRight,
- BackCenter,
- SideLeft,
- SideRight,
-
- UpperFrontLeft,
- UpperFrontRight,
- UpperBackLeft,
- UpperBackRight,
- LowerFrontLeft,
- LowerFrontRight,
- LowerBackLeft,
- LowerBackRight,
-
- Aux0,
- Aux1,
- Aux2,
- Aux3,
- Aux4,
- Aux5,
- Aux6,
- Aux7,
- Aux8,
- Aux9,
- Aux10,
- Aux11,
- Aux12,
- Aux13,
- Aux14,
- Aux15,
-
- MaxChannels
- };
-
-
- /* Device formats */
- enum DevFmtType {
- DevFmtByte = ALC_BYTE_SOFT,
- DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT,
- DevFmtShort = ALC_SHORT_SOFT,
- DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT,
- DevFmtInt = ALC_INT_SOFT,
- DevFmtUInt = ALC_UNSIGNED_INT_SOFT,
- DevFmtFloat = ALC_FLOAT_SOFT,
-
- DevFmtTypeDefault = DevFmtFloat
- };
- enum DevFmtChannels {
- DevFmtMono = ALC_MONO_SOFT,
- DevFmtStereo = ALC_STEREO_SOFT,
- DevFmtQuad = ALC_QUAD_SOFT,
- DevFmtX51 = ALC_5POINT1_SOFT,
- DevFmtX61 = ALC_6POINT1_SOFT,
- DevFmtX71 = ALC_7POINT1_SOFT,
- DevFmtAmbi3D = ALC_BFORMAT3D_SOFT,
-
- /* Similar to 5.1, except using rear channels instead of sides */
- DevFmtX51Rear = 0x80000000,
-
- DevFmtChannelsDefault = DevFmtStereo
- };
- #define MAX_OUTPUT_CHANNELS (16)
-
- /* DevFmtType traits, providing the type, etc given a DevFmtType. */
- template<DevFmtType T>
- struct DevFmtTypeTraits { };
-
- template<>
- struct DevFmtTypeTraits<DevFmtByte> { using Type = ALbyte; };
- template<>
- struct DevFmtTypeTraits<DevFmtUByte> { using Type = ALubyte; };
- template<>
- struct DevFmtTypeTraits<DevFmtShort> { using Type = ALshort; };
- template<>
- struct DevFmtTypeTraits<DevFmtUShort> { using Type = ALushort; };
- template<>
- struct DevFmtTypeTraits<DevFmtInt> { using Type = ALint; };
- template<>
- struct DevFmtTypeTraits<DevFmtUInt> { using Type = ALuint; };
- template<>
- struct DevFmtTypeTraits<DevFmtFloat> { using Type = ALfloat; };
-
-
- ALsizei BytesFromDevFmt(DevFmtType type) noexcept;
- ALsizei ChannelsFromDevFmt(DevFmtChannels chans, ALsizei ambiorder) noexcept;
- inline ALsizei FrameSizeFromDevFmt(DevFmtChannels chans, DevFmtType type, ALsizei ambiorder) noexcept
- { return ChannelsFromDevFmt(chans, ambiorder) * BytesFromDevFmt(type); }
-
- enum class AmbiLayout {
- FuMa = ALC_FUMA_SOFT, /* FuMa channel order */
- ACN = ALC_ACN_SOFT, /* ACN channel order */
-
- Default = ACN
- };
-
- enum class AmbiNorm {
- FuMa = ALC_FUMA_SOFT, /* FuMa normalization */
- SN3D = ALC_SN3D_SOFT, /* SN3D normalization */
- N3D = ALC_N3D_SOFT, /* N3D normalization */
-
- Default = SN3D
- };
-
-
- enum DeviceType {
- Playback,
- Capture,
- Loopback
- };
-
-
- enum RenderMode {
- NormalRender,
- StereoPair,
- HrtfRender
- };
-
-
- struct BufferSubList {
- uint64_t FreeMask{~0_u64};
- ALbuffer *Buffers{nullptr}; /* 64 */
-
- BufferSubList() noexcept = default;
- BufferSubList(const BufferSubList&) = delete;
- BufferSubList(BufferSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Buffers{rhs.Buffers}
- { rhs.FreeMask = ~0_u64; rhs.Buffers = nullptr; }
- ~BufferSubList();
-
- BufferSubList& operator=(const BufferSubList&) = delete;
- BufferSubList& operator=(BufferSubList&& rhs) noexcept
- { std::swap(FreeMask, rhs.FreeMask); std::swap(Buffers, rhs.Buffers); return *this; }
- };
-
- struct EffectSubList {
- uint64_t FreeMask{~0_u64};
- ALeffect *Effects{nullptr}; /* 64 */
-
- EffectSubList() noexcept = default;
- EffectSubList(const EffectSubList&) = delete;
- EffectSubList(EffectSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Effects{rhs.Effects}
- { rhs.FreeMask = ~0_u64; rhs.Effects = nullptr; }
- ~EffectSubList();
-
- EffectSubList& operator=(const EffectSubList&) = delete;
- EffectSubList& operator=(EffectSubList&& rhs) noexcept
- { std::swap(FreeMask, rhs.FreeMask); std::swap(Effects, rhs.Effects); return *this; }
- };
-
- struct FilterSubList {
- uint64_t FreeMask{~0_u64};
- ALfilter *Filters{nullptr}; /* 64 */
-
- FilterSubList() noexcept = default;
- FilterSubList(const FilterSubList&) = delete;
- FilterSubList(FilterSubList&& rhs) noexcept : FreeMask{rhs.FreeMask}, Filters{rhs.Filters}
- { rhs.FreeMask = ~0_u64; rhs.Filters = nullptr; }
- ~FilterSubList();
-
- FilterSubList& operator=(const FilterSubList&) = delete;
- FilterSubList& operator=(FilterSubList&& rhs) noexcept
- { std::swap(FreeMask, rhs.FreeMask); std::swap(Filters, rhs.Filters); return *this; }
- };
-
-
- /* Maximum delay in samples for speaker distance compensation. */
- #define MAX_DELAY_LENGTH 1024
-
- class DistanceComp {
- public:
- struct DistData {
- ALfloat Gain{1.0f};
- ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */
- ALfloat *Buffer{nullptr};
- };
-
- private:
- DistData mChannel[MAX_OUTPUT_CHANNELS];
- al::vector<ALfloat,16> mSamples;
-
- public:
- void resize(size_t new_size) { mSamples.resize(new_size); }
- void shrink_to_fit() { mSamples.shrink_to_fit(); }
- void clear() noexcept
- {
- for(auto &chan : mChannel)
- {
- chan.Gain = 1.0f;
- chan.Length = 0;
- chan.Buffer = nullptr;
- }
- mSamples.clear();
- }
-
- DistData *begin() noexcept { return std::begin(mChannel); }
- const DistData *begin() const noexcept { return std::begin(mChannel); }
- const DistData *cbegin() const noexcept { return std::begin(mChannel); }
- DistData *end() noexcept { return std::end(mChannel); }
- const DistData *end() const noexcept { return std::end(mChannel); }
- const DistData *cend() const noexcept { return std::end(mChannel); }
-
- ALfloat *data() noexcept { return mSamples.data(); }
- const ALfloat *data() const noexcept { return mSamples.data(); }
-
- DistData& operator[](size_t o) noexcept { return mChannel[o]; }
- const DistData& operator[](size_t o) const noexcept { return mChannel[o]; }
- };
-
- struct BFChannelConfig {
- ALfloat Scale;
- ALsizei Index;
- };
-
- /* Size for temporary storage of buffer data, in ALfloats. Larger values need
- * more memory, while smaller values may need more iterations. The value needs
- * to be a sensible size, however, as it constrains the max stepping value used
- * for mixing, as well as the maximum number of samples per mixing iteration.
- */
- #define BUFFERSIZE 1024
-
- /* Maximum number of samples to pad on either end of a buffer for resampling.
- * Note that both the beginning and end need padding!
- */
- #define MAX_RESAMPLE_PADDING 24
-
-
- struct MixParams {
- /* Coefficient channel mapping for mixing to the buffer. */
- std::array<BFChannelConfig,MAX_OUTPUT_CHANNELS> AmbiMap;
-
- ALfloat (*Buffer)[BUFFERSIZE]{nullptr};
- ALsizei NumChannels{0};
- };
-
- struct RealMixParams {
- std::array<ALint,MaxChannels> ChannelIndex{};
-
- ALfloat (*Buffer)[BUFFERSIZE]{nullptr};
- ALsizei NumChannels{0};
- };
-
- using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo);
-
- struct ALCdevice {
- RefCount ref{1u};
-
- std::atomic<bool> Connected{true};
- const DeviceType Type{};
-
- ALuint Frequency{};
- ALuint UpdateSize{};
- ALuint BufferSize{};
-
- DevFmtChannels FmtChans{};
- DevFmtType FmtType{};
- ALboolean IsHeadphones{AL_FALSE};
- ALsizei mAmbiOrder{0};
- /* For DevFmtAmbi* output only, specifies the channel order and
- * normalization.
- */
- AmbiLayout mAmbiLayout{AmbiLayout::Default};
- AmbiNorm mAmbiScale{AmbiNorm::Default};
-
- ALCenum LimiterState{ALC_DONT_CARE_SOFT};
-
- std::string DeviceName;
-
- // Device flags
- ALuint Flags{0u};
-
- std::string HrtfName;
- al::vector<EnumeratedHrtf> HrtfList;
- ALCenum HrtfStatus{ALC_FALSE};
-
- std::atomic<ALCenum> LastError{ALC_NO_ERROR};
-
- // Maximum number of sources that can be created
- ALuint SourcesMax{};
- // Maximum number of slots that can be created
- ALuint AuxiliaryEffectSlotMax{};
-
- ALCuint NumMonoSources{};
- ALCuint NumStereoSources{};
- ALsizei NumAuxSends{};
-
- // Map of Buffers for this device
- std::mutex BufferLock;
- al::vector<BufferSubList> BufferList;
-
- // Map of Effects for this device
- std::mutex EffectLock;
- al::vector<EffectSubList> EffectList;
-
- // Map of Filters for this device
- std::mutex FilterLock;
- al::vector<FilterSubList> FilterList;
-
- /* Rendering mode. */
- RenderMode mRenderMode{NormalRender};
-
- /* The average speaker distance as determined by the ambdec configuration
- * (or alternatively, by the NFC-HOA reference delay). Only used for NFC.
- */
- ALfloat AvgSpeakerDist{0.0f};
-
- ALuint SamplesDone{0u};
- std::chrono::nanoseconds ClockBase{0};
- std::chrono::nanoseconds FixedLatency{0};
-
- /* Temp storage used for mixer processing. */
- alignas(16) ALfloat SourceData[BUFFERSIZE + MAX_RESAMPLE_PADDING*2];
- alignas(16) ALfloat ResampledData[BUFFERSIZE];
- alignas(16) ALfloat FilteredData[BUFFERSIZE];
- union {
- alignas(16) ALfloat HrtfSourceData[BUFFERSIZE + HRTF_HISTORY_LENGTH];
- alignas(16) ALfloat NfcSampleData[BUFFERSIZE];
- };
- alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH];
-
- /* Mixing buffer used by the Dry mix and Real output. */
- al::vector<std::array<ALfloat,BUFFERSIZE>, 16> MixBuffer;
-
- /* The "dry" path corresponds to the main output. */
- MixParams Dry;
- ALsizei NumChannelsPerOrder[MAX_AMBI_ORDER+1]{};
-
- /* "Real" output, which will be written to the device buffer. May alias the
- * dry buffer.
- */
- RealMixParams RealOut;
-
- /* HRTF state and info */
- std::unique_ptr<DirectHrtfState> mHrtfState;
- HrtfEntry *mHrtf{nullptr};
-
- /* Ambisonic-to-UHJ encoder */
- std::unique_ptr<Uhj2Encoder> Uhj_Encoder;
-
- /* Ambisonic decoder for speakers */
- std::unique_ptr<BFormatDec> AmbiDecoder;
-
- /* Stereo-to-binaural filter */
- std::unique_ptr<bs2b> Bs2b;
-
- POSTPROCESS PostProcess{};
-
- std::unique_ptr<FrontStablizer> Stablizer;
-
- std::unique_ptr<Compressor> Limiter;
-
- /* Delay buffers used to compensate for speaker distances. */
- DistanceComp ChannelDelay;
-
- /* Dithering control. */
- ALfloat DitherDepth{0.0f};
- ALuint DitherSeed{0u};
-
- /* Running count of the mixer invocations, in 31.1 fixed point. This
- * actually increments *twice* when mixing, first at the start and then at
- * the end, so the bottom bit indicates if the device is currently mixing
- * and the upper bits indicates how many mixes have been done.
- */
- RefCount MixCount{0u};
-
- // Contexts created on this device
- std::atomic<ALCcontext*> ContextList{nullptr};
-
- /* This lock protects the device state (format, update size, etc) from
- * being from being changed in multiple threads, or being accessed while
- * being changed. It's also used to serialize calls to the backend.
- */
- std::mutex StateLock;
- std::unique_ptr<BackendBase> Backend;
-
-
- ALCdevice(DeviceType type);
- ALCdevice(const ALCdevice&) = delete;
- ALCdevice& operator=(const ALCdevice&) = delete;
- ~ALCdevice();
-
- ALsizei bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); }
- ALsizei channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); }
- ALsizei frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); }
-
- static constexpr inline const char *CurrentPrefix() noexcept { return "ALCdevice::"; }
- DEF_NEWDEL(ALCdevice)
- };
-
- // Frequency was requested by the app or config file
- #define DEVICE_FREQUENCY_REQUEST (1u<<1)
- // Channel configuration was requested by the config file
- #define DEVICE_CHANNELS_REQUEST (1u<<2)
- // Sample type was requested by the config file
- #define DEVICE_SAMPLE_TYPE_REQUEST (1u<<3)
-
- // Specifies if the DSP is paused at user request
- #define DEVICE_PAUSED (1u<<30)
-
- // Specifies if the device is currently running
- #define DEVICE_RUNNING (1u<<31)
-
-
- /* Must be less than 15 characters (16 including terminating null) for
- * compatibility with pthread_setname_np limitations. */
- #define MIXER_THREAD_NAME "alsoft-mixer"
-
- #define RECORD_THREAD_NAME "alsoft-record"
-
-
- enum {
- /* End event thread processing. */
- EventType_KillThread = 0,
-
- /* User event types. */
- EventType_SourceStateChange = 1<<0,
- EventType_BufferCompleted = 1<<1,
- EventType_Error = 1<<2,
- EventType_Performance = 1<<3,
- EventType_Deprecated = 1<<4,
- EventType_Disconnected = 1<<5,
-
- /* Internal events. */
- EventType_ReleaseEffectState = 65536,
- };
-
- struct AsyncEvent {
- unsigned int EnumType{0u};
- union {
- char dummy;
- struct {
- ALuint id;
- ALenum state;
- } srcstate;
- struct {
- ALuint id;
- ALsizei count;
- } bufcomp;
- struct {
- ALenum type;
- ALuint id;
- ALuint param;
- ALchar msg[1008];
- } user;
- EffectState *mEffectState;
- } u{};
-
- AsyncEvent() noexcept = default;
- constexpr AsyncEvent(unsigned int type) noexcept : EnumType{type} { }
- };
-
-
- void AllocateVoices(ALCcontext *context, ALsizei num_voices, ALsizei old_sends);
-
-
- extern ALint RTPrioLevel;
- void SetRTPriority(void);
-
- void SetDefaultChannelOrder(ALCdevice *device);
- void SetDefaultWFXChannelOrder(ALCdevice *device);
-
- const ALCchar *DevFmtTypeString(DevFmtType type) noexcept;
- const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept;
-
- /**
- * GetChannelIdxByName
- *
- * Returns the index for the given channel name (e.g. FrontCenter), or -1 if it
- * doesn't exist.
- */
- inline ALint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexcept
- { return real.ChannelIndex[chan]; }
-
-
- void StartEventThrd(ALCcontext *ctx);
- void StopEventThrd(ALCcontext *ctx);
-
-
- al::vector<std::string> SearchDataFiles(const char *match, const char *subdir);
-
- #endif
|