source: trunk/demos/spectrum/app/engine.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 23.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the examples of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:BSD$
10** You may use this file under the terms of the BSD license as follows:
11**
12** "Redistribution and use in source and binary forms, with or without
13** modification, are permitted provided that the following conditions are
14** met:
15** * Redistributions of source code must retain the above copyright
16** notice, this list of conditions and the following disclaimer.
17** * Redistributions in binary form must reproduce the above copyright
18** notice, this list of conditions and the following disclaimer in
19** the documentation and/or other materials provided with the
20** distribution.
21** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22** the names of its contributors may be used to endorse or promote
23** products derived from this software without specific prior written
24** permission.
25**
26** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "engine.h"
42#include "tonegenerator.h"
43#include "utils.h"
44
45#include <math.h>
46
47#include <QCoreApplication>
48#include <QMetaObject>
49#include <QSet>
50#include <QtMultimedia/QAudioInput>
51#include <QtMultimedia/QAudioOutput>
52#include <QDebug>
53#include <QThread>
54#include <QFile>
55
56//-----------------------------------------------------------------------------
57// Constants
58//-----------------------------------------------------------------------------
59
60const qint64 BufferDurationUs = 10 * 1000000;
61const int NotifyIntervalMs = 100;
62
63// Size of the level calculation window in microseconds
64const int LevelWindowUs = 0.1 * 1000000;
65
66
67//-----------------------------------------------------------------------------
68// Helper functions
69//-----------------------------------------------------------------------------
70
71QDebug& operator<<(QDebug &debug, const QAudioFormat &format)
72{
73 debug << format.frequency() << "Hz"
74 << format.channels() << "channels";
75 return debug;
76}
77
78//-----------------------------------------------------------------------------
79// Constructor and destructor
80//-----------------------------------------------------------------------------
81
82Engine::Engine(QObject *parent)
83 : QObject(parent)
84 , m_mode(QAudio::AudioInput)
85 , m_state(QAudio::StoppedState)
86 , m_generateTone(false)
87 , m_file(0)
88 , m_availableAudioInputDevices
89 (QAudioDeviceInfo::availableDevices(QAudio::AudioInput))
90 , m_audioInputDevice(QAudioDeviceInfo::defaultInputDevice())
91 , m_audioInput(0)
92 , m_audioInputIODevice(0)
93 , m_recordPosition(0)
94 , m_availableAudioOutputDevices
95 (QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
96 , m_audioOutputDevice(QAudioDeviceInfo::defaultOutputDevice())
97 , m_audioOutput(0)
98 , m_playPosition(0)
99 , m_dataLength(0)
100 , m_rmsLevel(0.0)
101 , m_peakLevel(0.0)
102 , m_spectrumLengthBytes(0)
103 , m_spectrumAnalyser()
104 , m_spectrumPosition(0)
105 , m_count(0)
106{
107 qRegisterMetaType<FrequencySpectrum>("FrequencySpectrum");
108 CHECKED_CONNECT(&m_spectrumAnalyser,
109 SIGNAL(spectrumChanged(FrequencySpectrum)),
110 this,
111 SLOT(spectrumChanged(FrequencySpectrum)));
112
113 initialize();
114
115#ifdef DUMP_DATA
116 createOutputDir();
117#endif
118
119#ifdef DUMP_SPECTRUM
120 m_spectrumAnalyser.setOutputPath(outputPath());
121#endif
122}
123
124Engine::~Engine()
125{
126
127}
128
129//-----------------------------------------------------------------------------
130// Public functions
131//-----------------------------------------------------------------------------
132
133bool Engine::loadFile(const QString &fileName)
134{
135 bool result = false;
136 m_generateTone = false;
137
138 Q_ASSERT(!fileName.isEmpty());
139 Q_ASSERT(!m_file);
140 m_file = new QFile(fileName, this);
141 m_file->setFileName(fileName);
142 Q_ASSERT(m_file->exists());
143 if (m_file->open(QFile::ReadOnly)) {
144 m_wavFile.readHeader(*m_file);
145 if (isPCMS16LE(m_wavFile.format())) {
146 result = initialize();
147 } else {
148 emit errorMessage(tr("Audio format not supported"),
149 formatToString(m_wavFile.format()));
150 }
151 } else {
152 emit errorMessage(tr("Could not open file"), fileName);
153 }
154
155 delete m_file;
156 m_file = 0;
157
158 return result;
159}
160
161bool Engine::generateTone(const Tone &tone)
162{
163 Q_ASSERT(!m_file);
164 m_generateTone = true;
165 m_tone = tone;
166 ENGINE_DEBUG << "Engine::generateTone"
167 << "startFreq" << m_tone.startFreq
168 << "endFreq" << m_tone.endFreq
169 << "amp" << m_tone.amplitude;
170 return initialize();
171}
172
173bool Engine::generateSweptTone(qreal amplitude)
174{
175 Q_ASSERT(!m_file);
176 m_generateTone = true;
177 m_tone.startFreq = 1;
178 m_tone.endFreq = 0;
179 m_tone.amplitude = amplitude;
180 ENGINE_DEBUG << "Engine::generateSweptTone"
181 << "startFreq" << m_tone.startFreq
182 << "amp" << m_tone.amplitude;
183 return initialize();
184}
185
186bool Engine::initializeRecord()
187{
188 ENGINE_DEBUG << "Engine::initializeRecord";
189 Q_ASSERT(!m_file);
190 m_generateTone = false;
191 m_tone = SweptTone();
192 return initialize();
193}
194
195qint64 Engine::bufferDuration() const
196{
197 return BufferDurationUs;
198}
199
200qint64 Engine::dataDuration() const
201{
202 qint64 result = 0;
203 if (QAudioFormat() != m_format)
204 result = audioDuration(m_format, m_dataLength);
205 return result;
206}
207
208qint64 Engine::audioBufferLength() const
209{
210 qint64 length = 0;
211 if (QAudio::ActiveState == m_state || QAudio::IdleState == m_state) {
212 Q_ASSERT(QAudioFormat() != m_format);
213 switch (m_mode) {
214 case QAudio::AudioInput:
215 length = m_audioInput->bufferSize();
216 break;
217 case QAudio::AudioOutput:
218 length = m_audioOutput->bufferSize();
219 break;
220 }
221 }
222 return length;
223}
224
225void Engine::setWindowFunction(WindowFunction type)
226{
227 m_spectrumAnalyser.setWindowFunction(type);
228}
229
230
231//-----------------------------------------------------------------------------
232// Public slots
233//-----------------------------------------------------------------------------
234
235void Engine::startRecording()
236{
237 if (m_audioInput) {
238 if (QAudio::AudioInput == m_mode &&
239 QAudio::SuspendedState == m_state) {
240 m_audioInput->resume();
241 } else {
242 m_spectrumAnalyser.cancelCalculation();
243 spectrumChanged(0, 0, FrequencySpectrum());
244
245 m_buffer.fill(0);
246 setRecordPosition(0, true);
247 stopPlayback();
248 m_mode = QAudio::AudioInput;
249 CHECKED_CONNECT(m_audioInput, SIGNAL(stateChanged(QAudio::State)),
250 this, SLOT(audioStateChanged(QAudio::State)));
251 CHECKED_CONNECT(m_audioInput, SIGNAL(notify()),
252 this, SLOT(audioNotify()));
253 m_count = 0;
254 m_dataLength = 0;
255 emit dataDurationChanged(0);
256 m_audioInputIODevice = m_audioInput->start();
257 CHECKED_CONNECT(m_audioInputIODevice, SIGNAL(readyRead()),
258 this, SLOT(audioDataReady()));
259 }
260 }
261}
262
263void Engine::startPlayback()
264{
265 if (m_audioOutput) {
266 if (QAudio::AudioOutput == m_mode &&
267 QAudio::SuspendedState == m_state) {
268#ifdef Q_OS_WIN
269 // The Windows backend seems to internally go back into ActiveState
270 // while still returning SuspendedState, so to ensure that it doesn't
271 // ignore the resume() call, we first re-suspend
272 m_audioOutput->suspend();
273#endif
274 m_audioOutput->resume();
275 } else {
276 m_spectrumAnalyser.cancelCalculation();
277 spectrumChanged(0, 0, FrequencySpectrum());
278
279 setPlayPosition(0, true);
280 stopRecording();
281 m_mode = QAudio::AudioOutput;
282 CHECKED_CONNECT(m_audioOutput, SIGNAL(stateChanged(QAudio::State)),
283 this, SLOT(audioStateChanged(QAudio::State)));
284 CHECKED_CONNECT(m_audioOutput, SIGNAL(notify()),
285 this, SLOT(audioNotify()));
286 m_count = 0;
287 m_audioOutputIODevice.close();
288 m_audioOutputIODevice.setBuffer(&m_buffer);
289 m_audioOutputIODevice.open(QIODevice::ReadOnly);
290 m_audioOutput->start(&m_audioOutputIODevice);
291 }
292 }
293}
294
295void Engine::suspend()
296{
297 if (QAudio::ActiveState == m_state ||
298 QAudio::IdleState == m_state) {
299 switch (m_mode) {
300 case QAudio::AudioInput:
301 m_audioInput->suspend();
302 break;
303 case QAudio::AudioOutput:
304 m_audioOutput->suspend();
305 break;
306 }
307 }
308}
309
310void Engine::setAudioInputDevice(const QAudioDeviceInfo &device)
311{
312 if (device.deviceName() != m_audioInputDevice.deviceName()) {
313 m_audioInputDevice = device;
314 initialize();
315 }
316}
317
318void Engine::setAudioOutputDevice(const QAudioDeviceInfo &device)
319{
320 if (device.deviceName() != m_audioOutputDevice.deviceName()) {
321 m_audioOutputDevice = device;
322 initialize();
323 }
324}
325
326
327//-----------------------------------------------------------------------------
328// Private slots
329//-----------------------------------------------------------------------------
330
331void Engine::audioNotify()
332{
333 switch (m_mode) {
334 case QAudio::AudioInput: {
335 const qint64 recordPosition =
336 qMin(BufferDurationUs, m_audioInput->processedUSecs());
337 setRecordPosition(recordPosition);
338
339 // Calculate level of most recently captured data
340 qint64 levelLength = audioLength(m_format, LevelWindowUs);
341 levelLength = qMin(m_dataLength, levelLength);
342 const qint64 levelPosition = m_dataLength - levelLength;
343 calculateLevel(levelPosition, levelLength);
344
345 // Calculate spectrum of most recently captured data
346 if (m_dataLength >= m_spectrumLengthBytes) {
347 const qint64 spectrumPosition = m_dataLength - m_spectrumLengthBytes;
348 calculateSpectrum(spectrumPosition);
349 }
350 }
351 break;
352 case QAudio::AudioOutput: {
353 const qint64 playPosition =
354 qMin(dataDuration(), m_audioOutput->processedUSecs());
355 setPlayPosition(playPosition);
356
357 qint64 analysisPosition = audioLength(m_format, playPosition);
358
359 // Calculate level of data starting at current playback position
360 const qint64 levelLength = audioLength(m_format, LevelWindowUs);
361 if (analysisPosition + levelLength < m_dataLength)
362 calculateLevel(analysisPosition, levelLength);
363
364 if (analysisPosition + m_spectrumLengthBytes < m_dataLength)
365 calculateSpectrum(analysisPosition);
366
367 if (dataDuration() == playPosition)
368 stopPlayback();
369 }
370 break;
371 }
372}
373
374void Engine::audioStateChanged(QAudio::State state)
375{
376 ENGINE_DEBUG << "Engine::audioStateChanged from" << m_state
377 << "to" << state;
378
379 if (QAudio::StoppedState == state) {
380 // Check error
381 QAudio::Error error = QAudio::NoError;
382 switch (m_mode) {
383 case QAudio::AudioInput:
384 error = m_audioInput->error();
385 break;
386 case QAudio::AudioOutput:
387 error = m_audioOutput->error();
388 break;
389 }
390 if (QAudio::NoError != error) {
391 reset();
392 return;
393 }
394 }
395 setState(state);
396}
397
398void Engine::audioDataReady()
399{
400 const qint64 bytesReady = m_audioInput->bytesReady();
401 const qint64 bytesSpace = m_buffer.size() - m_dataLength;
402 const qint64 bytesToRead = qMin(bytesReady, bytesSpace);
403
404 const qint64 bytesRead = m_audioInputIODevice->read(
405 m_buffer.data() + m_dataLength,
406 bytesToRead);
407
408 if (bytesRead) {
409 m_dataLength += bytesRead;
410
411 const qint64 duration = audioDuration(m_format, m_dataLength);
412 emit dataDurationChanged(duration);
413 }
414
415 if (m_buffer.size() == m_dataLength)
416 stopRecording();
417}
418
419void Engine::spectrumChanged(const FrequencySpectrum &spectrum)
420{
421 ENGINE_DEBUG << "Engine::spectrumChanged" << "pos" << m_spectrumPosition;
422 const qint64 positionUs = audioDuration(m_format, m_spectrumPosition);
423 const qint64 lengthUs = audioDuration(m_format, m_spectrumLengthBytes);
424 emit spectrumChanged(positionUs, lengthUs, spectrum);
425}
426
427
428//-----------------------------------------------------------------------------
429// Private functions
430//-----------------------------------------------------------------------------
431
432void Engine::reset()
433{
434 stopRecording();
435 stopPlayback();
436 setState(QAudio::AudioInput, QAudio::StoppedState);
437 setFormat(QAudioFormat());
438 delete m_audioInput;
439 m_audioInput = 0;
440 m_audioInputIODevice = 0;
441 setRecordPosition(0);
442 delete m_audioOutput;
443 m_audioOutput = 0;
444 setPlayPosition(0);
445 m_buffer.clear();
446 m_dataLength = 0;
447 m_spectrumPosition = 0;
448 emit dataDurationChanged(0);
449 setLevel(0.0, 0.0, 0);
450}
451
452bool Engine::initialize()
453{
454 bool result = false;
455
456 reset();
457
458 if (selectFormat()) {
459 const qint64 bufferLength = audioLength(m_format, BufferDurationUs);
460 m_buffer.resize(bufferLength);
461 m_buffer.fill(0);
462 emit bufferDurationChanged(BufferDurationUs);
463
464 if (m_generateTone) {
465 if (0 == m_tone.endFreq) {
466 const qreal nyquist = nyquistFrequency(m_format);
467 m_tone.endFreq = qMin(qreal(SpectrumHighFreq), nyquist);
468 }
469
470 // Call function defined in utils.h, at global scope
471 ::generateTone(m_tone, m_format, m_buffer);
472 m_dataLength = m_buffer.size();
473 emit dataDurationChanged(bufferDuration());
474 setRecordPosition(bufferDuration());
475 result = true;
476 } else if (m_file) {
477 const qint64 length = m_wavFile.readData(*m_file, m_buffer, m_format);
478 if (length) {
479 m_dataLength = length;
480 emit dataDurationChanged(dataDuration());
481 setRecordPosition(dataDuration());
482 result = true;
483 }
484 } else {
485 m_audioInput = new QAudioInput(m_audioInputDevice, m_format, this);
486 m_audioInput->setNotifyInterval(NotifyIntervalMs);
487 result = true;
488 }
489
490 m_audioOutput = new QAudioOutput(m_audioOutputDevice, m_format, this);
491 m_audioOutput->setNotifyInterval(NotifyIntervalMs);
492 m_spectrumLengthBytes = SpectrumLengthSamples *
493 (m_format.sampleSize() / 8) * m_format.channels();
494 } else {
495 if (m_file)
496 emit errorMessage(tr("Audio format not supported"),
497 formatToString(m_format));
498 else if (m_generateTone)
499 emit errorMessage(tr("No suitable format found"), "");
500 else
501 emit errorMessage(tr("No common input / output format found"), "");
502 }
503
504 ENGINE_DEBUG << "Engine::initialize" << "format" << m_format;
505
506 return result;
507}
508
509bool Engine::selectFormat()
510{
511 bool foundSupportedFormat = false;
512
513 if (m_file) {
514 // Header is read from the WAV file; just need to check whether
515 // it is supported by the audio output device
516 QAudioFormat format = m_wavFile.format();
517 if (m_audioOutputDevice.isFormatSupported(m_wavFile.format())) {
518 setFormat(m_wavFile.format());
519 foundSupportedFormat = true;
520 } else {
521 // Try flipping mono <-> stereo
522 const int channels = (format.channels() == 1) ? 2 : 1;
523 format.setChannels(channels);
524 if (m_audioOutputDevice.isFormatSupported(format)) {
525 setFormat(format);
526 foundSupportedFormat = true;
527 }
528 }
529 } else {
530
531 QList<int> frequenciesList;
532 #ifdef Q_OS_WIN
533 // The Windows audio backend does not correctly report format support
534 // (see QTBUG-9100). Furthermore, although the audio subsystem captures
535 // at 11025Hz, the resulting audio is corrupted.
536 frequenciesList += 8000;
537 #endif
538
539 if (!m_generateTone)
540 frequenciesList += m_audioInputDevice.supportedFrequencies();
541
542 frequenciesList += m_audioOutputDevice.supportedFrequencies();
543 frequenciesList = frequenciesList.toSet().toList(); // remove duplicates
544 qSort(frequenciesList);
545 ENGINE_DEBUG << "Engine::initialize frequenciesList" << frequenciesList;
546
547 QList<int> channelsList;
548 channelsList += m_audioInputDevice.supportedChannels();
549 channelsList += m_audioOutputDevice.supportedChannels();
550 channelsList = channelsList.toSet().toList();
551 qSort(channelsList);
552 ENGINE_DEBUG << "Engine::initialize channelsList" << channelsList;
553
554 QAudioFormat format;
555 format.setByteOrder(QAudioFormat::LittleEndian);
556 format.setCodec("audio/pcm");
557 format.setSampleSize(16);
558 format.setSampleType(QAudioFormat::SignedInt);
559 int frequency, channels;
560 foreach (frequency, frequenciesList) {
561 if (foundSupportedFormat)
562 break;
563 format.setFrequency(frequency);
564 foreach (channels, channelsList) {
565 format.setChannels(channels);
566 const bool inputSupport = m_generateTone ||
567 m_audioInputDevice.isFormatSupported(format);
568 const bool outputSupport = m_audioOutputDevice.isFormatSupported(format);
569 ENGINE_DEBUG << "Engine::initialize checking " << format
570 << "input" << inputSupport
571 << "output" << outputSupport;
572 if (inputSupport && outputSupport) {
573 foundSupportedFormat = true;
574 break;
575 }
576 }
577 }
578
579 if (!foundSupportedFormat)
580 format = QAudioFormat();
581
582 setFormat(format);
583 }
584
585 return foundSupportedFormat;
586}
587
588void Engine::stopRecording()
589{
590 if (m_audioInput) {
591 m_audioInput->stop();
592 QCoreApplication::instance()->processEvents();
593 m_audioInput->disconnect();
594 }
595 m_audioInputIODevice = 0;
596
597#ifdef DUMP_AUDIO
598 dumpData();
599#endif
600}
601
602void Engine::stopPlayback()
603{
604 if (m_audioOutput) {
605 m_audioOutput->stop();
606 QCoreApplication::instance()->processEvents();
607 m_audioOutput->disconnect();
608 setPlayPosition(0);
609 }
610}
611
612void Engine::setState(QAudio::State state)
613{
614 const bool changed = (m_state != state);
615 m_state = state;
616 if (changed)
617 emit stateChanged(m_mode, m_state);
618}
619
620void Engine::setState(QAudio::Mode mode, QAudio::State state)
621{
622 const bool changed = (m_mode != mode || m_state != state);
623 m_mode = mode;
624 m_state = state;
625 if (changed)
626 emit stateChanged(m_mode, m_state);
627}
628
629void Engine::setRecordPosition(qint64 position, bool forceEmit)
630{
631 const bool changed = (m_recordPosition != position);
632 m_recordPosition = position;
633 if (changed || forceEmit)
634 emit recordPositionChanged(m_recordPosition);
635}
636
637void Engine::setPlayPosition(qint64 position, bool forceEmit)
638{
639 const bool changed = (m_playPosition != position);
640 m_playPosition = position;
641 if (changed || forceEmit)
642 emit playPositionChanged(m_playPosition);
643}
644
645void Engine::calculateLevel(qint64 position, qint64 length)
646{
647#ifdef DISABLE_LEVEL
648 Q_UNUSED(position)
649 Q_UNUSED(length)
650#else
651 Q_ASSERT(position + length <= m_dataLength);
652
653 qreal peakLevel = 0.0;
654
655 qreal sum = 0.0;
656 const char *ptr = m_buffer.constData() + position;
657 const char *const end = ptr + length;
658 while (ptr < end) {
659 const qint16 value = *reinterpret_cast<const qint16*>(ptr);
660 const qreal fracValue = pcmToReal(value);
661 peakLevel = qMax(peakLevel, fracValue);
662 sum += fracValue * fracValue;
663 ptr += 2;
664 }
665 const int numSamples = length / 2;
666 qreal rmsLevel = sqrt(sum / numSamples);
667
668 rmsLevel = qMax(qreal(0.0), rmsLevel);
669 rmsLevel = qMin(qreal(1.0), rmsLevel);
670 setLevel(rmsLevel, peakLevel, numSamples);
671
672 ENGINE_DEBUG << "Engine::calculateLevel" << "pos" << position << "len" << length
673 << "rms" << rmsLevel << "peak" << peakLevel;
674#endif
675}
676
677void Engine::calculateSpectrum(qint64 position)
678{
679#ifdef DISABLE_SPECTRUM
680 Q_UNUSED(position)
681#else
682 Q_ASSERT(position + m_spectrumLengthBytes <= m_dataLength);
683 Q_ASSERT(0 == m_spectrumLengthBytes % 2); // constraint of FFT algorithm
684
685 // QThread::currentThread is marked 'for internal use only', but
686 // we're only using it for debug output here, so it's probably OK :)
687 ENGINE_DEBUG << "Engine::calculateSpectrum" << QThread::currentThread()
688 << "count" << m_count << "pos" << position << "len" << m_spectrumLengthBytes
689 << "spectrumAnalyser.isReady" << m_spectrumAnalyser.isReady();
690
691 if(m_spectrumAnalyser.isReady()) {
692 m_spectrumBuffer = QByteArray::fromRawData(m_buffer.constData() + position,
693 m_spectrumLengthBytes);
694 m_spectrumPosition = position;
695 m_spectrumAnalyser.calculate(m_spectrumBuffer, m_format);
696 }
697#endif
698}
699
700void Engine::setFormat(const QAudioFormat &format)
701{
702 const bool changed = (format != m_format);
703 m_format = format;
704 if (changed)
705 emit formatChanged(m_format);
706}
707
708void Engine::setLevel(qreal rmsLevel, qreal peakLevel, int numSamples)
709{
710 m_rmsLevel = rmsLevel;
711 m_peakLevel = peakLevel;
712 emit levelChanged(m_rmsLevel, m_peakLevel, numSamples);
713}
714
715#ifdef DUMP_DATA
716void Engine::createOutputDir()
717{
718 m_outputDir.setPath("output");
719
720 // Ensure output directory exists and is empty
721 if (m_outputDir.exists()) {
722 const QStringList files = m_outputDir.entryList(QDir::Files);
723 QString file;
724 foreach (file, files)
725 m_outputDir.remove(file);
726 } else {
727 QDir::current().mkdir("output");
728 }
729}
730#endif // DUMP_DATA
731
732#ifdef DUMP_AUDIO
733void Engine::dumpData()
734{
735 const QString txtFileName = m_outputDir.filePath("data.txt");
736 QFile txtFile(txtFileName);
737 txtFile.open(QFile::WriteOnly | QFile::Text);
738 QTextStream stream(&txtFile);
739 const qint16 *ptr = reinterpret_cast<const qint16*>(m_buffer.constData());
740 const int numSamples = m_dataLength / (2 * m_format.channels());
741 for (int i=0; i<numSamples; ++i) {
742 stream << i << "\t" << *ptr << "\n";
743 ptr += m_format.channels();
744 }
745
746 const QString pcmFileName = m_outputDir.filePath("data.pcm");
747 QFile pcmFile(pcmFileName);
748 pcmFile.open(QFile::WriteOnly);
749 pcmFile.write(m_buffer.constData(), m_dataLength);
750}
751#endif // DUMP_AUDIO
Note: See TracBrowser for help on using the repository browser.