Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
audiogenerationutils_p.h
Go to the documentation of this file.
1
// Copyright (C) 2024 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4
#
ifndef
AUDIOGENERATIONUTILS_H
5
#
define
AUDIOGENERATIONUTILS_H
6
7
8
//
9
// W A R N I N G
10
// -------------
11
//
12
// This file is not part of the Qt API. It exists purely as an
13
// implementation detail. This header file may change from version to
14
// version without notice, or even be removed.
15
//
16
// We mean it.
17
//
18
19
#
include
<
QtMultimedia
/
qaudioformat
.
h
>
20
#
include
<
QtMultimedia
/
qaudiobuffer
.
h
>
21
#
include
<
QtCore
/
qiodevice
.
h
>
22
#
include
<
QtCore
/
qmath
.
h
>
23
#
include
<
QtCore
/
qtemporaryfile
.
h
>
24
25
#
include
<
chrono
>
26
#
include
<
cmath
>
27
#
include
<
cstdint
>
28
#
include
<
limits
>
29
#
include
<
memory
>
30
31
QT_BEGIN_NAMESPACE
32
33
class
SineWaveGenerator
34
{
35
public
:
36
static
constexpr
double
tau = 2 *
M_PI
;
37
38
SineWaveGenerator(std::uint32_t phase, std::uint32_t increment)
39
: m_phase(phase), m_increment(increment)
40
{
41
}
42
43
SineWaveGenerator(
double
frequency,
double
sampleRate,
double
phase = 0.0)
44
: SineWaveGenerator(phaseToFixedPoint(phase), incrementFromFrequency(frequency, sampleRate))
45
{
46
}
47
48
static
std::uint32_t phaseToFixedPoint(
double
phase)
49
{
50
constexpr
double
scale =
static_cast
<
double
>(std::numeric_limits<std::uint32_t>::max());
51
double
normalizedPhase = std::fmod(phase, tau);
52
if
(normalizedPhase < 0.0)
53
normalizedPhase += tau;
54
return
std::uint32_t((normalizedPhase / tau) * scale);
55
}
56
57
static
std::uint32_t incrementFromFrequency(
double
frequency,
double
sampleRate)
58
{
59
constexpr
double
scale =
static_cast
<
double
>(std::numeric_limits<std::uint32_t>::max());
60
return
std::uint32_t((frequency / sampleRate) * scale);
61
}
62
63
double
getSample()
const
64
{
65
constexpr
double
scale =
static_cast
<
double
>(UINT32_MAX);
66
return
std::sin(tau * (
static_cast
<
double
>(m_phase) / scale));
67
}
68
69
void
advance()
70
{
71
m_phase += m_increment;
// wraps naturally
72
}
73
74
double
operator()()
75
{
76
double
result = getSample();
77
advance();
78
return
result;
79
}
80
81
private
:
82
std::uint32_t m_phase;
83
std::uint32_t m_increment;
84
};
85
86
class
SineWaveSignal
87
{
88
class
iterator
89
{
90
public
:
91
using
iterator_category =
std
::input_iterator_tag;
92
using
value_type =
double
;
93
using
difference_type =
std
::ptrdiff_t;
94
using
pointer =
void
;
95
using
reference =
double
;
96
97
iterator(
std
::uint32_t phase,
std
::uint32_t increment) : m_generator(phase, increment) { }
98
99
double
operator*()
const
{
return
m_generator.getSample(); }
100
101
iterator &operator++()
102
{
103
m_generator.advance();
104
return
*
this
;
105
}
106
107
bool
operator!=(
std
::nullptr_t)
const
108
{
109
return
true
;
// infinite range
110
}
111
112
private
:
113
SineWaveGenerator m_generator;
114
};
115
116
public
:
117
SineWaveSignal
(
double
frequency,
double
sample_rate,
double
phase = 0.0)
118
: m_phase(SineWaveGenerator::phaseToFixedPoint(phase)),
119
m_increment(SineWaveGenerator::incrementFromFrequency(frequency, sample_rate))
120
{
121
}
122
123
iterator
begin
()
const
124
{
125
return
iterator{
126
m_phase,
127
m_increment,
128
};
129
}
130
std
::nullptr_t
end
()
const
{
return
nullptr
; }
131
132
private
:
133
std
::uint32_t m_phase;
134
std
::uint32_t m_increment;
135
};
136
137
unsigned
char
*
writeSineSample
(
unsigned
char
*ptr, QAudioFormat::SampleFormat sampleFormat,
138
qreal x);
139
140
QByteArray
createSineWaveData
(
const
QAudioFormat &format,
std
::chrono::microseconds duration,
141
qint32 sampleIndex = 0, qreal frequency = 500, qreal volume = 0.8);
142
143
// Writes a mono, 16-bit PCM WAV file containing a sine wave to a new temporary file and
144
// returns it (already closed, ready to be opened for reading via its fileName()).
145
std
::
unique_ptr
<
QTemporaryFile
>
makeMonoPcm16WavFile
(
int
sampleRate,
146
std
::chrono::microseconds duration,
147
qreal frequency, qreal volume = 0.8);
148
149
class
SineWaveIODevice
:
public
QIODevice
150
{
151
public
:
152
explicit
SineWaveIODevice
(
const
QAudioFormat &format, qreal frequency = 500, qreal volume = 0.8)
153
:
m_format
(
format
), m_generator(frequency, format.sampleRate()),
m_volume
(
volume
)
154
{
155
open(QIODeviceBase::ReadOnly);
156
}
157
158
qint64
readData
(
char
*data, qint64 len)
override
159
{
160
unsigned
char
*ptr =
reinterpret_cast
<
unsigned
char
*>(data);
161
const
unsigned
char
*
const
end = ptr + len - (len % m_format.bytesPerFrame());
162
163
while
(ptr < end) {
164
const
qreal x = m_generator() * m_volume;
165
for
(
int
ch = 0; ch < m_format.channelCount(); ++ch)
166
ptr = writeSineSample(ptr, m_format.sampleFormat(), x);
167
}
168
169
return
ptr -
reinterpret_cast
<
unsigned
char
*>(data);
170
}
171
172
qint64
writeData
(
const
char
*,
qint64
)
override
{
return
0; }
173
bool
isSequential
()
const
override
{
return
true
; }
174
qint64
bytesAvailable
()
const
override
{
return
std::numeric_limits<qint64>::max(); }
175
176
private
:
177
QAudioFormat m_format;
178
SineWaveGenerator m_generator;
179
qreal m_volume;
180
};
181
182
class
AudioGenerator
:
public
QObject
183
{
184
Q_OBJECT
185
public
:
186
AudioGenerator
()
187
{
188
m_format
.
setSampleFormat
(
QAudioFormat
::
UInt8
);
189
m_format
.
setSampleRate
(8000);
190
m_format
.
setChannelConfig
(
QAudioFormat
::
ChannelConfigMono
);
191
}
192
193
void
setFormat
(
const
QAudioFormat
&
format
)
194
{
//
195
m_format
=
format
;
196
}
197
198
void
setBufferCount
(
int
count
)
199
{
//
200
m_maxBufferCount
=
std
::
max
(
count
, 1);
201
}
202
203
void
setDuration
(
std
::
chrono
::
microseconds
duration
)
204
{
//
205
m_duration
=
duration
;
206
}
207
208
void
setFrequency
(
qreal
frequency
)
209
{
//
210
m_frequency
=
frequency
;
211
}
212
213
void
emitEmptyBufferOnStop
()
214
{
//
215
m_emitEmptyBufferOnStop
=
true
;
216
}
217
218
QAudioBuffer
createAudioBuffer
()
219
{
220
const
std
::
chrono
::
microseconds
bufferDuration
=
m_duration
* (
m_bufferIndex
+ 1) /
m_maxBufferCount
221
-
m_duration
*
m_bufferIndex
/
m_maxBufferCount
;
222
QByteArray
data
=
createSineWaveData
(
m_format
,
bufferDuration
,
m_sampleIndex
,
m_frequency
);
223
Q_ASSERT
(
m_format
.
bytesPerSample
());
224
m_sampleIndex
+=
data
.
size
() /
m_format
.
bytesPerSample
();
225
return
QAudioBuffer
(
data
,
m_format
);
226
}
227
228
Q_SIGNALS
:
229
void
done
();
230
void
audioBufferCreated
(
const
QAudioBuffer &buffer);
231
232
public
Q_SLOTS
:
233
void
nextBuffer
()
234
{
235
if
(
m_bufferIndex
==
m_maxBufferCount
) {
236
Q_EMIT
done
();
237
if
(
m_emitEmptyBufferOnStop
)
238
Q_EMIT
audioBufferCreated
({});
239
return
;
240
}
241
242
const
QAudioBuffer
buffer
=
createAudioBuffer
();
243
244
Q_EMIT
audioBufferCreated
(
buffer
);
245
++
m_bufferIndex
;
246
}
247
248
private
:
249
int
m_maxBufferCount
= 1;
250
std
::chrono::microseconds m_duration{
std
::
chrono
::
seconds
{ 1 } };
251
int
m_bufferIndex = 0;
252
QAudioFormat m_format;
253
bool
m_emitEmptyBufferOnStop =
false
;
254
qreal m_frequency = 500.;
255
qint32 m_sampleIndex = 0;
256
};
257
258
QT_END_NAMESPACE
259
260
#
endif
// AUDIOGENERATIONUTILS_H
createSineWaveData
QByteArray createSineWaveData(const QAudioFormat &format, std::chrono::microseconds duration, qint32 sampleIndex, qreal frequency, qreal volume)
Definition
audiogenerationutils.cpp:45
makeMonoPcm16WavFile
std::unique_ptr< QTemporaryFile > makeMonoPcm16WavFile(int sampleRate, std::chrono::microseconds duration, qreal frequency, qreal volume)
Definition
audiogenerationutils.cpp:72
writeSineSample
QT_BEGIN_NAMESPACE unsigned char * writeSineSample(unsigned char *ptr, QAudioFormat::SampleFormat sampleFormat, qreal x)
Definition
audiogenerationutils.cpp:22
AudioGenerator
Definition
audiogenerationutils_p.h:183
AudioGenerator::audioBufferCreated
void audioBufferCreated(const QAudioBuffer &buffer)
SineWaveIODevice
Definition
audiogenerationutils_p.h:150
SineWaveIODevice::bytesAvailable
qint64 bytesAvailable() const override
Returns the number of bytes that are available for reading.
Definition
audiogenerationutils_p.h:174
SineWaveIODevice::readData
qint64 readData(char *data, qint64 len) override
Reads up to maxSize bytes from the device into data, and returns the number of bytes read or -1 if an...
Definition
audiogenerationutils_p.h:158
SineWaveIODevice::SineWaveIODevice
SineWaveIODevice(const QAudioFormat &format, qreal frequency=500, qreal volume=0.8)
Definition
audiogenerationutils_p.h:152
SineWaveIODevice::isSequential
bool isSequential() const override
Returns true if this device is sequential; otherwise returns false.
Definition
audiogenerationutils_p.h:173
SineWaveIODevice::writeData
qint64 writeData(const char *, qint64) override
Writes up to maxSize bytes from data to the device.
Definition
audiogenerationutils_p.h:172
SineWaveSignal
Definition
audiogenerationutils_p.h:87
SineWaveSignal::begin
iterator begin() const
Definition
audiogenerationutils_p.h:123
SineWaveSignal::SineWaveSignal
SineWaveSignal(double frequency, double sample_rate, double phase=0.0)
Definition
audiogenerationutils_p.h:117
SineWaveSignal::end
std::nullptr_t end() const
Definition
audiogenerationutils_p.h:130
std
[33]
Definition
src_corelib_tools_qhash.cpp:421
M_PI
#define M_PI
Definition
qmath.h:201
qtmultimedia
src
multimediatestlib
audiogenerationutils_p.h
Generated on
for Qt by
1.18.0