diff options
Diffstat (limited to 'examples/multimedia/spectrum/app/engine.cpp')
-rw-r--r-- | examples/multimedia/spectrum/app/engine.cpp | 783 |
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 |