<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>engine.cpp Example File | Qt Multimedia 5.12.2</title> <link rel="stylesheet" type="text/css" href="style/offline-simple.css" /> <script type="text/javascript"> document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css"); // loading style sheet breaks anchors that were jumped to before // so force jumping to anchor again setTimeout(function() { var anchor = location.hash; // need to jump to different anchor first (e.g. none) location.hash = "#"; setTimeout(function() { location.hash = anchor; }, 0); }, 0); </script> </head> <body> <div class="header" id="qtdocheader"> <div class="main"> <div class="main-rounded"> <div class="navigationbar"> <table><tr> <td >Qt 5.12</td><td ><a href="qtmultimedia-index.html">Qt Multimedia</a></td><td ><a href="qtmultimedia-multimedia-spectrum-example.html">Spectrum Example</a></td><td >engine.cpp Example File</td></tr></table><table class="buildversion"><tr> <td id="buildversion" width="100%" align="right"><a href="qtmultimedia-index.html">Qt 5.12.2 Reference Documentation</a></td> </tr></table> </div> </div> <div class="content"> <div class="line"> <div class="content mainContent"> <div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div> <h1 class="title">engine.cpp Example File</h1> <span class="subtitle">multimedia/spectrum/app/engine.cpp</span> <!-- $$$multimedia/spectrum/app/engine.cpp-description --> <div class="descr"> <a name="details"></a> <pre class="cpp"> <span class="comment">/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/</span> <span class="preprocessor">#include "engine.h"</span> <span class="preprocessor">#include "tonegenerator.h"</span> <span class="preprocessor">#include "utils.h"</span> <span class="preprocessor">#include <math.h></span> <span class="preprocessor">#include <QAudioInput></span> <span class="preprocessor">#include <QAudioOutput></span> <span class="preprocessor">#include <QCoreApplication></span> <span class="preprocessor">#include <QDebug></span> <span class="preprocessor">#include <QFile></span> <span class="preprocessor">#include <QMetaObject></span> <span class="preprocessor">#include <QSet></span> <span class="preprocessor">#include <QThread></span> <span class="comment">//-----------------------------------------------------------------------------</span> <span class="comment">// Constants</span> <span class="comment">//-----------------------------------------------------------------------------</span> <span class="keyword">const</span> <span class="type">qint64</span> BufferDurationUs <span class="operator">=</span> <span class="number">10</span> <span class="operator">*</span> <span class="number">1000000</span>; <span class="keyword">const</span> <span class="type">int</span> NotifyIntervalMs <span class="operator">=</span> <span class="number">100</span>; <span class="comment">// Size of the level calculation window in microseconds</span> <span class="keyword">const</span> <span class="type">int</span> LevelWindowUs <span class="operator">=</span> <span class="number">0.1</span> <span class="operator">*</span> <span class="number">1000000</span>; <span class="comment">//-----------------------------------------------------------------------------</span> <span class="comment">// Constructor and destructor</span> <span class="comment">//-----------------------------------------------------------------------------</span> Engine<span class="operator">::</span>Engine(<span class="type">QObject</span> <span class="operator">*</span>parent) : <span class="type">QObject</span>(parent) <span class="operator">,</span> m_mode(<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioInput) <span class="operator">,</span> m_state(<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>StoppedState) <span class="operator">,</span> m_generateTone(<span class="keyword">false</span>) <span class="operator">,</span> m_file(<span class="number">0</span>) <span class="operator">,</span> m_analysisFile(<span class="number">0</span>) <span class="operator">,</span> m_availableAudioInputDevices (<span class="type"><a href="qaudiodeviceinfo.html">QAudioDeviceInfo</a></span><span class="operator">::</span>availableDevices(<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioInput)) <span class="operator">,</span> m_audioInputDevice(<span class="type"><a href="qaudiodeviceinfo.html">QAudioDeviceInfo</a></span><span class="operator">::</span>defaultInputDevice()) <span class="operator">,</span> m_audioInput(<span class="number">0</span>) <span class="operator">,</span> m_audioInputIODevice(<span class="number">0</span>) <span class="operator">,</span> m_recordPosition(<span class="number">0</span>) <span class="operator">,</span> m_availableAudioOutputDevices (<span class="type"><a href="qaudiodeviceinfo.html">QAudioDeviceInfo</a></span><span class="operator">::</span>availableDevices(<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioOutput)) <span class="operator">,</span> m_audioOutputDevice(<span class="type"><a href="qaudiodeviceinfo.html">QAudioDeviceInfo</a></span><span class="operator">::</span>defaultOutputDevice()) <span class="operator">,</span> m_audioOutput(<span class="number">0</span>) <span class="operator">,</span> m_playPosition(<span class="number">0</span>) <span class="operator">,</span> m_bufferPosition(<span class="number">0</span>) <span class="operator">,</span> m_bufferLength(<span class="number">0</span>) <span class="operator">,</span> m_dataLength(<span class="number">0</span>) <span class="operator">,</span> m_levelBufferLength(<span class="number">0</span>) <span class="operator">,</span> m_rmsLevel(<span class="number">0.0</span>) <span class="operator">,</span> m_peakLevel(<span class="number">0.0</span>) <span class="operator">,</span> m_spectrumBufferLength(<span class="number">0</span>) <span class="operator">,</span> m_spectrumAnalyser() <span class="operator">,</span> m_spectrumPosition(<span class="number">0</span>) <span class="operator">,</span> m_count(<span class="number">0</span>) { qRegisterMetaType<span class="operator"><</span>FrequencySpectrum<span class="operator">></span>(<span class="string">"FrequencySpectrum"</span>); qRegisterMetaType<span class="operator"><</span>WindowFunction<span class="operator">></span>(<span class="string">"WindowFunction"</span>); connect(<span class="operator">&</span>m_spectrumAnalyser<span class="operator">,</span> <span class="type">QOverload</span><span class="operator"><</span><span class="keyword">const</span> FrequencySpectrum<span class="operator">&</span><span class="operator">></span><span class="operator">::</span>of(<span class="operator">&</span>SpectrumAnalyser<span class="operator">::</span>spectrumChanged)<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> <span class="type">QOverload</span><span class="operator"><</span><span class="keyword">const</span> FrequencySpectrum<span class="operator">&</span><span class="operator">></span><span class="operator">::</span>of(<span class="operator">&</span>Engine<span class="operator">::</span>spectrumChanged)); <span class="comment">// This code might misinterpret things like "-something -category". But</span> <span class="comment">// it's unlikely that that needs to be supported so we'll let it go.</span> <span class="type">QStringList</span> arguments <span class="operator">=</span> <span class="type">QCoreApplication</span><span class="operator">::</span>instance()<span class="operator">-</span><span class="operator">></span>arguments(); <span class="keyword">for</span> (<span class="type">int</span> i <span class="operator">=</span> <span class="number">0</span>; i <span class="operator"><</span> arguments<span class="operator">.</span>count(); <span class="operator">+</span><span class="operator">+</span>i) { <span class="keyword">if</span> (arguments<span class="operator">.</span>at(i) <span class="operator">=</span><span class="operator">=</span> <span class="type">QStringLiteral</span>(<span class="string">"--"</span>)) <span class="keyword">break</span>; <span class="keyword">if</span> (arguments<span class="operator">.</span>at(i) <span class="operator">=</span><span class="operator">=</span> <span class="type">QStringLiteral</span>(<span class="string">"-category"</span>) <span class="operator">|</span><span class="operator">|</span> arguments<span class="operator">.</span>at(i) <span class="operator">=</span><span class="operator">=</span> <span class="type">QStringLiteral</span>(<span class="string">"--category"</span>)) { <span class="operator">+</span><span class="operator">+</span>i; <span class="keyword">if</span> (i <span class="operator"><</span> arguments<span class="operator">.</span>count()) m_audioOutputCategory <span class="operator">=</span> arguments<span class="operator">.</span>at(i); <span class="keyword">else</span> <span class="operator">-</span><span class="operator">-</span>i; } } initialize(); <span class="preprocessor">#ifdef DUMP_DATA</span> createOutputDir(); <span class="preprocessor">#endif</span> <span class="preprocessor">#ifdef DUMP_SPECTRUM</span> m_spectrumAnalyser<span class="operator">.</span>setOutputPath(outputPath()); <span class="preprocessor">#endif</span> } Engine<span class="operator">::</span><span class="operator">~</span>Engine() { } <span class="comment">//-----------------------------------------------------------------------------</span> <span class="comment">// Public functions</span> <span class="comment">//-----------------------------------------------------------------------------</span> bool Engine<span class="operator">::</span>loadFile(<span class="keyword">const</span> <span class="type">QString</span> <span class="operator">&</span>fileName) { reset(); bool result <span class="operator">=</span> <span class="keyword">false</span>; Q_ASSERT(<span class="operator">!</span>m_generateTone); Q_ASSERT(<span class="operator">!</span>m_file); Q_ASSERT(<span class="operator">!</span>fileName<span class="operator">.</span>isEmpty()); m_file <span class="operator">=</span> <span class="keyword">new</span> WavFile(<span class="keyword">this</span>); <span class="keyword">if</span> (m_file<span class="operator">-</span><span class="operator">></span>open(fileName)) { <span class="keyword">if</span> (isPCMS16LE(m_file<span class="operator">-</span><span class="operator">></span>fileFormat())) { result <span class="operator">=</span> initialize(); } <span class="keyword">else</span> { <span class="keyword">emit</span> errorMessage(tr(<span class="string">"Audio format not supported"</span>)<span class="operator">,</span> formatToString(m_file<span class="operator">-</span><span class="operator">></span>fileFormat())); } } <span class="keyword">else</span> { <span class="keyword">emit</span> errorMessage(tr(<span class="string">"Could not open file"</span>)<span class="operator">,</span> fileName); } <span class="keyword">if</span> (result) { m_analysisFile <span class="operator">=</span> <span class="keyword">new</span> WavFile(<span class="keyword">this</span>); m_analysisFile<span class="operator">-</span><span class="operator">></span>open(fileName); } <span class="keyword">return</span> result; } bool Engine<span class="operator">::</span>generateTone(<span class="keyword">const</span> Tone <span class="operator">&</span>tone) { reset(); Q_ASSERT(<span class="operator">!</span>m_generateTone); Q_ASSERT(<span class="operator">!</span>m_file); m_generateTone <span class="operator">=</span> <span class="keyword">true</span>; m_tone <span class="operator">=</span> tone; ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::generateTone"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"startFreq"</span> <span class="operator"><</span><span class="operator"><</span> m_tone<span class="operator">.</span>startFreq <span class="operator"><</span><span class="operator"><</span> <span class="string">"endFreq"</span> <span class="operator"><</span><span class="operator"><</span> m_tone<span class="operator">.</span>endFreq <span class="operator"><</span><span class="operator"><</span> <span class="string">"amp"</span> <span class="operator"><</span><span class="operator"><</span> m_tone<span class="operator">.</span>amplitude; <span class="keyword">return</span> initialize(); } bool Engine<span class="operator">::</span>generateSweptTone(<span class="type">qreal</span> amplitude) { Q_ASSERT(<span class="operator">!</span>m_generateTone); Q_ASSERT(<span class="operator">!</span>m_file); m_generateTone <span class="operator">=</span> <span class="keyword">true</span>; m_tone<span class="operator">.</span>startFreq <span class="operator">=</span> <span class="number">1</span>; m_tone<span class="operator">.</span>endFreq <span class="operator">=</span> <span class="number">0</span>; m_tone<span class="operator">.</span>amplitude <span class="operator">=</span> amplitude; ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::generateSweptTone"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"startFreq"</span> <span class="operator"><</span><span class="operator"><</span> m_tone<span class="operator">.</span>startFreq <span class="operator"><</span><span class="operator"><</span> <span class="string">"amp"</span> <span class="operator"><</span><span class="operator"><</span> m_tone<span class="operator">.</span>amplitude; <span class="keyword">return</span> initialize(); } bool Engine<span class="operator">::</span>initializeRecord() { reset(); ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::initializeRecord"</span>; Q_ASSERT(<span class="operator">!</span>m_generateTone); Q_ASSERT(<span class="operator">!</span>m_file); m_generateTone <span class="operator">=</span> <span class="keyword">false</span>; m_tone <span class="operator">=</span> SweptTone(); <span class="keyword">return</span> initialize(); } <span class="type">qint64</span> Engine<span class="operator">::</span>bufferLength() <span class="keyword">const</span> { <span class="keyword">return</span> m_file <span class="operator">?</span> m_file<span class="operator">-</span><span class="operator">></span>size() : m_bufferLength; } <span class="type">void</span> Engine<span class="operator">::</span>setWindowFunction(WindowFunction type) { m_spectrumAnalyser<span class="operator">.</span>setWindowFunction(type); } <span class="comment">//-----------------------------------------------------------------------------</span> <span class="comment">// Public slots</span> <span class="comment">//-----------------------------------------------------------------------------</span> <span class="type">void</span> Engine<span class="operator">::</span>startRecording() { <span class="keyword">if</span> (m_audioInput) { <span class="keyword">if</span> (<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioInput <span class="operator">=</span><span class="operator">=</span> m_mode <span class="operator">&</span><span class="operator">&</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>SuspendedState <span class="operator">=</span><span class="operator">=</span> m_state) { m_audioInput<span class="operator">-</span><span class="operator">></span>resume(); } <span class="keyword">else</span> { m_spectrumAnalyser<span class="operator">.</span>cancelCalculation(); spectrumChanged(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> FrequencySpectrum()); m_buffer<span class="operator">.</span>fill(<span class="number">0</span>); setRecordPosition(<span class="number">0</span><span class="operator">,</span> <span class="keyword">true</span>); stopPlayback(); m_mode <span class="operator">=</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioInput; connect(m_audioInput<span class="operator">,</span> <span class="operator">&</span><span class="type"><a href="qaudioinput.html">QAudioInput</a></span><span class="operator">::</span>stateChanged<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> <span class="operator">&</span>Engine<span class="operator">::</span>audioStateChanged); connect(m_audioInput<span class="operator">,</span> <span class="operator">&</span><span class="type"><a href="qaudioinput.html">QAudioInput</a></span><span class="operator">::</span>notify<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> <span class="operator">&</span>Engine<span class="operator">::</span>audioNotify); m_count <span class="operator">=</span> <span class="number">0</span>; m_dataLength <span class="operator">=</span> <span class="number">0</span>; <span class="keyword">emit</span> dataLengthChanged(<span class="number">0</span>); m_audioInputIODevice <span class="operator">=</span> m_audioInput<span class="operator">-</span><span class="operator">></span>start(); connect(m_audioInputIODevice<span class="operator">,</span> <span class="operator">&</span><span class="type">QIODevice</span><span class="operator">::</span>readyRead<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> <span class="operator">&</span>Engine<span class="operator">::</span>audioDataReady); } } } <span class="type">void</span> Engine<span class="operator">::</span>startPlayback() { <span class="keyword">if</span> (m_audioOutput) { <span class="keyword">if</span> (<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioOutput <span class="operator">=</span><span class="operator">=</span> m_mode <span class="operator">&</span><span class="operator">&</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>SuspendedState <span class="operator">=</span><span class="operator">=</span> m_state) { <span class="preprocessor">#ifdef Q_OS_WIN</span> <span class="comment">// The Windows backend seems to internally go back into ActiveState</span> <span class="comment">// while still returning SuspendedState, so to ensure that it doesn't</span> <span class="comment">// ignore the resume() call, we first re-suspend</span> m_audioOutput<span class="operator">-</span><span class="operator">></span>suspend(); <span class="preprocessor">#endif</span> m_audioOutput<span class="operator">-</span><span class="operator">></span>resume(); } <span class="keyword">else</span> { m_spectrumAnalyser<span class="operator">.</span>cancelCalculation(); spectrumChanged(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> FrequencySpectrum()); setPlayPosition(<span class="number">0</span><span class="operator">,</span> <span class="keyword">true</span>); stopRecording(); m_mode <span class="operator">=</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioOutput; connect(m_audioOutput<span class="operator">,</span> <span class="operator">&</span><span class="type"><a href="qaudiooutput.html">QAudioOutput</a></span><span class="operator">::</span>stateChanged<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> <span class="operator">&</span>Engine<span class="operator">::</span>audioStateChanged); connect(m_audioOutput<span class="operator">,</span> <span class="operator">&</span><span class="type"><a href="qaudiooutput.html">QAudioOutput</a></span><span class="operator">::</span>notify<span class="operator">,</span> <span class="keyword">this</span><span class="operator">,</span> <span class="operator">&</span>Engine<span class="operator">::</span>audioNotify); m_count <span class="operator">=</span> <span class="number">0</span>; <span class="keyword">if</span> (m_file) { m_file<span class="operator">-</span><span class="operator">></span>seek(<span class="number">0</span>); m_bufferPosition <span class="operator">=</span> <span class="number">0</span>; m_dataLength <span class="operator">=</span> <span class="number">0</span>; m_audioOutput<span class="operator">-</span><span class="operator">></span>start(m_file); } <span class="keyword">else</span> { m_audioOutputIODevice<span class="operator">.</span>close(); m_audioOutputIODevice<span class="operator">.</span>setBuffer(<span class="operator">&</span>m_buffer); m_audioOutputIODevice<span class="operator">.</span>open(<span class="type">QIODevice</span><span class="operator">::</span>ReadOnly); m_audioOutput<span class="operator">-</span><span class="operator">></span>start(<span class="operator">&</span>m_audioOutputIODevice); } } } } <span class="type">void</span> Engine<span class="operator">::</span>suspend() { <span class="keyword">if</span> (<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>ActiveState <span class="operator">=</span><span class="operator">=</span> m_state <span class="operator">|</span><span class="operator">|</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>IdleState <span class="operator">=</span><span class="operator">=</span> m_state) { <span class="keyword">switch</span> (m_mode) { <span class="keyword">case</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioInput: m_audioInput<span class="operator">-</span><span class="operator">></span>suspend(); <span class="keyword">break</span>; <span class="keyword">case</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioOutput: m_audioOutput<span class="operator">-</span><span class="operator">></span>suspend(); <span class="keyword">break</span>; } } } <span class="type">void</span> Engine<span class="operator">::</span>setAudioInputDevice(<span class="keyword">const</span> <span class="type"><a href="qaudiodeviceinfo.html">QAudioDeviceInfo</a></span> <span class="operator">&</span>device) { <span class="keyword">if</span> (device<span class="operator">.</span>deviceName() <span class="operator">!</span><span class="operator">=</span> m_audioInputDevice<span class="operator">.</span>deviceName()) { m_audioInputDevice <span class="operator">=</span> device; initialize(); } } <span class="type">void</span> Engine<span class="operator">::</span>setAudioOutputDevice(<span class="keyword">const</span> <span class="type"><a href="qaudiodeviceinfo.html">QAudioDeviceInfo</a></span> <span class="operator">&</span>device) { <span class="keyword">if</span> (device<span class="operator">.</span>deviceName() <span class="operator">!</span><span class="operator">=</span> m_audioOutputDevice<span class="operator">.</span>deviceName()) { m_audioOutputDevice <span class="operator">=</span> device; initialize(); } } <span class="comment">//-----------------------------------------------------------------------------</span> <span class="comment">// Private slots</span> <span class="comment">//-----------------------------------------------------------------------------</span> <span class="type">void</span> Engine<span class="operator">::</span>audioNotify() { <span class="keyword">switch</span> (m_mode) { <span class="keyword">case</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioInput: { <span class="keyword">const</span> <span class="type">qint64</span> recordPosition <span class="operator">=</span> qMin(m_bufferLength<span class="operator">,</span> audioLength(m_format<span class="operator">,</span> m_audioInput<span class="operator">-</span><span class="operator">></span>processedUSecs())); setRecordPosition(recordPosition); <span class="keyword">const</span> <span class="type">qint64</span> levelPosition <span class="operator">=</span> m_dataLength <span class="operator">-</span> m_levelBufferLength; <span class="keyword">if</span> (levelPosition <span class="operator">></span><span class="operator">=</span> <span class="number">0</span>) calculateLevel(levelPosition<span class="operator">,</span> m_levelBufferLength); <span class="keyword">if</span> (m_dataLength <span class="operator">></span><span class="operator">=</span> m_spectrumBufferLength) { <span class="keyword">const</span> <span class="type">qint64</span> spectrumPosition <span class="operator">=</span> m_dataLength <span class="operator">-</span> m_spectrumBufferLength; calculateSpectrum(spectrumPosition); } <span class="keyword">emit</span> bufferChanged(<span class="number">0</span><span class="operator">,</span> m_dataLength<span class="operator">,</span> m_buffer); } <span class="keyword">break</span>; <span class="keyword">case</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioOutput: { <span class="keyword">const</span> <span class="type">qint64</span> playPosition <span class="operator">=</span> audioLength(m_format<span class="operator">,</span> m_audioOutput<span class="operator">-</span><span class="operator">></span>processedUSecs()); setPlayPosition(qMin(bufferLength()<span class="operator">,</span> playPosition)); <span class="keyword">const</span> <span class="type">qint64</span> levelPosition <span class="operator">=</span> playPosition <span class="operator">-</span> m_levelBufferLength; <span class="keyword">const</span> <span class="type">qint64</span> spectrumPosition <span class="operator">=</span> playPosition <span class="operator">-</span> m_spectrumBufferLength; <span class="keyword">if</span> (m_file) { <span class="keyword">if</span> (levelPosition <span class="operator">></span> m_bufferPosition <span class="operator">|</span><span class="operator">|</span> spectrumPosition <span class="operator">></span> m_bufferPosition <span class="operator">|</span><span class="operator">|</span> qMax(m_levelBufferLength<span class="operator">,</span> m_spectrumBufferLength) <span class="operator">></span> m_dataLength) { m_bufferPosition <span class="operator">=</span> <span class="number">0</span>; m_dataLength <span class="operator">=</span> <span class="number">0</span>; <span class="comment">// Data needs to be read into m_buffer in order to be analysed</span> <span class="keyword">const</span> <span class="type">qint64</span> readPos <span class="operator">=</span> qMax(<span class="type">qint64</span>(<span class="number">0</span>)<span class="operator">,</span> qMin(levelPosition<span class="operator">,</span> spectrumPosition)); <span class="keyword">const</span> <span class="type">qint64</span> readEnd <span class="operator">=</span> qMin(m_analysisFile<span class="operator">-</span><span class="operator">></span>size()<span class="operator">,</span> qMax(levelPosition <span class="operator">+</span> m_levelBufferLength<span class="operator">,</span> spectrumPosition <span class="operator">+</span> m_spectrumBufferLength)); <span class="keyword">const</span> <span class="type">qint64</span> readLen <span class="operator">=</span> readEnd <span class="operator">-</span> readPos <span class="operator">+</span> audioLength(m_format<span class="operator">,</span> WaveformWindowDuration); qDebug() <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::audioNotify [1]"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"analysisFileSize"</span> <span class="operator"><</span><span class="operator"><</span> m_analysisFile<span class="operator">-</span><span class="operator">></span>size() <span class="operator"><</span><span class="operator"><</span> <span class="string">"readPos"</span> <span class="operator"><</span><span class="operator"><</span> readPos <span class="operator"><</span><span class="operator"><</span> <span class="string">"readLen"</span> <span class="operator"><</span><span class="operator"><</span> readLen; <span class="keyword">if</span> (m_analysisFile<span class="operator">-</span><span class="operator">></span>seek(readPos <span class="operator">+</span> m_analysisFile<span class="operator">-</span><span class="operator">></span>headerLength())) { m_buffer<span class="operator">.</span>resize(readLen); m_bufferPosition <span class="operator">=</span> readPos; m_dataLength <span class="operator">=</span> m_analysisFile<span class="operator">-</span><span class="operator">></span>read(m_buffer<span class="operator">.</span>data()<span class="operator">,</span> readLen); qDebug() <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::audioNotify [2]"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"bufferPosition"</span> <span class="operator"><</span><span class="operator"><</span> m_bufferPosition <span class="operator"><</span><span class="operator"><</span> <span class="string">"dataLength"</span> <span class="operator"><</span><span class="operator"><</span> m_dataLength; } <span class="keyword">else</span> { qDebug() <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::audioNotify [2]"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"file seek error"</span>; } <span class="keyword">emit</span> bufferChanged(m_bufferPosition<span class="operator">,</span> m_dataLength<span class="operator">,</span> m_buffer); } } <span class="keyword">else</span> { <span class="keyword">if</span> (playPosition <span class="operator">></span><span class="operator">=</span> m_dataLength) stopPlayback(); } <span class="keyword">if</span> (levelPosition <span class="operator">></span><span class="operator">=</span> <span class="number">0</span> <span class="operator">&</span><span class="operator">&</span> levelPosition <span class="operator">+</span> m_levelBufferLength <span class="operator"><</span> m_bufferPosition <span class="operator">+</span> m_dataLength) calculateLevel(levelPosition<span class="operator">,</span> m_levelBufferLength); <span class="keyword">if</span> (spectrumPosition <span class="operator">></span><span class="operator">=</span> <span class="number">0</span> <span class="operator">&</span><span class="operator">&</span> spectrumPosition <span class="operator">+</span> m_spectrumBufferLength <span class="operator"><</span> m_bufferPosition <span class="operator">+</span> m_dataLength) calculateSpectrum(spectrumPosition); } <span class="keyword">break</span>; } } <span class="type">void</span> Engine<span class="operator">::</span>audioStateChanged(<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>State state) { ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::audioStateChanged from"</span> <span class="operator"><</span><span class="operator"><</span> m_state <span class="operator"><</span><span class="operator"><</span> <span class="string">"to"</span> <span class="operator"><</span><span class="operator"><</span> state; <span class="keyword">if</span> (<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>IdleState <span class="operator">=</span><span class="operator">=</span> state <span class="operator">&</span><span class="operator">&</span> m_file <span class="operator">&</span><span class="operator">&</span> m_file<span class="operator">-</span><span class="operator">></span>pos() <span class="operator">=</span><span class="operator">=</span> m_file<span class="operator">-</span><span class="operator">></span>size()) { stopPlayback(); } <span class="keyword">else</span> { <span class="keyword">if</span> (<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>StoppedState <span class="operator">=</span><span class="operator">=</span> state) { <span class="comment">// Check error</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>Error error <span class="operator">=</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>NoError; <span class="keyword">switch</span> (m_mode) { <span class="keyword">case</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioInput: error <span class="operator">=</span> m_audioInput<span class="operator">-</span><span class="operator">></span>error(); <span class="keyword">break</span>; <span class="keyword">case</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioOutput: error <span class="operator">=</span> m_audioOutput<span class="operator">-</span><span class="operator">></span>error(); <span class="keyword">break</span>; } <span class="keyword">if</span> (<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>NoError <span class="operator">!</span><span class="operator">=</span> error) { reset(); <span class="keyword">return</span>; } } setState(state); } } <span class="type">void</span> Engine<span class="operator">::</span>audioDataReady() { Q_ASSERT(<span class="number">0</span> <span class="operator">=</span><span class="operator">=</span> m_bufferPosition); <span class="keyword">const</span> <span class="type">qint64</span> bytesReady <span class="operator">=</span> m_audioInput<span class="operator">-</span><span class="operator">></span>bytesReady(); <span class="keyword">const</span> <span class="type">qint64</span> bytesSpace <span class="operator">=</span> m_buffer<span class="operator">.</span>size() <span class="operator">-</span> m_dataLength; <span class="keyword">const</span> <span class="type">qint64</span> bytesToRead <span class="operator">=</span> qMin(bytesReady<span class="operator">,</span> bytesSpace); <span class="keyword">const</span> <span class="type">qint64</span> bytesRead <span class="operator">=</span> m_audioInputIODevice<span class="operator">-</span><span class="operator">></span>read( m_buffer<span class="operator">.</span>data() <span class="operator">+</span> m_dataLength<span class="operator">,</span> bytesToRead); <span class="keyword">if</span> (bytesRead) { m_dataLength <span class="operator">+</span><span class="operator">=</span> bytesRead; <span class="keyword">emit</span> dataLengthChanged(dataLength()); } <span class="keyword">if</span> (m_buffer<span class="operator">.</span>size() <span class="operator">=</span><span class="operator">=</span> m_dataLength) stopRecording(); } <span class="type">void</span> Engine<span class="operator">::</span>spectrumChanged(<span class="keyword">const</span> FrequencySpectrum <span class="operator">&</span>spectrum) { ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::spectrumChanged"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"pos"</span> <span class="operator"><</span><span class="operator"><</span> m_spectrumPosition; <span class="keyword">emit</span> spectrumChanged(m_spectrumPosition<span class="operator">,</span> m_spectrumBufferLength<span class="operator">,</span> spectrum); } <span class="comment">//-----------------------------------------------------------------------------</span> <span class="comment">// Private functions</span> <span class="comment">//-----------------------------------------------------------------------------</span> <span class="type">void</span> Engine<span class="operator">::</span>resetAudioDevices() { <span class="keyword">delete</span> m_audioInput; m_audioInput <span class="operator">=</span> <span class="number">0</span>; m_audioInputIODevice <span class="operator">=</span> <span class="number">0</span>; setRecordPosition(<span class="number">0</span>); <span class="keyword">delete</span> m_audioOutput; m_audioOutput <span class="operator">=</span> <span class="number">0</span>; setPlayPosition(<span class="number">0</span>); m_spectrumPosition <span class="operator">=</span> <span class="number">0</span>; setLevel(<span class="number">0.0</span><span class="operator">,</span> <span class="number">0.0</span><span class="operator">,</span> <span class="number">0</span>); } <span class="type">void</span> Engine<span class="operator">::</span>reset() { stopRecording(); stopPlayback(); setState(<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>AudioInput<span class="operator">,</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>StoppedState); setFormat(<span class="type">QAudioFormat</span>()); m_generateTone <span class="operator">=</span> <span class="keyword">false</span>; <span class="keyword">delete</span> m_file; m_file <span class="operator">=</span> <span class="number">0</span>; <span class="keyword">delete</span> m_analysisFile; m_analysisFile <span class="operator">=</span> <span class="number">0</span>; m_buffer<span class="operator">.</span>clear(); m_bufferPosition <span class="operator">=</span> <span class="number">0</span>; m_bufferLength <span class="operator">=</span> <span class="number">0</span>; m_dataLength <span class="operator">=</span> <span class="number">0</span>; <span class="keyword">emit</span> dataLengthChanged(<span class="number">0</span>); resetAudioDevices(); } bool Engine<span class="operator">::</span>initialize() { bool result <span class="operator">=</span> <span class="keyword">false</span>; <span class="type">QAudioFormat</span> format <span class="operator">=</span> m_format; <span class="keyword">if</span> (selectFormat()) { <span class="keyword">if</span> (m_format <span class="operator">!</span><span class="operator">=</span> format) { resetAudioDevices(); <span class="keyword">if</span> (m_file) { <span class="keyword">emit</span> bufferLengthChanged(bufferLength()); <span class="keyword">emit</span> dataLengthChanged(dataLength()); <span class="keyword">emit</span> bufferChanged(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> m_buffer); setRecordPosition(bufferLength()); result <span class="operator">=</span> <span class="keyword">true</span>; } <span class="keyword">else</span> { m_bufferLength <span class="operator">=</span> audioLength(m_format<span class="operator">,</span> BufferDurationUs); m_buffer<span class="operator">.</span>resize(m_bufferLength); m_buffer<span class="operator">.</span>fill(<span class="number">0</span>); <span class="keyword">emit</span> bufferLengthChanged(bufferLength()); <span class="keyword">if</span> (m_generateTone) { <span class="keyword">if</span> (<span class="number">0</span> <span class="operator">=</span><span class="operator">=</span> m_tone<span class="operator">.</span>endFreq) { <span class="keyword">const</span> <span class="type">qreal</span> nyquist <span class="operator">=</span> nyquistFrequency(m_format); m_tone<span class="operator">.</span>endFreq <span class="operator">=</span> qMin(<span class="type">qreal</span>(SpectrumHighFreq)<span class="operator">,</span> nyquist); } <span class="comment">// Call function defined in utils.h, at global scope</span> <span class="operator">::</span>generateTone(m_tone<span class="operator">,</span> m_format<span class="operator">,</span> m_buffer); m_dataLength <span class="operator">=</span> m_bufferLength; <span class="keyword">emit</span> dataLengthChanged(dataLength()); <span class="keyword">emit</span> bufferChanged(<span class="number">0</span><span class="operator">,</span> m_dataLength<span class="operator">,</span> m_buffer); setRecordPosition(m_bufferLength); result <span class="operator">=</span> <span class="keyword">true</span>; } <span class="keyword">else</span> { <span class="keyword">emit</span> bufferChanged(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> m_buffer); m_audioInput <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qaudioinput.html">QAudioInput</a></span>(m_audioInputDevice<span class="operator">,</span> m_format<span class="operator">,</span> <span class="keyword">this</span>); m_audioInput<span class="operator">-</span><span class="operator">></span>setNotifyInterval(NotifyIntervalMs); result <span class="operator">=</span> <span class="keyword">true</span>; } } m_audioOutput <span class="operator">=</span> <span class="keyword">new</span> <span class="type"><a href="qaudiooutput.html">QAudioOutput</a></span>(m_audioOutputDevice<span class="operator">,</span> m_format<span class="operator">,</span> <span class="keyword">this</span>); m_audioOutput<span class="operator">-</span><span class="operator">></span>setNotifyInterval(NotifyIntervalMs); m_audioOutput<span class="operator">-</span><span class="operator">></span>setCategory(m_audioOutputCategory); } } <span class="keyword">else</span> { <span class="keyword">if</span> (m_file) <span class="keyword">emit</span> errorMessage(tr(<span class="string">"Audio format not supported"</span>)<span class="operator">,</span> formatToString(m_format)); <span class="keyword">else</span> <span class="keyword">if</span> (m_generateTone) <span class="keyword">emit</span> errorMessage(tr(<span class="string">"No suitable format found"</span>)<span class="operator">,</span> <span class="string">""</span>); <span class="keyword">else</span> <span class="keyword">emit</span> errorMessage(tr(<span class="string">"No common input / output format found"</span>)<span class="operator">,</span> <span class="string">""</span>); } ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::initialize"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"m_bufferLength"</span> <span class="operator"><</span><span class="operator"><</span> m_bufferLength; ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::initialize"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"m_dataLength"</span> <span class="operator"><</span><span class="operator"><</span> m_dataLength; ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::initialize"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"format"</span> <span class="operator"><</span><span class="operator"><</span> m_format; ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::initialize"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"m_audioOutputCategory"</span> <span class="operator"><</span><span class="operator"><</span> m_audioOutputCategory; <span class="keyword">return</span> result; } bool Engine<span class="operator">::</span>selectFormat() { bool foundSupportedFormat <span class="operator">=</span> <span class="keyword">false</span>; <span class="keyword">if</span> (m_file <span class="operator">|</span><span class="operator">|</span> <span class="type">QAudioFormat</span>() <span class="operator">!</span><span class="operator">=</span> m_format) { <span class="type">QAudioFormat</span> format <span class="operator">=</span> m_format; <span class="keyword">if</span> (m_file) <span class="comment">// Header is read from the WAV file; just need to check whether</span> <span class="comment">// it is supported by the audio output device</span> format <span class="operator">=</span> m_file<span class="operator">-</span><span class="operator">></span>fileFormat(); <span class="keyword">if</span> (m_audioOutputDevice<span class="operator">.</span>isFormatSupported(format)) { setFormat(format); foundSupportedFormat <span class="operator">=</span> <span class="keyword">true</span>; } } <span class="keyword">else</span> { <span class="type">QList</span><span class="operator"><</span><span class="type">int</span><span class="operator">></span> sampleRatesList; <span class="preprocessor">#ifdef Q_OS_WIN</span> <span class="comment">// The Windows audio backend does not correctly report format support</span> <span class="comment">// (see QTBUG-9100). Furthermore, although the audio subsystem captures</span> <span class="comment">// at 11025Hz, the resulting audio is corrupted.</span> sampleRatesList <span class="operator">+</span><span class="operator">=</span> <span class="number">8000</span>; <span class="preprocessor">#endif</span> <span class="keyword">if</span> (<span class="operator">!</span>m_generateTone) sampleRatesList <span class="operator">+</span><span class="operator">=</span> m_audioInputDevice<span class="operator">.</span>supportedSampleRates(); sampleRatesList <span class="operator">+</span><span class="operator">=</span> m_audioOutputDevice<span class="operator">.</span>supportedSampleRates(); sampleRatesList <span class="operator">=</span> sampleRatesList<span class="operator">.</span>toSet()<span class="operator">.</span>toList(); <span class="comment">// remove duplicates</span> qSort(sampleRatesList); ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::initialize frequenciesList"</span> <span class="operator"><</span><span class="operator"><</span> sampleRatesList; <span class="type">QList</span><span class="operator"><</span><span class="type">int</span><span class="operator">></span> channelsList; channelsList <span class="operator">+</span><span class="operator">=</span> m_audioInputDevice<span class="operator">.</span>supportedChannelCounts(); channelsList <span class="operator">+</span><span class="operator">=</span> m_audioOutputDevice<span class="operator">.</span>supportedChannelCounts(); channelsList <span class="operator">=</span> channelsList<span class="operator">.</span>toSet()<span class="operator">.</span>toList(); qSort(channelsList); ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::initialize channelsList"</span> <span class="operator"><</span><span class="operator"><</span> channelsList; <span class="type">QAudioFormat</span> format; format<span class="operator">.</span>setByteOrder(<span class="type">QAudioFormat</span><span class="operator">::</span>LittleEndian); format<span class="operator">.</span>setCodec(<span class="string">"audio/pcm"</span>); format<span class="operator">.</span>setSampleSize(<span class="number">16</span>); format<span class="operator">.</span>setSampleType(<span class="type">QAudioFormat</span><span class="operator">::</span>SignedInt); <span class="type">int</span> sampleRate<span class="operator">,</span> channels; foreach (sampleRate<span class="operator">,</span> sampleRatesList) { <span class="keyword">if</span> (foundSupportedFormat) <span class="keyword">break</span>; format<span class="operator">.</span>setSampleRate(sampleRate); foreach (channels<span class="operator">,</span> channelsList) { format<span class="operator">.</span>setChannelCount(channels); <span class="keyword">const</span> bool inputSupport <span class="operator">=</span> m_generateTone <span class="operator">|</span><span class="operator">|</span> m_audioInputDevice<span class="operator">.</span>isFormatSupported(format); <span class="keyword">const</span> bool outputSupport <span class="operator">=</span> m_audioOutputDevice<span class="operator">.</span>isFormatSupported(format); ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::initialize checking "</span> <span class="operator"><</span><span class="operator"><</span> format <span class="operator"><</span><span class="operator"><</span> <span class="string">"input"</span> <span class="operator"><</span><span class="operator"><</span> inputSupport <span class="operator"><</span><span class="operator"><</span> <span class="string">"output"</span> <span class="operator"><</span><span class="operator"><</span> outputSupport; <span class="keyword">if</span> (inputSupport <span class="operator">&</span><span class="operator">&</span> outputSupport) { foundSupportedFormat <span class="operator">=</span> <span class="keyword">true</span>; <span class="keyword">break</span>; } } } <span class="keyword">if</span> (<span class="operator">!</span>foundSupportedFormat) format <span class="operator">=</span> <span class="type">QAudioFormat</span>(); setFormat(format); } <span class="keyword">return</span> foundSupportedFormat; } <span class="type">void</span> Engine<span class="operator">::</span>stopRecording() { <span class="keyword">if</span> (m_audioInput) { m_audioInput<span class="operator">-</span><span class="operator">></span>stop(); <span class="type">QCoreApplication</span><span class="operator">::</span>instance()<span class="operator">-</span><span class="operator">></span>processEvents(); m_audioInput<span class="operator">-</span><span class="operator">></span>disconnect(); } m_audioInputIODevice <span class="operator">=</span> <span class="number">0</span>; <span class="preprocessor">#ifdef DUMP_AUDIO</span> dumpData(); <span class="preprocessor">#endif</span> } <span class="type">void</span> Engine<span class="operator">::</span>stopPlayback() { <span class="keyword">if</span> (m_audioOutput) { m_audioOutput<span class="operator">-</span><span class="operator">></span>stop(); <span class="type">QCoreApplication</span><span class="operator">::</span>instance()<span class="operator">-</span><span class="operator">></span>processEvents(); m_audioOutput<span class="operator">-</span><span class="operator">></span>disconnect(); setPlayPosition(<span class="number">0</span>); } } <span class="type">void</span> Engine<span class="operator">::</span>setState(<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>State state) { <span class="keyword">const</span> bool changed <span class="operator">=</span> (m_state <span class="operator">!</span><span class="operator">=</span> state); m_state <span class="operator">=</span> state; <span class="keyword">if</span> (changed) <span class="keyword">emit</span> stateChanged(m_mode<span class="operator">,</span> m_state); } <span class="type">void</span> Engine<span class="operator">::</span>setState(<span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>Mode mode<span class="operator">,</span> <span class="type"><a href="qaudio.html">QAudio</a></span><span class="operator">::</span>State state) { <span class="keyword">const</span> bool changed <span class="operator">=</span> (m_mode <span class="operator">!</span><span class="operator">=</span> mode <span class="operator">|</span><span class="operator">|</span> m_state <span class="operator">!</span><span class="operator">=</span> state); m_mode <span class="operator">=</span> mode; m_state <span class="operator">=</span> state; <span class="keyword">if</span> (changed) <span class="keyword">emit</span> stateChanged(m_mode<span class="operator">,</span> m_state); } <span class="type">void</span> Engine<span class="operator">::</span>setRecordPosition(<span class="type">qint64</span> position<span class="operator">,</span> bool forceEmit) { <span class="keyword">const</span> bool changed <span class="operator">=</span> (m_recordPosition <span class="operator">!</span><span class="operator">=</span> position); m_recordPosition <span class="operator">=</span> position; <span class="keyword">if</span> (changed <span class="operator">|</span><span class="operator">|</span> forceEmit) <span class="keyword">emit</span> recordPositionChanged(m_recordPosition); } <span class="type">void</span> Engine<span class="operator">::</span>setPlayPosition(<span class="type">qint64</span> position<span class="operator">,</span> bool forceEmit) { <span class="keyword">const</span> bool changed <span class="operator">=</span> (m_playPosition <span class="operator">!</span><span class="operator">=</span> position); m_playPosition <span class="operator">=</span> position; <span class="keyword">if</span> (changed <span class="operator">|</span><span class="operator">|</span> forceEmit) <span class="keyword">emit</span> playPositionChanged(m_playPosition); } <span class="type">void</span> Engine<span class="operator">::</span>calculateLevel(<span class="type">qint64</span> position<span class="operator">,</span> <span class="type">qint64</span> length) { <span class="preprocessor">#ifdef DISABLE_LEVEL</span> Q_UNUSED(position) Q_UNUSED(length) <span class="preprocessor">#else</span> Q_ASSERT(position <span class="operator">+</span> length <span class="operator"><</span><span class="operator">=</span> m_bufferPosition <span class="operator">+</span> m_dataLength); <span class="type">qreal</span> peakLevel <span class="operator">=</span> <span class="number">0.0</span>; <span class="type">qreal</span> sum <span class="operator">=</span> <span class="number">0.0</span>; <span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>ptr <span class="operator">=</span> m_buffer<span class="operator">.</span>constData() <span class="operator">+</span> position <span class="operator">-</span> m_bufferPosition; <span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span><span class="keyword">const</span> end <span class="operator">=</span> ptr <span class="operator">+</span> length; <span class="keyword">while</span> (ptr <span class="operator"><</span> end) { <span class="keyword">const</span> <span class="type">qint16</span> value <span class="operator">=</span> <span class="operator">*</span><span class="keyword">reinterpret_cast</span><span class="operator"><</span><span class="keyword">const</span> <span class="type">qint16</span><span class="operator">*</span><span class="operator">></span>(ptr); <span class="keyword">const</span> <span class="type">qreal</span> fracValue <span class="operator">=</span> pcmToReal(value); peakLevel <span class="operator">=</span> qMax(peakLevel<span class="operator">,</span> fracValue); sum <span class="operator">+</span><span class="operator">=</span> fracValue <span class="operator">*</span> fracValue; ptr <span class="operator">+</span><span class="operator">=</span> <span class="number">2</span>; } <span class="keyword">const</span> <span class="type">int</span> numSamples <span class="operator">=</span> length <span class="operator">/</span> <span class="number">2</span>; <span class="type">qreal</span> rmsLevel <span class="operator">=</span> sqrt(sum <span class="operator">/</span> numSamples); rmsLevel <span class="operator">=</span> qMax(<span class="type">qreal</span>(<span class="number">0.0</span>)<span class="operator">,</span> rmsLevel); rmsLevel <span class="operator">=</span> qMin(<span class="type">qreal</span>(<span class="number">1.0</span>)<span class="operator">,</span> rmsLevel); setLevel(rmsLevel<span class="operator">,</span> peakLevel<span class="operator">,</span> numSamples); ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::calculateLevel"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"pos"</span> <span class="operator"><</span><span class="operator"><</span> position <span class="operator"><</span><span class="operator"><</span> <span class="string">"len"</span> <span class="operator"><</span><span class="operator"><</span> length <span class="operator"><</span><span class="operator"><</span> <span class="string">"rms"</span> <span class="operator"><</span><span class="operator"><</span> rmsLevel <span class="operator"><</span><span class="operator"><</span> <span class="string">"peak"</span> <span class="operator"><</span><span class="operator"><</span> peakLevel; <span class="preprocessor">#endif</span> } <span class="type">void</span> Engine<span class="operator">::</span>calculateSpectrum(<span class="type">qint64</span> position) { <span class="preprocessor">#ifdef DISABLE_SPECTRUM</span> Q_UNUSED(position) <span class="preprocessor">#else</span> Q_ASSERT(position <span class="operator">+</span> m_spectrumBufferLength <span class="operator"><</span><span class="operator">=</span> m_bufferPosition <span class="operator">+</span> m_dataLength); Q_ASSERT(<span class="number">0</span> <span class="operator">=</span><span class="operator">=</span> m_spectrumBufferLength <span class="operator">%</span> <span class="number">2</span>); <span class="comment">// constraint of FFT algorithm</span> <span class="comment">// QThread::currentThread is marked 'for internal use only', but</span> <span class="comment">// we're only using it for debug output here, so it's probably OK :)</span> ENGINE_DEBUG <span class="operator"><</span><span class="operator"><</span> <span class="string">"Engine::calculateSpectrum"</span> <span class="operator"><</span><span class="operator"><</span> <span class="type">QThread</span><span class="operator">::</span>currentThread() <span class="operator"><</span><span class="operator"><</span> <span class="string">"count"</span> <span class="operator"><</span><span class="operator"><</span> m_count <span class="operator"><</span><span class="operator"><</span> <span class="string">"pos"</span> <span class="operator"><</span><span class="operator"><</span> position <span class="operator"><</span><span class="operator"><</span> <span class="string">"len"</span> <span class="operator"><</span><span class="operator"><</span> m_spectrumBufferLength <span class="operator"><</span><span class="operator"><</span> <span class="string">"spectrumAnalyser.isReady"</span> <span class="operator"><</span><span class="operator"><</span> m_spectrumAnalyser<span class="operator">.</span>isReady(); <span class="keyword">if</span> (m_spectrumAnalyser<span class="operator">.</span>isReady()) { m_spectrumBuffer <span class="operator">=</span> <span class="type">QByteArray</span><span class="operator">::</span>fromRawData(m_buffer<span class="operator">.</span>constData() <span class="operator">+</span> position <span class="operator">-</span> m_bufferPosition<span class="operator">,</span> m_spectrumBufferLength); m_spectrumPosition <span class="operator">=</span> position; m_spectrumAnalyser<span class="operator">.</span>calculate(m_spectrumBuffer<span class="operator">,</span> m_format); } <span class="preprocessor">#endif</span> } <span class="type">void</span> Engine<span class="operator">::</span>setFormat(<span class="keyword">const</span> <span class="type">QAudioFormat</span> <span class="operator">&</span>format) { <span class="keyword">const</span> bool changed <span class="operator">=</span> (format <span class="operator">!</span><span class="operator">=</span> m_format); m_format <span class="operator">=</span> format; m_levelBufferLength <span class="operator">=</span> audioLength(m_format<span class="operator">,</span> LevelWindowUs); m_spectrumBufferLength <span class="operator">=</span> SpectrumLengthSamples <span class="operator">*</span> (m_format<span class="operator">.</span>sampleSize() <span class="operator">/</span> <span class="number">8</span>) <span class="operator">*</span> m_format<span class="operator">.</span>channelCount(); <span class="keyword">if</span> (changed) <span class="keyword">emit</span> formatChanged(m_format); } <span class="type">void</span> Engine<span class="operator">::</span>setLevel(<span class="type">qreal</span> rmsLevel<span class="operator">,</span> <span class="type">qreal</span> peakLevel<span class="operator">,</span> <span class="type">int</span> numSamples) { m_rmsLevel <span class="operator">=</span> rmsLevel; m_peakLevel <span class="operator">=</span> peakLevel; <span class="keyword">emit</span> levelChanged(m_rmsLevel<span class="operator">,</span> m_peakLevel<span class="operator">,</span> numSamples); } <span class="preprocessor">#ifdef DUMP_DATA</span> <span class="type">void</span> Engine<span class="operator">::</span>createOutputDir() { m_outputDir<span class="operator">.</span>setPath(<span class="string">"output"</span>); <span class="comment">// Ensure output directory exists and is empty</span> <span class="keyword">if</span> (m_outputDir<span class="operator">.</span>exists()) { <span class="keyword">const</span> <span class="type">QStringList</span> files <span class="operator">=</span> m_outputDir<span class="operator">.</span>entryList(<span class="type">QDir</span><span class="operator">::</span>Files); <span class="type">QString</span> file; foreach (file<span class="operator">,</span> files) m_outputDir<span class="operator">.</span>remove(file); } <span class="keyword">else</span> { <span class="type">QDir</span><span class="operator">::</span>current()<span class="operator">.</span>mkdir(<span class="string">"output"</span>); } } <span class="preprocessor">#endif // DUMP_DATA</span> <span class="preprocessor">#ifdef DUMP_AUDIO</span> <span class="type">void</span> Engine<span class="operator">::</span>dumpData() { <span class="keyword">const</span> <span class="type">QString</span> txtFileName <span class="operator">=</span> m_outputDir<span class="operator">.</span>filePath(<span class="string">"data.txt"</span>); <span class="type">QFile</span> txtFile(txtFileName); txtFile<span class="operator">.</span>open(<span class="type">QFile</span><span class="operator">::</span>WriteOnly <span class="operator">|</span> <span class="type">QFile</span><span class="operator">::</span>Text); <span class="type">QTextStream</span> stream(<span class="operator">&</span>txtFile); <span class="keyword">const</span> <span class="type">qint16</span> <span class="operator">*</span>ptr <span class="operator">=</span> <span class="keyword">reinterpret_cast</span><span class="operator"><</span><span class="keyword">const</span> <span class="type">qint16</span><span class="operator">*</span><span class="operator">></span>(m_buffer<span class="operator">.</span>constData()); <span class="keyword">const</span> <span class="type">int</span> numSamples <span class="operator">=</span> m_dataLength <span class="operator">/</span> (<span class="number">2</span> <span class="operator">*</span> m_format<span class="operator">.</span>channels()); <span class="keyword">for</span> (<span class="type">int</span> i<span class="operator">=</span><span class="number">0</span>; i<span class="operator"><</span>numSamples; <span class="operator">+</span><span class="operator">+</span>i) { stream <span class="operator"><</span><span class="operator"><</span> i <span class="operator"><</span><span class="operator"><</span> <span class="string">"\t"</span> <span class="operator"><</span><span class="operator"><</span> <span class="operator">*</span>ptr <span class="operator"><</span><span class="operator"><</span> <span class="string">"\n"</span>; ptr <span class="operator">+</span><span class="operator">=</span> m_format<span class="operator">.</span>channels(); } <span class="keyword">const</span> <span class="type">QString</span> pcmFileName <span class="operator">=</span> m_outputDir<span class="operator">.</span>filePath(<span class="string">"data.pcm"</span>); <span class="type">QFile</span> pcmFile(pcmFileName); pcmFile<span class="operator">.</span>open(<span class="type">QFile</span><span class="operator">::</span>WriteOnly); pcmFile<span class="operator">.</span>write(m_buffer<span class="operator">.</span>constData()<span class="operator">,</span> m_dataLength); } <span class="preprocessor">#endif // DUMP_AUDIO</span> </pre> </div> <!-- @@@multimedia/spectrum/app/engine.cpp --> </div> </div> </div> </div> </div> <div class="footer"> <p> <acronym title="Copyright">©</acronym> 2019 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners.<br/> The documentation provided herein is licensed under the terms of the <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation License version 1.3</a> as published by the Free Software Foundation.<br/> Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners. </p> </div> </body> </html>