Changeset 846 for trunk/demos/spectrum/app
- Timestamp:
- May 5, 2011, 5:36:53 AM (14 years ago)
- Location:
- trunk
- Files:
-
- 1 deleted
- 30 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
- Property svn:mergeinfo changed
/branches/vendor/nokia/qt/4.7.2 (added) merged: 845 /branches/vendor/nokia/qt/current merged: 844 /branches/vendor/nokia/qt/4.6.3 removed
- Property svn:mergeinfo changed
-
trunk/demos/spectrum/app/app.pro
r769 r846 1 1 include(../spectrum.pri) 2 3 static: error(This application cannot be statically linked to the fftreal library) 2 4 3 5 TEMPLATE = app 4 6 5 7 TARGET = spectrum 6 unix: !macx: !symbian: TARGET = spectrum.bin7 8 8 9 QT += multimedia … … 49 50 50 51 # Provide unique ID for the generated binary, required by Symbian OS 51 TARGET.UID3 = 0xA000E 3FA52 TARGET.UID3 = 0xA000E402 52 53 } 53 54 … … 58 59 # Must explicitly add the .dll suffix to ensure dynamic linkage 59 60 LIBS += -lfftreal.dll 61 QMAKE_LIBDIR += $${fftreal_dir} 60 62 } else { 61 63 macx { … … 64 66 LIBS += -framework fftreal 65 67 } else { 66 # Link to dynamic library which is written to ../bin 67 LIBS += -L../bin 68 LIBS += -L..$${spectrum_build_dir} 68 69 LIBS += -lfftreal 69 70 } … … 86 87 !contains(DEFINES, DISABLE_FFT) { 87 88 # Include FFTReal DLL in the SIS file 88 fftreal.sources = $${EPOCROOT}epoc32/release/$(PLATFORM)/$(TARGET)/fftreal.dll89 fftreal.sources = ../fftreal.dll 89 90 fftreal.path = !:/sys/bin 90 91 DEPLOYMENT += fftreal 91 92 } 92 93 } else { 94 DESTDIR = ..$${spectrum_build_dir} 93 95 macx { 94 # Specify directory in which to create spectrum.app bundle95 DESTDIR = ..96 97 96 !contains(DEFINES, DISABLE_FFT) { 98 97 # Relocate fftreal.framework into spectrum.app bundle … … 110 109 } 111 110 } else { 112 # Specify directory in which to create spectrum application 113 DESTDIR = ../bin 114 115 unix: !symbian { 116 # On unices other than Mac OSX, we copy a shell script into the bin directory. 117 # This script takes care of correctly setting the LD_LIBRARY_PATH so that 118 # the dynamic library can be located. 119 copy_launch_script.target = copy_launch_script 120 copy_launch_script.commands = \ 121 install -m 0555 $$QT_SOURCE_TREE/demos/spectrum/app/spectrum.sh ../bin/spectrum 122 QMAKE_EXTRA_TARGETS += copy_launch_script 123 POST_TARGETDEPS += copy_launch_script 111 linux-g++*: { 112 # Provide relative path from application to fftreal library 113 QMAKE_LFLAGS += -Wl,--rpath=\\\$\$ORIGIN 124 114 } 125 115 } -
trunk/demos/spectrum/app/engine.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 86 86 , m_generateTone(false) 87 87 , m_file(0) 88 , m_analysisFile(0) 88 89 , m_availableAudioInputDevices 89 90 (QAudioDeviceInfo::availableDevices(QAudio::AudioInput)) … … 97 98 , m_audioOutput(0) 98 99 , m_playPosition(0) 100 , m_bufferPosition(0) 101 , m_bufferLength(0) 99 102 , m_dataLength(0) 103 , m_levelBufferLength(0) 100 104 , m_rmsLevel(0.0) 101 105 , m_peakLevel(0.0) 102 , m_spectrum LengthBytes(0)106 , m_spectrumBufferLength(0) 103 107 , m_spectrumAnalyser() 104 108 , m_spectrumPosition(0) … … 106 110 { 107 111 qRegisterMetaType<FrequencySpectrum>("FrequencySpectrum"); 112 qRegisterMetaType<WindowFunction>("WindowFunction"); 108 113 CHECKED_CONNECT(&m_spectrumAnalyser, 109 114 SIGNAL(spectrumChanged(FrequencySpectrum)), … … 133 138 bool Engine::loadFile(const QString &fileName) 134 139 { 140 reset(); 135 141 bool result = false; 136 m_generateTone = false;137 142 Q_ASSERT(!m_generateTone); 143 Q_ASSERT(!m_file); 138 144 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())) { 145 m_file = new WavFile(this); 146 if (m_file->open(fileName)) { 147 if (isPCMS16LE(m_file->fileFormat())) { 146 148 result = initialize(); 147 149 } else { 148 150 emit errorMessage(tr("Audio format not supported"), 149 formatToString(m_ wavFile.format()));151 formatToString(m_file->fileFormat())); 150 152 } 151 153 } else { 152 154 emit errorMessage(tr("Could not open file"), fileName); 153 155 } 154 155 delete m_file;156 m_file = 0;157 156 if (result) { 157 m_analysisFile = new WavFile(this); 158 m_analysisFile->open(fileName); 159 } 158 160 return result; 159 161 } … … 161 163 bool Engine::generateTone(const Tone &tone) 162 164 { 165 reset(); 166 Q_ASSERT(!m_generateTone); 163 167 Q_ASSERT(!m_file); 164 168 m_generateTone = true; … … 173 177 bool Engine::generateSweptTone(qreal amplitude) 174 178 { 179 Q_ASSERT(!m_generateTone); 175 180 Q_ASSERT(!m_file); 176 181 m_generateTone = true; … … 186 191 bool Engine::initializeRecord() 187 192 { 193 reset(); 188 194 ENGINE_DEBUG << "Engine::initializeRecord"; 195 Q_ASSERT(!m_generateTone); 189 196 Q_ASSERT(!m_file); 190 197 m_generateTone = false; … … 193 200 } 194 201 195 qint64 Engine::bufferDuration() const 196 { 197 return BufferDurationUs; 198 } 199 200 qint64 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 208 qint64 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; 202 qint64 Engine::bufferLength() const 203 { 204 return m_file ? m_file->size() : m_bufferLength; 223 205 } 224 206 … … 253 235 m_count = 0; 254 236 m_dataLength = 0; 255 emit data DurationChanged(0);237 emit dataLengthChanged(0); 256 238 m_audioInputIODevice = m_audioInput->start(); 257 239 CHECKED_CONNECT(m_audioInputIODevice, SIGNAL(readyRead()), … … 276 258 m_spectrumAnalyser.cancelCalculation(); 277 259 spectrumChanged(0, 0, FrequencySpectrum()); 278 279 260 setPlayPosition(0, true); 280 261 stopRecording(); … … 285 266 this, SLOT(audioNotify())); 286 267 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); 268 if (m_file) { 269 m_file->seek(0); 270 m_bufferPosition = 0; 271 m_dataLength = 0; 272 m_audioOutput->start(m_file); 273 } else { 274 m_audioOutputIODevice.close(); 275 m_audioOutputIODevice.setBuffer(&m_buffer); 276 m_audioOutputIODevice.open(QIODevice::ReadOnly); 277 m_audioOutput->start(&m_audioOutputIODevice); 278 } 291 279 } 292 280 } … … 333 321 switch (m_mode) { 334 322 case QAudio::AudioInput: { 335 const qint64 recordPosition = 336 qMin(BufferDurationUs, m_audioInput->processedUSecs()); 323 const qint64 recordPosition = qMin(m_bufferLength, audioLength(m_format, m_audioInput->processedUSecs())); 337 324 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; 325 const qint64 levelPosition = m_dataLength - m_levelBufferLength; 326 if (levelPosition >= 0) 327 calculateLevel(levelPosition, m_levelBufferLength); 328 if (m_dataLength >= m_spectrumBufferLength) { 329 const qint64 spectrumPosition = m_dataLength - m_spectrumBufferLength; 348 330 calculateSpectrum(spectrumPosition); 349 331 } 332 emit bufferChanged(0, m_dataLength, m_buffer); 350 333 } 351 334 break; 352 335 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(); 336 const qint64 playPosition = audioLength(m_format, m_audioOutput->processedUSecs()); 337 setPlayPosition(qMin(bufferLength(), playPosition)); 338 const qint64 levelPosition = playPosition - m_levelBufferLength; 339 const qint64 spectrumPosition = playPosition - m_spectrumBufferLength; 340 if (m_file) { 341 if (levelPosition > m_bufferPosition || 342 spectrumPosition > m_bufferPosition || 343 qMax(m_levelBufferLength, m_spectrumBufferLength) > m_dataLength) { 344 m_bufferPosition = 0; 345 m_dataLength = 0; 346 // Data needs to be read into m_buffer in order to be analysed 347 const qint64 readPos = qMax(qint64(0), qMin(levelPosition, spectrumPosition)); 348 const qint64 readEnd = qMin(m_analysisFile->size(), qMax(levelPosition + m_levelBufferLength, spectrumPosition + m_spectrumBufferLength)); 349 const qint64 readLen = readEnd - readPos + audioLength(m_format, WaveformWindowDuration); 350 qDebug() << "Engine::audioNotify [1]" 351 << "analysisFileSize" << m_analysisFile->size() 352 << "readPos" << readPos 353 << "readLen" << readLen; 354 if (m_analysisFile->seek(readPos + m_analysisFile->headerLength())) { 355 m_buffer.resize(readLen); 356 m_bufferPosition = readPos; 357 m_dataLength = m_analysisFile->read(m_buffer.data(), readLen); 358 qDebug() << "Engine::audioNotify [2]" << "bufferPosition" << m_bufferPosition << "dataLength" << m_dataLength; 359 } else { 360 qDebug() << "Engine::audioNotify [2]" << "file seek error"; 361 } 362 emit bufferChanged(m_bufferPosition, m_dataLength, m_buffer); 363 } 364 } else { 365 if (playPosition >= m_dataLength) 366 stopPlayback(); 367 } 368 if (levelPosition >= 0 && levelPosition + m_levelBufferLength < m_bufferPosition + m_dataLength) 369 calculateLevel(levelPosition, m_levelBufferLength); 370 if (spectrumPosition >= 0 && spectrumPosition + m_spectrumBufferLength < m_bufferPosition + m_dataLength) 371 calculateSpectrum(spectrumPosition); 369 372 } 370 373 break; … … 377 380 << "to" << state; 378 381 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); 382 if (QAudio::IdleState == state && m_file && m_file->pos() == m_file->size()) { 383 stopPlayback(); 384 } else { 385 if (QAudio::StoppedState == state) { 386 // Check error 387 QAudio::Error error = QAudio::NoError; 388 switch (m_mode) { 389 case QAudio::AudioInput: 390 error = m_audioInput->error(); 391 break; 392 case QAudio::AudioOutput: 393 error = m_audioOutput->error(); 394 break; 395 } 396 if (QAudio::NoError != error) { 397 reset(); 398 return; 399 } 400 } 401 setState(state); 402 } 396 403 } 397 404 398 405 void Engine::audioDataReady() 399 406 { 407 Q_ASSERT(0 == m_bufferPosition); 400 408 const qint64 bytesReady = m_audioInput->bytesReady(); 401 409 const qint64 bytesSpace = m_buffer.size() - m_dataLength; … … 408 416 if (bytesRead) { 409 417 m_dataLength += bytesRead; 410 411 const qint64 duration = audioDuration(m_format, m_dataLength); 412 emit dataDurationChanged(duration); 418 emit dataLengthChanged(dataLength()); 413 419 } 414 420 … … 420 426 { 421 427 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); 428 emit spectrumChanged(m_spectrumPosition, m_spectrumBufferLength, spectrum); 425 429 } 426 430 … … 430 434 //----------------------------------------------------------------------------- 431 435 432 void Engine::reset() 433 { 434 stopRecording(); 435 stopPlayback(); 436 setState(QAudio::AudioInput, QAudio::StoppedState); 437 setFormat(QAudioFormat()); 436 void Engine::resetAudioDevices() 437 { 438 438 delete m_audioInput; 439 439 m_audioInput = 0; … … 443 443 m_audioOutput = 0; 444 444 setPlayPosition(0); 445 m_spectrumPosition = 0; 446 setLevel(0.0, 0.0, 0); 447 } 448 449 void Engine::reset() 450 { 451 stopRecording(); 452 stopPlayback(); 453 setState(QAudio::AudioInput, QAudio::StoppedState); 454 setFormat(QAudioFormat()); 455 m_generateTone = false; 456 delete m_file; 457 m_file = 0; 458 delete m_analysisFile; 459 m_analysisFile = 0; 445 460 m_buffer.clear(); 461 m_bufferPosition = 0; 462 m_bufferLength = 0; 446 463 m_dataLength = 0; 447 m_spectrumPosition = 0; 448 emit dataDurationChanged(0); 449 setLevel(0.0, 0.0, 0); 464 emit dataLengthChanged(0); 465 resetAudioDevices(); 450 466 } 451 467 … … 454 470 bool result = false; 455 471 456 reset();472 QAudioFormat format = m_format; 457 473 458 474 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); 475 if (m_format != format) { 476 resetAudioDevices(); 477 if (m_file) { 478 emit bufferLengthChanged(bufferLength()); 479 emit dataLengthChanged(dataLength()); 480 emit bufferChanged(0, 0, m_buffer); 481 setRecordPosition(bufferLength()); 482 result = true; 483 } else { 484 m_bufferLength = audioLength(m_format, BufferDurationUs); 485 m_buffer.resize(m_bufferLength); 486 m_buffer.fill(0); 487 emit bufferLengthChanged(bufferLength()); 488 if (m_generateTone) { 489 if (0 == m_tone.endFreq) { 490 const qreal nyquist = nyquistFrequency(m_format); 491 m_tone.endFreq = qMin(qreal(SpectrumHighFreq), nyquist); 492 } 493 // Call function defined in utils.h, at global scope 494 ::generateTone(m_tone, m_format, m_buffer); 495 m_dataLength = m_bufferLength; 496 emit dataLengthChanged(dataLength()); 497 emit bufferChanged(0, m_dataLength, m_buffer); 498 setRecordPosition(m_bufferLength); 499 result = true; 500 } else { 501 emit bufferChanged(0, 0, m_buffer); 502 m_audioInput = new QAudioInput(m_audioInputDevice, m_format, this); 503 m_audioInput->setNotifyInterval(NotifyIntervalMs); 504 result = true; 505 } 468 506 } 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(); 507 m_audioOutput = new QAudioOutput(m_audioOutputDevice, m_format, this); 508 m_audioOutput->setNotifyInterval(NotifyIntervalMs); 509 } 494 510 } else { 495 511 if (m_file) … … 502 518 } 503 519 520 ENGINE_DEBUG << "Engine::initialize" << "m_bufferLength" << m_bufferLength; 521 ENGINE_DEBUG << "Engine::initialize" << "m_dataLength" << m_dataLength; 504 522 ENGINE_DEBUG << "Engine::initialize" << "format" << m_format; 505 523 … … 511 529 bool foundSupportedFormat = false; 512 530 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()); 531 if (m_file || QAudioFormat() != m_format) { 532 QAudioFormat format = m_format; 533 if (m_file) 534 // Header is read from the WAV file; just need to check whether 535 // it is supported by the audio output device 536 format = m_file->fileFormat(); 537 if (m_audioOutputDevice.isFormatSupported(format)) { 538 setFormat(format); 519 539 foundSupportedFormat = true; 520 } else {521 // Try flipping mono <-> stereo522 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 540 } 529 541 } else { … … 649 661 Q_UNUSED(length) 650 662 #else 651 Q_ASSERT(position + length <= m_ dataLength);663 Q_ASSERT(position + length <= m_bufferPosition + m_dataLength); 652 664 653 665 qreal peakLevel = 0.0; 654 666 655 667 qreal sum = 0.0; 656 const char *ptr = m_buffer.constData() + position ;668 const char *ptr = m_buffer.constData() + position - m_bufferPosition; 657 669 const char *const end = ptr + length; 658 670 while (ptr < end) { … … 680 692 Q_UNUSED(position) 681 693 #else 682 Q_ASSERT(position + m_spectrum LengthBytes <=m_dataLength);683 Q_ASSERT(0 == m_spectrum LengthBytes% 2); // constraint of FFT algorithm694 Q_ASSERT(position + m_spectrumBufferLength <= m_bufferPosition + m_dataLength); 695 Q_ASSERT(0 == m_spectrumBufferLength % 2); // constraint of FFT algorithm 684 696 685 697 // QThread::currentThread is marked 'for internal use only', but 686 698 // we're only using it for debug output here, so it's probably OK :) 687 699 ENGINE_DEBUG << "Engine::calculateSpectrum" << QThread::currentThread() 688 << "count" << m_count << "pos" << position << "len" << m_spectrum LengthBytes700 << "count" << m_count << "pos" << position << "len" << m_spectrumBufferLength 689 701 << "spectrumAnalyser.isReady" << m_spectrumAnalyser.isReady(); 690 702 691 703 if(m_spectrumAnalyser.isReady()) { 692 m_spectrumBuffer = QByteArray::fromRawData(m_buffer.constData() + position ,693 m_spectrum LengthBytes);704 m_spectrumBuffer = QByteArray::fromRawData(m_buffer.constData() + position - m_bufferPosition, 705 m_spectrumBufferLength); 694 706 m_spectrumPosition = position; 695 707 m_spectrumAnalyser.calculate(m_spectrumBuffer, m_format); … … 702 714 const bool changed = (format != m_format); 703 715 m_format = format; 716 m_levelBufferLength = audioLength(m_format, LevelWindowUs); 717 m_spectrumBufferLength = SpectrumLengthSamples * 718 (m_format.sampleSize() / 8) * m_format.channels(); 704 719 if (changed) 705 720 emit formatChanged(m_format); -
trunk/demos/spectrum/app/engine.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 66 66 67 67 class FrequencySpectrum; 68 69 68 QT_FORWARD_DECLARE_CLASS(QAudioInput) 70 69 QT_FORWARD_DECLARE_CLASS(QAudioOutput) … … 93 92 94 93 /** 95 * \return Reference to internal audio buffer96 * \note This reference is valid for the lifetime of the Engine97 */98 const QByteArray& buffer() const { return m_buffer; }99 100 /**101 94 * \return Current audio format 102 95 * \note May be QAudioFormat() if engine is not initialized … … 131 124 /** 132 125 * Position of the audio input device. 133 * \return Position in microseconds.126 * \return Position in bytes. 134 127 */ 135 128 qint64 recordPosition() const { return m_recordPosition; } … … 149 142 /** 150 143 * Position of the audio output device. 151 * \return Position in microseconds.144 * \return Position in bytes. 152 145 */ 153 146 qint64 playPosition() const { return m_playPosition; } … … 155 148 /** 156 149 * Length of the internal engine buffer. 157 * \return Buffer length in microseconds.158 */ 159 qint64 buffer Duration() const;150 * \return Buffer length in bytes. 151 */ 152 qint64 bufferLength() const; 160 153 161 154 /** 162 155 * Amount of data held in the buffer. 163 * \return Data duration in microseconds. 164 */ 165 qint64 dataDuration() const; 166 167 /** 168 * Returns the size of the underlying audio buffer in bytes. 169 * This should be an approximation of the capture latency. 170 */ 171 qint64 audioBufferLength() const; 156 * \return Data length in bytes. 157 */ 158 qint64 dataLength() const { return m_dataLength; } 172 159 173 160 /** … … 205 192 * \param duration Duration in microseconds 206 193 */ 207 void buffer DurationChanged(qint64 duration);194 void bufferLengthChanged(qint64 duration); 208 195 209 196 /** 210 197 * Amount of data in buffer has changed. 211 * \param duration Duration of data in microseconds212 */ 213 void data DurationChanged(qint64 duration);198 * \param Length of data in bytes 199 */ 200 void dataLengthChanged(qint64 duration); 214 201 215 202 /** 216 203 * Position of the audio input device has changed. 217 * \param position Position in microseconds204 * \param position Position in bytes 218 205 */ 219 206 void recordPositionChanged(qint64 position); … … 221 208 /** 222 209 * Position of the audio output device has changed. 223 * \param position Position in microseconds210 * \param position Position in bytes 224 211 */ 225 212 void playPositionChanged(qint64 position); … … 229 216 * \param rmsLevel RMS level in range 0.0 - 1.0 230 217 * \param peakLevel Peak level in range 0.0 - 1.0 231 * \param numSamples Number of audio samples analy sed218 * \param numSamples Number of audio samples analyzed 232 219 */ 233 220 void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples); … … 235 222 /** 236 223 * Spectrum has changed. 237 * \param position Position of start of window in microseconds238 * \param length Length of window in microseconds224 * \param position Position of start of window in bytes 225 * \param length Length of window in bytes 239 226 * \param spectrum Resulting frequency spectrum 240 227 */ 241 228 void spectrumChanged(qint64 position, qint64 length, const FrequencySpectrum &spectrum); 229 230 /** 231 * Buffer containing audio data has changed. 232 * \param position Position of start of buffer in bytes 233 * \param buffer Buffer 234 */ 235 void bufferChanged(qint64 position, qint64 length, const QByteArray &buffer); 242 236 243 237 private slots: … … 248 242 249 243 private: 244 void resetAudioDevices(); 250 245 bool initialize(); 251 246 bool selectFormat(); … … 277 272 SweptTone m_tone; 278 273 279 QFile* m_file; 280 WavFile m_wavFile; 274 WavFile* m_file; 275 // We need a second file handle via which to read data into m_buffer 276 // for analysis 277 WavFile* m_analysisFile; 281 278 282 279 QAudioFormat m_format; … … 295 292 296 293 QByteArray m_buffer; 294 qint64 m_bufferPosition; 295 qint64 m_bufferLength; 297 296 qint64 m_dataLength; 298 297 298 int m_levelBufferLength; 299 299 qreal m_rmsLevel; 300 300 qreal m_peakLevel; 301 301 302 int m_spectrum LengthBytes;302 int m_spectrumBufferLength; 303 303 QByteArray m_spectrumBuffer; 304 304 SpectrumAnalyser m_spectrumAnalyser; -
trunk/demos/spectrum/app/frequencyspectrum.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/frequencyspectrum.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/levelmeter.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/levelmeter.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 47 47 /** 48 48 * Widget which displays a vertical audio level meter, indicating the 49 * RMS and peak levels of the window of audio samples most recently analy sed49 * RMS and peak levels of the window of audio samples most recently analyzed 50 50 * by the Engine. 51 51 */ -
trunk/demos/spectrum/app/main.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 45 45 { 46 46 QApplication app(argc, argv); 47 app.setApplicationName("QtMultimedia spectrum analy ser");47 app.setApplicationName("QtMultimedia spectrum analyzer"); 48 48 MainWidget w; 49 49 -
trunk/demos/spectrum/app/mainwidget.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 66 66 , m_engine(new Engine(this)) 67 67 #ifndef DISABLE_WAVEFORM 68 , m_waveform(new Waveform( m_engine->buffer(),this))68 , m_waveform(new Waveform(this)) 69 69 #endif 70 70 , m_progressBar(new ProgressBar(this)) … … 167 167 } 168 168 169 void MainWidget::positionChanged(qint64 positionUs) 170 { 171 #ifndef DISABLE_WAVEFORM 172 qint64 positionBytes = audioLength(m_engine->format(), positionUs); 173 m_waveform->positionChanged(positionBytes); 169 void MainWidget::audioPositionChanged(qint64 position) 170 { 171 #ifndef DISABLE_WAVEFORM 172 m_waveform->audioPositionChanged(position); 174 173 #else 175 Q_UNUSED(position Us)176 #endif 177 } 178 179 void MainWidget::buffer DurationChanged(qint64 durationUs)180 { 181 m_progressBar->buffer DurationChanged(durationUs);174 Q_UNUSED(position) 175 #endif 176 } 177 178 void MainWidget::bufferLengthChanged(qint64 length) 179 { 180 m_progressBar->bufferLengthChanged(length); 182 181 } 183 182 … … 187 186 //----------------------------------------------------------------------------- 188 187 189 void MainWidget::dataDurationChanged(qint64 duration)190 {191 #ifndef DISABLE_WAVEFORM192 const qint64 dataLength = audioLength(m_engine->format(), duration);193 m_waveform->dataLengthChanged(dataLength);194 #else195 Q_UNUSED(duration)196 #endif197 198 updateButtonStates();199 }200 201 188 void MainWidget::showFileDialog() 202 189 { 203 reset();204 190 const QString dir; 205 191 const QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open WAV file"), dir, "*.wav"); 206 192 if (fileNames.count()) { 193 reset(); 207 194 setMode(LoadFileMode); 208 195 m_engine->loadFile(fileNames.front()); 209 196 updateButtonStates(); 197 } else { 198 updateModeMenu(); 210 199 } 211 200 } … … 213 202 void MainWidget::showSettingsDialog() 214 203 { 215 reset();216 204 m_settingsDialog->exec(); 217 205 if (m_settingsDialog->result() == QDialog::Accepted) { … … 224 212 void MainWidget::showToneGeneratorDialog() 225 213 { 226 reset();227 214 m_toneGeneratorDialog->exec(); 228 215 if (m_toneGeneratorDialog->result() == QDialog::Accepted) { 216 reset(); 229 217 setMode(GenerateToneMode); 230 218 const qreal amplitude = m_toneGeneratorDialog->amplitude(); … … 237 225 updateButtonStates(); 238 226 } 227 } else { 228 updateModeMenu(); 239 229 } 240 230 } … … 361 351 this, SLOT(formatChanged(const QAudioFormat &))); 362 352 363 m_progressBar->buffer DurationChanged(m_engine->bufferDuration());364 365 CHECKED_CONNECT(m_engine, SIGNAL(buffer DurationChanged(qint64)),366 this, SLOT(buffer DurationChanged(qint64)));367 368 CHECKED_CONNECT(m_engine, SIGNAL(data DurationChanged(qint64)),369 this, SLOT( dataDurationChanged(qint64)));353 m_progressBar->bufferLengthChanged(m_engine->bufferLength()); 354 355 CHECKED_CONNECT(m_engine, SIGNAL(bufferLengthChanged(qint64)), 356 this, SLOT(bufferLengthChanged(qint64))); 357 358 CHECKED_CONNECT(m_engine, SIGNAL(dataLengthChanged(qint64)), 359 this, SLOT(updateButtonStates())); 370 360 371 361 CHECKED_CONNECT(m_engine, SIGNAL(recordPositionChanged(qint64)), … … 376 366 377 367 CHECKED_CONNECT(m_engine, SIGNAL(recordPositionChanged(qint64)), 378 this, SLOT( positionChanged(qint64)));368 this, SLOT(audioPositionChanged(qint64))); 379 369 380 370 CHECKED_CONNECT(m_engine, SIGNAL(playPositionChanged(qint64)), 381 this, SLOT( positionChanged(qint64)));371 this, SLOT(audioPositionChanged(qint64))); 382 372 383 373 CHECKED_CONNECT(m_engine, SIGNAL(levelChanged(qreal, qreal, int)), … … 395 385 CHECKED_CONNECT(m_spectrograph, SIGNAL(infoMessage(QString, int)), 396 386 this, SLOT(infoMessage(QString, int))); 387 388 #ifndef DISABLE_WAVEFORM 389 CHECKED_CONNECT(m_engine, SIGNAL(bufferChanged(qint64, qint64, const QByteArray &)), 390 m_waveform, SLOT(bufferChanged(qint64, qint64, const QByteArray &))); 391 #endif 397 392 } 398 393 … … 426 421 m_pauseButton->setEnabled(pauseEnabled); 427 422 428 const bool playEnabled = ( m_engine->dataDuration() &&423 const bool playEnabled = (/*m_engine->dataLength() &&*/ 429 424 (QAudio::AudioOutput != m_engine->mode() || 430 425 (QAudio::ActiveState != m_engine->state() && … … 446 441 void MainWidget::setMode(Mode mode) 447 442 { 448 449 443 m_mode = mode; 450 m_loadFileAction->setChecked(LoadFileMode == mode); 451 m_generateToneAction->setChecked(GenerateToneMode == mode); 452 m_recordAction->setChecked(RecordMode == mode); 453 } 454 444 updateModeMenu(); 445 } 446 447 void MainWidget::updateModeMenu() 448 { 449 m_loadFileAction->setChecked(LoadFileMode == m_mode); 450 m_generateToneAction->setChecked(GenerateToneMode == m_mode); 451 m_recordAction->setChecked(RecordMode == m_mode); 452 } 453 -
trunk/demos/spectrum/app/mainwidget.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 81 81 void infoMessage(const QString &message, int timeoutMs); 82 82 void errorMessage(const QString &heading, const QString &detail); 83 void positionChanged(qint64 position);84 void buffer DurationChanged(qint64 duration);83 void audioPositionChanged(qint64 position); 84 void bufferLengthChanged(qint64 length); 85 85 86 86 private slots: … … 89 89 void showToneGeneratorDialog(); 90 90 void initializeRecord(); 91 void dataDurationChanged(qint64 duration); 91 void updateModeMenu(); 92 void updateButtonStates(); 92 93 93 94 private: … … 95 96 void createMenus(); 96 97 void connectUi(); 97 void updateButtonStates();98 98 void reset(); 99 99 … … 112 112 Engine* m_engine; 113 113 114 #ifndef DISABLE_WAVEFORM 114 115 Waveform* m_waveform; 116 #endif 115 117 ProgressBar* m_progressBar; 116 118 Spectrograph* m_spectrograph; -
trunk/demos/spectrum/app/progressbar.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 45 45 ProgressBar::ProgressBar(QWidget *parent) 46 46 : QWidget(parent) 47 , m_buffer Duration(0)47 , m_bufferLength(0) 48 48 , m_recordPosition(0) 49 49 , m_playPosition(0) … … 65 65 void ProgressBar::reset() 66 66 { 67 m_buffer Duration= 0;67 m_bufferLength = 0; 68 68 m_recordPosition = 0; 69 69 m_playPosition = 0; … … 87 87 #endif 88 88 89 if (m_buffer Duration) {89 if (m_bufferLength) { 90 90 QRect bar = rect(); 91 const qreal play = qreal(m_playPosition) / m_buffer Duration;91 const qreal play = qreal(m_playPosition) / m_bufferLength; 92 92 bar.setLeft(rect().left() + play * rect().width()); 93 const qreal record = qreal(m_recordPosition) / m_buffer Duration;93 const qreal record = qreal(m_recordPosition) / m_bufferLength; 94 94 bar.setRight(rect().left() + record * rect().width()); 95 95 painter.fillRect(bar, bufferColor); 96 96 97 97 QRect window = rect(); 98 const qreal windowLeft = qreal(m_windowPosition) / m_buffer Duration;98 const qreal windowLeft = qreal(m_windowPosition) / m_bufferLength; 99 99 window.setLeft(rect().left() + windowLeft * rect().width()); 100 const qreal windowWidth = qreal(m_windowLength) / m_buffer Duration;100 const qreal windowWidth = qreal(m_windowLength) / m_bufferLength; 101 101 window.setWidth(windowWidth * rect().width()); 102 102 painter.fillRect(window, windowColor); … … 104 104 } 105 105 106 void ProgressBar::buffer DurationChanged(qint64 bufferSize)106 void ProgressBar::bufferLengthChanged(qint64 bufferSize) 107 107 { 108 m_buffer Duration= bufferSize;108 m_bufferLength = bufferSize; 109 109 m_recordPosition = 0; 110 110 m_playPosition = 0; … … 117 117 { 118 118 Q_ASSERT(recordPosition >= 0); 119 Q_ASSERT(recordPosition <= m_buffer Duration);119 Q_ASSERT(recordPosition <= m_bufferLength); 120 120 m_recordPosition = recordPosition; 121 121 repaint(); … … 125 125 { 126 126 Q_ASSERT(playPosition >= 0); 127 Q_ASSERT(playPosition <= m_buffer Duration);127 Q_ASSERT(playPosition <= m_bufferLength); 128 128 m_playPosition = playPosition; 129 129 repaint(); … … 133 133 { 134 134 Q_ASSERT(position >= 0); 135 Q_ASSERT(position <= m_buffer Duration);136 Q_ASSERT(position + length <= m_buffer Duration);135 Q_ASSERT(position <= m_bufferLength); 136 Q_ASSERT(position + length <= m_bufferLength); 137 137 m_windowPosition = position; 138 138 m_windowLength = length; -
trunk/demos/spectrum/app/progressbar.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 58 58 59 59 public slots: 60 void buffer DurationChanged(qint64 bufferSize);60 void bufferLengthChanged(qint64 length); 61 61 void recordPositionChanged(qint64 recordPosition); 62 62 void playPositionChanged(qint64 playPosition); … … 64 64 65 65 private: 66 qint64 m_buffer Duration;66 qint64 m_bufferLength; 67 67 qint64 m_recordPosition; 68 68 qint64 m_playPosition; -
trunk/demos/spectrum/app/settingsdialog.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/settingsdialog.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/spectrograph.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/spectrograph.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 49 49 /** 50 50 * Widget which displays a spectrograph showing the frequency spectrum 51 * of the window of audio samples most recently analy sed by the Engine.51 * of the window of audio samples most recently analyzed by the Engine. 52 52 */ 53 53 class Spectrograph : public QWidget { -
trunk/demos/spectrum/app/spectrum.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/spectrumanalyser.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 65 65 { 66 66 #ifdef SPECTRUM_ANALYSER_SEPARATE_THREAD 67 // moveToThread() cannot be called on a QObject with a parent 68 setParent(0); 67 69 moveToThread(m_thread); 68 70 m_thread->start(); … … 125 127 m_fft->calculateFFT(m_output.data(), m_input.data()); 126 128 127 // Analy se output to obtain amplitude and phase for each frequency129 // Analyze output to obtain amplitude and phase for each frequency 128 130 for (int i=2; i<=m_numSamples/2; ++i) { 129 131 // Calculate frequency of this complex sample -
trunk/demos/spectrum/app/spectrumanalyser.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/tonegenerator.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/tonegenerator.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/tonegeneratordialog.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/tonegeneratordialog.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/utils.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 50 50 qint64 audioLength(const QAudioFormat &format, qint64 microSeconds) 51 51 { 52 return(format.frequency() * format.channels() * (format.sampleSize() / 8))52 qint64 result = (format.frequency() * format.channels() * (format.sampleSize() / 8)) 53 53 * microSeconds / 1000000; 54 result -= result % (format.channelCount() * format.sampleSize()); 55 return result; 54 56 } 55 57 -
trunk/demos/spectrum/app/utils.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) -
trunk/demos/spectrum/app/waveform.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 45 45 #include <QDebug> 46 46 47 48 Waveform::Waveform(const QByteArray &buffer, QWidget *parent) 47 //#define PAINT_EVENT_TRACE 48 #ifdef PAINT_EVENT_TRACE 49 # define WAVEFORM_PAINT_DEBUG qDebug() 50 #else 51 # define WAVEFORM_PAINT_DEBUG nullDebug() 52 #endif 53 54 Waveform::Waveform(QWidget *parent) 49 55 : QWidget(parent) 50 , m_buffer (buffer)51 , m_ dataLength(0)52 , m_ position(0)56 , m_bufferPosition(0) 57 , m_bufferLength(0) 58 , m_audioPosition(0) 53 59 , m_active(false) 54 60 , m_tileLength(0) … … 73 79 74 80 if (m_active) { 75 WAVEFORM_ DEBUG << "Waveform::paintEvent"76 << "windowPosition" << m_windowPosition77 << "windowLength" << m_windowLength;81 WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" 82 << "windowPosition" << m_windowPosition 83 << "windowLength" << m_windowLength; 78 84 qint64 pos = m_windowPosition; 79 85 const qint64 windowEnd = m_windowPosition + m_windowLength; … … 82 88 while (pos < windowEnd) { 83 89 const TilePoint point = tilePoint(pos); 84 WAVEFORM_ DEBUG << "Waveform::paintEvent" << "pos" << pos85 << "tileIndex" << point.index86 << "positionOffset" << point.positionOffset87 << "pixelOffset" << point.pixelOffset;90 WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "pos" << pos 91 << "tileIndex" << point.index 92 << "positionOffset" << point.positionOffset 93 << "pixelOffset" << point.pixelOffset; 88 94 89 95 if (point.index != NullIndex) { … … 105 111 sourceRect.setRight(sourceRight); 106 112 107 WAVEFORM_ DEBUG << "Waveform::paintEvent" << "tileIndex" << point.index108 << "source" << point.pixelOffset << sourceRight109 << "dest" << destLeft << destRight;113 WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "tileIndex" << point.index 114 << "source" << point.pixelOffset << sourceRight 115 << "dest" << destLeft << destRight; 110 116 111 117 painter.drawPixmap(destRect, *tile.pixmap, sourceRect); … … 115 121 if (point.index < m_tiles.count()) { 116 122 pos = tilePosition(point.index + 1); 117 WAVEFORM_ DEBUG << "Waveform::paintEvent" << "pos ->" << pos;123 WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "pos ->" << pos; 118 124 } else { 119 125 // Reached end of tile array 120 WAVEFORM_ DEBUG << "Waveform::paintEvent" << "reached end of tile array";126 WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "reached end of tile array"; 121 127 break; 122 128 } 123 129 } else { 124 130 // Passed last tile which is painted 125 WAVEFORM_ DEBUG << "Waveform::paintEvent" << "tile" << point.index << "not painted";131 WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "tile" << point.index << "not painted"; 126 132 break; 127 133 } 128 134 } else { 129 135 // pos is past end of tile array 130 WAVEFORM_ DEBUG << "Waveform::paintEvent" << "pos" << pos << "past end of tile array";136 WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "pos" << pos << "past end of tile array"; 131 137 break; 132 138 } 133 139 } 134 140 135 WAVEFORM_ DEBUG << "Waveform::paintEvent" << "final pos" << pos << "final x" << destRight;141 WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "final pos" << pos << "final x" << destRight; 136 142 } 137 143 } … … 147 153 WAVEFORM_DEBUG << "Waveform::initialize" 148 154 << "audioBufferSize" << audioBufferSize 149 << "m_buffer.size()" << m_buffer.size()150 155 << "windowDurationUs" << windowDurationUs; 151 156 … … 187 192 WAVEFORM_DEBUG << "Waveform::reset"; 188 193 189 m_dataLength = 0; 190 m_position = 0; 194 m_bufferPosition = 0; 195 m_buffer = QByteArray(); 196 m_audioPosition = 0; 191 197 m_format = QAudioFormat(); 192 198 m_active = false; … … 199 205 } 200 206 201 void Waveform::dataLengthChanged(qint64 length) 202 { 203 WAVEFORM_DEBUG << "Waveform::dataLengthChanged" << length; 204 const qint64 oldLength = m_dataLength; 205 m_dataLength = length; 206 207 if (m_active) { 208 if (m_dataLength < oldLength) 209 positionChanged(m_dataLength); 210 else 211 paintTiles(); 212 } 213 } 214 215 void Waveform::positionChanged(qint64 position) 216 { 217 WAVEFORM_DEBUG << "Waveform::positionChanged" << position; 218 219 if (position + m_windowLength > m_dataLength) 220 position = m_dataLength - m_windowLength; 221 222 m_position = position; 223 224 setWindowPosition(position); 207 void Waveform::bufferChanged(qint64 position, qint64 length, const QByteArray &buffer) 208 { 209 WAVEFORM_DEBUG << "Waveform::bufferChanged" 210 << "audioPosition" << m_audioPosition 211 << "bufferPosition" << position 212 << "bufferLength" << length; 213 m_bufferPosition = position; 214 m_bufferLength = length; 215 m_buffer = buffer; 216 paintTiles(); 217 } 218 219 void Waveform::audioPositionChanged(qint64 position) 220 { 221 WAVEFORM_DEBUG << "Waveform::audioPositionChanged" 222 << "audioPosition" << position 223 << "bufferPosition" << m_bufferPosition 224 << "bufferLength" << m_bufferLength; 225 226 if (position >= m_bufferPosition) { 227 if (position + m_windowLength > m_bufferPosition + m_bufferLength) 228 position = qMax(qint64(0), m_bufferPosition + m_bufferLength - m_windowLength); 229 m_audioPosition = position; 230 setWindowPosition(position); 231 } 225 232 } 226 233 … … 256 263 m_tiles[i].painted = false; 257 264 } 258 259 paintTiles();260 265 } 261 266 … … 328 333 const Tile &tile = m_tiles[i]; 329 334 if (!tile.painted) { 330 const qint64 tileEnd = m_tileArrayStart + (i + 1) * m_tileLength; 331 if (m_dataLength >= tileEnd) { 335 const qint64 tileStart = m_tileArrayStart + i * m_tileLength; 336 const qint64 tileEnd = tileStart + m_tileLength; 337 if (m_bufferPosition <= tileStart && m_bufferPosition + m_bufferLength >= tileEnd) { 332 338 paintTile(i); 333 339 updateRequired = true; … … 344 350 void Waveform::paintTile(int index) 345 351 { 346 WAVEFORM_DEBUG << "Waveform::paintTile" << "index" << index;347 348 352 const qint64 tileStart = m_tileArrayStart + index * m_tileLength; 349 Q_ASSERT(m_dataLength >= tileStart + m_tileLength); 353 354 WAVEFORM_DEBUG << "Waveform::paintTile" 355 << "index" << index 356 << "bufferPosition" << m_bufferPosition 357 << "bufferLength" << m_bufferLength 358 << "start" << tileStart 359 << "end" << tileStart + m_tileLength; 360 361 Q_ASSERT(m_bufferPosition <= tileStart); 362 Q_ASSERT(m_bufferPosition + m_bufferLength >= tileStart + m_tileLength); 350 363 351 364 Tile &tile = m_tiles[index]; … … 353 366 354 367 const qint16* base = reinterpret_cast<const qint16*>(m_buffer.constData()); 355 const qint16* buffer = base + ( tileStart/ 2);368 const qint16* buffer = base + ((tileStart - m_bufferPosition) / 2); 356 369 const int numSamples = m_tileLength / (2 * m_format.channels()); 357 370 … … 377 390 for (int i=0; i<numSamples; ++i) { 378 391 const qint16* ptr = buffer + i * m_format.channels(); 392 393 const int offset = reinterpret_cast<const char*>(ptr) - m_buffer.constData(); 394 Q_ASSERT(offset >= 0); 395 Q_ASSERT(offset < m_bufferLength); 396 379 397 const qint16 pcmValue = *ptr; 380 398 const qreal realValue = pcmToReal(pcmValue); -
trunk/demos/spectrum/app/waveform.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 61 61 Q_OBJECT 62 62 public: 63 Waveform( const QByteArray &buffer,QWidget *parent = 0);63 Waveform(QWidget *parent = 0); 64 64 ~Waveform(); 65 65 … … 74 74 75 75 public slots: 76 void dataLengthChanged(qint64 length);77 void positionChanged(qint64 position);76 void bufferChanged(qint64 position, qint64 length, const QByteArray &buffer); 77 void audioPositionChanged(qint64 position); 78 78 79 79 private: … … 168 168 169 169 private: 170 const QByteArray& m_buffer; 171 qint64 m_dataLength; 172 qint64 m_position; 170 qint64 m_bufferPosition; 171 qint64 m_bufferLength; 172 QByteArray m_buffer; 173 174 qint64 m_audioPosition; 173 175 QAudioFormat m_format; 174 176 -
trunk/demos/spectrum/app/wavfile.cpp
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 77 77 RIFFHeader riff; 78 78 WAVEHeader wave; 79 DATAHeader data;80 79 }; 81 80 82 static const int HeaderLength = sizeof(CombinedHeader); 83 84 85 WavFile::WavFile(const QAudioFormat &format, qint64 dataLength) 86 : m_format(format) 87 , m_dataLength(dataLength) 81 WavFile::WavFile(QObject *parent) 82 : QFile(parent) 83 , m_headerLength(0) 88 84 { 89 85 90 86 } 91 87 92 bool WavFile:: readHeader(QIODevice &device)88 bool WavFile::open(const QString &fileName) 93 89 { 94 bool result = true; 90 close(); 91 setFileName(fileName); 92 return QFile::open(QIODevice::ReadOnly) && readHeader(); 93 } 95 94 96 if (!device.isSequential()) 97 result = device.seek(0); 98 // else, assume that current position is the start of the header 95 const QAudioFormat &WavFile::fileFormat() const 96 { 97 return m_fileFormat; 98 } 99 99 100 qint64 WavFile::headerLength() const 101 { 102 return m_headerLength; 103 } 104 105 bool WavFile::readHeader() 106 { 107 seek(0); 108 CombinedHeader header; 109 bool result = read(reinterpret_cast<char *>(&header), sizeof(CombinedHeader)) == sizeof(CombinedHeader); 100 110 if (result) { 101 CombinedHeader header; 102 result = (device.read(reinterpret_cast<char *>(&header), HeaderLength) == HeaderLength); 103 if (result) { 104 if ((memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0 105 || memcmp(&header.riff.descriptor.id, "RIFX", 4) == 0) 106 && memcmp(&header.riff.type, "WAVE", 4) == 0 107 && memcmp(&header.wave.descriptor.id, "fmt ", 4) == 0 108 && header.wave.audioFormat == 1 // PCM 109 ) { 110 if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0) 111 m_format.setByteOrder(QAudioFormat::LittleEndian); 112 else 113 m_format.setByteOrder(QAudioFormat::BigEndian); 111 if ((memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0 112 || memcmp(&header.riff.descriptor.id, "RIFX", 4) == 0) 113 && memcmp(&header.riff.type, "WAVE", 4) == 0 114 && memcmp(&header.wave.descriptor.id, "fmt ", 4) == 0 115 && (header.wave.audioFormat == 1 || header.wave.audioFormat == 0)) { 114 116 115 m_format.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels)); 116 m_format.setCodec("audio/pcm"); 117 m_format.setFrequency(qFromLittleEndian<quint32>(header.wave.sampleRate)); 118 m_format.setSampleSize(qFromLittleEndian<quint16>(header.wave.bitsPerSample)); 117 // Read off remaining header information 118 DATAHeader dataHeader; 119 119 120 switch(header.wave.bitsPerSample) { 121 case 8: 122 m_format.setSampleType(QAudioFormat::UnSignedInt); 123 break; 124 case 16: 125 m_format.setSampleType(QAudioFormat::SignedInt); 126 break; 127 default: 128 result = false; 129 } 120 if (qFromLittleEndian<quint32>(header.wave.descriptor.size) > sizeof(WAVEHeader)) { 121 // Extended data available 122 quint16 extraFormatBytes; 123 if (peek((char*)&extraFormatBytes, sizeof(quint16)) != sizeof(quint16)) 124 return false; 125 const qint64 throwAwayBytes = sizeof(quint16) + qFromLittleEndian<quint16>(extraFormatBytes); 126 if (read(throwAwayBytes).size() != throwAwayBytes) 127 return false; 128 } 130 129 131 m_dataLength = device.size() - HeaderLength; 132 } else { 133 result = false; 134 } 130 if (read((char*)&dataHeader, sizeof(DATAHeader)) != sizeof(DATAHeader)) 131 return false; 132 133 // Establish format 134 if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0) 135 m_fileFormat.setByteOrder(QAudioFormat::LittleEndian); 136 else 137 m_fileFormat.setByteOrder(QAudioFormat::BigEndian); 138 139 int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample); 140 m_fileFormat.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels)); 141 m_fileFormat.setCodec("audio/pcm"); 142 m_fileFormat.setFrequency(qFromLittleEndian<quint32>(header.wave.sampleRate)); 143 m_fileFormat.setSampleSize(qFromLittleEndian<quint16>(header.wave.bitsPerSample)); 144 m_fileFormat.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt); 145 } else { 146 result = false; 135 147 } 136 148 } 137 149 m_headerLength = pos(); 138 150 return result; 139 151 } 140 141 bool WavFile::writeHeader(QIODevice &device)142 {143 CombinedHeader header;144 145 memset(&header, 0, HeaderLength);146 147 // RIFF header148 if (m_format.byteOrder() == QAudioFormat::LittleEndian)149 strncpy(&header.riff.descriptor.id[0], "RIFF", 4);150 else151 strncpy(&header.riff.descriptor.id[0], "RIFX", 4);152 qToLittleEndian<quint32>(quint32(m_dataLength + HeaderLength - 8),153 reinterpret_cast<unsigned char*>(&header.riff.descriptor.size));154 strncpy(&header.riff.type[0], "WAVE", 4);155 156 // WAVE header157 strncpy(&header.wave.descriptor.id[0], "fmt ", 4);158 qToLittleEndian<quint32>(quint32(16),159 reinterpret_cast<unsigned char*>(&header.wave.descriptor.size));160 qToLittleEndian<quint16>(quint16(1),161 reinterpret_cast<unsigned char*>(&header.wave.audioFormat));162 qToLittleEndian<quint16>(quint16(m_format.channels()),163 reinterpret_cast<unsigned char*>(&header.wave.numChannels));164 qToLittleEndian<quint32>(quint32(m_format.frequency()),165 reinterpret_cast<unsigned char*>(&header.wave.sampleRate));166 qToLittleEndian<quint32>(quint32(m_format.frequency() * m_format.channels() * m_format.sampleSize() / 8),167 reinterpret_cast<unsigned char*>(&header.wave.byteRate));168 qToLittleEndian<quint16>(quint16(m_format.channels() * m_format.sampleSize() / 8),169 reinterpret_cast<unsigned char*>(&header.wave.blockAlign));170 qToLittleEndian<quint16>(quint16(m_format.sampleSize()),171 reinterpret_cast<unsigned char*>(&header.wave.bitsPerSample));172 173 // DATA header174 strncpy(&header.data.descriptor.id[0], "data", 4);175 qToLittleEndian<quint32>(quint32(m_dataLength),176 reinterpret_cast<unsigned char*>(&header.data.descriptor.size));177 178 return (device.write(reinterpret_cast<const char *>(&header), HeaderLength) == HeaderLength);179 }180 181 const QAudioFormat& WavFile::format() const182 {183 return m_format;184 }185 186 qint64 WavFile::dataLength() const187 {188 return m_dataLength;189 }190 191 qint64 WavFile::headerLength()192 {193 return HeaderLength;194 }195 196 bool WavFile::writeDataLength(QIODevice &device, qint64 dataLength)197 {198 bool result = false;199 if (!device.isSequential()) {200 device.seek(40);201 unsigned char dataLengthLE[4];202 qToLittleEndian<quint32>(quint32(dataLength), dataLengthLE);203 result = (device.write(reinterpret_cast<const char *>(dataLengthLE), 4) == 4);204 }205 return result;206 }207 208 #include <QFile>209 #include <QTextStream>210 211 qint64 WavFile::readData(QIODevice &device, QByteArray &buffer,212 QAudioFormat outputFormat)213 {214 if (QAudioFormat() == outputFormat)215 outputFormat = m_format;216 217 qint64 result = 0;218 219 QFile file("wav.txt");220 file.open(QIODevice::WriteOnly | QIODevice::Text);221 QTextStream stream;222 stream.setDevice(&file);223 224 if (isPCMS16LE(outputFormat) && isPCMS16LE(m_format)) {225 QVector<char> inputSample(2 * m_format.channels());226 227 qint16 *output = reinterpret_cast<qint16*>(buffer.data());228 229 while (result < buffer.size()) {230 if (device.read(inputSample.data(), inputSample.count())) {231 int inputIdx = 0;232 for (int outputIdx = 0; outputIdx < outputFormat.channels(); ++outputIdx) {233 const qint16* input = reinterpret_cast<const qint16*>(inputSample.data() + 2 * inputIdx);234 *output++ = qFromLittleEndian<qint16>(*input);235 result += 2;236 if (inputIdx < m_format.channels())237 ++inputIdx;238 }239 } else {240 break;241 }242 }243 }244 return result;245 }246 -
trunk/demos/spectrum/app/wavfile.h
r769 r846 1 1 /**************************************************************************** 2 2 ** 3 ** Copyright (C) 201 0Nokia Corporation and/or its subsidiary(-ies).3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). 4 4 ** All rights reserved. 5 5 ** Contact: Nokia Corporation (qt-info@nokia.com) … … 47 47 #include <QtMultimedia/qaudioformat.h> 48 48 49 /** 50 * Helper class for reading WAV files 51 * 52 * See https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ 53 */ 54 class WavFile 49 class WavFile : public QFile 55 50 { 56 51 public: 57 WavFile(const QAudioFormat &format = QAudioFormat(), 58 qint64 dataLength = 0); 52 WavFile(QObject *parent = 0); 59 53 60 // Reads WAV header and seeks to start of data 61 bool readHeader(QIODevice &device); 62 63 // Writes WAV header 64 bool writeHeader(QIODevice &device); 65 66 // Read PCM data 67 qint64 readData(QIODevice &device, QByteArray &buffer, 68 QAudioFormat outputFormat = QAudioFormat()); 69 70 const QAudioFormat& format() const; 71 qint64 dataLength() const; 72 73 static qint64 headerLength(); 74 75 static bool writeDataLength(QIODevice &device, qint64 dataLength); 54 bool open(const QString &fileName); 55 const QAudioFormat &fileFormat() const; 56 qint64 headerLength() const; 76 57 77 58 private: 78 QAudioFormat m_format; 79 qint64 m_dataLength; 59 bool readHeader(); 60 61 private: 62 QAudioFormat m_fileFormat; 63 qint64 m_headerLength; 64 80 65 }; 81 66
Note:
See TracChangeset
for help on using the changeset viewer.