Clean up some case spaghetti
[openal-soft.git] / core / device.h
blob58a30f1b5216c9d2a543fc628762583b7fbe32ee
1 #ifndef CORE_DEVICE_H
2 #define CORE_DEVICE_H
4 #include <stddef.h>
6 #include <array>
7 #include <atomic>
8 #include <bitset>
9 #include <chrono>
10 #include <memory>
11 #include <mutex>
12 #include <string>
14 #include "almalloc.h"
15 #include "alspan.h"
16 #include "ambidefs.h"
17 #include "atomic.h"
18 #include "bufferline.h"
19 #include "devformat.h"
20 #include "filters/nfc.h"
21 #include "intrusive_ptr.h"
22 #include "mixer/hrtfdefs.h"
23 #include "opthelpers.h"
24 #include "resampler_limits.h"
25 #include "uhjfilter.h"
26 #include "vector.h"
28 class BFormatDec;
29 struct bs2b;
30 struct Compressor;
31 struct ContextBase;
32 struct DirectHrtfState;
33 struct HrtfStore;
35 using uint = unsigned int;
38 #define MIN_OUTPUT_RATE 8000
39 #define MAX_OUTPUT_RATE 192000
40 #define DEFAULT_OUTPUT_RATE 44100
42 #define DEFAULT_UPDATE_SIZE 882 /* 20ms */
43 #define DEFAULT_NUM_UPDATES 3
46 enum class DeviceType : unsigned char {
47 Playback,
48 Capture,
49 Loopback
53 enum class RenderMode : unsigned char {
54 Normal,
55 Pairwise,
56 Hrtf
59 enum class StereoEncoding : unsigned char {
60 Basic,
61 Uhj,
62 Hrtf,
64 Default = Basic
68 struct InputRemixMap {
69 struct TargetMix { Channel channel; float mix; };
71 Channel channel;
72 std::array<TargetMix,2> targets;
76 /* Maximum delay in samples for speaker distance compensation. */
77 #define MAX_DELAY_LENGTH 1024
79 struct DistanceComp {
80 struct ChanData {
81 float Gain{1.0f};
82 uint Length{0u}; /* Valid range is [0...MAX_DELAY_LENGTH). */
83 float *Buffer{nullptr};
86 std::array<ChanData,MAX_OUTPUT_CHANNELS> mChannels;
87 al::FlexArray<float,16> mSamples;
89 DistanceComp(size_t count) : mSamples{count} { }
91 static std::unique_ptr<DistanceComp> Create(size_t numsamples)
92 { return std::unique_ptr<DistanceComp>{new(FamCount(numsamples)) DistanceComp{numsamples}}; }
94 DEF_FAM_NEWDEL(DistanceComp, mSamples)
98 struct BFChannelConfig {
99 float Scale;
100 uint Index;
104 struct MixParams {
105 /* Coefficient channel mapping for mixing to the buffer. */
106 std::array<BFChannelConfig,MAX_OUTPUT_CHANNELS> AmbiMap{};
108 al::span<FloatBufferLine> Buffer;
111 struct RealMixParams {
112 al::span<const InputRemixMap> RemixMap;
113 std::array<uint,MaxChannels> ChannelIndex{};
115 al::span<FloatBufferLine> Buffer;
118 enum {
119 // Frequency was requested by the app or config file
120 FrequencyRequest,
121 // Channel configuration was requested by the config file
122 ChannelsRequest,
123 // Sample type was requested by the config file
124 SampleTypeRequest,
126 // Specifies if the DSP is paused at user request
127 DevicePaused,
128 // Specifies if the device is currently running
129 DeviceRunning,
131 // Specifies if the output plays directly on/in ears (headphones, headset,
132 // ear buds, etc).
133 DirectEar,
135 DeviceFlagsCount
138 struct DeviceBase {
139 /* To avoid extraneous allocations, a 0-sized FlexArray<ContextBase*> is
140 * defined globally as a sharable object.
142 static al::FlexArray<ContextBase*> sEmptyContextArray;
144 std::atomic<bool> Connected{true};
145 const DeviceType Type{};
147 uint Frequency{};
148 uint UpdateSize{};
149 uint BufferSize{};
151 DevFmtChannels FmtChans{};
152 DevFmtType FmtType{};
153 uint mAmbiOrder{0};
154 float mXOverFreq{400.0f};
155 /* For DevFmtAmbi* output only, specifies the channel order and
156 * normalization.
158 DevAmbiLayout mAmbiLayout{DevAmbiLayout::Default};
159 DevAmbiScaling mAmbiScale{DevAmbiScaling::Default};
161 std::string DeviceName;
163 // Device flags
164 std::bitset<DeviceFlagsCount> Flags{};
166 uint NumAuxSends{};
168 /* Rendering mode. */
169 RenderMode mRenderMode{RenderMode::Normal};
171 /* The average speaker distance as determined by the ambdec configuration,
172 * HRTF data set, or the NFC-HOA reference delay. Only used for NFC.
174 float AvgSpeakerDist{0.0f};
176 /* The default NFC filter. Not used directly, but is pre-initialized with
177 * the control distance from AvgSpeakerDist.
179 NfcFilter mNFCtrlFilter{};
181 uint SamplesDone{0u};
182 std::chrono::nanoseconds ClockBase{0};
183 std::chrono::nanoseconds FixedLatency{0};
185 /* Temp storage used for mixer processing. */
186 static constexpr size_t MixerLineSize{BufferLineSize + MaxResamplerPadding +
187 UhjDecoder::sFilterDelay};
188 static constexpr size_t MixerChannelsMax{16};
189 using MixerBufferLine = std::array<float,MixerLineSize>;
190 alignas(16) std::array<MixerBufferLine,MixerChannelsMax> mSampleData;
192 alignas(16) float ResampledData[BufferLineSize];
193 alignas(16) float FilteredData[BufferLineSize];
194 union {
195 alignas(16) float HrtfSourceData[BufferLineSize + HrtfHistoryLength];
196 alignas(16) float NfcSampleData[BufferLineSize];
199 /* Persistent storage for HRTF mixing. */
200 alignas(16) float2 HrtfAccumData[BufferLineSize + HrirLength];
202 /* Mixing buffer used by the Dry mix and Real output. */
203 al::vector<FloatBufferLine, 16> MixBuffer;
205 /* The "dry" path corresponds to the main output. */
206 MixParams Dry;
207 uint NumChannelsPerOrder[MaxAmbiOrder+1]{};
209 /* "Real" output, which will be written to the device buffer. May alias the
210 * dry buffer.
212 RealMixParams RealOut;
214 /* HRTF state and info */
215 std::unique_ptr<DirectHrtfState> mHrtfState;
216 al::intrusive_ptr<HrtfStore> mHrtf;
217 uint mIrSize{0};
219 /* Ambisonic-to-UHJ encoder */
220 std::unique_ptr<UhjEncoder> mUhjEncoder;
222 /* Ambisonic decoder for speakers */
223 std::unique_ptr<BFormatDec> AmbiDecoder;
225 /* Stereo-to-binaural filter */
226 std::unique_ptr<bs2b> Bs2b;
228 using PostProc = void(DeviceBase::*)(const size_t SamplesToDo);
229 PostProc PostProcess{nullptr};
231 std::unique_ptr<Compressor> Limiter;
233 /* Delay buffers used to compensate for speaker distances. */
234 std::unique_ptr<DistanceComp> ChannelDelays;
236 /* Dithering control. */
237 float DitherDepth{0.0f};
238 uint DitherSeed{0u};
240 /* Running count of the mixer invocations, in 31.1 fixed point. This
241 * actually increments *twice* when mixing, first at the start and then at
242 * the end, so the bottom bit indicates if the device is currently mixing
243 * and the upper bits indicates how many mixes have been done.
245 RefCount MixCount{0u};
247 // Contexts created on this device
248 std::atomic<al::FlexArray<ContextBase*>*> mContexts{nullptr};
251 DeviceBase(DeviceType type);
252 DeviceBase(const DeviceBase&) = delete;
253 DeviceBase& operator=(const DeviceBase&) = delete;
254 ~DeviceBase();
256 uint bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); }
257 uint channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); }
258 uint frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); }
260 uint waitForMix() const noexcept
262 uint refcount;
263 while((refcount=MixCount.load(std::memory_order_acquire))&1) {
265 return refcount;
268 void ProcessHrtf(const size_t SamplesToDo);
269 void ProcessAmbiDec(const size_t SamplesToDo);
270 void ProcessAmbiDecStablized(const size_t SamplesToDo);
271 void ProcessUhj(const size_t SamplesToDo);
272 void ProcessBs2b(const size_t SamplesToDo);
274 inline void postProcess(const size_t SamplesToDo)
275 { if LIKELY(PostProcess) (this->*PostProcess)(SamplesToDo); }
277 void renderSamples(const al::span<float*> outBuffers, const uint numSamples);
278 void renderSamples(void *outBuffer, const uint numSamples, const size_t frameStep);
280 /* Caller must lock the device state, and the mixer must not be running. */
281 #ifdef __USE_MINGW_ANSI_STDIO
282 [[gnu::format(gnu_printf,2,3)]]
283 #else
284 [[gnu::format(printf,2,3)]]
285 #endif
286 void handleDisconnect(const char *msg, ...);
288 DISABLE_ALLOC()
290 private:
291 uint renderSamples(const uint numSamples);
295 /* Must be less than 15 characters (16 including terminating null) for
296 * compatibility with pthread_setname_np limitations. */
297 #define MIXER_THREAD_NAME "alsoft-mixer"
299 #define RECORD_THREAD_NAME "alsoft-record"
303 * Returns the index for the given channel name (e.g. FrontCenter), or
304 * INVALID_CHANNEL_INDEX if it doesn't exist.
306 inline uint GetChannelIdxByName(const RealMixParams &real, Channel chan) noexcept
307 { return real.ChannelIndex[chan]; }
308 #define INVALID_CHANNEL_INDEX ~0u
310 #endif /* CORE_DEVICE_H */