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
audio.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
4/* Audio related snippets */
5#include <QFile>
6#include <QTimer>
7#include <QDebug>
8#include <qobject.h>
9#include <qfile.h>
10
11#include "qaudiodevice.h"
12#include "qaudiosource.h"
13#include "qaudiooutput.h"
14#include "qaudiodecoder.h"
15#include "qmediaplayer.h"
16#include "qmediadevices.h"
17
18class AudioInputExample : public QObject {
19 Q_OBJECT
20public:
21 void setup();
22
23
24public Q_SLOTS:
25 void stopRecording();
26 void handleStateChanged(QtAudio::State newState);
27
28private:
29 //! [Audio input class members]
30 QFile destinationFile; // Class member
31 QAudioSource* audio; // Class member
32 //! [Audio input class members]
33};
34
35
36void AudioInputExample::setup()
37//! [Audio input setup]
38{
39 destinationFile.setFileName("/tmp/test.raw");
40 destinationFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
41
42 QAudioFormat format;
43 // Set up the desired format, for example:
44 format.setSampleRate(44100);
45 format.setChannelCount(1);
46 format.setSampleFormat(QAudioFormat::Int16);
47
48 QAudioDevice info = QMediaDevices::defaultAudioInput();
49 if (!info.isFormatSupported(format)) {
50 qWarning() << "Default format not supported, trying to use the nearest.";
51 }
52
53 audio = new QAudioSource(format, this);
54 connect(audio, &QAudioSource::stateChanged, this, &AudioInputExample::handleStateChanged);
55
56 QTimer::singleShot(3000, this, &AudioInputExample::stopRecording);
57 audio->start(&destinationFile);
58 // Records audio for 3000ms
59}
60//! [Audio input setup]
61
62//! [Audio input stop recording]
63void AudioInputExample::stopRecording()
64{
65 audio->stop();
66 destinationFile.close();
67 delete audio;
68}
69//! [Audio input stop recording]
70
71//! [Audio input state changed]
72void AudioInputExample::handleStateChanged(QtAudio::State newState)
73{
74 switch (newState) {
75 case QtAudio::StoppedState:
76 if (audio->error() != QtAudio::NoError) {
77 // Error handling
78 } else {
79 // Finished recording
80 }
81 break;
82
83 case QtAudio::ActiveState:
84 // Started recording - read from IO device
85 break;
86
87 default:
88 // ... other cases as appropriate
89 break;
90 }
91}
92//! [Audio input state changed]
93
94
97public:
98 void setup();
99
100public Q_SLOTS:
103
104private:
105 //! [Audio output class members]
106 QFile sourceFile; // class member.
107 QAudioSink* audio; // class member.
108 //! [Audio output class members]
109};
110
111
113//! [Audio output setup]
114{
115 sourceFile.setFileName("/tmp/test.raw");
116 sourceFile.open(QIODevice::ReadOnly);
117
118 QAudioFormat format;
119 // Set up the format, eg.
120 format.setSampleRate(44100);
121 format.setChannelCount(1);
122 format.setSampleFormat(QAudioFormat::Int16);
123
124 QAudioDevice info(QMediaDevices::defaultAudioOutput());
125 if (!info.isFormatSupported(format)) {
126 qWarning() << "Raw audio format not supported by backend, cannot play audio.";
127 return;
128 }
129
130 audio = new QAudioSink(format, this);
131 connect(audio, QAudioSink::stateChanged, this, &AudioInputExample::handleStateChanged);
132 audio->start(&sourceFile);
133}
134//! [Audio output setup]
135
136//! [Audio output stop]
138{
139 audio->stop();
140 sourceFile.close();
141 delete audio;
142}
143//! [Audio output stop]
144
145//! [Audio output state changed]
146void AudioOutputExample::handleStateChanged(QtAudio::State newState)
147{
148 switch (newState) {
149 case QtAudio::IdleState:
150 // Finished playing (no more data)
152 break;
153
154 case QtAudio::StoppedState:
155 // Stopped for other reasons
156 if (audio->error() != QtAudio::NoError) {
157 // Error handling
158 }
159 break;
160
161 default:
162 // ... other cases as appropriate
163 break;
164 }
165}
166//! [Audio output state changed]
167
169{
171public:
173
174private:
175 //! [Audio callback output class members]
176 QAudioSink* audio; // class member.
177 float phase; // class member.
178 //! [Audio callback output class members]
179};
180
181
183//! [Audio callback output setup sine]
184{
185 QAudioFormat format;
186 // Set up the format, eg.
187 format.setSampleRate(44100);
188 format.setChannelCount(2);
189 format.setSampleFormat(QAudioFormat::Float);
190
191 QAudioDevice info(QMediaDevices::defaultAudioOutput());
192 if (!info.isFormatSupported(format)) {
193 qWarning() << "Raw audio format not supported by backend, cannot play audio.";
194 return;
195 }
196
197 audio = new QAudioSink(format, this);
198 float phaseIncrement = 2 * M_PI * 220.0 / format.sampleRate(); // 220 Hz sine wave
199 audio->start([&phase, phaseIncrement] (QSpan<float> interleavedAudioBuffer) {
200 // The audio callback should not call any functions that may potentially be blocking
201
202 // Fill the audio buffer with a sine wave
203 const int sampleCount = interleavedAudioBuffer.size() / 2; // Stereo, so divide by 2
204 for (int i = 0; i < sampleCount; ++i) {
205 float sample = std::sin(phase);
206 interleavedAudioBuffer[i * 2] = sample; // Left channel
207 interleavedAudioBuffer[i * 2 + 1] = sample; // Right channel
208 phase += phaseIncrement; // Increment phase for next sample
209 }
210 });
211
212 if (!audio->error() == QtAudio::Error::NoError) {
213 // in addition to the other start() signatures, starting the audio callback will fail if
214 // * the backend does not implement callback-based IO (the API is available on all major
215 // platforms)
216 // * the signature of the audio callback does not match format.sampleFormat()
217
218 qWarning() << "Error starting audio output:" << audio->errorString();
219 }
220}
221//! [Audio callback output setup sine]
222
224{
226public:
228
229private:
230 //! [Audio callback capture class members]
231 QAudioSource* audio; // class member.
232 std::atomic<float> peakLevel; // class member.
233 //! [Audio callback capture class members]
234};
235
236
237void AudioInputWithCallbackExample::setupPeakMeter()
238//! [Audio callback capture setup peak meter]
239{
240 QAudioFormat format;
241 // Set up the format, eg.
242 format.setSampleRate(44100);
243 format.setChannelCount(2);
244 format.setSampleFormat(QAudioFormat::Float);
245
246 QAudioDevice info(QMediaDevices::defaultAudioOutput());
247 if (!info.isFormatSupported(format)) {
248 qWarning() << "Raw audio format not supported by backend, cannot capture audio.";
249 return;
250 }
251
252 audio = new QAudioSource(format, this);
253 audio->start([&peakLevel] (QSpan<float> interleavedAudioBuffer) {
254 float level = peakLevel.load();
255
256 for (float sample : interleavedAudioBuffer) {
257 // Calculate the peak level from the audio samples
258 level = std::max(level, std::abs(sample));
259 }
260
261 peakLevel.store(level);
262 // Note: care needs to be taken if the application thread needs to be notified, as the
263 // audio callback should not use any potentially blocking system calls.
264 // Good options are autoreset events (windows), eventfd (linux) or kqueue/EVFILT_USER on macos.
265 });
266
267 if (!audio->error() == QtAudio::Error::NoError) {
268 // in addition to the other start() signatures, starting the audio callback will fail if
269 // * the backend does not implement callback-based IO (the API is available on all major
270 // platforms)
271 // * the signature of the audio callback does not match format.sampleFormat()
272
273 qWarning() << "Error starting audio output:" << audio->errorString();
274 }
275}
276//! [Audio callback capture setup peak meter]
277
279{
280 //! [Setting audio format]
281 QAudioFormat format;
282 format.setSampleRate(44100);
283 // ... other format parameters
284 format.setSampleFormat(QAudioFormat::Int16);
285 //! [Setting audio format]
286
287 //! [Dumping audio formats]
288 const auto devices = QMediaDevices::audioOutputs();
289 for (const QAudioDevice &device : devices)
290 qDebug() << "Device: " << device.description();
291 //! [Dumping audio formats]
292}
293
296public:
297 void decode();
298
299public Q_SLOTS:
302};
303
305{
306 //! [Local audio decoding]
307 QAudioFormat desiredFormat;
308 desiredFormat.setChannelCount(2);
309 desiredFormat.setSampleFormat(QAudioFormat::Int16);
310 desiredFormat.setSampleRate(48000);
311
312 QAudioDecoder *decoder = new QAudioDecoder(this);
313 decoder->setAudioFormat(desiredFormat);
314 decoder->setSource("level1.mp3");
315
316 connect(decoder, &QAudioDecoder::bufferReady, this, &AudioDecodingExample::readBuffer);
317 decoder->start();
318
319 // Now wait for bufferReady() signal and call decoder->read()
320 //! [Local audio decoding]
321}
322
324
325//! [Volume conversion]
326void applyVolume(int volumeSliderValue)
327{
328 // volumeSliderValue is in the range [0..100]
329
330 qreal linearVolume = QtAudio::convertVolume(volumeSliderValue / qreal(100.0),
331 QtAudio::LogarithmicVolumeScale,
332 QtAudio::LinearVolumeScale);
333
334 player.setVolume(qRound(linearVolume * 100));
335}
336//! [Volume conversion]
void applyVolume(int volumeSliderValue)
[Volume conversion]
Definition audio.cpp:326
void AudioDeviceInfo()
[Audio callback capture setup peak meter]
Definition audio.cpp:278
QMediaPlayer player
Definition audio.cpp:323
[Audio callback output setup sine]
Definition audio.cpp:224
[Audio input state changed]
Definition audio.cpp:95
void stopAudioOutput()
[Audio output setup]
Definition audio.cpp:137
[Audio output state changed]
Definition audio.cpp:169