summaryrefslogtreecommitdiffstats
path: root/examples/multimedia/spectrum/app/engine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/multimedia/spectrum/app/engine.cpp')
-rw-r--r--examples/multimedia/spectrum/app/engine.cpp783
1 files changed, 0 insertions, 783 deletions
diff --git a/examples/multimedia/spectrum/app/engine.cpp b/examples/multimedia/spectrum/app/engine.cpp
deleted file mode 100644
index f934f8788..000000000
--- a/examples/multimedia/spectrum/app/engine.cpp
+++ /dev/null
@@ -1,783 +0,0 @@
-/****************************************************************************
-**
-** 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$
-**
-****************************************************************************/
-
-#include "engine.h"
-#include "tonegenerator.h"
-#include "utils.h"
-
-#include <math.h>
-
-#include <QAudioInput>
-#include <QAudioOutput>
-#include <QCoreApplication>
-#include <QDebug>
-#include <QFile>
-#include <QMetaObject>
-#include <QSet>
-#include <QThread>
-
-//-----------------------------------------------------------------------------
-// Constants
-//-----------------------------------------------------------------------------
-
-const qint64 BufferDurationUs = 10 * 1000000;
-const int NotifyIntervalMs = 100;
-
-// Size of the level calculation window in microseconds
-const int LevelWindowUs = 0.1 * 1000000;
-
-//-----------------------------------------------------------------------------
-// Constructor and destructor
-//-----------------------------------------------------------------------------
-
-Engine::Engine(QObject *parent)
- : QObject(parent)
- , m_mode(QAudio::AudioInput)
- , m_state(QAudio::StoppedState)
- , m_generateTone(false)
- , m_file(0)
- , m_analysisFile(0)
- , m_availableAudioInputDevices
- (QAudioDeviceInfo::availableDevices(QAudio::AudioInput))
- , m_audioInputDevice(QAudioDeviceInfo::defaultInputDevice())
- , m_audioInput(0)
- , m_audioInputIODevice(0)
- , m_recordPosition(0)
- , m_availableAudioOutputDevices
- (QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
- , m_audioOutputDevice(QAudioDeviceInfo::defaultOutputDevice())
- , m_audioOutput(0)
- , m_playPosition(0)
- , m_bufferPosition(0)
- , m_bufferLength(0)
- , m_dataLength(0)
- , m_levelBufferLength(0)
- , m_rmsLevel(0.0)
- , m_peakLevel(0.0)
- , m_spectrumBufferLength(0)
- , m_spectrumAnalyser()
- , m_spectrumPosition(0)
- , m_count(0)
-{
- qRegisterMetaType<FrequencySpectrum>("FrequencySpectrum");
- qRegisterMetaType<WindowFunction>("WindowFunction");
- connect(&m_spectrumAnalyser, QOverload<const FrequencySpectrum&>::of(&SpectrumAnalyser::spectrumChanged),
- this, QOverload<const FrequencySpectrum&>::of(&Engine::spectrumChanged));
-
- // This code might misinterpret things like "-something -category". But
- // it's unlikely that that needs to be supported so we'll let it go.
- QStringList arguments = QCoreApplication::instance()->arguments();
- for (int i = 0; i < arguments.count(); ++i) {
- if (arguments.at(i) == QStringLiteral("--"))
- break;
-
- if (arguments.at(i) == QStringLiteral("-category")
- || arguments.at(i) == QStringLiteral("--category")) {
- ++i;
- if (i < arguments.count())
- m_audioOutputCategory = arguments.at(i);
- else
- --i;
- }
- }
-
- initialize();
-
-#ifdef DUMP_DATA
- createOutputDir();
-#endif
-
-#ifdef DUMP_SPECTRUM
- m_spectrumAnalyser.setOutputPath(outputPath());
-#endif
-}
-
-Engine::~Engine()
-{
-
-}
-
-//-----------------------------------------------------------------------------
-// Public functions
-//-----------------------------------------------------------------------------
-
-bool Engine::loadFile(const QString &fileName)
-{
- reset();
- bool result = false;
- Q_ASSERT(!m_generateTone);
- Q_ASSERT(!m_file);
- Q_ASSERT(!fileName.isEmpty());
- m_file = new WavFile(this);
- if (m_file->open(fileName)) {
- if (isPCMS16LE(m_file->fileFormat())) {
- result = initialize();
- } else {
- emit errorMessage(tr("Audio format not supported"),
- formatToString(m_file->fileFormat()));
- }
- } else {
- emit errorMessage(tr("Could not open file"), fileName);
- }
- if (result) {
- m_analysisFile = new WavFile(this);
- m_analysisFile->open(fileName);
- }
- return result;
-}
-
-bool Engine::generateTone(const Tone &tone)
-{
- reset();
- Q_ASSERT(!m_generateTone);
- Q_ASSERT(!m_file);
- m_generateTone = true;
- m_tone = tone;
- ENGINE_DEBUG << "Engine::generateTone"
- << "startFreq" << m_tone.startFreq
- << "endFreq" << m_tone.endFreq
- << "amp" << m_tone.amplitude;
- return initialize();
-}
-
-bool Engine::generateSweptTone(qreal amplitude)
-{
- Q_ASSERT(!m_generateTone);
- Q_ASSERT(!m_file);
- m_generateTone = true;
- m_tone.startFreq = 1;
- m_tone.endFreq = 0;
- m_tone.amplitude = amplitude;
- ENGINE_DEBUG << "Engine::generateSweptTone"
- << "startFreq" << m_tone.startFreq
- << "amp" << m_tone.amplitude;
- return initialize();
-}
-
-bool Engine::initializeRecord()
-{
- reset();
- ENGINE_DEBUG << "Engine::initializeRecord";
- Q_ASSERT(!m_generateTone);
- Q_ASSERT(!m_file);
- m_generateTone = false;
- m_tone = SweptTone();
- return initialize();
-}
-
-qint64 Engine::bufferLength() const
-{
- return m_file ? m_file->size() : m_bufferLength;
-}
-
-void Engine::setWindowFunction(WindowFunction type)
-{
- m_spectrumAnalyser.setWindowFunction(type);
-}
-
-
-//-----------------------------------------------------------------------------
-// Public slots
-//-----------------------------------------------------------------------------
-
-void Engine::startRecording()
-{
- if (m_audioInput) {
- if (QAudio::AudioInput == m_mode &&
- QAudio::SuspendedState == m_state) {
- m_audioInput->resume();
- } else {
- m_spectrumAnalyser.cancelCalculation();
- spectrumChanged(0, 0, FrequencySpectrum());
-
- m_buffer.fill(0);
- setRecordPosition(0, true);
- stopPlayback();
- m_mode = QAudio::AudioInput;
- connect(m_audioInput, &QAudioInput::stateChanged,
- this, &Engine::audioStateChanged);
- connect(m_audioInput, &QAudioInput::notify,
- this, &Engine::audioNotify);
-
- m_count = 0;
- m_dataLength = 0;
- emit dataLengthChanged(0);
- m_audioInputIODevice = m_audioInput->start();
- connect(m_audioInputIODevice, &QIODevice::readyRead,
- this, &Engine::audioDataReady);
- }
- }
-}
-
-void Engine::startPlayback()
-{
- if (m_audioOutput) {
- if (QAudio::AudioOutput == m_mode &&
- QAudio::SuspendedState == m_state) {
-#ifdef Q_OS_WIN
- // The Windows backend seems to internally go back into ActiveState
- // while still returning SuspendedState, so to ensure that it doesn't
- // ignore the resume() call, we first re-suspend
- m_audioOutput->suspend();
-#endif
- m_audioOutput->resume();
- } else {
- m_spectrumAnalyser.cancelCalculation();
- spectrumChanged(0, 0, FrequencySpectrum());
- setPlayPosition(0, true);
- stopRecording();
- m_mode = QAudio::AudioOutput;
- connect(m_audioOutput, &QAudioOutput::stateChanged,
- this, &Engine::audioStateChanged);
- connect(m_audioOutput, &QAudioOutput::notify,
- this, &Engine::audioNotify);
-
- m_count = 0;
- if (m_file) {
- m_file->seek(0);
- m_bufferPosition = 0;
- m_dataLength = 0;
- m_audioOutput->start(m_file);
- } else {
- m_audioOutputIODevice.close();
- m_audioOutputIODevice.setBuffer(&m_buffer);
- m_audioOutputIODevice.open(QIODevice::ReadOnly);
- m_audioOutput->start(&m_audioOutputIODevice);
- }
- }
- }
-}
-
-void Engine::suspend()
-{
- if (QAudio::ActiveState == m_state ||
- QAudio::IdleState == m_state) {
- switch (m_mode) {
- case QAudio::AudioInput:
- m_audioInput->suspend();
- break;
- case QAudio::AudioOutput:
- m_audioOutput->suspend();
- break;
- }
- }
-}
-
-void Engine::setAudioInputDevice(const QAudioDeviceInfo &device)
-{
- if (device.deviceName() != m_audioInputDevice.deviceName()) {
- m_audioInputDevice = device;
- initialize();
- }
-}
-
-void Engine::setAudioOutputDevice(const QAudioDeviceInfo &device)
-{
- if (device.deviceName() != m_audioOutputDevice.deviceName()) {
- m_audioOutputDevice = device;
- initialize();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Private slots
-//-----------------------------------------------------------------------------
-
-void Engine::audioNotify()
-{
- switch (m_mode) {
- case QAudio::AudioInput: {
- const qint64 recordPosition = qMin(m_bufferLength, audioLength(m_format, m_audioInput->processedUSecs()));
- setRecordPosition(recordPosition);
- const qint64 levelPosition = m_dataLength - m_levelBufferLength;
- if (levelPosition >= 0)
- calculateLevel(levelPosition, m_levelBufferLength);
- if (m_dataLength >= m_spectrumBufferLength) {
- const qint64 spectrumPosition = m_dataLength - m_spectrumBufferLength;
- calculateSpectrum(spectrumPosition);
- }
- emit bufferChanged(0, m_dataLength, m_buffer);
- }
- break;
- case QAudio::AudioOutput: {
- const qint64 playPosition = audioLength(m_format, m_audioOutput->processedUSecs());
- setPlayPosition(qMin(bufferLength(), playPosition));
- const qint64 levelPosition = playPosition - m_levelBufferLength;
- const qint64 spectrumPosition = playPosition - m_spectrumBufferLength;
- if (m_file) {
- if (levelPosition > m_bufferPosition ||
- spectrumPosition > m_bufferPosition ||
- qMax(m_levelBufferLength, m_spectrumBufferLength) > m_dataLength) {
- m_bufferPosition = 0;
- m_dataLength = 0;
- // Data needs to be read into m_buffer in order to be analysed
- const qint64 readPos = qMax(qint64(0), qMin(levelPosition, spectrumPosition));
- const qint64 readEnd = qMin(m_analysisFile->size(), qMax(levelPosition + m_levelBufferLength, spectrumPosition + m_spectrumBufferLength));
- const qint64 readLen = readEnd - readPos + audioLength(m_format, WaveformWindowDuration);
- qDebug() << "Engine::audioNotify [1]"
- << "analysisFileSize" << m_analysisFile->size()
- << "readPos" << readPos
- << "readLen" << readLen;
- if (m_analysisFile->seek(readPos + m_analysisFile->headerLength())) {
- m_buffer.resize(readLen);
- m_bufferPosition = readPos;
- m_dataLength = m_analysisFile->read(m_buffer.data(), readLen);
- qDebug() << "Engine::audioNotify [2]" << "bufferPosition" << m_bufferPosition << "dataLength" << m_dataLength;
- } else {
- qDebug() << "Engine::audioNotify [2]" << "file seek error";
- }
- emit bufferChanged(m_bufferPosition, m_dataLength, m_buffer);
- }
- } else {
- if (playPosition >= m_dataLength)
- stopPlayback();
- }
- if (levelPosition >= 0 && levelPosition + m_levelBufferLength < m_bufferPosition + m_dataLength)
- calculateLevel(levelPosition, m_levelBufferLength);
- if (spectrumPosition >= 0 && spectrumPosition + m_spectrumBufferLength < m_bufferPosition + m_dataLength)
- calculateSpectrum(spectrumPosition);
- }
- break;
- }
-}
-
-void Engine::audioStateChanged(QAudio::State state)
-{
- ENGINE_DEBUG << "Engine::audioStateChanged from" << m_state
- << "to" << state;
-
- if (QAudio::IdleState == state && m_file && m_file->pos() == m_file->size()) {
- stopPlayback();
- } else {
- if (QAudio::StoppedState == state) {
- // Check error
- QAudio::Error error = QAudio::NoError;
- switch (m_mode) {
- case QAudio::AudioInput:
- error = m_audioInput->error();
- break;
- case QAudio::AudioOutput:
- error = m_audioOutput->error();
- break;
- }
- if (QAudio::NoError != error) {
- reset();
- return;
- }
- }
- setState(state);
- }
-}
-
-void Engine::audioDataReady()
-{
- Q_ASSERT(0 == m_bufferPosition);
- const qint64 bytesReady = m_audioInput->bytesReady();
- const qint64 bytesSpace = m_buffer.size() - m_dataLength;
- const qint64 bytesToRead = qMin(bytesReady, bytesSpace);
-
- const qint64 bytesRead = m_audioInputIODevice->read(
- m_buffer.data() + m_dataLength,
- bytesToRead);
-
- if (bytesRead) {
- m_dataLength += bytesRead;
- emit dataLengthChanged(dataLength());
- }
-
- if (m_buffer.size() == m_dataLength)
- stopRecording();
-}
-
-void Engine::spectrumChanged(const FrequencySpectrum &spectrum)
-{
- ENGINE_DEBUG << "Engine::spectrumChanged" << "pos" << m_spectrumPosition;
- emit spectrumChanged(m_spectrumPosition, m_spectrumBufferLength, spectrum);
-}
-
-
-//-----------------------------------------------------------------------------
-// Private functions
-//-----------------------------------------------------------------------------
-
-void Engine::resetAudioDevices()
-{
- delete m_audioInput;
- m_audioInput = 0;
- m_audioInputIODevice = 0;
- setRecordPosition(0);
- delete m_audioOutput;
- m_audioOutput = 0;
- setPlayPosition(0);
- m_spectrumPosition = 0;
- setLevel(0.0, 0.0, 0);
-}
-
-void Engine::reset()
-{
- stopRecording();
- stopPlayback();
- setState(QAudio::AudioInput, QAudio::StoppedState);
- setFormat(QAudioFormat());
- m_generateTone = false;
- delete m_file;
- m_file = 0;
- delete m_analysisFile;
- m_analysisFile = 0;
- m_buffer.clear();
- m_bufferPosition = 0;
- m_bufferLength = 0;
- m_dataLength = 0;
- emit dataLengthChanged(0);
- resetAudioDevices();
-}
-
-bool Engine::initialize()
-{
- bool result = false;
-
- QAudioFormat format = m_format;
-
- if (selectFormat()) {
- if (m_format != format) {
- resetAudioDevices();
- if (m_file) {
- emit bufferLengthChanged(bufferLength());
- emit dataLengthChanged(dataLength());
- emit bufferChanged(0, 0, m_buffer);
- setRecordPosition(bufferLength());
- result = true;
- } else {
- m_bufferLength = audioLength(m_format, BufferDurationUs);
- m_buffer.resize(m_bufferLength);
- m_buffer.fill(0);
- emit bufferLengthChanged(bufferLength());
- if (m_generateTone) {
- if (0 == m_tone.endFreq) {
- const qreal nyquist = nyquistFrequency(m_format);
- m_tone.endFreq = qMin(qreal(SpectrumHighFreq), nyquist);
- }
- // Call function defined in utils.h, at global scope
- ::generateTone(m_tone, m_format, m_buffer);
- m_dataLength = m_bufferLength;
- emit dataLengthChanged(dataLength());
- emit bufferChanged(0, m_dataLength, m_buffer);
- setRecordPosition(m_bufferLength);
- result = true;
- } else {
- emit bufferChanged(0, 0, m_buffer);
- m_audioInput = new QAudioInput(m_audioInputDevice, m_format, this);
- m_audioInput->setNotifyInterval(NotifyIntervalMs);
- result = true;
- }
- }
- m_audioOutput = new QAudioOutput(m_audioOutputDevice, m_format, this);
- m_audioOutput->setNotifyInterval(NotifyIntervalMs);
- m_audioOutput->setCategory(m_audioOutputCategory);
- }
- } else {
- if (m_file)
- emit errorMessage(tr("Audio format not supported"),
- formatToString(m_format));
- else if (m_generateTone)
- emit errorMessage(tr("No suitable format found"), "");
- else
- emit errorMessage(tr("No common input / output format found"), "");
- }
-
- ENGINE_DEBUG << "Engine::initialize" << "m_bufferLength" << m_bufferLength;
- ENGINE_DEBUG << "Engine::initialize" << "m_dataLength" << m_dataLength;
- ENGINE_DEBUG << "Engine::initialize" << "format" << m_format;
- ENGINE_DEBUG << "Engine::initialize" << "m_audioOutputCategory" << m_audioOutputCategory;
-
- return result;
-}
-
-bool Engine::selectFormat()
-{
- bool foundSupportedFormat = false;
-
- if (m_file || QAudioFormat() != m_format) {
- QAudioFormat format = m_format;
- if (m_file)
- // Header is read from the WAV file; just need to check whether
- // it is supported by the audio output device
- format = m_file->fileFormat();
- if (m_audioOutputDevice.isFormatSupported(format)) {
- setFormat(format);
- foundSupportedFormat = true;
- }
- } else {
-
- QList<int> sampleRatesList;
- #ifdef Q_OS_WIN
- // The Windows audio backend does not correctly report format support
- // (see QTBUG-9100). Furthermore, although the audio subsystem captures
- // at 11025Hz, the resulting audio is corrupted.
- sampleRatesList += 8000;
- #endif
-
- if (!m_generateTone)
- sampleRatesList += m_audioInputDevice.supportedSampleRates();
-
- sampleRatesList += m_audioOutputDevice.supportedSampleRates();
- std::sort(sampleRatesList.begin(), sampleRatesList.end());
- const auto uniqueRatesEnd = std::unique(sampleRatesList.begin(), sampleRatesList.end());
- sampleRatesList.erase(uniqueRatesEnd, sampleRatesList.end());
- ENGINE_DEBUG << "Engine::initialize frequenciesList" << sampleRatesList;
-
- QList<int> channelsList;
- channelsList += m_audioInputDevice.supportedChannelCounts();
- channelsList += m_audioOutputDevice.supportedChannelCounts();
- std::sort(channelsList.begin(), channelsList.end());
- const auto uniqueChannelsEnd = std::unique(channelsList.begin(), channelsList.end());
- channelsList.erase(uniqueChannelsEnd, channelsList.end());
- ENGINE_DEBUG << "Engine::initialize channelsList" << channelsList;
-
- QAudioFormat format;
- format.setByteOrder(QAudioFormat::LittleEndian);
- format.setCodec("audio/pcm");
- format.setSampleSize(16);
- format.setSampleType(QAudioFormat::SignedInt);
- for (int sampleRate : qAsConst(sampleRatesList)) {
- if (foundSupportedFormat)
- break;
- format.setSampleRate(sampleRate);
- for (int channels : qAsConst(channelsList)) {
- format.setChannelCount(channels);
- const bool inputSupport = m_generateTone ||
- m_audioInputDevice.isFormatSupported(format);
- const bool outputSupport = m_audioOutputDevice.isFormatSupported(format);
- ENGINE_DEBUG << "Engine::initialize checking " << format
- << "input" << inputSupport
- << "output" << outputSupport;
- if (inputSupport && outputSupport) {
- foundSupportedFormat = true;
- break;
- }
- }
- }
-
- if (!foundSupportedFormat)
- format = QAudioFormat();
-
- setFormat(format);
- }
-
- return foundSupportedFormat;
-}
-
-void Engine::stopRecording()
-{
- if (m_audioInput) {
- m_audioInput->stop();
- QCoreApplication::instance()->processEvents();
- m_audioInput->disconnect();
- }
- m_audioInputIODevice = 0;
-
-#ifdef DUMP_AUDIO
- dumpData();
-#endif
-}
-
-void Engine::stopPlayback()
-{
- if (m_audioOutput) {
- m_audioOutput->stop();
- QCoreApplication::instance()->processEvents();
- m_audioOutput->disconnect();
- setPlayPosition(0);
- }
-}
-
-void Engine::setState(QAudio::State state)
-{
- const bool changed = (m_state != state);
- m_state = state;
- if (changed)
- emit stateChanged(m_mode, m_state);
-}
-
-void Engine::setState(QAudio::Mode mode, QAudio::State state)
-{
- const bool changed = (m_mode != mode || m_state != state);
- m_mode = mode;
- m_state = state;
- if (changed)
- emit stateChanged(m_mode, m_state);
-}
-
-void Engine::setRecordPosition(qint64 position, bool forceEmit)
-{
- const bool changed = (m_recordPosition != position);
- m_recordPosition = position;
- if (changed || forceEmit)
- emit recordPositionChanged(m_recordPosition);
-}
-
-void Engine::setPlayPosition(qint64 position, bool forceEmit)
-{
- const bool changed = (m_playPosition != position);
- m_playPosition = position;
- if (changed || forceEmit)
- emit playPositionChanged(m_playPosition);
-}
-
-void Engine::calculateLevel(qint64 position, qint64 length)
-{
-#ifdef DISABLE_LEVEL
- Q_UNUSED(position);
- Q_UNUSED(length);
-#else
- Q_ASSERT(position + length <= m_bufferPosition + m_dataLength);
-
- qreal peakLevel = 0.0;
-
- qreal sum = 0.0;
- const char *ptr = m_buffer.constData() + position - m_bufferPosition;
- const char *const end = ptr + length;
- while (ptr < end) {
- const qint16 value = *reinterpret_cast<const qint16*>(ptr);
- const qreal fracValue = pcmToReal(value);
- peakLevel = qMax(peakLevel, fracValue);
- sum += fracValue * fracValue;
- ptr += 2;
- }
- const int numSamples = length / 2;
- qreal rmsLevel = sqrt(sum / numSamples);
-
- rmsLevel = qMax(qreal(0.0), rmsLevel);
- rmsLevel = qMin(qreal(1.0), rmsLevel);
- setLevel(rmsLevel, peakLevel, numSamples);
-
- ENGINE_DEBUG << "Engine::calculateLevel" << "pos" << position << "len" << length
- << "rms" << rmsLevel << "peak" << peakLevel;
-#endif
-}
-
-void Engine::calculateSpectrum(qint64 position)
-{
-#ifdef DISABLE_SPECTRUM
- Q_UNUSED(position);
-#else
- Q_ASSERT(position + m_spectrumBufferLength <= m_bufferPosition + m_dataLength);
- Q_ASSERT(0 == m_spectrumBufferLength % 2); // constraint of FFT algorithm
-
- // QThread::currentThread is marked 'for internal use only', but
- // we're only using it for debug output here, so it's probably OK :)
- ENGINE_DEBUG << "Engine::calculateSpectrum" << QThread::currentThread()
- << "count" << m_count << "pos" << position << "len" << m_spectrumBufferLength
- << "spectrumAnalyser.isReady" << m_spectrumAnalyser.isReady();
-
- if (m_spectrumAnalyser.isReady()) {
- m_spectrumBuffer = QByteArray::fromRawData(m_buffer.constData() + position - m_bufferPosition,
- m_spectrumBufferLength);
- m_spectrumPosition = position;
- m_spectrumAnalyser.calculate(m_spectrumBuffer, m_format);
- }
-#endif
-}
-
-void Engine::setFormat(const QAudioFormat &format)
-{
- const bool changed = (format != m_format);
- m_format = format;
- m_levelBufferLength = audioLength(m_format, LevelWindowUs);
- m_spectrumBufferLength = SpectrumLengthSamples *
- (m_format.sampleSize() / 8) * m_format.channelCount();
- if (changed)
- emit formatChanged(m_format);
-}
-
-void Engine::setLevel(qreal rmsLevel, qreal peakLevel, int numSamples)
-{
- m_rmsLevel = rmsLevel;
- m_peakLevel = peakLevel;
- emit levelChanged(m_rmsLevel, m_peakLevel, numSamples);
-}
-
-#ifdef DUMP_DATA
-void Engine::createOutputDir()
-{
- m_outputDir.setPath("output");
-
- // Ensure output directory exists and is empty
- if (m_outputDir.exists()) {
- const QStringList files = m_outputDir.entryList(QDir::Files);
- for (const QString &file : files)
- m_outputDir.remove(file);
- } else {
- QDir::current().mkdir("output");
- }
-}
-#endif // DUMP_DATA
-
-#ifdef DUMP_AUDIO
-void Engine::dumpData()
-{
- const QString txtFileName = m_outputDir.filePath("data.txt");
- QFile txtFile(txtFileName);
- txtFile.open(QFile::WriteOnly | QFile::Text);
- QTextStream stream(&txtFile);
- const qint16 *ptr = reinterpret_cast<const qint16*>(m_buffer.constData());
- const int numSamples = m_dataLength / (2 * m_format.channels());
- for (int i=0; i<numSamples; ++i) {
- stream << i << "\t" << *ptr << "\n";
- ptr += m_format.channels();
- }
-
- const QString pcmFileName = m_outputDir.filePath("data.pcm");
- QFile pcmFile(pcmFileName);
- pcmFile.open(QFile::WriteOnly);
- pcmFile.write(m_buffer.constData(), m_dataLength);
-}
-#endif // DUMP_AUDIO