Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

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

Location:
trunk
Files:
1 deleted
30 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/demos/spectrum/app/app.pro

    r769 r846  
    11include(../spectrum.pri)
     2
     3static: error(This application cannot be statically linked to the fftreal library)
    24
    35TEMPLATE = app
    46
    57TARGET = spectrum
    6 unix: !macx: !symbian: TARGET = spectrum.bin
    78
    89QT       += multimedia
     
    4950
    5051    # Provide unique ID for the generated binary, required by Symbian OS
    51     TARGET.UID3 = 0xA000E3FA
     52    TARGET.UID3 = 0xA000E402
    5253}
    5354
     
    5859        # Must explicitly add the .dll suffix to ensure dynamic linkage
    5960        LIBS += -lfftreal.dll
     61        QMAKE_LIBDIR += $${fftreal_dir}
    6062    } else {
    6163        macx {
     
    6466            LIBS += -framework fftreal
    6567        } else {
    66             # Link to dynamic library which is written to ../bin
    67             LIBS += -L../bin
     68            LIBS += -L..$${spectrum_build_dir}
    6869            LIBS += -lfftreal
    6970        }
     
    8687    !contains(DEFINES, DISABLE_FFT) {
    8788        # Include FFTReal DLL in the SIS file
    88         fftreal.sources = $${EPOCROOT}epoc32/release/$(PLATFORM)/$(TARGET)/fftreal.dll
     89        fftreal.sources = ../fftreal.dll
    8990        fftreal.path = !:/sys/bin
    9091        DEPLOYMENT += fftreal
    9192    }
    9293} else {
     94        DESTDIR = ..$${spectrum_build_dir}
    9395    macx {
    94         # Specify directory in which to create spectrum.app bundle
    95         DESTDIR = ..
    96 
    9796        !contains(DEFINES, DISABLE_FFT) {
    9897            # Relocate fftreal.framework into spectrum.app bundle
     
    110109        }
    111110    } 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
    124114        }
    125115    }
  • trunk/demos/spectrum/app/engine.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    8686    ,   m_generateTone(false)
    8787    ,   m_file(0)
     88    ,   m_analysisFile(0)
    8889    ,   m_availableAudioInputDevices
    8990            (QAudioDeviceInfo::availableDevices(QAudio::AudioInput))
     
    9798    ,   m_audioOutput(0)
    9899    ,   m_playPosition(0)
     100    ,   m_bufferPosition(0)
     101    ,   m_bufferLength(0)
    99102    ,   m_dataLength(0)
     103    ,   m_levelBufferLength(0)
    100104    ,   m_rmsLevel(0.0)
    101105    ,   m_peakLevel(0.0)
    102     ,   m_spectrumLengthBytes(0)
     106    ,   m_spectrumBufferLength(0)
    103107    ,   m_spectrumAnalyser()
    104108    ,   m_spectrumPosition(0)
     
    106110{
    107111    qRegisterMetaType<FrequencySpectrum>("FrequencySpectrum");
     112    qRegisterMetaType<WindowFunction>("WindowFunction");
    108113    CHECKED_CONNECT(&m_spectrumAnalyser,
    109114                    SIGNAL(spectrumChanged(FrequencySpectrum)),
     
    133138bool Engine::loadFile(const QString &fileName)
    134139{
     140    reset();
    135141    bool result = false;
    136     m_generateTone = false;
    137 
     142    Q_ASSERT(!m_generateTone);
     143    Q_ASSERT(!m_file);
    138144    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())) {
    146148            result = initialize();
    147149        } else {
    148150            emit errorMessage(tr("Audio format not supported"),
    149                               formatToString(m_wavFile.format()));
     151                              formatToString(m_file->fileFormat()));
    150152        }
    151153    } else {
    152154        emit errorMessage(tr("Could not open file"), fileName);
    153155    }
    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    }
    158160    return result;
    159161}
     
    161163bool Engine::generateTone(const Tone &tone)
    162164{
     165    reset();
     166    Q_ASSERT(!m_generateTone);
    163167    Q_ASSERT(!m_file);
    164168    m_generateTone = true;
     
    173177bool Engine::generateSweptTone(qreal amplitude)
    174178{
     179    Q_ASSERT(!m_generateTone);
    175180    Q_ASSERT(!m_file);
    176181    m_generateTone = true;
     
    186191bool Engine::initializeRecord()
    187192{
     193    reset();
    188194    ENGINE_DEBUG << "Engine::initializeRecord";
     195    Q_ASSERT(!m_generateTone);
    189196    Q_ASSERT(!m_file);
    190197    m_generateTone = false;
     
    193200}
    194201
    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;
     202qint64 Engine::bufferLength() const
     203{
     204    return m_file ? m_file->size() : m_bufferLength;
    223205}
    224206
     
    253235            m_count = 0;
    254236            m_dataLength = 0;
    255             emit dataDurationChanged(0);
     237            emit dataLengthChanged(0);
    256238            m_audioInputIODevice = m_audioInput->start();
    257239            CHECKED_CONNECT(m_audioInputIODevice, SIGNAL(readyRead()),
     
    276258            m_spectrumAnalyser.cancelCalculation();
    277259            spectrumChanged(0, 0, FrequencySpectrum());
    278 
    279260            setPlayPosition(0, true);
    280261            stopRecording();
     
    285266                            this, SLOT(audioNotify()));
    286267            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            }
    291279        }
    292280    }
     
    333321    switch (m_mode) {
    334322    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()));
    337324            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;
    348330                calculateSpectrum(spectrumPosition);
    349331            }
     332            emit bufferChanged(0, m_dataLength, m_buffer);
    350333        }
    351334        break;
    352335    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);
    369372        }
    370373        break;
     
    377380                 << "to" << state;
    378381
    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    }
    396403}
    397404
    398405void Engine::audioDataReady()
    399406{
     407    Q_ASSERT(0 == m_bufferPosition);
    400408    const qint64 bytesReady = m_audioInput->bytesReady();
    401409    const qint64 bytesSpace = m_buffer.size() - m_dataLength;
     
    408416    if (bytesRead) {
    409417        m_dataLength += bytesRead;
    410 
    411         const qint64 duration = audioDuration(m_format, m_dataLength);
    412         emit dataDurationChanged(duration);
     418        emit dataLengthChanged(dataLength());
    413419    }
    414420
     
    420426{
    421427    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);
    425429}
    426430
     
    430434//-----------------------------------------------------------------------------
    431435
    432 void Engine::reset()
    433 {
    434     stopRecording();
    435     stopPlayback();
    436     setState(QAudio::AudioInput, QAudio::StoppedState);
    437     setFormat(QAudioFormat());
     436void Engine::resetAudioDevices()
     437{
    438438    delete m_audioInput;
    439439    m_audioInput = 0;
     
    443443    m_audioOutput = 0;
    444444    setPlayPosition(0);
     445    m_spectrumPosition = 0;
     446    setLevel(0.0, 0.0, 0);
     447}
     448
     449void 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;
    445460    m_buffer.clear();
     461    m_bufferPosition = 0;
     462    m_bufferLength = 0;
    446463    m_dataLength = 0;
    447     m_spectrumPosition = 0;
    448     emit dataDurationChanged(0);
    449     setLevel(0.0, 0.0, 0);
     464    emit dataLengthChanged(0);
     465    resetAudioDevices();
    450466}
    451467
     
    454470    bool result = false;
    455471
    456     reset();
     472    QAudioFormat format = m_format;
    457473
    458474    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                }
    468506            }
    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        }
    494510    } else {
    495511        if (m_file)
     
    502518    }
    503519
     520    ENGINE_DEBUG << "Engine::initialize" << "m_bufferLength" << m_bufferLength;
     521    ENGINE_DEBUG << "Engine::initialize" << "m_dataLength" << m_dataLength;
    504522    ENGINE_DEBUG << "Engine::initialize" << "format" << m_format;
    505523
     
    511529    bool foundSupportedFormat = false;
    512530
    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);
    519539            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             }
    528540        }
    529541    } else {
     
    649661    Q_UNUSED(length)
    650662#else
    651     Q_ASSERT(position + length <= m_dataLength);
     663    Q_ASSERT(position + length <= m_bufferPosition + m_dataLength);
    652664
    653665    qreal peakLevel = 0.0;
    654666
    655667    qreal sum = 0.0;
    656     const char *ptr = m_buffer.constData() + position;
     668    const char *ptr = m_buffer.constData() + position - m_bufferPosition;
    657669    const char *const end = ptr + length;
    658670    while (ptr < end) {
     
    680692    Q_UNUSED(position)
    681693#else
    682     Q_ASSERT(position + m_spectrumLengthBytes <= m_dataLength);
    683     Q_ASSERT(0 == m_spectrumLengthBytes % 2); // constraint of FFT algorithm
     694    Q_ASSERT(position + m_spectrumBufferLength <= m_bufferPosition + m_dataLength);
     695    Q_ASSERT(0 == m_spectrumBufferLength % 2); // constraint of FFT algorithm
    684696
    685697    // QThread::currentThread is marked 'for internal use only', but
    686698    // we're only using it for debug output here, so it's probably OK :)
    687699    ENGINE_DEBUG << "Engine::calculateSpectrum" << QThread::currentThread()
    688                  << "count" << m_count << "pos" << position << "len" << m_spectrumLengthBytes
     700                 << "count" << m_count << "pos" << position << "len" << m_spectrumBufferLength
    689701                 << "spectrumAnalyser.isReady" << m_spectrumAnalyser.isReady();
    690702
    691703    if(m_spectrumAnalyser.isReady()) {
    692         m_spectrumBuffer = QByteArray::fromRawData(m_buffer.constData() + position,
    693                                                    m_spectrumLengthBytes);
     704        m_spectrumBuffer = QByteArray::fromRawData(m_buffer.constData() + position - m_bufferPosition,
     705                                                   m_spectrumBufferLength);
    694706        m_spectrumPosition = position;
    695707        m_spectrumAnalyser.calculate(m_spectrumBuffer, m_format);
     
    702714    const bool changed = (format != m_format);
    703715    m_format = format;
     716    m_levelBufferLength = audioLength(m_format, LevelWindowUs);
     717    m_spectrumBufferLength = SpectrumLengthSamples *
     718                            (m_format.sampleSize() / 8) * m_format.channels();
    704719    if (changed)
    705720        emit formatChanged(m_format);
  • trunk/demos/spectrum/app/engine.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6666
    6767class FrequencySpectrum;
    68 
    6968QT_FORWARD_DECLARE_CLASS(QAudioInput)
    7069QT_FORWARD_DECLARE_CLASS(QAudioOutput)
     
    9392
    9493    /**
    95      * \return Reference to internal audio buffer
    96      * \note This reference is valid for the lifetime of the Engine
    97      */
    98     const QByteArray& buffer() const    { return m_buffer; }
    99 
    100     /**
    10194     * \return Current audio format
    10295     * \note May be QAudioFormat() if engine is not initialized
     
    131124    /**
    132125     * Position of the audio input device.
    133      * \return Position in microseconds.
     126     * \return Position in bytes.
    134127     */
    135128    qint64 recordPosition() const   { return m_recordPosition; }
     
    149142    /**
    150143     * Position of the audio output device.
    151      * \return Position in microseconds.
     144     * \return Position in bytes.
    152145     */
    153146    qint64 playPosition() const     { return m_playPosition; }
     
    155148    /**
    156149     * Length of the internal engine buffer.
    157      * \return Buffer length in microseconds.
    158      */
    159     qint64 bufferDuration() const;
     150     * \return Buffer length in bytes.
     151     */
     152    qint64 bufferLength() const;
    160153
    161154    /**
    162155     * 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; }
    172159
    173160    /**
     
    205192     * \param duration Duration in microseconds
    206193     */
    207     void bufferDurationChanged(qint64 duration);
     194    void bufferLengthChanged(qint64 duration);
    208195
    209196    /**
    210197     * Amount of data in buffer has changed.
    211      * \param duration Duration of data in microseconds
    212      */
    213     void dataDurationChanged(qint64 duration);
     198     * \param Length of data in bytes
     199     */
     200    void dataLengthChanged(qint64 duration);
    214201
    215202    /**
    216203     * Position of the audio input device has changed.
    217      * \param position Position in microseconds
     204     * \param position Position in bytes
    218205     */
    219206    void recordPositionChanged(qint64 position);
     
    221208    /**
    222209     * Position of the audio output device has changed.
    223      * \param position Position in microseconds
     210     * \param position Position in bytes
    224211     */
    225212    void playPositionChanged(qint64 position);
     
    229216     * \param rmsLevel RMS level in range 0.0 - 1.0
    230217     * \param peakLevel Peak level in range 0.0 - 1.0
    231      * \param numSamples Number of audio samples analysed
     218     * \param numSamples Number of audio samples analyzed
    232219     */
    233220    void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples);
     
    235222    /**
    236223     * Spectrum has changed.
    237      * \param position Position of start of window in microseconds
    238      * \param length   Length of window in microseconds
     224     * \param position Position of start of window in bytes
     225     * \param length   Length of window in bytes
    239226     * \param spectrum Resulting frequency spectrum
    240227     */
    241228    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);
    242236
    243237private slots:
     
    248242
    249243private:
     244    void resetAudioDevices();
    250245    bool initialize();
    251246    bool selectFormat();
     
    277272    SweptTone           m_tone;
    278273
    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;
    281278
    282279    QAudioFormat        m_format;
     
    295292
    296293    QByteArray          m_buffer;
     294    qint64              m_bufferPosition;
     295    qint64              m_bufferLength;
    297296    qint64              m_dataLength;
    298297
     298    int                 m_levelBufferLength;
    299299    qreal               m_rmsLevel;
    300300    qreal               m_peakLevel;
    301301
    302     int                 m_spectrumLengthBytes;
     302    int                 m_spectrumBufferLength;
    303303    QByteArray          m_spectrumBuffer;
    304304    SpectrumAnalyser    m_spectrumAnalyser;
  • trunk/demos/spectrum/app/frequencyspectrum.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/frequencyspectrum.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/levelmeter.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/levelmeter.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4747/**
    4848 * Widget which displays a vertical audio level meter, indicating the
    49  * RMS and peak levels of the window of audio samples most recently analysed
     49 * RMS and peak levels of the window of audio samples most recently analyzed
    5050 * by the Engine.
    5151 */
  • trunk/demos/spectrum/app/main.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4545{
    4646    QApplication app(argc, argv);
    47     app.setApplicationName("QtMultimedia spectrum analyser");
     47    app.setApplicationName("QtMultimedia spectrum analyzer");
    4848    MainWidget w;
    4949
  • trunk/demos/spectrum/app/mainwidget.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6666    ,   m_engine(new Engine(this))
    6767#ifndef DISABLE_WAVEFORM
    68     ,   m_waveform(new Waveform(m_engine->buffer(), this))
     68    ,   m_waveform(new Waveform(this))
    6969#endif
    7070    ,   m_progressBar(new ProgressBar(this))
     
    167167}
    168168
    169 void MainWidget::positionChanged(qint64 positionUs)
    170 {
    171 #ifndef DISABLE_WAVEFORM
    172     qint64 positionBytes = audioLength(m_engine->format(), positionUs);
    173     m_waveform->positionChanged(positionBytes);
     169void MainWidget::audioPositionChanged(qint64 position)
     170{
     171#ifndef DISABLE_WAVEFORM
     172    m_waveform->audioPositionChanged(position);
    174173#else
    175     Q_UNUSED(positionUs)
    176 #endif
    177 }
    178 
    179 void MainWidget::bufferDurationChanged(qint64 durationUs)
    180 {
    181     m_progressBar->bufferDurationChanged(durationUs);
     174    Q_UNUSED(position)
     175#endif
     176}
     177
     178void MainWidget::bufferLengthChanged(qint64 length)
     179{
     180    m_progressBar->bufferLengthChanged(length);
    182181}
    183182
     
    187186//-----------------------------------------------------------------------------
    188187
    189 void MainWidget::dataDurationChanged(qint64 duration)
    190 {
    191 #ifndef DISABLE_WAVEFORM
    192     const qint64 dataLength = audioLength(m_engine->format(), duration);
    193     m_waveform->dataLengthChanged(dataLength);
    194 #else
    195     Q_UNUSED(duration)
    196 #endif
    197 
    198     updateButtonStates();
    199 }
    200 
    201188void MainWidget::showFileDialog()
    202189{
    203     reset();
    204190    const QString dir;
    205191    const QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open WAV file"), dir, "*.wav");
    206192    if (fileNames.count()) {
     193        reset();
    207194        setMode(LoadFileMode);
    208195        m_engine->loadFile(fileNames.front());
    209196        updateButtonStates();
     197    } else {
     198        updateModeMenu();
    210199    }
    211200}
     
    213202void MainWidget::showSettingsDialog()
    214203{
    215     reset();
    216204    m_settingsDialog->exec();
    217205    if (m_settingsDialog->result() == QDialog::Accepted) {
     
    224212void MainWidget::showToneGeneratorDialog()
    225213{
    226     reset();
    227214    m_toneGeneratorDialog->exec();
    228215    if (m_toneGeneratorDialog->result() == QDialog::Accepted) {
     216        reset();
    229217        setMode(GenerateToneMode);
    230218        const qreal amplitude = m_toneGeneratorDialog->amplitude();
     
    237225            updateButtonStates();
    238226        }
     227    } else {
     228        updateModeMenu();
    239229    }
    240230}
     
    361351            this, SLOT(formatChanged(const QAudioFormat &)));
    362352
    363     m_progressBar->bufferDurationChanged(m_engine->bufferDuration());
    364 
    365     CHECKED_CONNECT(m_engine, SIGNAL(bufferDurationChanged(qint64)),
    366             this, SLOT(bufferDurationChanged(qint64)));
    367 
    368     CHECKED_CONNECT(m_engine, SIGNAL(dataDurationChanged(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()));
    370360
    371361    CHECKED_CONNECT(m_engine, SIGNAL(recordPositionChanged(qint64)),
     
    376366
    377367    CHECKED_CONNECT(m_engine, SIGNAL(recordPositionChanged(qint64)),
    378             this, SLOT(positionChanged(qint64)));
     368            this, SLOT(audioPositionChanged(qint64)));
    379369
    380370    CHECKED_CONNECT(m_engine, SIGNAL(playPositionChanged(qint64)),
    381             this, SLOT(positionChanged(qint64)));
     371            this, SLOT(audioPositionChanged(qint64)));
    382372
    383373    CHECKED_CONNECT(m_engine, SIGNAL(levelChanged(qreal, qreal, int)),
     
    395385    CHECKED_CONNECT(m_spectrograph, SIGNAL(infoMessage(QString, int)),
    396386            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
    397392}
    398393
     
    426421    m_pauseButton->setEnabled(pauseEnabled);
    427422
    428     const bool playEnabled = (m_engine->dataDuration() &&
     423    const bool playEnabled = (/*m_engine->dataLength() &&*/
    429424                              (QAudio::AudioOutput != m_engine->mode() ||
    430425                               (QAudio::ActiveState != m_engine->state() &&
     
    446441void MainWidget::setMode(Mode mode)
    447442{
    448 
    449443    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
     447void 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  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    8181    void infoMessage(const QString &message, int timeoutMs);
    8282    void errorMessage(const QString &heading, const QString &detail);
    83     void positionChanged(qint64 position);
    84     void bufferDurationChanged(qint64 duration);
     83    void audioPositionChanged(qint64 position);
     84    void bufferLengthChanged(qint64 length);
    8585
    8686private slots:
     
    8989    void showToneGeneratorDialog();
    9090    void initializeRecord();
    91     void dataDurationChanged(qint64 duration);
     91    void updateModeMenu();
     92    void updateButtonStates();
    9293
    9394private:
     
    9596    void createMenus();
    9697    void connectUi();
    97     void updateButtonStates();
    9898    void reset();
    9999
     
    112112    Engine*                 m_engine;
    113113
     114#ifndef DISABLE_WAVEFORM
    114115    Waveform*               m_waveform;
     116#endif
    115117    ProgressBar*            m_progressBar;
    116118    Spectrograph*           m_spectrograph;
  • trunk/demos/spectrum/app/progressbar.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4545ProgressBar::ProgressBar(QWidget *parent)
    4646    :   QWidget(parent)
    47     ,   m_bufferDuration(0)
     47    ,   m_bufferLength(0)
    4848    ,   m_recordPosition(0)
    4949    ,   m_playPosition(0)
     
    6565void ProgressBar::reset()
    6666{
    67     m_bufferDuration = 0;
     67    m_bufferLength = 0;
    6868    m_recordPosition = 0;
    6969    m_playPosition = 0;
     
    8787#endif
    8888
    89     if (m_bufferDuration) {
     89    if (m_bufferLength) {
    9090        QRect bar = rect();
    91         const qreal play = qreal(m_playPosition) / m_bufferDuration;
     91        const qreal play = qreal(m_playPosition) / m_bufferLength;
    9292        bar.setLeft(rect().left() + play * rect().width());
    93         const qreal record = qreal(m_recordPosition) / m_bufferDuration;
     93        const qreal record = qreal(m_recordPosition) / m_bufferLength;
    9494        bar.setRight(rect().left() + record * rect().width());
    9595        painter.fillRect(bar, bufferColor);
    9696
    9797        QRect window = rect();
    98         const qreal windowLeft = qreal(m_windowPosition) / m_bufferDuration;
     98        const qreal windowLeft = qreal(m_windowPosition) / m_bufferLength;
    9999        window.setLeft(rect().left() + windowLeft * rect().width());
    100         const qreal windowWidth = qreal(m_windowLength) / m_bufferDuration;
     100        const qreal windowWidth = qreal(m_windowLength) / m_bufferLength;
    101101        window.setWidth(windowWidth * rect().width());
    102102        painter.fillRect(window, windowColor);
     
    104104}
    105105
    106 void ProgressBar::bufferDurationChanged(qint64 bufferSize)
     106void ProgressBar::bufferLengthChanged(qint64 bufferSize)
    107107{
    108     m_bufferDuration = bufferSize;
     108    m_bufferLength = bufferSize;
    109109    m_recordPosition = 0;
    110110    m_playPosition = 0;
     
    117117{
    118118    Q_ASSERT(recordPosition >= 0);
    119     Q_ASSERT(recordPosition <= m_bufferDuration);
     119    Q_ASSERT(recordPosition <= m_bufferLength);
    120120    m_recordPosition = recordPosition;
    121121    repaint();
     
    125125{
    126126    Q_ASSERT(playPosition >= 0);
    127     Q_ASSERT(playPosition <= m_bufferDuration);
     127    Q_ASSERT(playPosition <= m_bufferLength);
    128128    m_playPosition = playPosition;
    129129    repaint();
     
    133133{
    134134    Q_ASSERT(position >= 0);
    135     Q_ASSERT(position <= m_bufferDuration);
    136     Q_ASSERT(position + length <= m_bufferDuration);
     135    Q_ASSERT(position <= m_bufferLength);
     136    Q_ASSERT(position + length <= m_bufferLength);
    137137    m_windowPosition = position;
    138138    m_windowLength = length;
  • trunk/demos/spectrum/app/progressbar.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5858
    5959public slots:
    60     void bufferDurationChanged(qint64 bufferSize);
     60    void bufferLengthChanged(qint64 length);
    6161    void recordPositionChanged(qint64 recordPosition);
    6262    void playPositionChanged(qint64 playPosition);
     
    6464
    6565private:
    66     qint64 m_bufferDuration;
     66    qint64 m_bufferLength;
    6767    qint64 m_recordPosition;
    6868    qint64 m_playPosition;
  • trunk/demos/spectrum/app/settingsdialog.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/settingsdialog.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/spectrograph.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/spectrograph.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4949/**
    5050 * Widget which displays a spectrograph showing the frequency spectrum
    51  * of the window of audio samples most recently analysed by the Engine.
     51 * of the window of audio samples most recently analyzed by the Engine.
    5252 */
    5353class Spectrograph : public QWidget {
  • trunk/demos/spectrum/app/spectrum.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/spectrumanalyser.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6565{
    6666#ifdef SPECTRUM_ANALYSER_SEPARATE_THREAD
     67    // moveToThread() cannot be called on a QObject with a parent
     68    setParent(0);
    6769    moveToThread(m_thread);
    6870    m_thread->start();
     
    125127    m_fft->calculateFFT(m_output.data(), m_input.data());
    126128
    127     // Analyse output to obtain amplitude and phase for each frequency
     129    // Analyze output to obtain amplitude and phase for each frequency
    128130    for (int i=2; i<=m_numSamples/2; ++i) {
    129131        // Calculate frequency of this complex sample
  • trunk/demos/spectrum/app/spectrumanalyser.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/tonegenerator.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/tonegenerator.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/tonegeneratordialog.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/tonegeneratordialog.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/utils.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5050qint64 audioLength(const QAudioFormat &format, qint64 microSeconds)
    5151{
    52    return (format.frequency() * format.channels() * (format.sampleSize() / 8))
     52   qint64 result = (format.frequency() * format.channels() * (format.sampleSize() / 8))
    5353       * microSeconds / 1000000;
     54   result -= result % (format.channelCount() * format.sampleSize());
     55   return result;
    5456}
    5557
  • trunk/demos/spectrum/app/utils.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/demos/spectrum/app/waveform.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4545#include <QDebug>
    4646
    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
     54Waveform::Waveform(QWidget *parent)
    4955    :   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)
    5359    ,   m_active(false)
    5460    ,   m_tileLength(0)
     
    7379
    7480    if (m_active) {
    75         WAVEFORM_DEBUG << "Waveform::paintEvent"
    76                        << "windowPosition" << m_windowPosition
    77                        << "windowLength" << m_windowLength;
     81        WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent"
     82                             << "windowPosition" << m_windowPosition
     83                             << "windowLength" << m_windowLength;
    7884        qint64 pos = m_windowPosition;
    7985        const qint64 windowEnd = m_windowPosition + m_windowLength;
     
    8288        while (pos < windowEnd) {
    8389            const TilePoint point = tilePoint(pos);
    84             WAVEFORM_DEBUG << "Waveform::paintEvent" << "pos" << pos
    85                            << "tileIndex" << point.index
    86                            << "positionOffset" << point.positionOffset
    87                            << "pixelOffset" << point.pixelOffset;
     90            WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "pos" << pos
     91                                 << "tileIndex" << point.index
     92                                 << "positionOffset" << point.positionOffset
     93                                 << "pixelOffset" << point.pixelOffset;
    8894
    8995            if (point.index != NullIndex) {
     
    105111                    sourceRect.setRight(sourceRight);
    106112
    107                     WAVEFORM_DEBUG << "Waveform::paintEvent" << "tileIndex" << point.index
    108                                    << "source" << point.pixelOffset << sourceRight
    109                                    << "dest" << destLeft << destRight;
     113                    WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "tileIndex" << point.index
     114                                         << "source" << point.pixelOffset << sourceRight
     115                                         << "dest" << destLeft << destRight;
    110116
    111117                    painter.drawPixmap(destRect, *tile.pixmap, sourceRect);
     
    115121                    if (point.index < m_tiles.count()) {
    116122                        pos = tilePosition(point.index + 1);
    117                         WAVEFORM_DEBUG << "Waveform::paintEvent" << "pos ->" << pos;
     123                        WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "pos ->" << pos;
    118124                    } else {
    119125                        // 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";
    121127                        break;
    122128                    }
    123129                } else {
    124130                    // 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";
    126132                    break;
    127133                }
    128134            } else {
    129135                // 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";
    131137                break;
    132138            }
    133139        }
    134140
    135         WAVEFORM_DEBUG << "Waveform::paintEvent" << "final pos" << pos << "final x" << destRight;
     141        WAVEFORM_PAINT_DEBUG << "Waveform::paintEvent" << "final pos" << pos << "final x" << destRight;
    136142    }
    137143}
     
    147153    WAVEFORM_DEBUG << "Waveform::initialize"
    148154                   << "audioBufferSize" << audioBufferSize
    149                    << "m_buffer.size()" << m_buffer.size()
    150155                   << "windowDurationUs" << windowDurationUs;
    151156
     
    187192    WAVEFORM_DEBUG << "Waveform::reset";
    188193
    189     m_dataLength = 0;
    190     m_position = 0;
     194    m_bufferPosition = 0;
     195    m_buffer = QByteArray();
     196    m_audioPosition = 0;
    191197    m_format = QAudioFormat();
    192198    m_active = false;
     
    199205}
    200206
    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);
     207void 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
     219void 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    }
    225232}
    226233
     
    256263        m_tiles[i].painted = false;
    257264    }
    258 
    259     paintTiles();
    260265}
    261266
     
    328333        const Tile &tile = m_tiles[i];
    329334        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) {
    332338                paintTile(i);
    333339                updateRequired = true;
     
    344350void Waveform::paintTile(int index)
    345351{
    346     WAVEFORM_DEBUG << "Waveform::paintTile" << "index" << index;
    347 
    348352    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);
    350363
    351364    Tile &tile = m_tiles[index];
     
    353366
    354367    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);
    356369    const int numSamples = m_tileLength / (2 * m_format.channels());
    357370
     
    377390    for (int i=0; i<numSamples; ++i) {
    378391        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
    379397        const qint16 pcmValue = *ptr;
    380398        const qreal realValue = pcmToReal(pcmValue);
  • trunk/demos/spectrum/app/waveform.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6161    Q_OBJECT
    6262public:
    63     Waveform(const QByteArray &buffer, QWidget *parent = 0);
     63    Waveform(QWidget *parent = 0);
    6464    ~Waveform();
    6565
     
    7474
    7575public 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);
    7878
    7979private:
     
    168168
    169169private:
    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;
    173175    QAudioFormat            m_format;
    174176
  • trunk/demos/spectrum/app/wavfile.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7777    RIFFHeader  riff;
    7878    WAVEHeader  wave;
    79     DATAHeader  data;
    8079};
    8180
    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)
     81WavFile::WavFile(QObject *parent)
     82    : QFile(parent)
     83    , m_headerLength(0)
    8884{
    8985
    9086}
    9187
    92 bool WavFile::readHeader(QIODevice &device)
     88bool WavFile::open(const QString &fileName)
    9389{
    94     bool result = true;
     90    close();
     91    setFileName(fileName);
     92    return QFile::open(QIODevice::ReadOnly) && readHeader();
     93}
    9594
    96     if (!device.isSequential())
    97         result = device.seek(0);
    98     // else, assume that current position is the start of the header
     95const QAudioFormat &WavFile::fileFormat() const
     96{
     97    return m_fileFormat;
     98}
    9999
     100qint64 WavFile::headerLength() const
     101{
     102return m_headerLength;
     103}
     104
     105bool WavFile::readHeader()
     106{
     107    seek(0);
     108    CombinedHeader header;
     109    bool result = read(reinterpret_cast<char *>(&header), sizeof(CombinedHeader)) == sizeof(CombinedHeader);
    100110    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)) {
    114116
    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;
    119119
    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            }
    130129
    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;
    135147        }
    136148    }
    137 
     149    m_headerLength = pos();
    138150    return result;
    139151}
    140 
    141 bool WavFile::writeHeader(QIODevice &device)
    142 {
    143     CombinedHeader header;
    144 
    145     memset(&header, 0, HeaderLength);
    146 
    147     // RIFF header
    148     if (m_format.byteOrder() == QAudioFormat::LittleEndian)
    149         strncpy(&header.riff.descriptor.id[0], "RIFF", 4);
    150     else
    151         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 header
    157     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 header
    174     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() const
    182 {
    183     return m_format;
    184 }
    185 
    186 qint64 WavFile::dataLength() const
    187 {
    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  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4747#include <QtMultimedia/qaudioformat.h>
    4848
    49 /**
    50  * Helper class for reading WAV files
    51  *
    52  * See https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
    53  */
    54 class WavFile
     49class WavFile : public QFile
    5550{
    5651public:
    57     WavFile(const QAudioFormat &format = QAudioFormat(),
    58               qint64 dataLength = 0);
     52    WavFile(QObject *parent = 0);
    5953
    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;
    7657
    7758private:
    78     QAudioFormat m_format;
    79     qint64 m_dataLength;
     59    bool readHeader();
     60
     61private:
     62    QAudioFormat m_fileFormat;
     63    qint64 m_headerLength;
     64
    8065};
    8166
Note: See TracChangeset for help on using the changeset viewer.