1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#ifndef ENGINE_H
52#define ENGINE_H
53
54#include "spectrum.h"
55#include "spectrumanalyser.h"
56#include "wavfile.h"
57
58#include <QAudioDeviceInfo>
59#include <QAudioFormat>
60#include <QBuffer>
61#include <QByteArray>
62#include <QDir>
63#include <QObject>
64#include <QVector>
65
66#ifdef DUMP_CAPTURED_AUDIO
67#define DUMP_DATA
68#endif
69
70#ifdef DUMP_SPECTRUM
71#define DUMP_DATA
72#endif
73
74class FrequencySpectrum;
75QT_BEGIN_NAMESPACE
76class QAudioInput;
77class QAudioOutput;
78QT_END_NAMESPACE
79
80/**
81 * This class interfaces with the Qt Multimedia audio classes, and also with
82 * the SpectrumAnalyser class. Its role is to manage the capture and playback
83 * of audio data, meanwhile performing real-time analysis of the audio level
84 * and frequency spectrum.
85 */
86class Engine : public QObject
87{
88 Q_OBJECT
89
90public:
91 explicit Engine(QObject *parent = 0);
92 ~Engine();
93
94 const QList<QAudioDeviceInfo> &availableAudioInputDevices() const
95 { return m_availableAudioInputDevices; }
96
97 const QList<QAudioDeviceInfo> &availableAudioOutputDevices() const
98 { return m_availableAudioOutputDevices; }
99
100 QAudio::Mode mode() const { return m_mode; }
101 QAudio::State state() const { return m_state; }
102
103 /**
104 * \return Current audio format
105 * \note May be QAudioFormat() if engine is not initialized
106 */
107 const QAudioFormat& format() const { return m_format; }
108
109 /**
110 * Stop any ongoing recording or playback, and reset to ground state.
111 */
112 void reset();
113
114 /**
115 * Load data from WAV file
116 */
117 bool loadFile(const QString &fileName);
118
119 /**
120 * Generate tone
121 */
122 bool generateTone(const Tone &tone);
123
124 /**
125 * Generate tone
126 */
127 bool generateSweptTone(qreal amplitude);
128
129 /**
130 * Initialize for recording
131 */
132 bool initializeRecord();
133
134 /**
135 * Position of the audio input device.
136 * \return Position in bytes.
137 */
138 qint64 recordPosition() const { return m_recordPosition; }
139
140 /**
141 * RMS level of the most recently processed set of audio samples.
142 * \return Level in range (0.0, 1.0)
143 */
144 qreal rmsLevel() const { return m_rmsLevel; }
145
146 /**
147 * Peak level of the most recently processed set of audio samples.
148 * \return Level in range (0.0, 1.0)
149 */
150 qreal peakLevel() const { return m_peakLevel; }
151
152 /**
153 * Position of the audio output device.
154 * \return Position in bytes.
155 */
156 qint64 playPosition() const { return m_playPosition; }
157
158 /**
159 * Length of the internal engine buffer.
160 * \return Buffer length in bytes.
161 */
162 qint64 bufferLength() const;
163
164 /**
165 * Amount of data held in the buffer.
166 * \return Data length in bytes.
167 */
168 qint64 dataLength() const { return m_dataLength; }
169
170 /**
171 * Set window function applied to audio data before spectral analysis.
172 */
173 void setWindowFunction(WindowFunction type);
174
175public slots:
176 void startRecording();
177 void startPlayback();
178 void suspend();
179 void setAudioInputDevice(const QAudioDeviceInfo &device);
180 void setAudioOutputDevice(const QAudioDeviceInfo &device);
181
182signals:
183 void stateChanged(QAudio::Mode mode, QAudio::State state);
184
185 /**
186 * Informational message for non-modal display
187 */
188 void infoMessage(const QString &message, int durationMs);
189
190 /**
191 * Error message for modal display
192 */
193 void errorMessage(const QString &heading, const QString &detail);
194
195 /**
196 * Format of audio data has changed
197 */
198 void formatChanged(const QAudioFormat &format);
199
200 /**
201 * Length of buffer has changed.
202 * \param duration Duration in microseconds
203 */
204 void bufferLengthChanged(qint64 duration);
205
206 /**
207 * Amount of data in buffer has changed.
208 * \param Length of data in bytes
209 */
210 void dataLengthChanged(qint64 duration);
211
212 /**
213 * Position of the audio input device has changed.
214 * \param position Position in bytes
215 */
216 void recordPositionChanged(qint64 position);
217
218 /**
219 * Position of the audio output device has changed.
220 * \param position Position in bytes
221 */
222 void playPositionChanged(qint64 position);
223
224 /**
225 * Level changed
226 * \param rmsLevel RMS level in range 0.0 - 1.0
227 * \param peakLevel Peak level in range 0.0 - 1.0
228 * \param numSamples Number of audio samples analyzed
229 */
230 void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples);
231
232 /**
233 * Spectrum has changed.
234 * \param position Position of start of window in bytes
235 * \param length Length of window in bytes
236 * \param spectrum Resulting frequency spectrum
237 */
238 void spectrumChanged(qint64 position, qint64 length, const FrequencySpectrum &spectrum);
239
240 /**
241 * Buffer containing audio data has changed.
242 * \param position Position of start of buffer in bytes
243 * \param buffer Buffer
244 */
245 void bufferChanged(qint64 position, qint64 length, const QByteArray &buffer);
246
247private slots:
248 void audioNotify();
249 void audioStateChanged(QAudio::State state);
250 void audioDataReady();
251 void spectrumChanged(const FrequencySpectrum &spectrum);
252
253private:
254 void resetAudioDevices();
255 bool initialize();
256 bool selectFormat();
257 void stopRecording();
258 void stopPlayback();
259 void setState(QAudio::State state);
260 void setState(QAudio::Mode mode, QAudio::State state);
261 void setFormat(const QAudioFormat &format);
262 void setRecordPosition(qint64 position, bool forceEmit = false);
263 void setPlayPosition(qint64 position, bool forceEmit = false);
264 void calculateLevel(qint64 position, qint64 length);
265 void calculateSpectrum(qint64 position);
266 void setLevel(qreal rmsLevel, qreal peakLevel, int numSamples);
267
268#ifdef DUMP_DATA
269 void createOutputDir();
270 QString outputPath() const { return m_outputDir.path(); }
271#endif
272
273#ifdef DUMP_CAPTURED_AUDIO
274 void dumpData();
275#endif
276
277private:
278 QAudio::Mode m_mode;
279 QAudio::State m_state;
280
281 bool m_generateTone;
282 SweptTone m_tone;
283
284 WavFile* m_file;
285 // We need a second file handle via which to read data into m_buffer
286 // for analysis
287 WavFile* m_analysisFile;
288
289 QAudioFormat m_format;
290
291 const QList<QAudioDeviceInfo> m_availableAudioInputDevices;
292 QAudioDeviceInfo m_audioInputDevice;
293 QAudioInput* m_audioInput;
294 QIODevice* m_audioInputIODevice;
295 qint64 m_recordPosition;
296
297 const QList<QAudioDeviceInfo> m_availableAudioOutputDevices;
298 QAudioDeviceInfo m_audioOutputDevice;
299 QAudioOutput* m_audioOutput;
300 QString m_audioOutputCategory;
301 qint64 m_playPosition;
302 QBuffer m_audioOutputIODevice;
303
304 QByteArray m_buffer;
305 qint64 m_bufferPosition;
306 qint64 m_bufferLength;
307 qint64 m_dataLength;
308
309 int m_levelBufferLength;
310 qreal m_rmsLevel;
311 qreal m_peakLevel;
312
313 int m_spectrumBufferLength;
314 QByteArray m_spectrumBuffer;
315 SpectrumAnalyser m_spectrumAnalyser;
316 qint64 m_spectrumPosition;
317
318 int m_count;
319
320#ifdef DUMP_DATA
321 QDir m_outputDir;
322#endif
323
324};
325
326#endif // ENGINE_H
327

source code of qtmultimedia/examples/multimedia/spectrum/app/engine.h