/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef ENGINE_H#define ENGINE_H#include "spectrum.h"#include "spectrumanalyser.h"#include "wavfile.h"#include <QAudioDeviceInfo>#include <QAudioFormat>#include <QBuffer>#include <QByteArray>#include <QDir>#include <QObject>#include <QVector>#ifdef DUMP_CAPTURED_AUDIO#define DUMP_DATA#endif#ifdef DUMP_SPECTRUM#define DUMP_DATA#endifclass FrequencySpectrum;
classQAudioInput;
classQAudioOutput;
/**
* This class interfaces with the Qt Multimedia audio classes, and also with
* the SpectrumAnalyser class. Its role is to manage the capture and playback
* of audio data, meanwhile performing real-time analysis of the audio level
* and frequency spectrum.
*/class Engine : publicQObject
{
Q_OBJECT
public:
explicit Engine(QObject*parent =0);
~Engine();
constQList<QAudioDeviceInfo>&availableAudioInputDevices() const
{ return m_availableAudioInputDevices; }
constQList<QAudioDeviceInfo>&availableAudioOutputDevices() const
{ return m_availableAudioOutputDevices; }
QAudio::Mode mode() const { return m_mode; }
QAudio::State state() const { return m_state; }
/**
* \return Current audio format
* \note May be QAudioFormat() if engine is not initialized
*/constQAudioFormat& format() const { return m_format; }
/**
* Stop any ongoing recording or playback, and reset to ground state.
*/void reset();
/**
* Load data from WAV file
*/
bool loadFile(constQString&fileName);
/**
* Generate tone
*/
bool generateTone(const Tone &tone);
/**
* Generate tone
*/
bool generateSweptTone(qreal amplitude);
/**
* Initialize for recording
*/
bool initializeRecord();
/**
* Position of the audio input device.
* \return Position in bytes.
*/qint64 recordPosition() const { return m_recordPosition; }
/**
* RMS level of the most recently processed set of audio samples.
* \return Level in range (0.0, 1.0)
*/qreal rmsLevel() const { return m_rmsLevel; }
/**
* Peak level of the most recently processed set of audio samples.
* \return Level in range (0.0, 1.0)
*/qreal peakLevel() const { return m_peakLevel; }
/**
* Position of the audio output device.
* \return Position in bytes.
*/qint64 playPosition() const { return m_playPosition; }
/**
* Length of the internal engine buffer.
* \return Buffer length in bytes.
*/qint64 bufferLength() const;
/**
* Amount of data held in the buffer.
* \return Data length in bytes.
*/qint64 dataLength() const { return m_dataLength; }
/**
* Set window function applied to audio data before spectral analysis.
*/void setWindowFunction(WindowFunction type);
publicslots:
void startRecording();
void startPlayback();
void suspend();
void setAudioInputDevice(constQAudioDeviceInfo&device);
void setAudioOutputDevice(constQAudioDeviceInfo&device);
signals:
void stateChanged(QAudio::Mode mode,QAudio::State state);
/**
* Informational message for non-modal display
*/void infoMessage(constQString&message,int durationMs);
/**
* Error message for modal display
*/void errorMessage(constQString&heading,constQString&detail);
/**
* Format of audio data has changed
*/void formatChanged(constQAudioFormat&format);
/**
* Length of buffer has changed.
* \param duration Duration in microseconds
*/void bufferLengthChanged(qint64 duration);
/**
* Amount of data in buffer has changed.
* \param Length of data in bytes
*/void dataLengthChanged(qint64 duration);
/**
* Position of the audio input device has changed.
* \param position Position in bytes
*/void recordPositionChanged(qint64 position);
/**
* Position of the audio output device has changed.
* \param position Position in bytes
*/void playPositionChanged(qint64 position);
/**
* Level changed
* \param rmsLevel RMS level in range 0.0 - 1.0
* \param peakLevel Peak level in range 0.0 - 1.0
* \param numSamples Number of audio samples analyzed
*/void levelChanged(qreal rmsLevel,qreal peakLevel,int numSamples);
/**
* Spectrum has changed.
* \param position Position of start of window in bytes
* \param length Length of window in bytes
* \param spectrum Resulting frequency spectrum
*/void spectrumChanged(qint64 position,qint64 length,const FrequencySpectrum &spectrum);
/**
* Buffer containing audio data has changed.
* \param position Position of start of buffer in bytes
* \param buffer Buffer
*/void bufferChanged(qint64 position,qint64 length,constQByteArray&buffer);
privateslots:
void audioNotify();
void audioStateChanged(QAudio::State state);
void audioDataReady();
void spectrumChanged(const FrequencySpectrum &spectrum);
private:
void resetAudioDevices();
bool initialize();
bool selectFormat();
void stopRecording();
void stopPlayback();
void setState(QAudio::State state);
void setState(QAudio::Mode mode,QAudio::State state);
void setFormat(constQAudioFormat&format);
void setRecordPosition(qint64 position, bool forceEmit =false);
void setPlayPosition(qint64 position, bool forceEmit =false);
void calculateLevel(qint64 position,qint64 length);
void calculateSpectrum(qint64 position);
void setLevel(qreal rmsLevel,qreal peakLevel,int numSamples);
#ifdef DUMP_DATAvoid createOutputDir();
QString outputPath() const { return m_outputDir.path(); }
#endif#ifdef DUMP_CAPTURED_AUDIOvoid dumpData();
#endifprivate:
QAudio::Mode m_mode;
QAudio::State m_state;
bool m_generateTone;
SweptTone m_tone;
WavFile* m_file;
// We need a second file handle via which to read data into m_buffer// for analysis
WavFile* m_analysisFile;
QAudioFormat m_format;
constQList<QAudioDeviceInfo> m_availableAudioInputDevices;
QAudioDeviceInfo m_audioInputDevice;
QAudioInput* m_audioInput;
QIODevice* m_audioInputIODevice;
qint64 m_recordPosition;
constQList<QAudioDeviceInfo> m_availableAudioOutputDevices;
QAudioDeviceInfo m_audioOutputDevice;
QAudioOutput* m_audioOutput;
QString m_audioOutputCategory;
qint64 m_playPosition;
QBuffer m_audioOutputIODevice;
QByteArray m_buffer;
qint64 m_bufferPosition;
qint64 m_bufferLength;
qint64 m_dataLength;
int m_levelBufferLength;
qreal m_rmsLevel;
qreal m_peakLevel;
int m_spectrumBufferLength;
QByteArray m_spectrumBuffer;
SpectrumAnalyser m_spectrumAnalyser;
qint64 m_spectrumPosition;
int m_count;
#ifdef DUMP_DATAQDir m_outputDir;
#endif
};
#endif // ENGINE_H