openal-soft/alc/alcmain.h

387 lines
11 KiB
C
Raw Normal View History

#ifndef ALC_MAIN_H
#define ALC_MAIN_H
2007-11-13 18:02:18 -08:00
#include <algorithm>
2018-11-19 06:50:37 -08:00
#include <array>
#include <atomic>
#include <chrono>
#include <cstdint>
#include <cstddef>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
2009-05-16 23:26:39 -07:00
#include "AL/al.h"
#include "AL/alc.h"
#include "AL/alext.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 "ambidefs.h"
#include "atomic.h"
#include "bufferline.h"
#include "devformat.h"
#include "filters/splitter.h"
#include "hrtf.h"
#include "inprogext.h"
#include "intrusive_ptr.h"
#include "vector.h"
class BFormatDec;
struct ALbuffer;
struct ALeffect;
struct ALfilter;
struct BackendBase;
struct Compressor;
struct EffectState;
struct Uhj2Encoder;
struct bs2b;
2013-10-28 12:48:13 -07:00
2019-04-26 18:56:54 -07:00
#define MIN_OUTPUT_RATE 8000
2020-04-28 16:30:11 -07:00
#define MAX_OUTPUT_RATE 192000
2019-04-26 18:56:54 -07:00
#define DEFAULT_OUTPUT_RATE 44100
2020-04-28 16:30:11 -07:00
2019-04-26 18:56:54 -07:00
#define DEFAULT_UPDATE_SIZE 882 /* 20ms */
#define DEFAULT_NUM_UPDATES 3
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 InputRemixMap {
struct TargetMix { Channel channel; float mix; };
Channel channel;
std::array<TargetMix,2> targets;
};
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 {
2020-03-30 13:43:49 -07:00
float Gain{1.0f};
ALuint Length{0u}; /* Valid range is [0...MAX_DELAY_LENGTH). */
2020-03-30 13:43:49 -07:00
float *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;
2020-03-30 13:43:49 -07:00
al::vector<float,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);
}
2020-03-30 13:43:49 -07:00
float *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 {
2020-03-30 13:43:49 -07:00
float Scale;
2019-09-14 08:50:07 -07:00
ALuint Index;
};
/* Maximum number of samples to pad on the ends of a buffer for resampling.
* Note that the padding is symmetric (half at the beginning and half at the
* end)!
*/
#define MAX_RESAMPLER_PADDING 48
2012-09-14 02:14:29 -07:00
struct MixParams {
/* Coefficient channel mapping for mixing to the buffer. */
2019-07-04 15:02:12 -07:00
std::array<BFChannelConfig,MAX_OUTPUT_CHANNELS> AmbiMap{};
2019-07-04 15:02:12 -07:00
al::span<FloatBufferLine> Buffer;
};
struct RealMixParams {
al::span<const InputRemixMap> RemixMap;
2019-09-12 04:17:21 -07:00
std::array<ALuint,MaxChannels> ChannelIndex{};
2019-07-03 23:26:33 -07:00
al::span<FloatBufferLine> Buffer;
};
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 : public al::intrusive_ref<ALCdevice> {
std::atomic<bool> Connected{true};
const DeviceType Type{};
ALuint Frequency{};
ALuint UpdateSize{};
ALuint BufferSize{};
DevFmtChannels FmtChans{};
2019-09-13 20:04:22 -07:00
DevFmtType FmtType{};
2020-03-28 15:37:34 -07:00
bool IsHeadphones{false};
2019-09-13 20:04:22 -07:00
ALuint 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<std::string> HrtfList;
2018-11-29 13:08:03 -08:00
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{};
2019-09-13 04:15:05 -07:00
ALCuint 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};
/* The average speaker distance as determined by the ambdec configuration,
* HRTF data set, or the NFC-HOA reference delay. Only used for NFC.
2018-11-29 13:08:03 -08:00
*/
2020-03-30 13:43:49 -07:00
float 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. */
2020-03-30 13:43:49 -07:00
alignas(16) float SourceData[BUFFERSIZE + MAX_RESAMPLER_PADDING];
alignas(16) float ResampledData[BUFFERSIZE];
alignas(16) float FilteredData[BUFFERSIZE];
union {
2020-03-30 13:43:49 -07:00
alignas(16) float HrtfSourceData[BUFFERSIZE + HRTF_HISTORY_LENGTH];
alignas(16) float NfcSampleData[BUFFERSIZE];
};
/* Persistent storage for HRTF mixing. */
alignas(16) float2 HrtfAccumData[BUFFERSIZE + HRIR_LENGTH + HRTF_DIRECT_DELAY];
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;
al::intrusive_ptr<HrtfStore> mHrtf;
/* 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;
using PostProc = void(ALCdevice::*)(const size_t SamplesToDo);
PostProc PostProcess{nullptr};
2018-11-29 13:08:03 -08:00
std::unique_ptr<Compressor> Limiter;
/* Delay buffers used to compensate for speaker distances. */
DistanceComp ChannelDelay;
/* Dithering control. */
2020-03-30 13:43:49 -07:00
float 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<al::FlexArray<ALCcontext*>*> mContexts{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();
ALuint bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); }
ALuint channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); }
ALuint frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); }
ALuint waitForMix() const noexcept
{
ALuint refcount;
while((refcount=MixCount.load(std::memory_order_acquire))&1) {
}
return refcount;
}
void ProcessHrtf(const size_t SamplesToDo);
void ProcessAmbiDec(const size_t SamplesToDo);
void ProcessAmbiDecStablized(const size_t SamplesToDo);
void ProcessUhj(const size_t SamplesToDo);
void ProcessBs2b(const size_t SamplesToDo);
inline void postProcess(const size_t SamplesToDo)
{ if LIKELY(PostProcess) (this->*PostProcess)(SamplesToDo); }
void renderSamples(void *outBuffer, const ALuint numSamples, const size_t frameStep);
/* Caller must lock the device state, and the mixer must not be running. */
[[gnu::format(printf,2,3)]] void handleDisconnect(const char *msg, ...);
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"
extern int RTPrioLevel;
void SetRTPriority(void);
const ALCchar *DevFmtTypeString(DevFmtType type) noexcept;
const ALCchar *DevFmtChannelsString(DevFmtChannels chans) noexcept;
/**
2019-09-12 04:17:21 -07:00
* Returns the index for the given channel name (e.g. FrontCenter), or
* INVALID_CHANNEL_INDEX if it doesn't exist.
*/
2019-09-12 04:17:21 -07:00
inline ALuint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexcept
{ return real.ChannelIndex[chan]; }
2019-09-12 04:17:21 -07:00
#define INVALID_CHANNEL_INDEX ~0u
2010-01-12 09:05:57 -08:00
2012-08-13 08:53:36 -07:00
al::vector<std::string> SearchDataFiles(const char *match, const char *subdir);
2007-11-13 18:02:18 -08:00
#endif