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 44100
42 #define DEFAULT_UPDATE_SIZE 882 /* 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 {
66 struct InputRemixMap
{
67 struct TargetMix
{ Channel channel
; float mix
; };
70 std::array
<TargetMix
,2> targets
;
74 /* Maximum delay in samples for speaker distance compensation. */
75 #define MAX_DELAY_LENGTH 1024
80 uint Length
{0u}; /* Valid range is [0...MAX_DELAY_LENGTH). */
81 float *Buffer
{nullptr};
84 std::array
<ChanData
,MAX_OUTPUT_CHANNELS
> mChannels
;
85 al::FlexArray
<float,16> mSamples
;
87 DistanceComp(size_t count
) : mSamples
{count
} { }
89 static std::unique_ptr
<DistanceComp
> Create(size_t numsamples
)
90 { return std::unique_ptr
<DistanceComp
>{new(FamCount(numsamples
)) DistanceComp
{numsamples
}}; }
92 DEF_FAM_NEWDEL(DistanceComp
, mSamples
)
96 struct BFChannelConfig
{
103 /* Coefficient channel mapping for mixing to the buffer. */
104 std::array
<BFChannelConfig
,MAX_OUTPUT_CHANNELS
> AmbiMap
{};
106 al::span
<FloatBufferLine
> Buffer
;
109 struct RealMixParams
{
110 al::span
<const InputRemixMap
> RemixMap
;
111 std::array
<uint
,MaxChannels
> ChannelIndex
{};
113 al::span
<FloatBufferLine
> Buffer
;
117 // Frequency was requested by the app or config file
119 // Channel configuration was requested by the config file
121 // Sample type was requested by the config file
124 // Specifies if the DSP is paused at user request
126 // Specifies if the device is currently running
129 // Specifies if the output plays directly on/in ears (headphones, headset,
137 /* To avoid extraneous allocations, a 0-sized FlexArray<ContextBase*> is
138 * defined globally as a sharable object.
140 static al::FlexArray
<ContextBase
*> sEmptyContextArray
;
142 std::atomic
<bool> Connected
{true};
143 const DeviceType Type
{};
149 DevFmtChannels FmtChans
{};
150 DevFmtType FmtType
{};
152 float mXOverFreq
{400.0f
};
153 /* For DevFmtAmbi* output only, specifies the channel order and
156 DevAmbiLayout mAmbiLayout
{DevAmbiLayout::Default
};
157 DevAmbiScaling mAmbiScale
{DevAmbiScaling::Default
};
159 std::string DeviceName
;
162 std::bitset
<DeviceFlagsCount
> Flags
{};
166 /* Rendering mode. */
167 RenderMode mRenderMode
{RenderMode::Normal
};
169 /* The average speaker distance as determined by the ambdec configuration,
170 * HRTF data set, or the NFC-HOA reference delay. Only used for NFC.
172 float AvgSpeakerDist
{0.0f
};
174 /* The default NFC filter. Not used directly, but is pre-initialized with
175 * the control distance from AvgSpeakerDist.
177 NfcFilter mNFCtrlFilter
{};
179 uint SamplesDone
{0u};
180 std::chrono::nanoseconds ClockBase
{0};
181 std::chrono::nanoseconds FixedLatency
{0};
183 /* Temp storage used for mixer processing. */
184 static constexpr size_t MixerLineSize
{BufferLineSize
+ MaxResamplerPadding
+
185 UhjDecoder::sFilterDelay
};
186 static constexpr size_t MixerChannelsMax
{16};
187 using MixerBufferLine
= std::array
<float,MixerLineSize
>;
188 alignas(16) std::array
<MixerBufferLine
,MixerChannelsMax
> mSampleData
;
190 alignas(16) float ResampledData
[BufferLineSize
];
191 alignas(16) float FilteredData
[BufferLineSize
];
193 alignas(16) float HrtfSourceData
[BufferLineSize
+ HrtfHistoryLength
];
194 alignas(16) float NfcSampleData
[BufferLineSize
];
197 /* Persistent storage for HRTF mixing. */
198 alignas(16) float2 HrtfAccumData
[BufferLineSize
+ HrirLength
+ HrtfDirectDelay
];
200 /* Mixing buffer used by the Dry mix and Real output. */
201 al::vector
<FloatBufferLine
, 16> MixBuffer
;
203 /* The "dry" path corresponds to the main output. */
205 uint NumChannelsPerOrder
[MaxAmbiOrder
+1]{};
207 /* "Real" output, which will be written to the device buffer. May alias the
210 RealMixParams RealOut
;
212 /* HRTF state and info */
213 std::unique_ptr
<DirectHrtfState
> mHrtfState
;
214 al::intrusive_ptr
<HrtfStore
> mHrtf
;
217 /* Ambisonic-to-UHJ encoder */
218 std::unique_ptr
<UhjEncoder
> mUhjEncoder
;
220 /* Ambisonic decoder for speakers */
221 std::unique_ptr
<BFormatDec
> AmbiDecoder
;
223 /* Stereo-to-binaural filter */
224 std::unique_ptr
<bs2b
> Bs2b
;
226 using PostProc
= void(DeviceBase::*)(const size_t SamplesToDo
);
227 PostProc PostProcess
{nullptr};
229 std::unique_ptr
<Compressor
> Limiter
;
231 /* Delay buffers used to compensate for speaker distances. */
232 std::unique_ptr
<DistanceComp
> ChannelDelays
;
234 /* Dithering control. */
235 float DitherDepth
{0.0f
};
238 /* Running count of the mixer invocations, in 31.1 fixed point. This
239 * actually increments *twice* when mixing, first at the start and then at
240 * the end, so the bottom bit indicates if the device is currently mixing
241 * and the upper bits indicates how many mixes have been done.
243 RefCount MixCount
{0u};
245 // Contexts created on this device
246 std::atomic
<al::FlexArray
<ContextBase
*>*> mContexts
{nullptr};
249 DeviceBase(DeviceType type
);
250 DeviceBase(const DeviceBase
&) = delete;
251 DeviceBase
& operator=(const DeviceBase
&) = delete;
254 uint
bytesFromFmt() const noexcept
{ return BytesFromDevFmt(FmtType
); }
255 uint
channelsFromFmt() const noexcept
{ return ChannelsFromDevFmt(FmtChans
, mAmbiOrder
); }
256 uint
frameSizeFromFmt() const noexcept
{ return bytesFromFmt() * channelsFromFmt(); }
258 uint
waitForMix() const noexcept
261 while((refcount
=MixCount
.load(std::memory_order_acquire
))&1) {
266 void ProcessHrtf(const size_t SamplesToDo
);
267 void ProcessAmbiDec(const size_t SamplesToDo
);
268 void ProcessAmbiDecStablized(const size_t SamplesToDo
);
269 void ProcessUhj(const size_t SamplesToDo
);
270 void ProcessBs2b(const size_t SamplesToDo
);
272 inline void postProcess(const size_t SamplesToDo
)
273 { if LIKELY(PostProcess
) (this->*PostProcess
)(SamplesToDo
); }
275 void renderSamples(const al::span
<float*> outBuffers
, const uint numSamples
);
276 void renderSamples(void *outBuffer
, const uint numSamples
, const size_t frameStep
);
278 /* Caller must lock the device state, and the mixer must not be running. */
279 #ifdef __USE_MINGW_ANSI_STDIO
280 [[gnu::format(gnu_printf
,2,3)]]
282 [[gnu::format(printf
,2,3)]]
284 void handleDisconnect(const char *msg
, ...);
289 uint
renderSamples(const uint numSamples
);
293 /* Must be less than 15 characters (16 including terminating null) for
294 * compatibility with pthread_setname_np limitations. */
295 #define MIXER_THREAD_NAME "alsoft-mixer"
297 #define RECORD_THREAD_NAME "alsoft-record"
301 * Returns the index for the given channel name (e.g. FrontCenter), or
302 * INVALID_CHANNEL_INDEX if it doesn't exist.
304 inline uint
GetChannelIdxByName(const RealMixParams
&real
, Channel chan
) noexcept
305 { return real
.ChannelIndex
[chan
]; }
306 #define INVALID_CHANNEL_INDEX ~0u
308 #endif /* CORE_DEVICE_H */