564 lines
14 KiB
C
Raw Normal View History

2007-11-13 18:02:18 -08:00
#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>
2007-11-13 18:02:18 -08:00
2013-11-05 13:07:46 -08:00
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
2018-11-19 06:50:37 -08:00
#include <array>
#include <vector>
#include <string>
#include <chrono>
2018-11-22 22:53:22 -08:00
#include <algorithm>
2009-05-16 23:26:39 -07:00
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.h"
2018-01-26 21:32:43 -08:00
#include "inprogext.h"
2013-10-28 12:48:13 -07:00
#include "atomic.h"
#include "vector.h"
2019-06-08 23:49:15 -07:00
#include "albyte.h"
#include "almalloc.h"
#include "alnumeric.h"
2019-06-08 01:39:28 -07:00
#include "alspan.h"
#include "threads.h"
#include "ambidefs.h"
#include "hrtf.h"
2013-10-28 12:48:13 -07:00
#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
2012-02-15 21:47:35 -08:00
static const union {
ALuint u;
ALubyte b[sizeof(ALuint)];
} EndianTest = { 1 };
#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1)
#endif
2012-02-15 21:47:35 -08:00
struct HrtfEntry;
2018-12-22 09:20:50 -08:00
struct HrtfHandle;
2018-12-25 11:09:41 -08:00
struct EnumeratedHrtf;
2018-01-11 03:53:25 -08:00
struct DirectHrtfState;
struct FrontStablizer;
struct Compressor;
struct BackendBase;
2018-01-26 21:32:43 -08:00
struct ALbuffer;
2018-01-27 19:01:25 -08:00
struct ALeffect;
2018-01-27 19:40:47 -08:00
struct ALfilter;
struct EffectState;
2018-11-21 15:31:32 -08:00
struct Uhj2Encoder;
class BFormatDec;
class AmbiUpsampler;
2018-11-22 06:49:37 -08:00
struct bs2b;
2019-04-26 18:56:54 -07:00
#define MIN_OUTPUT_RATE 8000
#define DEFAULT_OUTPUT_RATE 44100
#define DEFAULT_UPDATE_SIZE 882 /* 20ms */
#define DEFAULT_NUM_UPDATES 3
2012-09-14 02:14:29 -07:00
enum Channel {
FrontLeft = 0,
FrontRight,
FrontCenter,
LFE,
BackLeft,
BackRight,
BackCenter,
SideLeft,
SideRight,
UpperFrontLeft,
UpperFrontRight,
UpperBackLeft,
UpperBackRight,
LowerFrontLeft,
LowerFrontRight,
LowerBackLeft,
LowerBackRight,
2016-03-16 06:49:35 -07:00
Aux0,
Aux1,
Aux2,
Aux3,
Aux4,
Aux5,
Aux6,
Aux7,
Aux8,
Aux9,
Aux10,
Aux11,
Aux12,
Aux13,
Aux14,
Aux15,
MaxChannels
2012-09-14 02:14:29 -07:00
};
2014-11-07 15:47:41 -08:00
2012-09-14 02:42:36 -07:00
/* 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
};
2012-02-23 15:25:30 -08:00
enum DeviceType {
Playback,
Capture,
Loopback
};
2012-09-14 02:14:29 -07:00
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 */
2018-01-27 19:01:25 -08:00
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; }
};
2018-01-27 19:40:47 -08:00
/* Maximum delay in samples for speaker distance compensation. */
#define MAX_DELAY_LENGTH 1024
class DistanceComp {
2018-12-10 14:49:57 -08:00
public:
struct DistData {
ALfloat Gain{1.0f};
ALsizei Length{0}; /* Valid range is [0...MAX_DELAY_LENGTH). */
ALfloat *Buffer{nullptr};
2018-12-10 14:49:57 -08:00
};
private:
2019-06-08 02:17:08 -07:00
std::array<DistData,MAX_OUTPUT_CHANNELS> mChannels;
al::vector<ALfloat,16> mSamples;
public:
2019-06-08 01:39:28 -07:00
void setSampleCount(size_t new_size) { mSamples.resize(new_size); }
void clear() noexcept
{
2019-06-08 02:17:08 -07:00
for(auto &chan : mChannels)
{
chan.Gain = 1.0f;
chan.Length = 0;
chan.Buffer = nullptr;
}
2019-06-08 01:39:28 -07:00
using SampleVecT = decltype(mSamples);
SampleVecT{}.swap(mSamples);
}
2019-06-08 01:39:28 -07:00
ALfloat *getSamples() noexcept { return mSamples.data(); }
2018-12-10 14:49:57 -08:00
2019-06-08 02:17:08 -07:00
al::span<DistData,MAX_OUTPUT_CHANNELS> as_span() { return mChannels; }
};
struct BFChannelConfig {
ALfloat Scale;
ALsizei Index;
};
2012-09-14 02:14:29 -07:00
/* Size for temporary storage of buffer data, in ALfloats. Larger values need
* more memory, while smaller values may need more iterations. The value needs
2012-09-14 02:14:29 -07:00
* 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
using FloatBufferLine = std::array<float,BUFFERSIZE>;
/* 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
2012-09-14 02:14:29 -07:00
struct MixParams {
/* Coefficient channel mapping for mixing to the buffer. */
std::array<BFChannelConfig,MAX_OUTPUT_CHANNELS> AmbiMap;
FloatBufferLine *Buffer{nullptr};
2019-06-05 19:26:54 -07:00
ALuint NumChannels{0u};
};
struct RealMixParams {
std::array<ALint,MaxChannels> ChannelIndex{};
FloatBufferLine *Buffer{nullptr};
ALuint NumChannels{0u};
};
2019-01-12 21:08:34 -08:00
using POSTPROCESS = void(*)(ALCdevice *device, const ALsizei SamplesToDo);
2019-06-08 23:49:15 -07:00
enum {
// Frequency was requested by the app or config file
FrequencyRequest,
// Channel configuration was requested by the config file
ChannelsRequest,
// Sample type was requested by the config file
SampleTypeRequest,
// Specifies if the DSP is paused at user request
DevicePaused,
// Specifies if the device is currently running
DeviceRunning,
DeviceFlagsCount
};
struct ALCdevice {
2018-11-18 08:14:23 -08:00
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};
2007-11-13 18:02:18 -08:00
ALCenum LimiterState{ALC_DONT_CARE_SOFT};
2018-11-18 18:45:45 -08:00
std::string DeviceName;
2007-11-13 18:02:18 -08:00
2018-11-29 13:08:03 -08:00
// Device flags
2019-06-08 23:49:15 -07:00
al::bitfield<DeviceFlagsCount> Flags{};
2018-11-29 13:08:03 -08:00
std::string HrtfName;
al::vector<EnumeratedHrtf> HrtfList;
ALCenum HrtfStatus{ALC_FALSE};
2018-11-26 14:48:26 -08:00
std::atomic<ALCenum> LastError{ALC_NO_ERROR};
2007-11-13 18:02:18 -08:00
// Maximum number of sources that can be created
ALuint SourcesMax{};
// Maximum number of slots that can be created
ALuint AuxiliaryEffectSlotMax{};
2007-11-13 18:02:18 -08:00
ALCuint NumMonoSources{};
ALCuint NumStereoSources{};
ALsizei NumAuxSends{};
// Map of Buffers for this device
std::mutex BufferLock;
al::vector<BufferSubList> BufferList;
2009-08-15 09:14:08 -07:00
2010-05-18 17:41:06 -07:00
// Map of Effects for this device
std::mutex EffectLock;
al::vector<EffectSubList> EffectList;
2010-05-18 17:54:45 -07:00
// Map of Filters for this device
std::mutex FilterLock;
al::vector<FilterSubList> FilterList;
/* Rendering mode. */
RenderMode mRenderMode{NormalRender};
2018-11-29 13:08:03 -08:00
/* 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};
2011-05-01 13:19:23 -07:00
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];
2019-03-22 18:37:47 -07:00
/* Mixing buffer used by the Dry mix and Real output. */
al::vector<FloatBufferLine, 16> MixBuffer;
/* The "dry" path corresponds to the main output. */
2018-09-19 21:31:46 -07:00
MixParams Dry;
ALuint NumChannelsPerOrder[MAX_AMBI_ORDER+1]{};
2016-07-05 14:18:17 -07:00
/* "Real" output, which will be written to the device buffer. May alias the
* dry buffer.
*/
RealMixParams RealOut;
2018-11-29 13:08:03 -08:00
/* HRTF state and info */
std::unique_ptr<DirectHrtfState> mHrtfState;
2018-12-22 09:20:50 -08:00
HrtfEntry *mHrtf{nullptr};
/* Ambisonic-to-UHJ encoder */
2018-11-29 13:08:03 -08:00
std::unique_ptr<Uhj2Encoder> Uhj_Encoder;
/* Ambisonic decoder for speakers */
2018-11-29 13:08:03 -08:00
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
2018-11-26 14:48:26 -08:00
std::atomic<ALCcontext*> ContextList{nullptr};
2007-11-13 18:02:18 -08:00
2018-12-30 21:38:42 -08:00
/* 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;
2018-12-29 02:16:16 -08:00
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(); }
DEF_NEWDEL(ALCdevice)
2007-11-13 18:02:18 -08:00
};
/* Must be less than 15 characters (16 including terminating null) for
* compatibility with pthread_setname_np limitations. */
#define MIXER_THREAD_NAME "alsoft-mixer"
2014-12-21 10:38:40 -08:00
#define RECORD_THREAD_NAME "alsoft-record"
enum {
2018-09-20 21:59:38 -07:00
/* 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,
2018-02-03 01:07:06 -08:00
EventType_Disconnected = 1<<5,
/* Internal events. */
EventType_ReleaseEffectState = 65536,
};
struct AsyncEvent {
unsigned int EnumType{0u};
2018-09-20 21:59:38 -07:00
union {
char dummy;
struct {
ALuint id;
ALenum state;
} srcstate;
struct {
ALuint id;
ALsizei count;
} bufcomp;
2018-09-20 21:59:38 -07:00
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} { }
};
2018-01-12 02:37:48 -08:00
void AllocateVoices(ALCcontext *context, size_t num_voices);
2007-11-13 18:02:18 -08:00
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]; }
2010-01-12 09:05:57 -08:00
2012-08-13 08:53:36 -07:00
2018-11-18 18:04:27 -08:00
void StartEventThrd(ALCcontext *ctx);
void StopEventThrd(ALCcontext *ctx);
al::vector<std::string> SearchDataFiles(const char *match, const char *subdir);
2007-11-13 18:02:18 -08:00
#endif