diff options
Diffstat (limited to 'examples/spectrum/app')
33 files changed, 0 insertions, 5165 deletions
diff --git a/examples/spectrum/app/.gitignore b/examples/spectrum/app/.gitignore deleted file mode 100644 index 82cf2a2..0000000 --- a/examples/spectrum/app/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -spectrum -spectrum.exe diff --git a/examples/spectrum/app/app.pro b/examples/spectrum/app/app.pro deleted file mode 100644 index aec69d2..0000000 --- a/examples/spectrum/app/app.pro +++ /dev/null @@ -1,93 +0,0 @@ -include(../spectrum.pri) - -static: error(This application cannot be statically linked to the fftreal library) - -TEMPLATE = app - -TARGET = spectrum - -QT += multimedia - -SOURCES += main.cpp \ - engine.cpp \ - frequencyspectrum.cpp \ - levelmeter.cpp \ - mainwidget.cpp \ - progressbar.cpp \ - settingsdialog.cpp \ - spectrograph.cpp \ - spectrumanalyser.cpp \ - tonegenerator.cpp \ - tonegeneratordialog.cpp \ - utils.cpp \ - waveform.cpp \ - wavfile.cpp - -HEADERS += engine.h \ - frequencyspectrum.h \ - levelmeter.h \ - mainwidget.h \ - progressbar.h \ - settingsdialog.h \ - spectrograph.h \ - spectrum.h \ - spectrumanalyser.h \ - tonegenerator.h \ - tonegeneratordialog.h \ - utils.h \ - waveform.h \ - wavfile.h - -fftreal_dir = ../3rdparty/fftreal - -INCLUDEPATH += $${fftreal_dir} - -RESOURCES = spectrum.qrc - -# Dynamic linkage against FFTReal DLL -!contains(DEFINES, DISABLE_FFT) { - macx { - # Link to fftreal framework - LIBS += -F$${fftreal_dir} - LIBS += -framework fftreal - } else { - LIBS += -L..$${spectrum_build_dir} - LIBS += -lfftreal - } -} - -# Install - -sources.files = $$SOURCES $$HEADERS $$RESOURCES app.pro -sources.path = $$[QT_INSTALL_EXAMPLES]/qtmultimedia/spectrum/app -images.files += images/record.png images/settings.png -images.path = $$[QT_INSTALL_EXAMPLES]/qtmultimedia/spectrum/app/images -INSTALLS += sources images - -# Deployment - -DESTDIR = ..$${spectrum_build_dir} -macx { - !contains(DEFINES, DISABLE_FFT) { - # Relocate fftreal.framework into spectrum.app bundle - framework_dir = ../spectrum.app/Contents/Frameworks - framework_name = fftreal.framework/Versions/1/fftreal - QMAKE_POST_LINK = \ - mkdir -p $${framework_dir} &&\ - rm -rf $${framework_dir}/fftreal.framework &&\ - cp -R $${fftreal_dir}/fftreal.framework $${framework_dir} &&\ - install_name_tool -id @executable_path/../Frameworks/$${framework_name} \ - $${framework_dir}/$${framework_name} &&\ - install_name_tool -change $${framework_name} \ - @executable_path/../Frameworks/$${framework_name} \ - ../spectrum.app/Contents/MacOS/spectrum - } -} else { - linux-g++*: { - # Provide relative path from application to fftreal library - QMAKE_LFLAGS += -Wl,--rpath=\\\$\$ORIGIN - } -} - - -QT+=widgets diff --git a/examples/spectrum/app/engine.cpp b/examples/spectrum/app/engine.cpp deleted file mode 100644 index bea2452..0000000 --- a/examples/spectrum/app/engine.cpp +++ /dev/null @@ -1,766 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 <QCoreApplication> -#include <QMetaObject> -#include <QSet> -#include <QtMultimedia/QAudioInput> -#include <QtMultimedia/QAudioOutput> -#include <QDebug> -#include <QThread> -#include <QFile> - -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - -const qint64 BufferDurationUs = 10 * 1000000; -const int NotifyIntervalMs = 100; - -// Size of the level calculation window in microseconds -const int LevelWindowUs = 0.1 * 1000000; - - -//----------------------------------------------------------------------------- -// Helper functions -//----------------------------------------------------------------------------- - -QDebug& operator<<(QDebug &debug, const QAudioFormat &format) -{ - debug << format.frequency() << "Hz" - << format.channels() << "channels"; - return debug; -} - -//----------------------------------------------------------------------------- -// 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"); - CHECKED_CONNECT(&m_spectrumAnalyser, - SIGNAL(spectrumChanged(FrequencySpectrum)), - this, - SLOT(spectrumChanged(FrequencySpectrum))); - - 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; - CHECKED_CONNECT(m_audioInput, SIGNAL(stateChanged(QAudio::State)), - this, SLOT(audioStateChanged(QAudio::State))); - CHECKED_CONNECT(m_audioInput, SIGNAL(notify()), - this, SLOT(audioNotify())); - m_count = 0; - m_dataLength = 0; - emit dataLengthChanged(0); - m_audioInputIODevice = m_audioInput->start(); - CHECKED_CONNECT(m_audioInputIODevice, SIGNAL(readyRead()), - this, SLOT(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; - CHECKED_CONNECT(m_audioOutput, SIGNAL(stateChanged(QAudio::State)), - this, SLOT(audioStateChanged(QAudio::State))); - CHECKED_CONNECT(m_audioOutput, SIGNAL(notify()), - this, SLOT(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); - } - } 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; - - 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> frequenciesList; - #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. - frequenciesList += 8000; - #endif - - if (!m_generateTone) - frequenciesList += m_audioInputDevice.supportedFrequencies(); - - frequenciesList += m_audioOutputDevice.supportedFrequencies(); - frequenciesList = frequenciesList.toSet().toList(); // remove duplicates - qSort(frequenciesList); - ENGINE_DEBUG << "Engine::initialize frequenciesList" << frequenciesList; - - QList<int> channelsList; - channelsList += m_audioInputDevice.supportedChannels(); - channelsList += m_audioOutputDevice.supportedChannels(); - channelsList = channelsList.toSet().toList(); - qSort(channelsList); - ENGINE_DEBUG << "Engine::initialize channelsList" << channelsList; - - QAudioFormat format; - format.setByteOrder(QAudioFormat::LittleEndian); - format.setCodec("audio/pcm"); - format.setSampleSize(16); - format.setSampleType(QAudioFormat::SignedInt); - int frequency, channels; - foreach (frequency, frequenciesList) { - if (foundSupportedFormat) - break; - format.setFrequency(frequency); - foreach (channels, channelsList) { - format.setChannels(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.channels(); - 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); - QString file; - foreach (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 diff --git a/examples/spectrum/app/engine.h b/examples/spectrum/app/engine.h deleted file mode 100644 index 51c63b3..0000000 --- a/examples/spectrum/app/engine.h +++ /dev/null @@ -1,315 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 <QObject> -#include <QByteArray> -#include <QBuffer> -#include <QVector> -#include <QtMultimedia/QAudioDeviceInfo> -#include <QtMultimedia/QAudioFormat> - -#ifdef DUMP_CAPTURED_AUDIO -#define DUMP_DATA -#endif - -#ifdef DUMP_SPECTRUM -#define DUMP_DATA -#endif - -#ifdef DUMP_DATA -#include <QDir> -#endif - -class FrequencySpectrum; -QT_FORWARD_DECLARE_CLASS(QAudioInput) -QT_FORWARD_DECLARE_CLASS(QAudioOutput) -QT_FORWARD_DECLARE_CLASS(QFile) - -/** - * This class interfaces with the QtMultimedia 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 : public QObject { - Q_OBJECT -public: - Engine(QObject *parent = 0); - ~Engine(); - - const QList<QAudioDeviceInfo>& availableAudioInputDevices() const - { return m_availableAudioInputDevices; } - - const QList<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 - */ - const QAudioFormat& 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(const QString &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); - -public slots: - void startRecording(); - void startPlayback(); - void suspend(); - void setAudioInputDevice(const QAudioDeviceInfo &device); - void setAudioOutputDevice(const QAudioDeviceInfo &device); - -signals: - void stateChanged(QAudio::Mode mode, QAudio::State state); - - /** - * Informational message for non-modal display - */ - void infoMessage(const QString &message, int durationMs); - - /** - * Error message for modal display - */ - void errorMessage(const QString &heading, const QString &detail); - - /** - * Format of audio data has changed - */ - void formatChanged(const QAudioFormat &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, const QByteArray &buffer); - -private slots: - 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(const QAudioFormat &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_DATA - void createOutputDir(); - QString outputPath() const { return m_outputDir.path(); } -#endif - -#ifdef DUMP_CAPTURED_AUDIO - void dumpData(); -#endif - -private: - 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; - - const QList<QAudioDeviceInfo> m_availableAudioInputDevices; - QAudioDeviceInfo m_audioInputDevice; - QAudioInput* m_audioInput; - QIODevice* m_audioInputIODevice; - qint64 m_recordPosition; - - const QList<QAudioDeviceInfo> m_availableAudioOutputDevices; - QAudioDeviceInfo m_audioOutputDevice; - QAudioOutput* m_audioOutput; - 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_DATA - QDir m_outputDir; -#endif - -}; - -#endif // ENGINE_H diff --git a/examples/spectrum/app/frequencyspectrum.cpp b/examples/spectrum/app/frequencyspectrum.cpp deleted file mode 100644 index b4a4843..0000000 --- a/examples/spectrum/app/frequencyspectrum.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "frequencyspectrum.h" - -FrequencySpectrum::FrequencySpectrum(int numPoints) - : m_elements(numPoints) -{ - -} - -void FrequencySpectrum::reset() -{ - iterator i = begin(); - for ( ; i != end(); ++i) - *i = Element(); -} - -int FrequencySpectrum::count() const -{ - return m_elements.count(); -} - -FrequencySpectrum::Element& FrequencySpectrum::operator[](int index) -{ - return m_elements[index]; -} - -const FrequencySpectrum::Element& FrequencySpectrum::operator[](int index) const -{ - return m_elements[index]; -} - -FrequencySpectrum::iterator FrequencySpectrum::begin() -{ - return m_elements.begin(); -} - -FrequencySpectrum::iterator FrequencySpectrum::end() -{ - return m_elements.end(); -} - -FrequencySpectrum::const_iterator FrequencySpectrum::begin() const -{ - return m_elements.begin(); -} - -FrequencySpectrum::const_iterator FrequencySpectrum::end() const -{ - return m_elements.end(); -} diff --git a/examples/spectrum/app/frequencyspectrum.h b/examples/spectrum/app/frequencyspectrum.h deleted file mode 100644 index 8b2acf2..0000000 --- a/examples/spectrum/app/frequencyspectrum.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 FREQUENCYSPECTRUM_H -#define FREQUENCYSPECTRUM_H - -#include <QtCore/QVector> - -/** - * Represents a frequency spectrum as a series of elements, each of which - * consists of a frequency, an amplitude and a phase. - */ -class FrequencySpectrum { -public: - FrequencySpectrum(int numPoints = 0); - - struct Element { - Element() - : frequency(0.0), amplitude(0.0), phase(0.0), clipped(false) - { } - - /** - * Frequency in Hertz - */ - qreal frequency; - - /** - * Amplitude in range [0.0, 1.0] - */ - qreal amplitude; - - /** - * Phase in range [0.0, 2*PI] - */ - qreal phase; - - /** - * Indicates whether value has been clipped during spectrum analysis - */ - bool clipped; - }; - - typedef QVector<Element>::iterator iterator; - typedef QVector<Element>::const_iterator const_iterator; - - void reset(); - - int count() const; - Element& operator[](int index); - const Element& operator[](int index) const; - iterator begin(); - iterator end(); - const_iterator begin() const; - const_iterator end() const; - -private: - QVector<Element> m_elements; - -}; - -#endif // FREQUENCYSPECTRUM_H diff --git a/examples/spectrum/app/images/record.png b/examples/spectrum/app/images/record.png Binary files differdeleted file mode 100644 index e7493aa..0000000 --- a/examples/spectrum/app/images/record.png +++ /dev/null diff --git a/examples/spectrum/app/images/settings.png b/examples/spectrum/app/images/settings.png Binary files differdeleted file mode 100644 index 12179dc..0000000 --- a/examples/spectrum/app/images/settings.png +++ /dev/null diff --git a/examples/spectrum/app/levelmeter.cpp b/examples/spectrum/app/levelmeter.cpp deleted file mode 100644 index 35dd388..0000000 --- a/examples/spectrum/app/levelmeter.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "levelmeter.h" - -#include <math.h> - -#include <QPainter> -#include <QTimer> -#include <QDebug> - - -// Constants -const int RedrawInterval = 100; // ms -const qreal PeakDecayRate = 0.001; -const int PeakHoldLevelDuration = 2000; // ms - - -LevelMeter::LevelMeter(QWidget *parent) - : QWidget(parent) - , m_rmsLevel(0.0) - , m_peakLevel(0.0) - , m_decayedPeakLevel(0.0) - , m_peakDecayRate(PeakDecayRate) - , m_peakHoldLevel(0.0) - , m_redrawTimer(new QTimer(this)) - , m_rmsColor(Qt::red) - , m_peakColor(255, 200, 200, 255) -{ - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); - setMinimumWidth(30); - - connect(m_redrawTimer, SIGNAL(timeout()), this, SLOT(redrawTimerExpired())); - m_redrawTimer->start(RedrawInterval); -} - -LevelMeter::~LevelMeter() -{ - -} - -void LevelMeter::reset() -{ - m_rmsLevel = 0.0; - m_peakLevel = 0.0; - update(); -} - -void LevelMeter::levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples) -{ - // Smooth the RMS signal - const qreal smooth = pow(qreal(0.9), static_cast<qreal>(numSamples) / 256); // TODO: remove this magic number - m_rmsLevel = (m_rmsLevel * smooth) + (rmsLevel * (1.0 - smooth)); - - if (peakLevel > m_decayedPeakLevel) { - m_peakLevel = peakLevel; - m_decayedPeakLevel = peakLevel; - m_peakLevelChanged.start(); - } - - if (peakLevel > m_peakHoldLevel) { - m_peakHoldLevel = peakLevel; - m_peakHoldLevelChanged.start(); - } - - update(); -} - -void LevelMeter::redrawTimerExpired() -{ - // Decay the peak signal - const int elapsedMs = m_peakLevelChanged.elapsed(); - const qreal decayAmount = m_peakDecayRate * elapsedMs; - if (decayAmount < m_peakLevel) - m_decayedPeakLevel = m_peakLevel - decayAmount; - else - m_decayedPeakLevel = 0.0; - - // Check whether to clear the peak hold level - if (m_peakHoldLevelChanged.elapsed() > PeakHoldLevelDuration) - m_peakHoldLevel = 0.0; - - update(); -} - -void LevelMeter::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event) - - QPainter painter(this); - painter.fillRect(rect(), Qt::black); - - QRect bar = rect(); - - bar.setTop(rect().top() + (1.0 - m_peakHoldLevel) * rect().height()); - bar.setBottom(bar.top() + 5); - painter.fillRect(bar, m_rmsColor); - bar.setBottom(rect().bottom()); - - bar.setTop(rect().top() + (1.0 - m_decayedPeakLevel) * rect().height()); - painter.fillRect(bar, m_peakColor); - - bar.setTop(rect().top() + (1.0 - m_rmsLevel) * rect().height()); - painter.fillRect(bar, m_rmsColor); -} diff --git a/examples/spectrum/app/levelmeter.h b/examples/spectrum/app/levelmeter.h deleted file mode 100644 index 79aa124..0000000 --- a/examples/spectrum/app/levelmeter.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 LEVELMETER_H -#define LEVELMETER_H - -#include <QTime> -#include <QWidget> - -/** - * Widget which displays a vertical audio level meter, indicating the - * RMS and peak levels of the window of audio samples most recently analyzed - * by the Engine. - */ -class LevelMeter : public QWidget { - Q_OBJECT -public: - LevelMeter(QWidget *parent = 0); - ~LevelMeter(); - - void paintEvent(QPaintEvent *event); - -public slots: - void reset(); - void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples); - -private slots: - void redrawTimerExpired(); - -private: - /** - * Height of RMS level bar. - * Range 0.0 - 1.0. - */ - qreal m_rmsLevel; - - /** - * Most recent peak level. - * Range 0.0 - 1.0. - */ - qreal m_peakLevel; - - /** - * Height of peak level bar. - * This is calculated by decaying m_peakLevel depending on the - * elapsed time since m_peakLevelChanged, and the value of m_decayRate. - */ - qreal m_decayedPeakLevel; - - /** - * Time at which m_peakLevel was last changed. - */ - QTime m_peakLevelChanged; - - /** - * Rate at which peak level bar decays. - * Expressed in level units / millisecond. - */ - qreal m_peakDecayRate; - - /** - * High watermark of peak level. - * Range 0.0 - 1.0. - */ - qreal m_peakHoldLevel; - - /** - * Time at which m_peakHoldLevel was last changed. - */ - QTime m_peakHoldLevelChanged; - - QTimer *m_redrawTimer; - - QColor m_rmsColor; - QColor m_peakColor; - -}; - -#endif // LEVELMETER_H diff --git a/examples/spectrum/app/main.cpp b/examples/spectrum/app/main.cpp deleted file mode 100644 index c776499..0000000 --- a/examples/spectrum/app/main.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 <QtWidgets/QApplication> -#include "mainwidget.h" - -int main(int argc, char **argv) -{ - QApplication app(argc, argv); - app.setApplicationName("QtMultimedia spectrum analyzer"); - MainWidget w; - - w.show(); - - return app.exec(); -} diff --git a/examples/spectrum/app/mainwidget.cpp b/examples/spectrum/app/mainwidget.cpp deleted file mode 100644 index b5cf66e..0000000 --- a/examples/spectrum/app/mainwidget.cpp +++ /dev/null @@ -1,448 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "levelmeter.h" -#include "mainwidget.h" -#include "waveform.h" -#include "progressbar.h" -#include "settingsdialog.h" -#include "spectrograph.h" -#include "tonegeneratordialog.h" -#include "utils.h" - -#include <QLabel> -#include <QPushButton> -#include <QHBoxLayout> -#include <QVBoxLayout> -#include <QStyle> -#include <QMenu> -#include <QFileDialog> -#include <QTimerEvent> -#include <QMessageBox> - -const int NullTimerId = -1; - -MainWidget::MainWidget(QWidget *parent) - : QWidget(parent) - , m_mode(NoMode) - , m_engine(new Engine(this)) -#ifndef DISABLE_WAVEFORM - , m_waveform(new Waveform(this)) -#endif - , m_progressBar(new ProgressBar(this)) - , m_spectrograph(new Spectrograph(this)) - , m_levelMeter(new LevelMeter(this)) - , m_modeButton(new QPushButton(this)) - , m_recordButton(new QPushButton(this)) - , m_pauseButton(new QPushButton(this)) - , m_playButton(new QPushButton(this)) - , m_settingsButton(new QPushButton(this)) - , m_infoMessage(new QLabel(tr("Select a mode to begin"), this)) - , m_infoMessageTimerId(NullTimerId) - , m_settingsDialog(new SettingsDialog( - m_engine->availableAudioInputDevices(), - m_engine->availableAudioOutputDevices(), - this)) - , m_toneGeneratorDialog(new ToneGeneratorDialog(this)) - , m_modeMenu(new QMenu(this)) - , m_loadFileAction(0) - , m_generateToneAction(0) - , m_recordAction(0) -{ - m_spectrograph->setParams(SpectrumNumBands, SpectrumLowFreq, SpectrumHighFreq); - - createUi(); - connectUi(); -} - -MainWidget::~MainWidget() -{ - -} - - -//----------------------------------------------------------------------------- -// Public slots -//----------------------------------------------------------------------------- - -void MainWidget::stateChanged(QAudio::Mode mode, QAudio::State state) -{ - Q_UNUSED(mode); - - updateButtonStates(); - - if (QAudio::ActiveState != state && QAudio::SuspendedState != state) { - m_levelMeter->reset(); - m_spectrograph->reset(); - } -} - -void MainWidget::formatChanged(const QAudioFormat &format) -{ - infoMessage(formatToString(format), NullMessageTimeout); - -#ifndef DISABLE_WAVEFORM - if (QAudioFormat() != format) { - m_waveform->initialize(format, WaveformTileLength, - WaveformWindowDuration); - } -#endif -} - -void MainWidget::spectrumChanged(qint64 position, qint64 length, - const FrequencySpectrum &spectrum) -{ - m_progressBar->windowChanged(position, length); - m_spectrograph->spectrumChanged(spectrum); -} - -void MainWidget::infoMessage(const QString &message, int timeoutMs) -{ - m_infoMessage->setText(message); - - if (NullTimerId != m_infoMessageTimerId) { - killTimer(m_infoMessageTimerId); - m_infoMessageTimerId = NullTimerId; - } - - if (NullMessageTimeout != timeoutMs) - m_infoMessageTimerId = startTimer(timeoutMs); -} - -void MainWidget::errorMessage(const QString &heading, const QString &detail) -{ - QMessageBox::warning(this, heading, detail, QMessageBox::Close); -} - -void MainWidget::timerEvent(QTimerEvent *event) -{ - Q_ASSERT(event->timerId() == m_infoMessageTimerId); - Q_UNUSED(event) // suppress warnings in release builds - killTimer(m_infoMessageTimerId); - m_infoMessageTimerId = NullTimerId; - m_infoMessage->setText(""); -} - -void MainWidget::audioPositionChanged(qint64 position) -{ -#ifndef DISABLE_WAVEFORM - m_waveform->audioPositionChanged(position); -#else - Q_UNUSED(position) -#endif -} - -void MainWidget::bufferLengthChanged(qint64 length) -{ - m_progressBar->bufferLengthChanged(length); -} - - -//----------------------------------------------------------------------------- -// Private slots -//----------------------------------------------------------------------------- - -void MainWidget::showFileDialog() -{ - const QString dir; - const QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open WAV file"), dir, "*.wav"); - if (fileNames.count()) { - reset(); - setMode(LoadFileMode); - m_engine->loadFile(fileNames.front()); - updateButtonStates(); - } else { - updateModeMenu(); - } -} - -void MainWidget::showSettingsDialog() -{ - m_settingsDialog->exec(); - if (m_settingsDialog->result() == QDialog::Accepted) { - m_engine->setAudioInputDevice(m_settingsDialog->inputDevice()); - m_engine->setAudioOutputDevice(m_settingsDialog->outputDevice()); - m_engine->setWindowFunction(m_settingsDialog->windowFunction()); - } -} - -void MainWidget::showToneGeneratorDialog() -{ - m_toneGeneratorDialog->exec(); - if (m_toneGeneratorDialog->result() == QDialog::Accepted) { - reset(); - setMode(GenerateToneMode); - const qreal amplitude = m_toneGeneratorDialog->amplitude(); - if (m_toneGeneratorDialog->isFrequencySweepEnabled()) { - m_engine->generateSweptTone(amplitude); - } else { - const qreal frequency = m_toneGeneratorDialog->frequency(); - const Tone tone(frequency, amplitude); - m_engine->generateTone(tone); - updateButtonStates(); - } - } else { - updateModeMenu(); - } -} - -void MainWidget::initializeRecord() -{ - reset(); - setMode(RecordMode); - if (m_engine->initializeRecord()) - updateButtonStates(); -} - - -//----------------------------------------------------------------------------- -// Private functions -//----------------------------------------------------------------------------- - -void MainWidget::createUi() -{ - createMenus(); - - setWindowTitle(tr("Spectrum Analyser")); - - QVBoxLayout *windowLayout = new QVBoxLayout(this); - - m_infoMessage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - m_infoMessage->setAlignment(Qt::AlignHCenter); - windowLayout->addWidget(m_infoMessage); - -#ifdef SUPERIMPOSE_PROGRESS_ON_WAVEFORM - QScopedPointer<QHBoxLayout> waveformLayout(new QHBoxLayout); - waveformLayout->addWidget(m_progressBar); - m_progressBar->setMinimumHeight(m_waveform->minimumHeight()); - waveformLayout->setMargin(0); - m_waveform->setLayout(waveformLayout.data()); - waveformLayout.take(); - windowLayout->addWidget(m_waveform); -#else -#ifndef DISABLE_WAVEFORM - windowLayout->addWidget(m_waveform); -#endif // DISABLE_WAVEFORM - windowLayout->addWidget(m_progressBar); -#endif // SUPERIMPOSE_PROGRESS_ON_WAVEFORM - - // Spectrograph and level meter - - QScopedPointer<QHBoxLayout> analysisLayout(new QHBoxLayout); - analysisLayout->addWidget(m_spectrograph); - analysisLayout->addWidget(m_levelMeter); - windowLayout->addLayout(analysisLayout.data()); - analysisLayout.take(); - - // Button panel - - const QSize buttonSize(30, 30); - - m_modeButton->setText(tr("Mode")); - - m_recordIcon = QIcon(":/images/record.png"); - m_recordButton->setIcon(m_recordIcon); - m_recordButton->setEnabled(false); - m_recordButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - m_recordButton->setMinimumSize(buttonSize); - - m_pauseIcon = style()->standardIcon(QStyle::SP_MediaPause); - m_pauseButton->setIcon(m_pauseIcon); - m_pauseButton->setEnabled(false); - m_pauseButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - m_pauseButton->setMinimumSize(buttonSize); - - m_playIcon = style()->standardIcon(QStyle::SP_MediaPlay); - m_playButton->setIcon(m_playIcon); - m_playButton->setEnabled(false); - m_playButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - m_playButton->setMinimumSize(buttonSize); - - m_settingsIcon = QIcon(":/images/settings.png"); - m_settingsButton->setIcon(m_settingsIcon); - m_settingsButton->setEnabled(true); - m_settingsButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - m_settingsButton->setMinimumSize(buttonSize); - - QScopedPointer<QHBoxLayout> buttonPanelLayout(new QHBoxLayout); - buttonPanelLayout->addStretch(); - buttonPanelLayout->addWidget(m_modeButton); - buttonPanelLayout->addWidget(m_recordButton); - buttonPanelLayout->addWidget(m_pauseButton); - buttonPanelLayout->addWidget(m_playButton); - buttonPanelLayout->addWidget(m_settingsButton); - - QWidget *buttonPanel = new QWidget(this); - buttonPanel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - buttonPanel->setLayout(buttonPanelLayout.data()); - buttonPanelLayout.take(); // ownership transferred to buttonPanel - - QScopedPointer<QHBoxLayout> bottomPaneLayout(new QHBoxLayout); - bottomPaneLayout->addWidget(buttonPanel); - windowLayout->addLayout(bottomPaneLayout.data()); - bottomPaneLayout.take(); // ownership transferred to windowLayout - - // Apply layout - - setLayout(windowLayout); -} - -void MainWidget::connectUi() -{ - CHECKED_CONNECT(m_recordButton, SIGNAL(clicked()), - m_engine, SLOT(startRecording())); - - CHECKED_CONNECT(m_pauseButton, SIGNAL(clicked()), - m_engine, SLOT(suspend())); - - CHECKED_CONNECT(m_playButton, SIGNAL(clicked()), - m_engine, SLOT(startPlayback())); - - CHECKED_CONNECT(m_settingsButton, SIGNAL(clicked()), - this, SLOT(showSettingsDialog())); - - CHECKED_CONNECT(m_engine, SIGNAL(stateChanged(QAudio::Mode,QAudio::State)), - this, SLOT(stateChanged(QAudio::Mode,QAudio::State))); - - CHECKED_CONNECT(m_engine, SIGNAL(formatChanged(const QAudioFormat &)), - this, SLOT(formatChanged(const QAudioFormat &))); - - m_progressBar->bufferLengthChanged(m_engine->bufferLength()); - - CHECKED_CONNECT(m_engine, SIGNAL(bufferLengthChanged(qint64)), - this, SLOT(bufferLengthChanged(qint64))); - - CHECKED_CONNECT(m_engine, SIGNAL(dataLengthChanged(qint64)), - this, SLOT(updateButtonStates())); - - CHECKED_CONNECT(m_engine, SIGNAL(recordPositionChanged(qint64)), - m_progressBar, SLOT(recordPositionChanged(qint64))); - - CHECKED_CONNECT(m_engine, SIGNAL(playPositionChanged(qint64)), - m_progressBar, SLOT(playPositionChanged(qint64))); - - CHECKED_CONNECT(m_engine, SIGNAL(recordPositionChanged(qint64)), - this, SLOT(audioPositionChanged(qint64))); - - CHECKED_CONNECT(m_engine, SIGNAL(playPositionChanged(qint64)), - this, SLOT(audioPositionChanged(qint64))); - - CHECKED_CONNECT(m_engine, SIGNAL(levelChanged(qreal, qreal, int)), - m_levelMeter, SLOT(levelChanged(qreal, qreal, int))); - - CHECKED_CONNECT(m_engine, SIGNAL(spectrumChanged(qint64, qint64, const FrequencySpectrum &)), - this, SLOT(spectrumChanged(qint64, qint64, const FrequencySpectrum &))); - - CHECKED_CONNECT(m_engine, SIGNAL(infoMessage(QString, int)), - this, SLOT(infoMessage(QString, int))); - - CHECKED_CONNECT(m_engine, SIGNAL(errorMessage(QString, QString)), - this, SLOT(errorMessage(QString, QString))); - - CHECKED_CONNECT(m_spectrograph, SIGNAL(infoMessage(QString, int)), - this, SLOT(infoMessage(QString, int))); - -#ifndef DISABLE_WAVEFORM - CHECKED_CONNECT(m_engine, SIGNAL(bufferChanged(qint64, qint64, const QByteArray &)), - m_waveform, SLOT(bufferChanged(qint64, qint64, const QByteArray &))); -#endif -} - -void MainWidget::createMenus() -{ - m_modeButton->setMenu(m_modeMenu); - - m_generateToneAction = m_modeMenu->addAction(tr("Play generated tone")); - m_recordAction = m_modeMenu->addAction(tr("Record and play back")); - m_loadFileAction = m_modeMenu->addAction(tr("Play file")); - - m_loadFileAction->setCheckable(true); - m_generateToneAction->setCheckable(true); - m_recordAction->setCheckable(true); - - connect(m_loadFileAction, SIGNAL(triggered(bool)), this, SLOT(showFileDialog())); - connect(m_generateToneAction, SIGNAL(triggered(bool)), this, SLOT(showToneGeneratorDialog())); - connect(m_recordAction, SIGNAL(triggered(bool)), this, SLOT(initializeRecord())); -} - -void MainWidget::updateButtonStates() -{ - const bool recordEnabled = ((QAudio::AudioOutput == m_engine->mode() || - (QAudio::ActiveState != m_engine->state() && - QAudio::IdleState != m_engine->state())) && - RecordMode == m_mode); - m_recordButton->setEnabled(recordEnabled); - - const bool pauseEnabled = (QAudio::ActiveState == m_engine->state() || - QAudio::IdleState == m_engine->state()); - m_pauseButton->setEnabled(pauseEnabled); - - const bool playEnabled = (/*m_engine->dataLength() &&*/ - (QAudio::AudioOutput != m_engine->mode() || - (QAudio::ActiveState != m_engine->state() && - QAudio::IdleState != m_engine->state()))); - m_playButton->setEnabled(playEnabled); -} - -void MainWidget::reset() -{ -#ifndef DISABLE_WAVEFORM - m_waveform->reset(); -#endif - m_engine->reset(); - m_levelMeter->reset(); - m_spectrograph->reset(); - m_progressBar->reset(); -} - -void MainWidget::setMode(Mode mode) -{ - m_mode = mode; - updateModeMenu(); -} - -void MainWidget::updateModeMenu() -{ - m_loadFileAction->setChecked(LoadFileMode == m_mode); - m_generateToneAction->setChecked(GenerateToneMode == m_mode); - m_recordAction->setChecked(RecordMode == m_mode); -} - diff --git a/examples/spectrum/app/mainwidget.h b/examples/spectrum/app/mainwidget.h deleted file mode 100644 index 14c62a2..0000000 --- a/examples/spectrum/app/mainwidget.h +++ /dev/null @@ -1,144 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 MAINWIDGET_H -#define MAINWIDGET_H - -#include <QWidget> -#include <QIcon> -#include <QtMultimedia/qaudio.h> - -class Engine; -class FrequencySpectrum; -class ProgressBar; -class Spectrograph; -class Waveform; -class LevelMeter; -class SettingsDialog; -class ToneGeneratorDialog; - -QT_FORWARD_DECLARE_CLASS(QAudioFormat) -QT_FORWARD_DECLARE_CLASS(QLabel) -QT_FORWARD_DECLARE_CLASS(QPushButton) -QT_FORWARD_DECLARE_CLASS(QMenu) -QT_FORWARD_DECLARE_CLASS(QAction) - -/** - * Main application widget, responsible for connecting the various UI - * elements to the Engine. - */ -class MainWidget : public QWidget { - Q_OBJECT -public: - MainWidget(QWidget *parent = 0); - ~MainWidget(); - - // QObject - void timerEvent(QTimerEvent *event); - -public slots: - void stateChanged(QAudio::Mode mode, QAudio::State state); - void formatChanged(const QAudioFormat &format); - void spectrumChanged(qint64 position, qint64 length, - const FrequencySpectrum &spectrum); - void infoMessage(const QString &message, int timeoutMs); - void errorMessage(const QString &heading, const QString &detail); - void audioPositionChanged(qint64 position); - void bufferLengthChanged(qint64 length); - -private slots: - void showFileDialog(); - void showSettingsDialog(); - void showToneGeneratorDialog(); - void initializeRecord(); - void updateModeMenu(); - void updateButtonStates(); - -private: - void createUi(); - void createMenus(); - void connectUi(); - void reset(); - - enum Mode { - NoMode, - RecordMode, - GenerateToneMode, - LoadFileMode - }; - - void setMode(Mode mode); - -private: - Mode m_mode; - - Engine* m_engine; - -#ifndef DISABLE_WAVEFORM - Waveform* m_waveform; -#endif - ProgressBar* m_progressBar; - Spectrograph* m_spectrograph; - LevelMeter* m_levelMeter; - - QPushButton* m_modeButton; - QPushButton* m_recordButton; - QIcon m_recordIcon; - QPushButton* m_pauseButton; - QIcon m_pauseIcon; - QPushButton* m_playButton; - QIcon m_playIcon; - QPushButton* m_settingsButton; - QIcon m_settingsIcon; - - QLabel* m_infoMessage; - int m_infoMessageTimerId; - - SettingsDialog* m_settingsDialog; - ToneGeneratorDialog* m_toneGeneratorDialog; - - QMenu* m_modeMenu; - QAction* m_loadFileAction; - QAction* m_generateToneAction; - QAction* m_recordAction; - -}; - -#endif // MAINWIDGET_H diff --git a/examples/spectrum/app/progressbar.cpp b/examples/spectrum/app/progressbar.cpp deleted file mode 100644 index 4660510..0000000 --- a/examples/spectrum/app/progressbar.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "progressbar.h" -#include "spectrum.h" -#include <QPainter> - -ProgressBar::ProgressBar(QWidget *parent) - : QWidget(parent) - , m_bufferLength(0) - , m_recordPosition(0) - , m_playPosition(0) - , m_windowPosition(0) - , m_windowLength(0) -{ - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - setMinimumHeight(30); -#ifdef SUPERIMPOSE_PROGRESS_ON_WAVEFORM - setAutoFillBackground(false); -#endif -} - -ProgressBar::~ProgressBar() -{ - -} - -void ProgressBar::reset() -{ - m_bufferLength = 0; - m_recordPosition = 0; - m_playPosition = 0; - m_windowPosition = 0; - m_windowLength = 0; - update(); -} - -void ProgressBar::paintEvent(QPaintEvent * /*event*/) -{ - QPainter painter(this); - - QColor bufferColor(0, 0, 255); - QColor windowColor(0, 255, 0); - -#ifdef SUPERIMPOSE_PROGRESS_ON_WAVEFORM - bufferColor.setAlphaF(0.5); - windowColor.setAlphaF(0.5); -#else - painter.fillRect(rect(), Qt::black); -#endif - - if (m_bufferLength) { - QRect bar = rect(); - const qreal play = qreal(m_playPosition) / m_bufferLength; - bar.setLeft(rect().left() + play * rect().width()); - const qreal record = qreal(m_recordPosition) / m_bufferLength; - bar.setRight(rect().left() + record * rect().width()); - painter.fillRect(bar, bufferColor); - - QRect window = rect(); - const qreal windowLeft = qreal(m_windowPosition) / m_bufferLength; - window.setLeft(rect().left() + windowLeft * rect().width()); - const qreal windowWidth = qreal(m_windowLength) / m_bufferLength; - window.setWidth(windowWidth * rect().width()); - painter.fillRect(window, windowColor); - } -} - -void ProgressBar::bufferLengthChanged(qint64 bufferSize) -{ - m_bufferLength = bufferSize; - m_recordPosition = 0; - m_playPosition = 0; - m_windowPosition = 0; - m_windowLength = 0; - repaint(); -} - -void ProgressBar::recordPositionChanged(qint64 recordPosition) -{ - Q_ASSERT(recordPosition >= 0); - Q_ASSERT(recordPosition <= m_bufferLength); - m_recordPosition = recordPosition; - repaint(); -} - -void ProgressBar::playPositionChanged(qint64 playPosition) -{ - Q_ASSERT(playPosition >= 0); - Q_ASSERT(playPosition <= m_bufferLength); - m_playPosition = playPosition; - repaint(); -} - -void ProgressBar::windowChanged(qint64 position, qint64 length) -{ - Q_ASSERT(position >= 0); - Q_ASSERT(position <= m_bufferLength); - Q_ASSERT(position + length <= m_bufferLength); - m_windowPosition = position; - m_windowLength = length; - repaint(); -} diff --git a/examples/spectrum/app/progressbar.h b/examples/spectrum/app/progressbar.h deleted file mode 100644 index b12f1c5..0000000 --- a/examples/spectrum/app/progressbar.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 PROGRESSBAR_H -#define PROGRESSBAR_H - -#include <QWidget> - -/** - * Widget which displays a the current fill state of the Engine's internal - * buffer, and the current play/record position within that buffer. - */ -class ProgressBar : public QWidget { - Q_OBJECT -public: - ProgressBar(QWidget *parent = 0); - ~ProgressBar(); - - void reset(); - void paintEvent(QPaintEvent *event); - -public slots: - void bufferLengthChanged(qint64 length); - void recordPositionChanged(qint64 recordPosition); - void playPositionChanged(qint64 playPosition); - void windowChanged(qint64 position, qint64 length); - -private: - qint64 m_bufferLength; - qint64 m_recordPosition; - qint64 m_playPosition; - qint64 m_windowPosition; - qint64 m_windowLength; - -}; - -#endif // PROGRESSBAR_H diff --git a/examples/spectrum/app/settingsdialog.cpp b/examples/spectrum/app/settingsdialog.cpp deleted file mode 100644 index 78c2db9..0000000 --- a/examples/spectrum/app/settingsdialog.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "settingsdialog.h" -#include <QComboBox> -#include <QDialogButtonBox> -#include <QLabel> -#include <QPushButton> -#include <QVBoxLayout> -#include <QCheckBox> -#include <QSlider> -#include <QSpinBox> - -SettingsDialog::SettingsDialog( - const QList<QAudioDeviceInfo> &availableInputDevices, - const QList<QAudioDeviceInfo> &availableOutputDevices, - QWidget *parent) - : QDialog(parent) - , m_windowFunction(DefaultWindowFunction) - , m_inputDeviceComboBox(new QComboBox(this)) - , m_outputDeviceComboBox(new QComboBox(this)) - , m_windowFunctionComboBox(new QComboBox(this)) -{ - QVBoxLayout *dialogLayout = new QVBoxLayout(this); - - // Populate combo boxes - - QAudioDeviceInfo device; - foreach (device, availableInputDevices) - m_inputDeviceComboBox->addItem(device.deviceName(), - QVariant::fromValue(device)); - foreach (device, availableOutputDevices) - m_outputDeviceComboBox->addItem(device.deviceName(), - QVariant::fromValue(device)); - - m_windowFunctionComboBox->addItem(tr("None"), QVariant::fromValue(int(NoWindow))); - m_windowFunctionComboBox->addItem("Hann", QVariant::fromValue(int(HannWindow))); - m_windowFunctionComboBox->setCurrentIndex(m_windowFunction); - - // Initialize default devices - if (!availableInputDevices.empty()) - m_inputDevice = availableInputDevices.front(); - if (!availableOutputDevices.empty()) - m_outputDevice = availableOutputDevices.front(); - - // Add widgets to layout - - QScopedPointer<QHBoxLayout> inputDeviceLayout(new QHBoxLayout); - QLabel *inputDeviceLabel = new QLabel(tr("Input device"), this); - inputDeviceLayout->addWidget(inputDeviceLabel); - inputDeviceLayout->addWidget(m_inputDeviceComboBox); - dialogLayout->addLayout(inputDeviceLayout.data()); - inputDeviceLayout.take(); // ownership transferred to dialogLayout - - QScopedPointer<QHBoxLayout> outputDeviceLayout(new QHBoxLayout); - QLabel *outputDeviceLabel = new QLabel(tr("Output device"), this); - outputDeviceLayout->addWidget(outputDeviceLabel); - outputDeviceLayout->addWidget(m_outputDeviceComboBox); - dialogLayout->addLayout(outputDeviceLayout.data()); - outputDeviceLayout.take(); // ownership transferred to dialogLayout - - QScopedPointer<QHBoxLayout> windowFunctionLayout(new QHBoxLayout); - QLabel *windowFunctionLabel = new QLabel(tr("Window function"), this); - windowFunctionLayout->addWidget(windowFunctionLabel); - windowFunctionLayout->addWidget(m_windowFunctionComboBox); - dialogLayout->addLayout(windowFunctionLayout.data()); - windowFunctionLayout.take(); // ownership transferred to dialogLayout - - // Connect - CHECKED_CONNECT(m_inputDeviceComboBox, SIGNAL(activated(int)), - this, SLOT(inputDeviceChanged(int))); - CHECKED_CONNECT(m_outputDeviceComboBox, SIGNAL(activated(int)), - this, SLOT(outputDeviceChanged(int))); - CHECKED_CONNECT(m_windowFunctionComboBox, SIGNAL(activated(int)), - this, SLOT(windowFunctionChanged(int))); - - // Add standard buttons to layout - QDialogButtonBox *buttonBox = new QDialogButtonBox(this); - buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - dialogLayout->addWidget(buttonBox); - - // Connect standard buttons - CHECKED_CONNECT(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), - this, SLOT(accept())); - CHECKED_CONNECT(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), - this, SLOT(reject())); - - setLayout(dialogLayout); -} - -SettingsDialog::~SettingsDialog() -{ - -} - -void SettingsDialog::windowFunctionChanged(int index) -{ - m_windowFunction = static_cast<WindowFunction>( - m_windowFunctionComboBox->itemData(index).value<int>()); -} - -void SettingsDialog::inputDeviceChanged(int index) -{ - m_inputDevice = m_inputDeviceComboBox->itemData(index).value<QAudioDeviceInfo>(); -} - -void SettingsDialog::outputDeviceChanged(int index) -{ - m_outputDevice = m_outputDeviceComboBox->itemData(index).value<QAudioDeviceInfo>(); -} - diff --git a/examples/spectrum/app/settingsdialog.h b/examples/spectrum/app/settingsdialog.h deleted file mode 100644 index 71d1796..0000000 --- a/examples/spectrum/app/settingsdialog.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 SETTINGSDIALOG_H -#define SETTINGSDIALOG_H - -#include "spectrum.h" -#include <QDialog> -#include <QtMultimedia/QAudioDeviceInfo> - -QT_FORWARD_DECLARE_CLASS(QComboBox) -QT_FORWARD_DECLARE_CLASS(QCheckBox) -QT_FORWARD_DECLARE_CLASS(QSlider) -QT_FORWARD_DECLARE_CLASS(QSpinBox) -QT_FORWARD_DECLARE_CLASS(QGridLayout) - -/** - * Dialog used to control settings such as the audio input / output device - * and the windowing function. - */ -class SettingsDialog : public QDialog { - Q_OBJECT -public: - SettingsDialog(const QList<QAudioDeviceInfo> &availableInputDevices, - const QList<QAudioDeviceInfo> &availableOutputDevices, - QWidget *parent = 0); - ~SettingsDialog(); - - WindowFunction windowFunction() const { return m_windowFunction; } - const QAudioDeviceInfo& inputDevice() const { return m_inputDevice; } - const QAudioDeviceInfo& outputDevice() const { return m_outputDevice; } - -private slots: - void windowFunctionChanged(int index); - void inputDeviceChanged(int index); - void outputDeviceChanged(int index); - -private: - WindowFunction m_windowFunction; - QAudioDeviceInfo m_inputDevice; - QAudioDeviceInfo m_outputDevice; - - QComboBox* m_inputDeviceComboBox; - QComboBox* m_outputDeviceComboBox; - - QComboBox* m_windowFunctionComboBox; - -}; - -#endif // SETTINGSDIALOG_H diff --git a/examples/spectrum/app/spectrograph.cpp b/examples/spectrum/app/spectrograph.cpp deleted file mode 100644 index 7551491..0000000 --- a/examples/spectrum/app/spectrograph.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "spectrograph.h" -#include <QPainter> -#include <QMouseEvent> -#include <QDebug> -#include <QTimerEvent> - -const int NullTimerId = -1; -const int NullIndex = -1; -const int BarSelectionInterval = 2000; - -Spectrograph::Spectrograph(QWidget *parent) - : QWidget(parent) - , m_barSelected(NullIndex) - , m_timerId(NullTimerId) - , m_lowFreq(0.0) - , m_highFreq(0.0) -{ - setMinimumHeight(100); -} - -Spectrograph::~Spectrograph() -{ - -} - -void Spectrograph::setParams(int numBars, qreal lowFreq, qreal highFreq) -{ - Q_ASSERT(numBars > 0); - Q_ASSERT(highFreq > lowFreq); - m_bars.resize(numBars); - m_lowFreq = lowFreq; - m_highFreq = highFreq; - updateBars(); -} - -void Spectrograph::timerEvent(QTimerEvent *event) -{ - Q_ASSERT(event->timerId() == m_timerId); - Q_UNUSED(event) // suppress warnings in release builds - killTimer(m_timerId); - m_timerId = NullTimerId; - m_barSelected = NullIndex; - update(); -} - -void Spectrograph::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event) - - QPainter painter(this); - painter.fillRect(rect(), Qt::black); - - const int numBars = m_bars.count(); - - // Highlight region of selected bar - if (m_barSelected != NullIndex && numBars) { - QRect regionRect = rect(); - regionRect.setLeft(m_barSelected * rect().width() / numBars); - regionRect.setWidth(rect().width() / numBars); - QColor regionColor(202, 202, 64); - painter.setBrush(Qt::DiagCrossPattern); - painter.fillRect(regionRect, regionColor); - painter.setBrush(Qt::NoBrush); - } - - QColor barColor(51, 204, 102); - QColor clipColor(255, 255, 0); - - // Draw the outline - const QColor gridColor = barColor.darker(); - QPen gridPen(gridColor); - painter.setPen(gridPen); - painter.drawLine(rect().topLeft(), rect().topRight()); - painter.drawLine(rect().topRight(), rect().bottomRight()); - painter.drawLine(rect().bottomRight(), rect().bottomLeft()); - painter.drawLine(rect().bottomLeft(), rect().topLeft()); - - QVector<qreal> dashes; - dashes << 2 << 2; - gridPen.setDashPattern(dashes); - painter.setPen(gridPen); - - // Draw vertical lines between bars - if (numBars) { - const int numHorizontalSections = numBars; - QLine line(rect().topLeft(), rect().bottomLeft()); - for (int i=1; i<numHorizontalSections; ++i) { - line.translate(rect().width()/numHorizontalSections, 0); - painter.drawLine(line); - } - } - - // Draw horizontal lines - const int numVerticalSections = 10; - QLine line(rect().topLeft(), rect().topRight()); - for (int i=1; i<numVerticalSections; ++i) { - line.translate(0, rect().height()/numVerticalSections); - painter.drawLine(line); - } - - barColor = barColor.lighter(); - barColor.setAlphaF(0.75); - clipColor.setAlphaF(0.75); - - // Draw the bars - if (numBars) { - // Calculate width of bars and gaps - const int widgetWidth = rect().width(); - const int barPlusGapWidth = widgetWidth / numBars; - const int barWidth = 0.8 * barPlusGapWidth; - const int gapWidth = barPlusGapWidth - barWidth; - const int paddingWidth = widgetWidth - numBars * (barWidth + gapWidth); - const int leftPaddingWidth = (paddingWidth + gapWidth) / 2; - const int barHeight = rect().height() - 2 * gapWidth; - - for (int i=0; i<numBars; ++i) { - const qreal value = m_bars[i].value; - Q_ASSERT(value >= 0.0 && value <= 1.0); - QRect bar = rect(); - bar.setLeft(rect().left() + leftPaddingWidth + (i * (gapWidth + barWidth))); - bar.setWidth(barWidth); - bar.setTop(rect().top() + gapWidth + (1.0 - value) * barHeight); - bar.setBottom(rect().bottom() - gapWidth); - - QColor color = barColor; - if (m_bars[i].clipped) - color = clipColor; - - painter.fillRect(bar, color); - } - } -} - -void Spectrograph::mousePressEvent(QMouseEvent *event) -{ - const QPoint pos = event->pos(); - const int index = m_bars.count() * (pos.x() - rect().left()) / rect().width(); - selectBar(index); -} - -void Spectrograph::reset() -{ - m_spectrum.reset(); - spectrumChanged(m_spectrum); -} - -void Spectrograph::spectrumChanged(const FrequencySpectrum &spectrum) -{ - m_spectrum = spectrum; - updateBars(); -} - -int Spectrograph::barIndex(qreal frequency) const -{ - Q_ASSERT(frequency >= m_lowFreq && frequency < m_highFreq); - const qreal bandWidth = (m_highFreq - m_lowFreq) / m_bars.count(); - const int index = (frequency - m_lowFreq) / bandWidth; - if (index <0 || index >= m_bars.count()) - Q_ASSERT(false); - return index; -} - -QPair<qreal, qreal> Spectrograph::barRange(int index) const -{ - Q_ASSERT(index >= 0 && index < m_bars.count()); - const qreal bandWidth = (m_highFreq - m_lowFreq) / m_bars.count(); - return QPair<qreal, qreal>(index * bandWidth, (index+1) * bandWidth); -} - -void Spectrograph::updateBars() -{ - m_bars.fill(Bar()); - FrequencySpectrum::const_iterator i = m_spectrum.begin(); - const FrequencySpectrum::const_iterator end = m_spectrum.end(); - for ( ; i != end; ++i) { - const FrequencySpectrum::Element e = *i; - if (e.frequency >= m_lowFreq && e.frequency < m_highFreq) { - Bar &bar = m_bars[barIndex(e.frequency)]; - bar.value = qMax(bar.value, e.amplitude); - bar.clipped |= e.clipped; - } - } - update(); -} - -void Spectrograph::selectBar(int index) { - const QPair<qreal, qreal> frequencyRange = barRange(index); - const QString message = QString("%1 - %2 Hz") - .arg(frequencyRange.first) - .arg(frequencyRange.second); - emit infoMessage(message, BarSelectionInterval); - - if (NullTimerId != m_timerId) - killTimer(m_timerId); - m_timerId = startTimer(BarSelectionInterval); - - m_barSelected = index; - update(); -} - - diff --git a/examples/spectrum/app/spectrograph.h b/examples/spectrum/app/spectrograph.h deleted file mode 100644 index bfcefd8..0000000 --- a/examples/spectrum/app/spectrograph.h +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 SPECTROGRAPH_H -#define SPECTROGRAPH_H - -#include <QWidget> -#include "frequencyspectrum.h" - -QT_FORWARD_DECLARE_CLASS(QMouseEvent) - -/** - * Widget which displays a spectrograph showing the frequency spectrum - * of the window of audio samples most recently analyzed by the Engine. - */ -class Spectrograph : public QWidget { - Q_OBJECT -public: - Spectrograph(QWidget *parent = 0); - ~Spectrograph(); - - void setParams(int numBars, qreal lowFreq, qreal highFreq); - - // QObject - void timerEvent(QTimerEvent *event); - - // QWidget - void paintEvent(QPaintEvent *event); - void mousePressEvent(QMouseEvent *event); - -signals: - void infoMessage(const QString &message, int intervalMs); - -public slots: - void reset(); - void spectrumChanged(const FrequencySpectrum &spectrum); - -private: - int barIndex(qreal frequency) const; - QPair<qreal, qreal> barRange(int barIndex) const; - void updateBars(); - - void selectBar(int index); - -private: - struct Bar { - Bar() : value(0.0), clipped(false) { } - qreal value; - bool clipped; - }; - - QVector<Bar> m_bars; - int m_barSelected; - int m_timerId; - qreal m_lowFreq; - qreal m_highFreq; - FrequencySpectrum m_spectrum; - - -}; - -#endif // SPECTROGRAPH_H diff --git a/examples/spectrum/app/spectrum.h b/examples/spectrum/app/spectrum.h deleted file mode 100644 index e8e34e6..0000000 --- a/examples/spectrum/app/spectrum.h +++ /dev/null @@ -1,144 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 SPECTRUM_H -#define SPECTRUM_H - -#include <QtCore/qglobal.h> -#include "utils.h" -#include "fftreal_wrapper.h" // For FFTLengthPowerOfTwo - -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - -// Number of audio samples used to calculate the frequency spectrum -const int SpectrumLengthSamples = PowerOfTwo<FFTLengthPowerOfTwo>::Result; - -// Number of bands in the frequency spectrum -const int SpectrumNumBands = 10; - -// Lower bound of first band in the spectrum -const qreal SpectrumLowFreq = 0.0; // Hz - -// Upper band of last band in the spectrum -const qreal SpectrumHighFreq = 1000.0; // Hz - -// Waveform window size in microseconds -const qint64 WaveformWindowDuration = 500 * 1000; - -// Length of waveform tiles in bytes -// Ideally, these would match the QAudio*::bufferSize(), but that isn't -// available until some time after QAudio*::start() has been called, and we -// need this value in order to initialize the waveform display. -// We therefore just choose a sensible value. -const int WaveformTileLength = 4096; - -// Fudge factor used to calculate the spectrum bar heights -const qreal SpectrumAnalyserMultiplier = 0.15; - -// Disable message timeout -const int NullMessageTimeout = -1; - - -//----------------------------------------------------------------------------- -// Types and data structures -//----------------------------------------------------------------------------- - -enum WindowFunction { - NoWindow, - HannWindow -}; - -const WindowFunction DefaultWindowFunction = HannWindow; - -struct Tone { - Tone(qreal freq = 0.0, qreal amp = 0.0) - : frequency(freq), amplitude(amp) - { } - - // Start and end frequencies for swept tone generation - qreal frequency; - - // Amplitude in range [0.0, 1.0] - qreal amplitude; -}; - -struct SweptTone { - SweptTone(qreal start = 0.0, qreal end = 0.0, qreal amp = 0.0) - : startFreq(start), endFreq(end), amplitude(amp) - { Q_ASSERT(end >= start); } - - SweptTone(const Tone &tone) - : startFreq(tone.frequency), endFreq(tone.frequency), amplitude(tone.amplitude) - { } - - // Start and end frequencies for swept tone generation - qreal startFreq; - qreal endFreq; - - // Amplitude in range [0.0, 1.0] - qreal amplitude; -}; - - -//----------------------------------------------------------------------------- -// Macros -//----------------------------------------------------------------------------- - -// Macro which connects a signal to a slot, and which causes application to -// abort if the connection fails. This is intended to catch programming errors -// such as mis-typing a signal or slot name. It is necessary to write our own -// macro to do this - the following idiom -// Q_ASSERT(connect(source, signal, receiver, slot)); -// will not work because Q_ASSERT compiles to a no-op in release builds. - -#define CHECKED_CONNECT(source, signal, receiver, slot) \ - if (!connect(source, signal, receiver, slot)) \ - qt_assert_x(Q_FUNC_INFO, "CHECKED_CONNECT failed", __FILE__, __LINE__); - -// Handle some dependencies between macros defined in the .pro file - -#ifdef DISABLE_WAVEFORM -#undef SUPERIMPOSE_PROGRESS_ON_WAVEFORM -#endif - -#endif // SPECTRUM_H - diff --git a/examples/spectrum/app/spectrum.qrc b/examples/spectrum/app/spectrum.qrc deleted file mode 100644 index 6100479..0000000 --- a/examples/spectrum/app/spectrum.qrc +++ /dev/null @@ -1,7 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource> - <file>images/record.png</file> - <file>images/settings.png</file> -</qresource> -</RCC> - diff --git a/examples/spectrum/app/spectrumanalyser.cpp b/examples/spectrum/app/spectrumanalyser.cpp deleted file mode 100644 index 8c3212d..0000000 --- a/examples/spectrum/app/spectrumanalyser.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "spectrumanalyser.h" -#include "utils.h" - -#include <QtCore/qmath.h> -#include <QtCore/qmetatype.h> -#include <QtMultimedia/QAudioFormat> -#include <QThread> - -#include "fftreal_wrapper.h" - -SpectrumAnalyserThread::SpectrumAnalyserThread(QObject *parent) - : QObject(parent) -#ifndef DISABLE_FFT - , m_fft(new FFTRealWrapper) -#endif - , m_numSamples(SpectrumLengthSamples) - , m_windowFunction(DefaultWindowFunction) - , m_window(SpectrumLengthSamples, 0.0) - , m_input(SpectrumLengthSamples, 0.0) - , m_output(SpectrumLengthSamples, 0.0) - , m_spectrum(SpectrumLengthSamples) -#ifdef SPECTRUM_ANALYSER_SEPARATE_THREAD - , m_thread(new QThread(this)) -#endif -{ -#ifdef SPECTRUM_ANALYSER_SEPARATE_THREAD - // moveToThread() cannot be called on a QObject with a parent - setParent(0); - moveToThread(m_thread); - m_thread->start(); -#endif - calculateWindow(); -} - -SpectrumAnalyserThread::~SpectrumAnalyserThread() -{ -#ifndef DISABLE_FFT - delete m_fft; -#endif -} - -void SpectrumAnalyserThread::setWindowFunction(WindowFunction type) -{ - m_windowFunction = type; - calculateWindow(); -} - -void SpectrumAnalyserThread::calculateWindow() -{ - for (int i=0; i<m_numSamples; ++i) { - DataType x = 0.0; - - switch (m_windowFunction) { - case NoWindow: - x = 1.0; - break; - case HannWindow: - x = 0.5 * (1 - qCos((2 * M_PI * i) / (m_numSamples - 1))); - break; - default: - Q_ASSERT(false); - } - - m_window[i] = x; - } -} - -void SpectrumAnalyserThread::calculateSpectrum(const QByteArray &buffer, - int inputFrequency, - int bytesPerSample) -{ -#ifndef DISABLE_FFT - Q_ASSERT(buffer.size() == m_numSamples * bytesPerSample); - - // Initialize data array - const char *ptr = buffer.constData(); - for (int i=0; i<m_numSamples; ++i) { - const qint16 pcmSample = *reinterpret_cast<const qint16*>(ptr); - // Scale down to range [-1.0, 1.0] - const DataType realSample = pcmToReal(pcmSample); - const DataType windowedSample = realSample * m_window[i]; - m_input[i] = windowedSample; - ptr += bytesPerSample; - } - - // Calculate the FFT - m_fft->calculateFFT(m_output.data(), m_input.data()); - - // Analyze output to obtain amplitude and phase for each frequency - for (int i=2; i<=m_numSamples/2; ++i) { - // Calculate frequency of this complex sample - m_spectrum[i].frequency = qreal(i * inputFrequency) / (m_numSamples); - - const qreal real = m_output[i]; - qreal imag = 0.0; - if (i>0 && i<m_numSamples/2) - imag = m_output[m_numSamples/2 + i]; - - const qreal magnitude = sqrt(real*real + imag*imag); - qreal amplitude = SpectrumAnalyserMultiplier * log(magnitude); - - // Bound amplitude to [0.0, 1.0] - m_spectrum[i].clipped = (amplitude > 1.0); - amplitude = qMax(qreal(0.0), amplitude); - amplitude = qMin(qreal(1.0), amplitude); - m_spectrum[i].amplitude = amplitude; - } -#endif - - emit calculationComplete(m_spectrum); -} - - -//============================================================================= -// SpectrumAnalyser -//============================================================================= - -SpectrumAnalyser::SpectrumAnalyser(QObject *parent) - : QObject(parent) - , m_thread(new SpectrumAnalyserThread(this)) - , m_state(Idle) -#ifdef DUMP_SPECTRUMANALYSER - , m_count(0) -#endif -{ - CHECKED_CONNECT(m_thread, SIGNAL(calculationComplete(FrequencySpectrum)), - this, SLOT(calculationComplete(FrequencySpectrum))); -} - -SpectrumAnalyser::~SpectrumAnalyser() -{ - -} - -#ifdef DUMP_SPECTRUMANALYSER -void SpectrumAnalyser::setOutputPath(const QString &outputDir) -{ - m_outputDir.setPath(outputDir); - m_textFile.setFileName(m_outputDir.filePath("spectrum.txt")); - m_textFile.open(QIODevice::WriteOnly | QIODevice::Text); - m_textStream.setDevice(&m_textFile); -} -#endif - -//----------------------------------------------------------------------------- -// Public functions -//----------------------------------------------------------------------------- - -void SpectrumAnalyser::setWindowFunction(WindowFunction type) -{ - const bool b = QMetaObject::invokeMethod(m_thread, "setWindowFunction", - Qt::AutoConnection, - Q_ARG(WindowFunction, type)); - Q_ASSERT(b); - Q_UNUSED(b) // suppress warnings in release builds -} - -void SpectrumAnalyser::calculate(const QByteArray &buffer, - const QAudioFormat &format) -{ - // QThread::currentThread is marked 'for internal use only', but - // we're only using it for debug output here, so it's probably OK :) - SPECTRUMANALYSER_DEBUG << "SpectrumAnalyser::calculate" - << QThread::currentThread() - << "state" << m_state; - - if (isReady()) { - Q_ASSERT(isPCMS16LE(format)); - - const int bytesPerSample = format.sampleSize() * format.channels() / 8; - -#ifdef DUMP_SPECTRUMANALYSER - m_count++; - const QString pcmFileName = m_outputDir.filePath(QString("spectrum_%1.pcm").arg(m_count, 4, 10, QChar('0'))); - QFile pcmFile(pcmFileName); - pcmFile.open(QIODevice::WriteOnly); - const int bufferLength = m_numSamples * bytesPerSample; - pcmFile.write(buffer, bufferLength); - - m_textStream << "TimeDomain " << m_count << "\n"; - const qint16* input = reinterpret_cast<const qint16*>(buffer); - for (int i=0; i<m_numSamples; ++i) { - m_textStream << i << "\t" << *input << "\n"; - input += format.channels(); - } -#endif - - m_state = Busy; - - // Invoke SpectrumAnalyserThread::calculateSpectrum using QMetaObject. If - // m_thread is in a different thread from the current thread, the - // calculation will be done in the child thread. - // Once the calculation is finished, a calculationChanged signal will be - // emitted by m_thread. - const bool b = QMetaObject::invokeMethod(m_thread, "calculateSpectrum", - Qt::AutoConnection, - Q_ARG(QByteArray, buffer), - Q_ARG(int, format.frequency()), - Q_ARG(int, bytesPerSample)); - Q_ASSERT(b); - Q_UNUSED(b) // suppress warnings in release builds - -#ifdef DUMP_SPECTRUMANALYSER - m_textStream << "FrequencySpectrum " << m_count << "\n"; - FrequencySpectrum::const_iterator x = m_spectrum.begin(); - for (int i=0; i<m_numSamples; ++i, ++x) - m_textStream << i << "\t" - << x->frequency << "\t" - << x->amplitude<< "\t" - << x->phase << "\n"; -#endif - } -} - -bool SpectrumAnalyser::isReady() const -{ - return (Idle == m_state); -} - -void SpectrumAnalyser::cancelCalculation() -{ - if (Busy == m_state) - m_state = Cancelled; -} - - -//----------------------------------------------------------------------------- -// Private slots -//----------------------------------------------------------------------------- - -void SpectrumAnalyser::calculationComplete(const FrequencySpectrum &spectrum) -{ - Q_ASSERT(Idle != m_state); - if (Busy == m_state) - emit spectrumChanged(spectrum); - m_state = Idle; -} - - - - diff --git a/examples/spectrum/app/spectrumanalyser.h b/examples/spectrum/app/spectrumanalyser.h deleted file mode 100644 index 663c213..0000000 --- a/examples/spectrum/app/spectrumanalyser.h +++ /dev/null @@ -1,194 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 SPECTRUMANALYSER_H -#define SPECTRUMANALYSER_H - -#include <QByteArray> -#include <QObject> -#include <QVector> - -#ifdef DUMP_SPECTRUMANALYSER -#include <QDir> -#include <QFile> -#include <QTextStream> -#endif - -#include "frequencyspectrum.h" -#include "spectrum.h" - -#ifndef DISABLE_FFT -#include "FFTRealFixLenParam.h" -#endif - -QT_FORWARD_DECLARE_CLASS(QAudioFormat) -QT_FORWARD_DECLARE_CLASS(QThread) - -class FFTRealWrapper; - -class SpectrumAnalyserThreadPrivate; - -/** - * Implementation of the spectrum analysis which can be run in a - * separate thread. - */ -class SpectrumAnalyserThread : public QObject -{ - Q_OBJECT -public: - SpectrumAnalyserThread(QObject *parent); - ~SpectrumAnalyserThread(); - -public slots: - void setWindowFunction(WindowFunction type); - void calculateSpectrum(const QByteArray &buffer, - int inputFrequency, - int bytesPerSample); - -signals: - void calculationComplete(const FrequencySpectrum &spectrum); - -private: - void calculateWindow(); - -private: -#ifndef DISABLE_FFT - FFTRealWrapper* m_fft; -#endif - - const int m_numSamples; - - WindowFunction m_windowFunction; - -#ifdef DISABLE_FFT - typedef qreal DataType; -#else - typedef FFTRealFixLenParam::DataType DataType; -#endif - QVector<DataType> m_window; - - QVector<DataType> m_input; - QVector<DataType> m_output; - - FrequencySpectrum m_spectrum; - -#ifdef SPECTRUM_ANALYSER_SEPARATE_THREAD - QThread* m_thread; -#endif -}; - -/** - * Class which performs frequency spectrum analysis on a window of - * audio samples, provided to it by the Engine. - */ -class SpectrumAnalyser : public QObject -{ - Q_OBJECT -public: - SpectrumAnalyser(QObject *parent = 0); - ~SpectrumAnalyser(); - -#ifdef DUMP_SPECTRUMANALYSER - void setOutputPath(const QString &outputPath); -#endif - -public: - /* - * Set the windowing function which is applied before calculating the FFT - */ - void setWindowFunction(WindowFunction type); - - /* - * Calculate a frequency spectrum - * - * \param buffer Audio data - * \param format Format of audio data - * - * Frequency spectrum is calculated asynchronously. The result is returned - * via the spectrumChanged signal. - * - * An ongoing calculation can be cancelled by calling cancelCalculation(). - * - */ - void calculate(const QByteArray &buffer, const QAudioFormat &format); - - /* - * Check whether the object is ready to perform another calculation - */ - bool isReady() const; - - /* - * Cancel an ongoing calculation - * - * Note that cancelling is asynchronous. - */ - void cancelCalculation(); - -signals: - void spectrumChanged(const FrequencySpectrum &spectrum); - -private slots: - void calculationComplete(const FrequencySpectrum &spectrum); - -private: - void calculateWindow(); - -private: - - SpectrumAnalyserThread* m_thread; - - enum State { - Idle, - Busy, - Cancelled - }; - - State m_state; - -#ifdef DUMP_SPECTRUMANALYSER - QDir m_outputDir; - int m_count; - QFile m_textFile; - QTextStream m_textStream; -#endif -}; - -#endif // SPECTRUMANALYSER_H - diff --git a/examples/spectrum/app/tonegenerator.cpp b/examples/spectrum/app/tonegenerator.cpp deleted file mode 100644 index f3cad99..0000000 --- a/examples/spectrum/app/tonegenerator.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "spectrum.h" -#include "utils.h" -#include <QByteArray> -#include <QtMultimedia/QAudioFormat> -#include <QtCore/qmath.h> -#include <QtCore/qendian.h> - -void generateTone(const SweptTone &tone, const QAudioFormat &format, QByteArray &buffer) -{ - Q_ASSERT(isPCMS16LE(format)); - - const int channelBytes = format.sampleSize() / 8; - const int sampleBytes = format.channels() * channelBytes; - int length = buffer.size(); - const int numSamples = buffer.size() / sampleBytes; - - Q_ASSERT(length % sampleBytes == 0); - Q_UNUSED(sampleBytes) // suppress warning in release builds - - unsigned char *ptr = reinterpret_cast<unsigned char *>(buffer.data()); - - qreal phase = 0.0; - - const qreal d = 2 * M_PI / format.frequency(); - - // We can't generate a zero-frequency sine wave - const qreal startFreq = tone.startFreq ? tone.startFreq : 1.0; - - // Amount by which phase increases on each sample - qreal phaseStep = d * startFreq; - - // Amount by which phaseStep increases on each sample - // If this is non-zero, the output is a frequency-swept tone - const qreal phaseStepStep = d * (tone.endFreq - startFreq) / numSamples; - - while (length) { - const qreal x = tone.amplitude * qSin(phase); - const qint16 value = realToPcm(x); - for (int i=0; i<format.channels(); ++i) { - qToLittleEndian<qint16>(value, ptr); - ptr += channelBytes; - length -= channelBytes; - } - - phase += phaseStep; - while (phase > 2 * M_PI) - phase -= 2 * M_PI; - phaseStep += phaseStepStep; - } -} - diff --git a/examples/spectrum/app/tonegenerator.h b/examples/spectrum/app/tonegenerator.h deleted file mode 100644 index d2aadb2..0000000 --- a/examples/spectrum/app/tonegenerator.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 TONEGENERATOR_H -#define TONEGENERATOR_H - -#include <QtCore/qglobal.h> -#include "spectrum.h" - -QT_FORWARD_DECLARE_CLASS(QAudioFormat) -QT_FORWARD_DECLARE_CLASS(QByteArray) - -/** - * Generate a sine wave - */ -void generateTone(const SweptTone &tone, const QAudioFormat &format, QByteArray &buffer); - -#endif // TONEGENERATOR_H - diff --git a/examples/spectrum/app/tonegeneratordialog.cpp b/examples/spectrum/app/tonegeneratordialog.cpp deleted file mode 100644 index 5e5cd63..0000000 --- a/examples/spectrum/app/tonegeneratordialog.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "tonegeneratordialog.h" -#include <QComboBox> -#include <QDialogButtonBox> -#include <QLabel> -#include <QPushButton> -#include <QVBoxLayout> -#include <QCheckBox> -#include <QSlider> -#include <QSpinBox> - -const int ToneGeneratorFreqMin = 1; -const int ToneGeneratorFreqMax = 1000; -const int ToneGeneratorFreqDefault = 440; -const int ToneGeneratorAmplitudeDefault = 75; - -ToneGeneratorDialog::ToneGeneratorDialog(QWidget *parent) - : QDialog(parent) - , m_toneGeneratorSweepCheckBox(new QCheckBox(tr("Frequency sweep"), this)) - , m_frequencySweepEnabled(true) - , m_toneGeneratorControl(new QWidget(this)) - , m_toneGeneratorFrequencyControl(new QWidget(this)) - , m_frequencySlider(new QSlider(Qt::Horizontal, this)) - , m_frequencySpinBox(new QSpinBox(this)) - , m_frequency(ToneGeneratorFreqDefault) - , m_amplitudeSlider(new QSlider(Qt::Horizontal, this)) -{ - QVBoxLayout *dialogLayout = new QVBoxLayout(this); - - m_toneGeneratorSweepCheckBox->setChecked(true); - - // Configure tone generator controls - m_frequencySlider->setRange(ToneGeneratorFreqMin, ToneGeneratorFreqMax); - m_frequencySlider->setValue(ToneGeneratorFreqDefault); - m_frequencySpinBox->setRange(ToneGeneratorFreqMin, ToneGeneratorFreqMax); - m_frequencySpinBox->setValue(ToneGeneratorFreqDefault); - m_amplitudeSlider->setRange(0, 100); - m_amplitudeSlider->setValue(ToneGeneratorAmplitudeDefault); - - // Add widgets to layout - - QScopedPointer<QGridLayout> frequencyControlLayout(new QGridLayout); - QLabel *frequencyLabel = new QLabel(tr("Frequency (Hz)"), this); - frequencyControlLayout->addWidget(frequencyLabel, 0, 0, 2, 1); - frequencyControlLayout->addWidget(m_frequencySlider, 0, 1); - frequencyControlLayout->addWidget(m_frequencySpinBox, 1, 1); - m_toneGeneratorFrequencyControl->setLayout(frequencyControlLayout.data()); - frequencyControlLayout.take(); // ownership transferred to m_toneGeneratorFrequencyControl - m_toneGeneratorFrequencyControl->setEnabled(false); - - QScopedPointer<QGridLayout> toneGeneratorLayout(new QGridLayout); - QLabel *amplitudeLabel = new QLabel(tr("Amplitude"), this); - toneGeneratorLayout->addWidget(m_toneGeneratorSweepCheckBox, 0, 1); - toneGeneratorLayout->addWidget(m_toneGeneratorFrequencyControl, 1, 0, 1, 2); - toneGeneratorLayout->addWidget(amplitudeLabel, 2, 0); - toneGeneratorLayout->addWidget(m_amplitudeSlider, 2, 1); - m_toneGeneratorControl->setLayout(toneGeneratorLayout.data()); - m_toneGeneratorControl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - dialogLayout->addWidget(m_toneGeneratorControl); - toneGeneratorLayout.take(); // ownership transferred - - // Connect - CHECKED_CONNECT(m_toneGeneratorSweepCheckBox, SIGNAL(toggled(bool)), - this, SLOT(frequencySweepEnabled(bool))); - CHECKED_CONNECT(m_frequencySlider, SIGNAL(valueChanged(int)), - m_frequencySpinBox, SLOT(setValue(int))); - CHECKED_CONNECT(m_frequencySpinBox, SIGNAL(valueChanged(int)), - m_frequencySlider, SLOT(setValue(int))); - - // Add standard buttons to layout - QDialogButtonBox *buttonBox = new QDialogButtonBox(this); - buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - dialogLayout->addWidget(buttonBox); - - // Connect standard buttons - CHECKED_CONNECT(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), - this, SLOT(accept())); - CHECKED_CONNECT(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), - this, SLOT(reject())); - - setLayout(dialogLayout); -} - -ToneGeneratorDialog::~ToneGeneratorDialog() -{ - -} - -bool ToneGeneratorDialog::isFrequencySweepEnabled() const -{ - return m_toneGeneratorSweepCheckBox->isChecked(); -} - -qreal ToneGeneratorDialog::frequency() const -{ - return qreal(m_frequencySlider->value()); -} - -qreal ToneGeneratorDialog::amplitude() const -{ - return qreal(m_amplitudeSlider->value()) / 100.0; -} - -void ToneGeneratorDialog::frequencySweepEnabled(bool enabled) -{ - m_frequencySweepEnabled = enabled; - m_toneGeneratorFrequencyControl->setEnabled(!enabled); -} diff --git a/examples/spectrum/app/tonegeneratordialog.h b/examples/spectrum/app/tonegeneratordialog.h deleted file mode 100644 index 788a0ea..0000000 --- a/examples/spectrum/app/tonegeneratordialog.h +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 TONEGENERATORDIALOG_H -#define TONEGENERATORDIALOG_H - -#include "spectrum.h" -#include <QDialog> -#include <QtMultimedia/QAudioDeviceInfo> - -QT_FORWARD_DECLARE_CLASS(QCheckBox) -QT_FORWARD_DECLARE_CLASS(QSlider) -QT_FORWARD_DECLARE_CLASS(QSpinBox) -QT_FORWARD_DECLARE_CLASS(QGridLayout) - -/** - * Dialog which controls the parameters of the tone generator. - */ -class ToneGeneratorDialog : public QDialog { - Q_OBJECT -public: - ToneGeneratorDialog(QWidget *parent = 0); - ~ToneGeneratorDialog(); - - bool isFrequencySweepEnabled() const; - qreal frequency() const; - qreal amplitude() const; - -private slots: - void frequencySweepEnabled(bool enabled); - -private: - QCheckBox* m_toneGeneratorSweepCheckBox; - bool m_frequencySweepEnabled; - QWidget* m_toneGeneratorControl; - QWidget* m_toneGeneratorFrequencyControl; - QSlider* m_frequencySlider; - QSpinBox* m_frequencySpinBox; - qreal m_frequency; - QSlider* m_amplitudeSlider; - -}; - -#endif // TONEGENERATORDIALOG_H diff --git a/examples/spectrum/app/utils.cpp b/examples/spectrum/app/utils.cpp deleted file mode 100644 index 31cc25b..0000000 --- a/examples/spectrum/app/utils.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 <QtMultimedia/QAudioFormat> -#include "utils.h" - -qint64 audioDuration(const QAudioFormat &format, qint64 bytes) -{ - return (bytes * 1000000) / - (format.frequency() * format.channels() * (format.sampleSize() / 8)); -} - -qint64 audioLength(const QAudioFormat &format, qint64 microSeconds) -{ - qint64 result = (format.frequency() * format.channels() * (format.sampleSize() / 8)) - * microSeconds / 1000000; - result -= result % (format.channelCount() * format.sampleSize()); - return result; -} - -qreal nyquistFrequency(const QAudioFormat &format) -{ - return format.frequency() / 2; -} - -QString formatToString(const QAudioFormat &format) -{ - QString result; - - if (QAudioFormat() != format) { - if (format.codec() == "audio/pcm") { - Q_ASSERT(format.sampleType() == QAudioFormat::SignedInt); - - const QString formatEndian = (format.byteOrder() == QAudioFormat::LittleEndian) - ? QString("LE") : QString("BE"); - - QString formatType; - switch (format.sampleType()) { - case QAudioFormat::SignedInt: - formatType = "signed"; - break; - case QAudioFormat::UnSignedInt: - formatType = "unsigned"; - break; - case QAudioFormat::Float: - formatType = "float"; - break; - case QAudioFormat::Unknown: - formatType = "unknown"; - break; - } - - QString formatChannels = QString("%1 channels").arg(format.channels()); - switch (format.channels()) { - case 1: - formatChannels = "mono"; - break; - case 2: - formatChannels = "stereo"; - break; - } - - result = QString("%1 Hz %2 bit %3 %4 %5") - .arg(format.frequency()) - .arg(format.sampleSize()) - .arg(formatType) - .arg(formatEndian) - .arg(formatChannels); - } else { - result = format.codec(); - } - } - - return result; -} - -bool isPCM(const QAudioFormat &format) -{ - return (format.codec() == "audio/pcm"); -} - - -bool isPCMS16LE(const QAudioFormat &format) -{ - return (isPCM(format) && - format.sampleType() == QAudioFormat::SignedInt && - format.sampleSize() == 16 && - format.byteOrder() == QAudioFormat::LittleEndian); -} - -const qint16 PCMS16MaxValue = 32767; -const quint16 PCMS16MaxAmplitude = 32768; // because minimum is -32768 - -qreal pcmToReal(qint16 pcm) -{ - return qreal(pcm) / PCMS16MaxAmplitude; -} - -qint16 realToPcm(qreal real) -{ - return real * PCMS16MaxValue; -} diff --git a/examples/spectrum/app/utils.h b/examples/spectrum/app/utils.h deleted file mode 100644 index 9c85c61..0000000 --- a/examples/spectrum/app/utils.h +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 UTILS_H -#define UTILS_H - -#include <QtCore/qglobal.h> -#include <QDebug> - -QT_FORWARD_DECLARE_CLASS(QAudioFormat) - -//----------------------------------------------------------------------------- -// Miscellaneous utility functions -//----------------------------------------------------------------------------- - -qint64 audioDuration(const QAudioFormat &format, qint64 bytes); -qint64 audioLength(const QAudioFormat &format, qint64 microSeconds); - -QString formatToString(const QAudioFormat &format); - -qreal nyquistFrequency(const QAudioFormat &format); - -// Scale PCM value to [-1.0, 1.0] -qreal pcmToReal(qint16 pcm); - -// Scale real value in [-1.0, 1.0] to PCM -qint16 realToPcm(qreal real); - -// Check whether the audio format is PCM -bool isPCM(const QAudioFormat &format); - -// Check whether the audio format is signed, little-endian, 16-bit PCM -bool isPCMS16LE(const QAudioFormat &format); - -// Compile-time calculation of powers of two - -template<int N> class PowerOfTwo -{ public: static const int Result = PowerOfTwo<N-1>::Result * 2; }; - -template<> class PowerOfTwo<0> -{ public: static const int Result = 1; }; - - -//----------------------------------------------------------------------------- -// Debug output -//----------------------------------------------------------------------------- - -class NullDebug -{ -public: - template <typename T> - NullDebug& operator<<(const T&) { return *this; } -}; - -inline NullDebug nullDebug() { return NullDebug(); } - -#ifdef LOG_ENGINE -# define ENGINE_DEBUG qDebug() -#else -# define ENGINE_DEBUG nullDebug() -#endif - -#ifdef LOG_SPECTRUMANALYSER -# define SPECTRUMANALYSER_DEBUG qDebug() -#else -# define SPECTRUMANALYSER_DEBUG nullDebug() -#endif - -#ifdef LOG_WAVEFORM -# define WAVEFORM_DEBUG qDebug() -#else -# define WAVEFORM_DEBUG nullDebug() -#endif - -#endif // UTILS_H diff --git a/examples/spectrum/app/waveform.cpp b/examples/spectrum/app/waveform.cpp deleted file mode 100644 index fe44a4f..0000000 --- a/examples/spectrum/app/waveform.cpp +++ /dev/null @@ -1,436 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 "waveform.h" -#include "utils.h" -#include <QPainter> -#include <QResizeEvent> -#include <QDebug> - -//#define PAINT_EVENT_TRACE -#ifdef PAINT_EVENT_TRACE -# define WAVEFORM_PAINT_DEBUG qDebug() -#else -# define WAVEFORM_PAINT_DEBUG nullDebug() -#endif - -Waveform::Waveform(QWidget *parent) - : QWidget(parent) - , m_bufferPosition(0) - , m_bufferLength(0) - , m_audioPosition(0) - , m_active(false) - , m_tileLength(0) - , m_tileArrayStart(0) - , m_windowPosition(0) - , m_windowLength(0) -{ - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - setMinimumHeight(50); -} - -Waveform::~Waveform() -{ - deletePixmaps(); -} - -void Waveform::paintEvent(QPaintEvent * /*event*/) -{ - QPainter painter(this); - - painter.fillRect(rect(), Qt::black); - - if (m_active) { - WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" - << "windowPosition" << m_windowPosition - << "windowLength" << m_windowLength; - qint64 pos = m_windowPosition; - const qint64 windowEnd = m_windowPosition + m_windowLength; - int destLeft = 0; - int destRight = 0; - while (pos < windowEnd) { - const TilePoint point = tilePoint(pos); - WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "pos" << pos - << "tileIndex" << point.index - << "positionOffset" << point.positionOffset - << "pixelOffset" << point.pixelOffset; - - if (point.index != NullIndex) { - const Tile &tile = m_tiles[point.index]; - if (tile.painted) { - const qint64 sectionLength = qMin((m_tileLength - point.positionOffset), - (windowEnd - pos)); - Q_ASSERT(sectionLength > 0); - - const int sourceRight = tilePixelOffset(point.positionOffset + sectionLength); - destRight = windowPixelOffset(pos - m_windowPosition + sectionLength); - - QRect destRect = rect(); - destRect.setLeft(destLeft); - destRect.setRight(destRight); - - QRect sourceRect(QPoint(), m_pixmapSize); - sourceRect.setLeft(point.pixelOffset); - sourceRect.setRight(sourceRight); - - WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "tileIndex" << point.index - << "source" << point.pixelOffset << sourceRight - << "dest" << destLeft << destRight; - - painter.drawPixmap(destRect, *tile.pixmap, sourceRect); - - destLeft = destRight; - - if (point.index < m_tiles.count()) { - pos = tilePosition(point.index + 1); - WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "pos ->" << pos; - } else { - // Reached end of tile array - WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "reached end of tile array"; - break; - } - } else { - // Passed last tile which is painted - WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "tile" << point.index << "not painted"; - break; - } - } else { - // pos is past end of tile array - WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "pos" << pos << "past end of tile array"; - break; - } - } - - WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "final pos" << pos << "final x" << destRight; - } -} - -void Waveform::resizeEvent(QResizeEvent *event) -{ - if (event->size() != event->oldSize()) - createPixmaps(event->size()); -} - -void Waveform::initialize(const QAudioFormat &format, qint64 audioBufferSize, qint64 windowDurationUs) -{ - WAVEFORM_DEBUG << "Waveform::initialize" - << "audioBufferSize" << audioBufferSize - << "windowDurationUs" << windowDurationUs; - - reset(); - - m_format = format; - - // Calculate tile size - m_tileLength = audioBufferSize; - - // Calculate window size - m_windowLength = audioLength(m_format, windowDurationUs); - - // Calculate number of tiles required - int nTiles; - if (m_tileLength > m_windowLength) { - nTiles = 2; - } else { - nTiles = m_windowLength / m_tileLength + 1; - if (m_windowLength % m_tileLength) - ++nTiles; - } - - WAVEFORM_DEBUG << "Waveform::initialize" - << "tileLength" << m_tileLength - << "windowLength" << m_windowLength - << "nTiles" << nTiles; - - m_pixmaps.fill(0, nTiles); - m_tiles.resize(nTiles); - - createPixmaps(rect().size()); - - m_active = true; -} - -void Waveform::reset() -{ - WAVEFORM_DEBUG << "Waveform::reset"; - - m_bufferPosition = 0; - m_buffer = QByteArray(); - m_audioPosition = 0; - m_format = QAudioFormat(); - m_active = false; - deletePixmaps(); - m_tiles.clear(); - m_tileLength = 0; - m_tileArrayStart = 0; - m_windowPosition = 0; - m_windowLength = 0; -} - -void Waveform::bufferChanged(qint64 position, qint64 length, const QByteArray &buffer) -{ - WAVEFORM_DEBUG << "Waveform::bufferChanged" - << "audioPosition" << m_audioPosition - << "bufferPosition" << position - << "bufferLength" << length; - m_bufferPosition = position; - m_bufferLength = length; - m_buffer = buffer; - paintTiles(); -} - -void Waveform::audioPositionChanged(qint64 position) -{ - WAVEFORM_DEBUG << "Waveform::audioPositionChanged" - << "audioPosition" << position - << "bufferPosition" << m_bufferPosition - << "bufferLength" << m_bufferLength; - - if (position >= m_bufferPosition) { - if (position + m_windowLength > m_bufferPosition + m_bufferLength) - position = qMax(qint64(0), m_bufferPosition + m_bufferLength - m_windowLength); - m_audioPosition = position; - setWindowPosition(position); - } -} - -void Waveform::deletePixmaps() -{ - QPixmap *pixmap; - foreach (pixmap, m_pixmaps) - delete pixmap; - m_pixmaps.clear(); -} - -void Waveform::createPixmaps(const QSize &widgetSize) -{ - m_pixmapSize = widgetSize; - m_pixmapSize.setWidth(qreal(widgetSize.width()) * m_tileLength / m_windowLength); - - WAVEFORM_DEBUG << "Waveform::createPixmaps" - << "widgetSize" << widgetSize - << "pixmapSize" << m_pixmapSize; - - Q_ASSERT(m_tiles.count() == m_pixmaps.count()); - - // (Re)create pixmaps - for (int i=0; i<m_pixmaps.size(); ++i) { - delete m_pixmaps[i]; - m_pixmaps[i] = 0; - m_pixmaps[i] = new QPixmap(m_pixmapSize); - } - - // Update tile pixmap pointers, and mark for repainting - for (int i=0; i<m_tiles.count(); ++i) { - m_tiles[i].pixmap = m_pixmaps[i]; - m_tiles[i].painted = false; - } -} - -void Waveform::setWindowPosition(qint64 position) -{ - WAVEFORM_DEBUG << "Waveform::setWindowPosition" - << "old" << m_windowPosition << "new" << position - << "tileArrayStart" << m_tileArrayStart; - - const qint64 oldPosition = m_windowPosition; - m_windowPosition = position; - - if ((m_windowPosition >= oldPosition) && - (m_windowPosition - m_tileArrayStart < (m_tiles.count() * m_tileLength))) { - // Work out how many tiles need to be shuffled - const qint64 offset = m_windowPosition - m_tileArrayStart; - const int nTiles = offset / m_tileLength; - shuffleTiles(nTiles); - } else { - resetTiles(m_windowPosition); - } - - if (!paintTiles() && m_windowPosition != oldPosition) - update(); -} - -qint64 Waveform::tilePosition(int index) const -{ - return m_tileArrayStart + index * m_tileLength; -} - -Waveform::TilePoint Waveform::tilePoint(qint64 position) const -{ - TilePoint result; - if (position >= m_tileArrayStart) { - const qint64 tileArrayEnd = m_tileArrayStart + m_tiles.count() * m_tileLength; - if (position < tileArrayEnd) { - const qint64 offsetIntoTileArray = position - m_tileArrayStart; - result.index = offsetIntoTileArray / m_tileLength; - Q_ASSERT(result.index >= 0 && result.index <= m_tiles.count()); - result.positionOffset = offsetIntoTileArray % m_tileLength; - result.pixelOffset = tilePixelOffset(result.positionOffset); - Q_ASSERT(result.pixelOffset >= 0 && result.pixelOffset <= m_pixmapSize.width()); - } - } - - return result; -} - -int Waveform::tilePixelOffset(qint64 positionOffset) const -{ - Q_ASSERT(positionOffset >= 0 && positionOffset <= m_tileLength); - const int result = (qreal(positionOffset) / m_tileLength) * m_pixmapSize.width(); - return result; -} - -int Waveform::windowPixelOffset(qint64 positionOffset) const -{ - Q_ASSERT(positionOffset >= 0 && positionOffset <= m_windowLength); - const int result = (qreal(positionOffset) / m_windowLength) * rect().width(); - return result; -} - -bool Waveform::paintTiles() -{ - WAVEFORM_DEBUG << "Waveform::paintTiles"; - bool updateRequired = false; - - for (int i=0; i<m_tiles.count(); ++i) { - const Tile &tile = m_tiles[i]; - if (!tile.painted) { - const qint64 tileStart = m_tileArrayStart + i * m_tileLength; - const qint64 tileEnd = tileStart + m_tileLength; - if (m_bufferPosition <= tileStart && m_bufferPosition + m_bufferLength >= tileEnd) { - paintTile(i); - updateRequired = true; - } - } - } - - if (updateRequired) - update(); - - return updateRequired; -} - -void Waveform::paintTile(int index) -{ - const qint64 tileStart = m_tileArrayStart + index * m_tileLength; - - WAVEFORM_DEBUG << "Waveform::paintTile" - << "index" << index - << "bufferPosition" << m_bufferPosition - << "bufferLength" << m_bufferLength - << "start" << tileStart - << "end" << tileStart + m_tileLength; - - Q_ASSERT(m_bufferPosition <= tileStart); - Q_ASSERT(m_bufferPosition + m_bufferLength >= tileStart + m_tileLength); - - Tile &tile = m_tiles[index]; - Q_ASSERT(!tile.painted); - - const qint16* base = reinterpret_cast<const qint16*>(m_buffer.constData()); - const qint16* buffer = base + ((tileStart - m_bufferPosition) / 2); - const int numSamples = m_tileLength / (2 * m_format.channels()); - - QPainter painter(tile.pixmap); - - painter.fillRect(tile.pixmap->rect(), Qt::black); - - QPen pen(Qt::white); - painter.setPen(pen); - - // Calculate initial PCM value - qint16 previousPcmValue = 0; - if (buffer > base) - previousPcmValue = *(buffer - m_format.channels()); - - // Calculate initial point - const qreal previousRealValue = pcmToReal(previousPcmValue); - const int originY = ((previousRealValue + 1.0) / 2) * m_pixmapSize.height(); - const QPoint origin(0, originY); - - QLine line(origin, origin); - - for (int i=0; i<numSamples; ++i) { - const qint16* ptr = buffer + i * m_format.channels(); - - const int offset = reinterpret_cast<const char*>(ptr) - m_buffer.constData(); - Q_ASSERT(offset >= 0); - Q_ASSERT(offset < m_bufferLength); - - const qint16 pcmValue = *ptr; - const qreal realValue = pcmToReal(pcmValue); - - const int x = tilePixelOffset(i * 2 * m_format.channels()); - const int y = ((realValue + 1.0) / 2) * m_pixmapSize.height(); - - line.setP2(QPoint(x, y)); - painter.drawLine(line); - line.setP1(line.p2()); - } - - tile.painted = true; -} - -void Waveform::shuffleTiles(int n) -{ - WAVEFORM_DEBUG << "Waveform::shuffleTiles" << "n" << n; - - while (n--) { - Tile tile = m_tiles.first(); - tile.painted = false; - m_tiles.erase(m_tiles.begin()); - m_tiles += tile; - m_tileArrayStart += m_tileLength; - } - - WAVEFORM_DEBUG << "Waveform::shuffleTiles" << "tileArrayStart" << m_tileArrayStart; -} - -void Waveform::resetTiles(qint64 newStartPos) -{ - WAVEFORM_DEBUG << "Waveform::resetTiles" << "newStartPos" << newStartPos; - - QVector<Tile>::iterator i = m_tiles.begin(); - for ( ; i != m_tiles.end(); ++i) - i->painted = false; - - m_tileArrayStart = newStartPos; -} - diff --git a/examples/spectrum/app/waveform.h b/examples/spectrum/app/waveform.h deleted file mode 100644 index a3b706d..0000000 --- a/examples/spectrum/app/waveform.h +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 WAVEFORM_H -#define WAVEFORM_H - -#include <QWidget> -#include <QtMultimedia/QAudioFormat> -#include <QPixmap> -#include <QScopedPointer> - -QT_FORWARD_DECLARE_CLASS(QByteArray) - -/** - * Widget which displays a section of the audio waveform. - * - * The waveform is rendered on a set of QPixmaps which form a group of tiles - * whose extent covers the widget. As the audio position is updated, these - * tiles are scrolled from left to right; when the left-most tile scrolls - * outside the widget, it is moved to the right end of the tile array and - * painted with the next section of the waveform. - */ -class Waveform : public QWidget { - Q_OBJECT -public: - Waveform(QWidget *parent = 0); - ~Waveform(); - - // QWidget - void paintEvent(QPaintEvent *event); - void resizeEvent(QResizeEvent *event); - - void initialize(const QAudioFormat &format, qint64 audioBufferSize, qint64 windowDurationUs); - void reset(); - - void setAutoUpdatePosition(bool enabled); - -public slots: - void bufferChanged(qint64 position, qint64 length, const QByteArray &buffer); - void audioPositionChanged(qint64 position); - -private: - static const int NullIndex = -1; - - void deletePixmaps(); - - /* - * (Re)create all pixmaps, repaint and update the display. - * Triggers an update(); - */ - void createPixmaps(const QSize &newSize); - - /* - * Update window position. - * Triggers an update(). - */ - void setWindowPosition(qint64 position); - - /* - * Base position of tile - */ - qint64 tilePosition(int index) const; - - /* - * Structure which identifies a point within a given - * tile. - */ - struct TilePoint - { - TilePoint(int idx = 0, qint64 pos = 0, qint64 pix = 0) - : index(idx), positionOffset(pos), pixelOffset(pix) - { } - - // Index of tile - int index; - - // Number of bytes from start of tile - qint64 positionOffset; - - // Number of pixels from left of corresponding pixmap - int pixelOffset; - }; - - /* - * Convert position in m_buffer into a tile index and an offset in pixels - * into the corresponding pixmap. - * - * \param position Offset into m_buffer, in bytes - - * If position is outside the tile array, index is NullIndex and - * offset is zero. - */ - TilePoint tilePoint(qint64 position) const; - - /* - * Convert offset in bytes into a tile into an offset in pixels - * within that tile. - */ - int tilePixelOffset(qint64 positionOffset) const; - - /* - * Convert offset in bytes into the window into an offset in pixels - * within the widget rect(). - */ - int windowPixelOffset(qint64 positionOffset) const; - - /* - * Paint all tiles which can be painted. - * \return true iff update() was called - */ - bool paintTiles(); - - /* - * Paint the specified tile - * - * \pre Sufficient data is available to completely paint the tile, i.e. - * m_dataLength is greater than the upper bound of the tile. - */ - void paintTile(int index); - - /* - * Move the first n tiles to the end of the array, and mark them as not - * painted. - */ - void shuffleTiles(int n); - - /* - * Reset tile array - */ - void resetTiles(qint64 newStartPos); - -private: - qint64 m_bufferPosition; - qint64 m_bufferLength; - QByteArray m_buffer; - - qint64 m_audioPosition; - QAudioFormat m_format; - - bool m_active; - - QSize m_pixmapSize; - QVector<QPixmap*> m_pixmaps; - - struct Tile { - // Pointer into parent m_pixmaps array - QPixmap* pixmap; - - // Flag indicating whether this tile has been painted - bool painted; - }; - - QVector<Tile> m_tiles; - - // Length of audio data in bytes depicted by each tile - qint64 m_tileLength; - - // Position in bytes of the first tile, relative to m_buffer - qint64 m_tileArrayStart; - - qint64 m_windowPosition; - qint64 m_windowLength; - -}; - -#endif // WAVEFORM_H diff --git a/examples/spectrum/app/wavfile.cpp b/examples/spectrum/app/wavfile.cpp deleted file mode 100644 index 7c17ba9..0000000 --- a/examples/spectrum/app/wavfile.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 <QtCore/qendian.h> -#include <QVector> -#include <QDebug> -#include "utils.h" -#include "wavfile.h" - -struct chunk -{ - char id[4]; - quint32 size; -}; - -struct RIFFHeader -{ - chunk descriptor; // "RIFF" - char type[4]; // "WAVE" -}; - -struct WAVEHeader -{ - chunk descriptor; - quint16 audioFormat; - quint16 numChannels; - quint32 sampleRate; - quint32 byteRate; - quint16 blockAlign; - quint16 bitsPerSample; -}; - -struct DATAHeader -{ - chunk descriptor; -}; - -struct CombinedHeader -{ - RIFFHeader riff; - WAVEHeader wave; -}; - -WavFile::WavFile(QObject *parent) - : QFile(parent) - , m_headerLength(0) -{ - -} - -bool WavFile::open(const QString &fileName) -{ - close(); - setFileName(fileName); - return QFile::open(QIODevice::ReadOnly) && readHeader(); -} - -const QAudioFormat &WavFile::fileFormat() const -{ - return m_fileFormat; -} - -qint64 WavFile::headerLength() const -{ -return m_headerLength; -} - -bool WavFile::readHeader() -{ - seek(0); - CombinedHeader header; - bool result = read(reinterpret_cast<char *>(&header), sizeof(CombinedHeader)) == sizeof(CombinedHeader); - if (result) { - if ((memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0 - || memcmp(&header.riff.descriptor.id, "RIFX", 4) == 0) - && memcmp(&header.riff.type, "WAVE", 4) == 0 - && memcmp(&header.wave.descriptor.id, "fmt ", 4) == 0 - && (header.wave.audioFormat == 1 || header.wave.audioFormat == 0)) { - - // Read off remaining header information - DATAHeader dataHeader; - - if (qFromLittleEndian<quint32>(header.wave.descriptor.size) > sizeof(WAVEHeader)) { - // Extended data available - quint16 extraFormatBytes; - if (peek((char*)&extraFormatBytes, sizeof(quint16)) != sizeof(quint16)) - return false; - const qint64 throwAwayBytes = sizeof(quint16) + qFromLittleEndian<quint16>(extraFormatBytes); - if (read(throwAwayBytes).size() != throwAwayBytes) - return false; - } - - if (read((char*)&dataHeader, sizeof(DATAHeader)) != sizeof(DATAHeader)) - return false; - - // Establish format - if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0) - m_fileFormat.setByteOrder(QAudioFormat::LittleEndian); - else - m_fileFormat.setByteOrder(QAudioFormat::BigEndian); - - int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample); - m_fileFormat.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels)); - m_fileFormat.setCodec("audio/pcm"); - m_fileFormat.setFrequency(qFromLittleEndian<quint32>(header.wave.sampleRate)); - m_fileFormat.setSampleSize(qFromLittleEndian<quint16>(header.wave.bitsPerSample)); - m_fileFormat.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt); - } else { - result = false; - } - } - m_headerLength = pos(); - return result; -} diff --git a/examples/spectrum/app/wavfile.h b/examples/spectrum/app/wavfile.h deleted file mode 100644 index b974c47..0000000 --- a/examples/spectrum/app/wavfile.h +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** 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 Nokia Corporation and its Subsidiary(-ies) 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 WAVFILE_H -#define WAVFILE_H - -#include <QtCore/qobject.h> -#include <QtCore/qfile.h> -#include <QtMultimedia/qaudioformat.h> - -class WavFile : public QFile -{ -public: - WavFile(QObject *parent = 0); - - bool open(const QString &fileName); - const QAudioFormat &fileFormat() const; - qint64 headerLength() const; - -private: - bool readHeader(); - -private: - QAudioFormat m_fileFormat; - qint64 m_headerLength; - -}; - -#endif - |