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"
32 struct DirectHrtfState;
35 using uint = unsigned int;
38 #define MIN_OUTPUT_RATE 8000
39 #define MAX_OUTPUT_RATE 192000
40 #define DEFAULT_OUTPUT_RATE 48000
42 #define DEFAULT_UPDATE_SIZE 960 /* 20ms */
43 #define DEFAULT_NUM_UPDATES 3
46 enum class DeviceType : unsigned char {
53 enum class RenderMode : unsigned char {
59 enum class StereoEncoding : unsigned char {
68 struct InputRemixMap {
69 struct TargetMix { Channel channel; float mix; };
72 al::span<const TargetMix> targets;
77 /* Maximum delay in samples for speaker distance compensation. */
78 static constexpr uint MaxDelay{1024};
82 uint Length{0u}; /* Valid range is [0...MaxDelay). */
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 constexpr uint InvalidChannelIndex{~0u};
100 struct BFChannelConfig {
106 /* Coefficient channel mapping for mixing to the buffer. */
107 std::array<BFChannelConfig,MaxAmbiChannels> AmbiMap{};
109 al::span<FloatBufferLine> Buffer;
112 * Helper to set an identity/pass-through panning for ambisonic mixing. The
113 * source is expected to be a 3D ACN/N3D ambisonic buffer, and for each
114 * channel [0...count), the given functor is called with the source channel
115 * index, destination channel index, and the gain for that channel. If the
116 * destination channel is INVALID_CHANNEL_INDEX, the given source channel
117 * is not used for output.
120 void setAmbiMixParams(const MixParams &inmix, const float gainbase, F func) const
122 const size_t numIn{inmix.Buffer.size()};
123 const size_t numOut{Buffer.size()};
124 for(size_t i{0};i < numIn;++i)
126 auto idx = InvalidChannelIndex;
129 for(size_t j{0};j < numOut;++j)
131 if(AmbiMap[j].Index == inmix.AmbiMap[i].Index)
133 idx = static_cast<uint>(j);
134 gain = AmbiMap[j].Scale * gainbase;
143 struct RealMixParams {
144 al::span<const InputRemixMap> RemixMap;
145 std::array<uint,MaxChannels> ChannelIndex{};
147 al::span<FloatBufferLine> Buffer;
150 using AmbiRotateMatrix = std::array<std::array<float,MaxAmbiChannels>,MaxAmbiChannels>;
153 // Frequency was requested by the app or config file
155 // Channel configuration was requested by the app or config file
157 // Sample type was requested by the config file
160 // Specifies if the DSP is paused at user request
162 // Specifies if the device is currently running
165 // Specifies if the output plays directly on/in ears (headphones, headset,
173 /* To avoid extraneous allocations, a 0-sized FlexArray<ContextBase*> is
174 * defined globally as a sharable object.
176 static al::FlexArray<ContextBase*> sEmptyContextArray;
178 std::atomic<bool> Connected{true};
179 const DeviceType Type{};
185 DevFmtChannels FmtChans{};
186 DevFmtType FmtType{};
188 float mXOverFreq{400.0f};
189 /* If the main device mix is horizontal/2D only. */
190 bool m2DMixing{false};
191 /* For DevFmtAmbi* output only, specifies the channel order and
194 DevAmbiLayout mAmbiLayout{DevAmbiLayout::Default};
195 DevAmbiScaling mAmbiScale{DevAmbiScaling::Default};
197 std::string DeviceName;
200 std::bitset<DeviceFlagsCount> Flags{};
204 /* Rendering mode. */
205 RenderMode mRenderMode{RenderMode::Normal};
207 /* The average speaker distance as determined by the ambdec configuration,
208 * HRTF data set, or the NFC-HOA reference delay. Only used for NFC.
210 float AvgSpeakerDist{0.0f};
212 /* The default NFC filter. Not used directly, but is pre-initialized with
213 * the control distance from AvgSpeakerDist.
215 NfcFilter mNFCtrlFilter{};
217 uint SamplesDone{0u};
218 std::chrono::nanoseconds ClockBase{0};
219 std::chrono::nanoseconds FixedLatency{0};
221 AmbiRotateMatrix mAmbiRotateMatrix{};
222 AmbiRotateMatrix mAmbiRotateMatrix2{};
224 /* Temp storage used for mixer processing. */
225 static constexpr size_t MixerLineSize{BufferLineSize + DecoderBase::sMaxPadding};
226 static constexpr size_t MixerChannelsMax{16};
227 using MixerBufferLine = std::array<float,MixerLineSize>;
228 alignas(16) std::array<MixerBufferLine,MixerChannelsMax> mSampleData;
229 alignas(16) std::array<float,MixerLineSize+MaxResamplerPadding> mResampleData;
231 alignas(16) float FilteredData[BufferLineSize];
233 alignas(16) float HrtfSourceData[BufferLineSize + HrtfHistoryLength];
234 alignas(16) float NfcSampleData[BufferLineSize];
237 /* Persistent storage for HRTF mixing. */
238 alignas(16) float2 HrtfAccumData[BufferLineSize + HrirLength];
240 /* Mixing buffer used by the Dry mix and Real output. */
241 al::vector<FloatBufferLine, 16> MixBuffer;
243 /* The "dry" path corresponds to the main output. */
245 uint NumChannelsPerOrder[MaxAmbiOrder+1]{};
247 /* "Real" output, which will be written to the device buffer. May alias the
250 RealMixParams RealOut;
252 /* HRTF state and info */
253 std::unique_ptr<DirectHrtfState> mHrtfState;
254 al::intrusive_ptr<HrtfStore> mHrtf;
257 /* Ambisonic-to-UHJ encoder */
258 std::unique_ptr<UhjEncoderBase> mUhjEncoder;
260 /* Ambisonic decoder for speakers */
261 std::unique_ptr<BFormatDec> AmbiDecoder;
263 /* Stereo-to-binaural filter */
264 std::unique_ptr<bs2b> Bs2b;
266 using PostProc = void(DeviceBase::*)(const size_t SamplesToDo);
267 PostProc PostProcess{nullptr};
269 std::unique_ptr<Compressor> Limiter;
271 /* Delay buffers used to compensate for speaker distances. */
272 std::unique_ptr<DistanceComp> ChannelDelays;
274 /* Dithering control. */
275 float DitherDepth{0.0f};
278 /* Running count of the mixer invocations, in 31.1 fixed point. This
279 * actually increments *twice* when mixing, first at the start and then at
280 * the end, so the bottom bit indicates if the device is currently mixing
281 * and the upper bits indicates how many mixes have been done.
283 RefCount MixCount{0u};
285 // Contexts created on this device
286 std::atomic<al::FlexArray<ContextBase*>*> mContexts{nullptr};
289 DeviceBase(DeviceType type);
290 DeviceBase(const DeviceBase&) = delete;
291 DeviceBase& operator=(const DeviceBase&) = delete;
294 uint bytesFromFmt() const noexcept { return BytesFromDevFmt(FmtType); }
295 uint channelsFromFmt() const noexcept { return ChannelsFromDevFmt(FmtChans, mAmbiOrder); }
296 uint frameSizeFromFmt() const noexcept { return bytesFromFmt() * channelsFromFmt(); }
298 uint waitForMix() const noexcept
301 while((refcount=MixCount.load(std::memory_order_acquire))&1) {
306 void ProcessHrtf(const size_t SamplesToDo);
307 void ProcessAmbiDec(const size_t SamplesToDo);
308 void ProcessAmbiDecStablized(const size_t SamplesToDo);
309 void ProcessUhj(const size_t SamplesToDo);
310 void ProcessBs2b(const size_t SamplesToDo);
312 inline void postProcess(const size_t SamplesToDo)
313 { if(PostProcess) LIKELY (this->*PostProcess)(SamplesToDo); }
315 void renderSamples(const al::span<float*> outBuffers, const uint numSamples);
316 void renderSamples(void *outBuffer, const uint numSamples, const size_t frameStep);
318 /* Caller must lock the device state, and the mixer must not be running. */
319 #ifdef __USE_MINGW_ANSI_STDIO
320 [[gnu::format(gnu_printf,2,3)]]
322 [[gnu::format(printf,2,3)]]
324 void handleDisconnect(const char *msg, ...);
327 * Returns the index for the given channel name (e.g. FrontCenter), or
328 * INVALID_CHANNEL_INDEX if it doesn't exist.
330 uint channelIdxByName(Channel chan) const noexcept
331 { return RealOut.ChannelIndex[chan]; }
336 uint renderSamples(const uint numSamples);
339 /* Must be less than 15 characters (16 including terminating null) for
340 * compatibility with pthread_setname_np limitations. */
341 #define MIXER_THREAD_NAME "alsoft-mixer"
343 #define RECORD_THREAD_NAME "alsoft-record"
345 #endif /* CORE_DEVICE_H */