summaryrefslogtreecommitdiffstats
path: root/demos/spectrum/app/engine.cpp
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-10-29 12:52:31 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2010-10-29 12:52:31 (GMT)
commit969750777896dc50f9f5b8043b5da3a4a161e616 (patch)
tree11e8599f5727df234be8c9ab783db47ac12f2a43 /demos/spectrum/app/engine.cpp
parentc02ef9eb331f03dbd59d2fd938c53b54f5c65cea (diff)
parent3cf35876400cb008fb25c8a3191c996af6059264 (diff)
downloadQt-969750777896dc50f9f5b8043b5da3a4a161e616.zip
Qt-969750777896dc50f9f5b8043b5da3a4a161e616.tar.gz
Qt-969750777896dc50f9f5b8043b5da3a4a161e616.tar.bz2
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/qt-s60-public into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/qt-s60-public: Play whole file in spectrum analyzer demo Do not unnecessarily reset state of spectrum demo Set SpectrumAnalyserThread parent to 0 before calling moveToThread() Avoid being killed by graphics out-of-memory monitor. Revert function renaming in QtOpenVG. Support tactile feedback in QWidgets from QS60Style Support tactile feeedback from QS60Style for QWidgets Making the buttons less finger unfriendly Readded .def file entries after a little stunt Do not crash on Symbian Temporarily remove .def file entries for a little stunt Fixed crash with QClipboard in Symbian^3 Fallback to vgWritePixels in drawPixmap.
Diffstat (limited to 'demos/spectrum/app/engine.cpp')
-rw-r--r--demos/spectrum/app/engine.cpp333
1 files changed, 174 insertions, 159 deletions
diff --git a/demos/spectrum/app/engine.cpp b/demos/spectrum/app/engine.cpp
index 119a0e3..cd847fe 100644
--- a/demos/spectrum/app/engine.cpp
+++ b/demos/spectrum/app/engine.cpp
@@ -85,6 +85,7 @@ Engine::Engine(QObject *parent)
, m_state(QAudio::StoppedState)
, m_generateTone(false)
, m_file(0)
+ , m_analysisFile(0)
, m_availableAudioInputDevices
(QAudioDeviceInfo::availableDevices(QAudio::AudioInput))
, m_audioInputDevice(QAudioDeviceInfo::defaultInputDevice())
@@ -96,15 +97,19 @@ Engine::Engine(QObject *parent)
, 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_spectrumLengthBytes(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,
@@ -132,34 +137,33 @@ Engine::~Engine()
bool Engine::loadFile(const QString &fileName)
{
+ reset();
bool result = false;
- m_generateTone = false;
-
- Q_ASSERT(!fileName.isEmpty());
+ Q_ASSERT(!m_generateTone);
Q_ASSERT(!m_file);
- m_file = new QFile(fileName, this);
- m_file->setFileName(fileName);
- Q_ASSERT(m_file->exists());
- if (m_file->open(QFile::ReadOnly)) {
- m_wavFile.readHeader(*m_file);
- if (isPCMS16LE(m_wavFile.format())) {
+ 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_wavFile.format()));
+ formatToString(m_file->fileFormat()));
}
} else {
emit errorMessage(tr("Could not open file"), fileName);
}
-
- delete m_file;
- m_file = 0;
-
+ 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;
@@ -172,6 +176,7 @@ bool Engine::generateTone(const Tone &tone)
bool Engine::generateSweptTone(qreal amplitude)
{
+ Q_ASSERT(!m_generateTone);
Q_ASSERT(!m_file);
m_generateTone = true;
m_tone.startFreq = 1;
@@ -185,41 +190,18 @@ bool Engine::generateSweptTone(qreal amplitude)
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::bufferDuration() const
-{
- return BufferDurationUs;
-}
-
-qint64 Engine::dataDuration() const
+qint64 Engine::bufferLength() const
{
- qint64 result = 0;
- if (QAudioFormat() != m_format)
- result = audioDuration(m_format, m_dataLength);
- return result;
-}
-
-qint64 Engine::audioBufferLength() const
-{
- qint64 length = 0;
- if (QAudio::ActiveState == m_state || QAudio::IdleState == m_state) {
- Q_ASSERT(QAudioFormat() != m_format);
- switch (m_mode) {
- case QAudio::AudioInput:
- length = m_audioInput->bufferSize();
- break;
- case QAudio::AudioOutput:
- length = m_audioOutput->bufferSize();
- break;
- }
- }
- return length;
+ return m_file ? m_file->size() : m_bufferLength;
}
void Engine::setWindowFunction(WindowFunction type)
@@ -252,7 +234,7 @@ void Engine::startRecording()
this, SLOT(audioNotify()));
m_count = 0;
m_dataLength = 0;
- emit dataDurationChanged(0);
+ emit dataLengthChanged(0);
m_audioInputIODevice = m_audioInput->start();
CHECKED_CONNECT(m_audioInputIODevice, SIGNAL(readyRead()),
this, SLOT(audioDataReady()));
@@ -275,7 +257,6 @@ void Engine::startPlayback()
} else {
m_spectrumAnalyser.cancelCalculation();
spectrumChanged(0, 0, FrequencySpectrum());
-
setPlayPosition(0, true);
stopRecording();
m_mode = QAudio::AudioOutput;
@@ -284,10 +265,17 @@ void Engine::startPlayback()
CHECKED_CONNECT(m_audioOutput, SIGNAL(notify()),
this, SLOT(audioNotify()));
m_count = 0;
- m_audioOutputIODevice.close();
- m_audioOutputIODevice.setBuffer(&m_buffer);
- m_audioOutputIODevice.open(QIODevice::ReadOnly);
- m_audioOutput->start(&m_audioOutputIODevice);
+ 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);
+ }
}
}
}
@@ -332,40 +320,55 @@ void Engine::audioNotify()
{
switch (m_mode) {
case QAudio::AudioInput: {
- const qint64 recordPosition =
- qMin(BufferDurationUs, m_audioInput->processedUSecs());
+ const qint64 recordPosition = qMin(m_bufferLength, audioLength(m_format, m_audioInput->processedUSecs()));
setRecordPosition(recordPosition);
-
- // Calculate level of most recently captured data
- qint64 levelLength = audioLength(m_format, LevelWindowUs);
- levelLength = qMin(m_dataLength, levelLength);
- const qint64 levelPosition = m_dataLength - levelLength;
- calculateLevel(levelPosition, levelLength);
-
- // Calculate spectrum of most recently captured data
- if (m_dataLength >= m_spectrumLengthBytes) {
- const qint64 spectrumPosition = m_dataLength - m_spectrumLengthBytes;
+ 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 =
- qMin(dataDuration(), m_audioOutput->processedUSecs());
- setPlayPosition(playPosition);
-
- qint64 analysisPosition = audioLength(m_format, playPosition);
-
- // Calculate level of data starting at current playback position
- const qint64 levelLength = audioLength(m_format, LevelWindowUs);
- if (analysisPosition + levelLength < m_dataLength)
- calculateLevel(analysisPosition, levelLength);
-
- if (analysisPosition + m_spectrumLengthBytes < m_dataLength)
- calculateSpectrum(analysisPosition);
-
- if (dataDuration() == playPosition)
- stopPlayback();
+ 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;
}
@@ -376,27 +379,32 @@ void Engine::audioStateChanged(QAudio::State state)
ENGINE_DEBUG << "Engine::audioStateChanged from" << m_state
<< "to" << state;
- 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;
+ 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);
}
- 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);
@@ -407,9 +415,7 @@ void Engine::audioDataReady()
if (bytesRead) {
m_dataLength += bytesRead;
-
- const qint64 duration = audioDuration(m_format, m_dataLength);
- emit dataDurationChanged(duration);
+ emit dataLengthChanged(dataLength());
}
if (m_buffer.size() == m_dataLength)
@@ -419,9 +425,7 @@ void Engine::audioDataReady()
void Engine::spectrumChanged(const FrequencySpectrum &spectrum)
{
ENGINE_DEBUG << "Engine::spectrumChanged" << "pos" << m_spectrumPosition;
- const qint64 positionUs = audioDuration(m_format, m_spectrumPosition);
- const qint64 lengthUs = audioDuration(m_format, m_spectrumLengthBytes);
- emit spectrumChanged(positionUs, lengthUs, spectrum);
+ emit spectrumChanged(m_spectrumPosition, m_spectrumBufferLength, spectrum);
}
@@ -429,12 +433,8 @@ void Engine::spectrumChanged(const FrequencySpectrum &spectrum)
// Private functions
//-----------------------------------------------------------------------------
-void Engine::reset()
+void Engine::resetAudioDevices()
{
- stopRecording();
- stopPlayback();
- setState(QAudio::AudioInput, QAudio::StoppedState);
- setFormat(QAudioFormat());
delete m_audioInput;
m_audioInput = 0;
m_audioInputIODevice = 0;
@@ -442,55 +442,71 @@ void Engine::reset()
delete m_audioOutput;
m_audioOutput = 0;
setPlayPosition(0);
- m_buffer.clear();
- m_dataLength = 0;
m_spectrumPosition = 0;
- emit dataDurationChanged(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;
- reset();
+ QAudioFormat format = m_format;
if (selectFormat()) {
- const qint64 bufferLength = audioLength(m_format, BufferDurationUs);
- m_buffer.resize(bufferLength);
- m_buffer.fill(0);
- emit bufferDurationChanged(BufferDurationUs);
-
- 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_buffer.size();
- emit dataDurationChanged(bufferDuration());
- setRecordPosition(bufferDuration());
- result = true;
- } else if (m_file) {
- const qint64 length = m_wavFile.readData(*m_file, m_buffer, m_format);
- if (length) {
- m_dataLength = length;
- emit dataDurationChanged(dataDuration());
- setRecordPosition(dataDuration());
+ 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;
+ }
}
- } else {
- m_audioInput = new QAudioInput(m_audioInputDevice, m_format, this);
- m_audioInput->setNotifyInterval(NotifyIntervalMs);
- result = true;
+ m_audioOutput = new QAudioOutput(m_audioOutputDevice, m_format, this);
+ m_audioOutput->setNotifyInterval(NotifyIntervalMs);
}
-
- m_audioOutput = new QAudioOutput(m_audioOutputDevice, m_format, this);
- m_audioOutput->setNotifyInterval(NotifyIntervalMs);
- m_spectrumLengthBytes = SpectrumLengthSamples *
- (m_format.sampleSize() / 8) * m_format.channels();
} else {
if (m_file)
emit errorMessage(tr("Audio format not supported"),
@@ -501,6 +517,8 @@ bool Engine::initialize()
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;
@@ -510,21 +528,15 @@ bool Engine::selectFormat()
{
bool foundSupportedFormat = false;
- if (m_file) {
- // Header is read from the WAV file; just need to check whether
- // it is supported by the audio output device
- QAudioFormat format = m_wavFile.format();
- if (m_audioOutputDevice.isFormatSupported(m_wavFile.format())) {
- setFormat(m_wavFile.format());
+ 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 {
- // Try flipping mono <-> stereo
- const int channels = (format.channels() == 1) ? 2 : 1;
- format.setChannels(channels);
- if (m_audioOutputDevice.isFormatSupported(format)) {
- setFormat(format);
- foundSupportedFormat = true;
- }
}
} else {
@@ -648,12 +660,12 @@ void Engine::calculateLevel(qint64 position, qint64 length)
Q_UNUSED(position)
Q_UNUSED(length)
#else
- Q_ASSERT(position + length <= m_dataLength);
+ Q_ASSERT(position + length <= m_bufferPosition + m_dataLength);
qreal peakLevel = 0.0;
qreal sum = 0.0;
- const char *ptr = m_buffer.constData() + position;
+ 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);
@@ -679,18 +691,18 @@ void Engine::calculateSpectrum(qint64 position)
#ifdef DISABLE_SPECTRUM
Q_UNUSED(position)
#else
- Q_ASSERT(position + m_spectrumLengthBytes <= m_dataLength);
- Q_ASSERT(0 == m_spectrumLengthBytes % 2); // constraint of FFT algorithm
+ 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_spectrumLengthBytes
+ << "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_spectrumLengthBytes);
+ m_spectrumBuffer = QByteArray::fromRawData(m_buffer.constData() + position - m_bufferPosition,
+ m_spectrumBufferLength);
m_spectrumPosition = position;
m_spectrumAnalyser.calculate(m_spectrumBuffer, m_format);
}
@@ -701,6 +713,9 @@ 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);
}