Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qaudiohelpers.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtCore/qdebug.h>
7#include <QtMultimedia/private/qaudio_qspan_support_p.h>
8#include <QtMultimedia/private/qmultimedia_enum_to_string_converter_p.h>
9
10#include <limits>
11
12QT_BEGIN_NAMESPACE
13
15{
16
17#if defined(Q_CC_GNU)
18# define QT_MM_RESTRICT __restrict__
19#elif defined(Q_CC_MSVC)
20# define QT_MM_RESTRICT __restrict
21#else
22# define QT_MM_RESTRICT /*__restrict__*/
23#endif
24
25namespace {
26
27template<class T>
28inline T applyVolumeOnSample(T sample, float factor)
29{
30 if constexpr (std::is_signed_v<T>) {
31 return sample * factor;
32 } else {
33 using SignedT = std::make_signed_t<T>;
34 // Unsigned samples are biased around 0x80/0x8000
35 constexpr T offset = SignedT(1) << (std::numeric_limits<T>::digits - 1);
36 return offset + (SignedT(sample - offset) * factor);
37 }
38}
39
40template<class T>
41void adjustSamples(float factor,
42 const void *QT_MM_RESTRICT src,
43 void *QT_MM_RESTRICT dst,
44 int samples)
45{
46 const T *pSrc = (const T *)src;
47 T *pDst = (T *)dst;
48
49 for (int i = 0; i < samples; i++)
50 pDst[i] = applyVolumeOnSample(pSrc[i], factor);
51}
52
53} // namespace
54
56 const QAudioFormat &format,
57 const void *src,
58 void *dest,
60{
61 const int samplesCount = len / qMax(1, format.bytesPerSample());
62
63 auto clamp = [](float arg) {
64 float realVolume = std::clamp<float>(arg, 0.f, 1.f);
65 return realVolume;
66 };
67
68 switch (format.sampleFormat()) {
69 case QAudioFormat::UInt8:
71 case QAudioFormat::Int16:
73 case QAudioFormat::Int32:
75 case QAudioFormat::Float:
77 default:
79 }
80}
81
83 const QAudioFormat &format,
84 QSpan<const std::byte> source,
86{
88
89 if (Q_LIKELY(volume == 1.f)) {
91 } else if (volume == 0) {
92 std::byte zero =
93 format.sampleFormat() == QAudioFormat::UInt8 ? std::byte{ 0x80 } : std::byte{ 0 };
94
96 } else {
98 source.size());
99 }
100}
101
102namespace {
103
104template <NativeSampleFormat Format>
106{
107 switch (Format) {
109 constexpr int32_t offset = (1 << 7);
111 int32_t val = (int32_t(smp) - offset) << 24;
112 return val;
113 }
115 union CastUnion {
116 std::int16_t i16;
117 std::byte b[2];
118 } castUnion = {};
119
121
122 int32_t val = castUnion.i16 << 16;
123 return val;
124 }
126 union CastUnion {
127 std::int32_t i32;
128 std::byte b[4];
129 } castUnion = {};
130
132
133 int32_t val = castUnion.i32 << 8;
134 return val;
135 }
137 union CastUnion {
138 std::int32_t i32;
139 std::byte b[4];
140 } castUnion = {};
141
143 int32_t val = castUnion.i32 << 8;
144 return val;
145 }
147 union CastUnion {
148 float f32;
149 std::byte b[4];
150 } castUnion = {};
151
153 constexpr double range = std::numeric_limits<int32_t>::max();
155 return val;
156 }
158 union CastUnion {
159 std::int32_t i32;
160 std::byte b[4];
161 } castUnion = {};
162
164 return castUnion.i32;
165 }
166
167 default:
169 }
170}
171
172template <NativeSampleFormat Format>
175{
176 switch (Format) {
178 value = value >> 24;
179 constexpr int32_t offset = 1 << 7;
181 std::copy_n(reinterpret_cast<const std::byte *>(&sampleValue), 1, destination.data());
182 return;
183 }
185 value = value >> 16;
187 std::copy_n(reinterpret_cast<const std::byte *>(&sampleValue), 2, destination.data());
188 return;
189 }
190
193 std::copy_n(reinterpret_cast<const std::byte *>(&sampleValue), 3, destination.data());
194 return;
195 }
196
198 int32_t sampleValue = (value >> 8) & 0x00ffffff;
199 std::copy_n(reinterpret_cast<const std::byte *>(&sampleValue), 4, destination.data());
200 return;
201 }
203 std::copy_n(reinterpret_cast<const std::byte *>(&value), 4, destination.data());
204 return;
205 }
207 constexpr double normalizationFactor = 1.0 / std::numeric_limits<int32_t>::max();
208 float sampleValue = float(double(value) * normalizationFactor);
209 std::copy_n(reinterpret_cast<const std::byte *>(&sampleValue), 4, destination.data());
210 return;
211 }
212 default:
214 }
215}
216
218struct WordConverter
219{
221 {
222 if constexpr (sourceFormat == destinationFormat) {
224 } else {
227
228 using namespace QtMultimediaPrivate;
229 while (!source.isEmpty()) {
230 if (size_t(source.size()) >= 4 * bytesPerSampleSource) {
231 // unroll by 4.
232 // should help the compiler to vectorize, or at least avoid pipeline stalls.
233
242
247
256
261 } else {
264
267
270 }
271 }
272 }
273 }
274};
275
280{
281 switch (sourceFormat) {
297 default:
299 }
300}
301
302} // namespace
303
307{
308 using namespace QtMultimediaPrivate;
309
312
314
315 switch (destinationFormat) {
334 default:
336 }
337}
338
341{
343
347
348 if (it != candidates.end())
349 return *it;
350
351 qFatal() << "No candidate for conversion found. That should not happen";
353 };
354
355 // heuristics:
356 // select the best format that does not involve precision
357 // if that does not yield a format, find a format with the least loss of precision.
358 switch (fmt.sampleFormat()) {
360 constexpr auto candidates = std::array{
364 };
365
367 }
369 constexpr auto candidates = std::array{
373 };
374
376 }
378 constexpr auto candidates = std::array{
382
383 };
384
386 }
388 constexpr auto candidates = std::array{
392 };
393
395 }
398 qFatal() << "bestNativeSampleFormat called with invalid argument" << fmt.sampleFormat();
400 }
401
402 default: {
404 }
405 }
406}
407
423
441
442} // namespace QAudioHelperInternal
443
444#undef QT_MM_RESTRICT
445
446// clang-format off
448 (QAudioHelperInternal::NativeSampleFormat::uint8_t, "uint8_t")
449 (QAudioHelperInternal::NativeSampleFormat::int16_t, "int16_t")
450 (QAudioHelperInternal::NativeSampleFormat::int32_t, "int32_t")
451 (QAudioHelperInternal::NativeSampleFormat::int24_t_3b, "int24_t_3b")
452 (QAudioHelperInternal::NativeSampleFormat::int24_t_4b_low, "int24_t_4b_low")
453 (QAudioHelperInternal::NativeSampleFormat::float32_t, "float32_t")
454 );
455// clang-format on
456
458
459QT_END_NAMESPACE
QT_MM_MAKE_STRING_RESOLVER(QAudioHelperInternal::NativeSampleFormat, QtMultimediaPrivate::EnumName,(QAudioHelperInternal::NativeSampleFormat::uint8_t, "uint8_t")(QAudioHelperInternal::NativeSampleFormat::int16_t, "int16_t")(QAudioHelperInternal::NativeSampleFormat::int32_t, "int32_t")(QAudioHelperInternal::NativeSampleFormat::int24_t_3b, "int24_t_3b")(QAudioHelperInternal::NativeSampleFormat::int24_t_4b_low, "int24_t_4b_low")(QAudioHelperInternal::NativeSampleFormat::float32_t, "float32_t"))
#define QT_MM_RESTRICT
QT_MM_DEFINE_QDEBUG_ENUM(QAudioHelperInternal::NativeSampleFormat)