Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites 
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Toutes les fonctions  ·  Vues d'ensemble  · 

engine.cpp Example File

demos/spectrum/app/engine.cpp
 /****************************************************************************
 **
 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
 ** This file is part of the examples of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:BSD$
 ** You may use this file under the terms of the BSD license as follows:
 **
 ** "Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions are
 ** met:
 **   * Redistributions of source code must retain the above copyright
 **     notice, this list of conditions and the following disclaimer.
 **   * Redistributions in binary form must reproduce the above copyright
 **     notice, this list of conditions and the following disclaimer in
 **     the documentation and/or other materials provided with the
 **     distribution.
 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
 **     the names of its contributors may be used to endorse or promote
 **     products derived from this software without specific prior written
 **     permission.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/

 #include "engine.h"
 #include "tonegenerator.h"
 #include "utils.h"

 #include <math.h>

 #include <QCoreApplication>
 #include <QMetaObject>
 #include <QSet>
 #include <QtMultimedia/QAudioInput>
 #include <QtMultimedia/QAudioOutput>
 #include <QDebug>
 #include <QThread>
 #include <QFile>

 //-----------------------------------------------------------------------------
 // Constants
 //-----------------------------------------------------------------------------

 const qint64 BufferDurationUs       = 10 * 1000000;
 const int    NotifyIntervalMs       = 100;

 // Size of the level calculation window in microseconds
 const int    LevelWindowUs          = 0.1 * 1000000;

 //-----------------------------------------------------------------------------
 // Helper functions
 //-----------------------------------------------------------------------------

 QDebug& operator<<(QDebug &debug, const QAudioFormat &format)
 {
     debug << format.frequency() << "Hz"
           << format.channels() << "channels";
     return debug;
 }

 //-----------------------------------------------------------------------------
 // Constructor and destructor
 //-----------------------------------------------------------------------------

 Engine::Engine(QObject *parent)
     :   QObject(parent)
     ,   m_mode(QAudio::AudioInput)
     ,   m_state(QAudio::StoppedState)
     ,   m_generateTone(false)
     ,   m_file(0)
     ,   m_analysisFile(0)
     ,   m_availableAudioInputDevices
             (QAudioDeviceInfo::availableDevices(QAudio::AudioInput))
     ,   m_audioInputDevice(QAudioDeviceInfo::defaultInputDevice())
     ,   m_audioInput(0)
     ,   m_audioInputIODevice(0)
     ,   m_recordPosition(0)
     ,   m_availableAudioOutputDevices
             (QAudioDeviceInfo::availableDevices(QAudio::AudioOutput))
     ,   m_audioOutputDevice(QAudioDeviceInfo::defaultOutputDevice())
     ,   m_audioOutput(0)
     ,   m_playPosition(0)
     ,   m_bufferPosition(0)
     ,   m_bufferLength(0)
     ,   m_dataLength(0)
     ,   m_levelBufferLength(0)
     ,   m_rmsLevel(0.0)
     ,   m_peakLevel(0.0)
     ,   m_spectrumBufferLength(0)
     ,   m_spectrumAnalyser()
     ,   m_spectrumPosition(0)
     ,   m_count(0)
 {
     qRegisterMetaType<FrequencySpectrum>("FrequencySpectrum");
     qRegisterMetaType<WindowFunction>("WindowFunction");
     CHECKED_CONNECT(&m_spectrumAnalyser,
                     SIGNAL(spectrumChanged(FrequencySpectrum)),
                     this,
                     SLOT(spectrumChanged(FrequencySpectrum)));

     initialize();

 #ifdef DUMP_DATA
     createOutputDir();
 #endif

 #ifdef DUMP_SPECTRUM
     m_spectrumAnalyser.setOutputPath(outputPath());
 #endif
 }

 Engine::~Engine()
 {

 }

 //-----------------------------------------------------------------------------
 // Public functions
 //-----------------------------------------------------------------------------

 bool Engine::loadFile(const QString &fileName)
 {
     reset();
     bool result = false;
     Q_ASSERT(!m_generateTone);
     Q_ASSERT(!m_file);
     Q_ASSERT(!fileName.isEmpty());
     m_file = new WavFile(this);
     if (m_file->open(fileName)) {
         if (isPCMS16LE(m_file->fileFormat())) {
             result = initialize();
         } else {
             emit errorMessage(tr("Audio format not supported"),
                               formatToString(m_file->fileFormat()));
         }
     } else {
         emit errorMessage(tr("Could not open file"), fileName);
     }
     if (result) {
         m_analysisFile = new WavFile(this);
         m_analysisFile->open(fileName);
     }
     return result;
 }

 bool Engine::generateTone(const Tone &tone)
 {
     reset();
     Q_ASSERT(!m_generateTone);
     Q_ASSERT(!m_file);
     m_generateTone = true;
     m_tone = tone;
     ENGINE_DEBUG << "Engine::generateTone"
                  << "startFreq" << m_tone.startFreq
                  << "endFreq" << m_tone.endFreq
                  << "amp" << m_tone.amplitude;
     return initialize();
 }

 bool Engine::generateSweptTone(qreal amplitude)
 {
     Q_ASSERT(!m_generateTone);
     Q_ASSERT(!m_file);
     m_generateTone = true;
     m_tone.startFreq = 1;
     m_tone.endFreq = 0;
     m_tone.amplitude = amplitude;
     ENGINE_DEBUG << "Engine::generateSweptTone"
                  << "startFreq" << m_tone.startFreq
                  << "amp" << m_tone.amplitude;
     return initialize();
 }

 bool Engine::initializeRecord()
 {
     reset();
     ENGINE_DEBUG << "Engine::initializeRecord";
     Q_ASSERT(!m_generateTone);
     Q_ASSERT(!m_file);
     m_generateTone = false;
     m_tone = SweptTone();
     return initialize();
 }

 qint64 Engine::bufferLength() const
 {
     return m_file ? m_file->size() : m_bufferLength;
 }

 void Engine::setWindowFunction(WindowFunction type)
 {
     m_spectrumAnalyser.setWindowFunction(type);
 }

 //-----------------------------------------------------------------------------
 // Public slots
 //-----------------------------------------------------------------------------

 void Engine::startRecording()
 {
     if (m_audioInput) {
         if (QAudio::AudioInput == m_mode &&
             QAudio::SuspendedState == m_state) {
             m_audioInput->resume();
         } else {
             m_spectrumAnalyser.cancelCalculation();
             spectrumChanged(0, 0, FrequencySpectrum());

             m_buffer.fill(0);
             setRecordPosition(0, true);
             stopPlayback();
             m_mode = QAudio::AudioInput;
             CHECKED_CONNECT(m_audioInput, SIGNAL(stateChanged(QAudio::State)),
                             this, SLOT(audioStateChanged(QAudio::State)));
             CHECKED_CONNECT(m_audioInput, SIGNAL(notify()),
                             this, SLOT(audioNotify()));
             m_count = 0;
             m_dataLength = 0;
             emit dataLengthChanged(0);
             m_audioInputIODevice = m_audioInput->start();
             CHECKED_CONNECT(m_audioInputIODevice, SIGNAL(readyRead()),
                             this, SLOT(audioDataReady()));
         }
     }
 }

 void Engine::startPlayback()
 {
     if (m_audioOutput) {
         if (QAudio::AudioOutput == m_mode &&
             QAudio::SuspendedState == m_state) {
 #ifdef Q_OS_WIN
             // The Windows backend seems to internally go back into ActiveState
             // while still returning SuspendedState, so to ensure that it doesn't
             // ignore the resume() call, we first re-suspend
             m_audioOutput->suspend();
 #endif
             m_audioOutput->resume();
         } else {
             m_spectrumAnalyser.cancelCalculation();
             spectrumChanged(0, 0, FrequencySpectrum());
             setPlayPosition(0, true);
             stopRecording();
             m_mode = QAudio::AudioOutput;
             CHECKED_CONNECT(m_audioOutput, SIGNAL(stateChanged(QAudio::State)),
                             this, SLOT(audioStateChanged(QAudio::State)));
             CHECKED_CONNECT(m_audioOutput, SIGNAL(notify()),
                             this, SLOT(audioNotify()));
             m_count = 0;
             if (m_file) {
                 m_file->seek(0);
                 m_bufferPosition = 0;
                 m_dataLength = 0;
                 m_audioOutput->start(m_file);
             } else {
                 m_audioOutputIODevice.close();
                 m_audioOutputIODevice.setBuffer(&m_buffer);
                 m_audioOutputIODevice.open(QIODevice::ReadOnly);
                 m_audioOutput->start(&m_audioOutputIODevice);
             }
         }
     }
 }

 void Engine::suspend()
 {
     if (QAudio::ActiveState == m_state ||
         QAudio::IdleState == m_state) {
         switch (m_mode) {
         case QAudio::AudioInput:
             m_audioInput->suspend();
             break;
         case QAudio::AudioOutput:
             m_audioOutput->suspend();
             break;
         }
     }
 }

 void Engine::setAudioInputDevice(const QAudioDeviceInfo &device)
 {
     if (device.deviceName() != m_audioInputDevice.deviceName()) {
         m_audioInputDevice = device;
         initialize();
     }
 }

 void Engine::setAudioOutputDevice(const QAudioDeviceInfo &device)
 {
     if (device.deviceName() != m_audioOutputDevice.deviceName()) {
         m_audioOutputDevice = device;
         initialize();
     }
 }

 //-----------------------------------------------------------------------------
 // Private slots
 //-----------------------------------------------------------------------------

 void Engine::audioNotify()
 {
     switch (m_mode) {
     case QAudio::AudioInput: {
             const qint64 recordPosition = qMin(m_bufferLength, audioLength(m_format, m_audioInput->processedUSecs()));
             setRecordPosition(recordPosition);
             const qint64 levelPosition = m_dataLength - m_levelBufferLength;
             if (levelPosition >= 0)
                 calculateLevel(levelPosition, m_levelBufferLength);
             if (m_dataLength >= m_spectrumBufferLength) {
                 const qint64 spectrumPosition = m_dataLength - m_spectrumBufferLength;
                 calculateSpectrum(spectrumPosition);
             }
             emit bufferChanged(0, m_dataLength, m_buffer);
         }
         break;
     case QAudio::AudioOutput: {
             const qint64 playPosition = audioLength(m_format, m_audioOutput->processedUSecs());
             setPlayPosition(qMin(bufferLength(), playPosition));
             const qint64 levelPosition = playPosition - m_levelBufferLength;
             const qint64 spectrumPosition = playPosition - m_spectrumBufferLength;
             if (m_file) {
                 if (levelPosition > m_bufferPosition ||
                     spectrumPosition > m_bufferPosition ||
                     qMax(m_levelBufferLength, m_spectrumBufferLength) > m_dataLength) {
                     m_bufferPosition = 0;
                     m_dataLength = 0;
                     // Data needs to be read into m_buffer in order to be analysed
                     const qint64 readPos = qMax(qint64(0), qMin(levelPosition, spectrumPosition));
                     const qint64 readEnd = qMin(m_analysisFile->size(), qMax(levelPosition + m_levelBufferLength, spectrumPosition + m_spectrumBufferLength));
                     const qint64 readLen = readEnd - readPos + audioLength(m_format, WaveformWindowDuration);
                     qDebug() << "Engine::audioNotify [1]"
                              << "analysisFileSize" << m_analysisFile->size()
                              << "readPos" << readPos
                              << "readLen" << readLen;
                     if (m_analysisFile->seek(readPos + m_analysisFile->headerLength())) {
                         m_buffer.resize(readLen);
                         m_bufferPosition = readPos;
                         m_dataLength = m_analysisFile->read(m_buffer.data(), readLen);
                         qDebug() << "Engine::audioNotify [2]" << "bufferPosition" << m_bufferPosition << "dataLength" << m_dataLength;
                     } else {
                         qDebug() << "Engine::audioNotify [2]" << "file seek error";
                     }
                     emit bufferChanged(m_bufferPosition, m_dataLength, m_buffer);
                 }
             } else {
                 if (playPosition >= m_dataLength)
                     stopPlayback();
             }
             if (levelPosition >= 0 && levelPosition + m_levelBufferLength < m_bufferPosition + m_dataLength)
                 calculateLevel(levelPosition, m_levelBufferLength);
             if (spectrumPosition >= 0 && spectrumPosition + m_spectrumBufferLength < m_bufferPosition + m_dataLength)
                 calculateSpectrum(spectrumPosition);
         }
         break;
     }
 }

 void Engine::audioStateChanged(QAudio::State state)
 {
     ENGINE_DEBUG << "Engine::audioStateChanged from" << m_state
                  << "to" << state;

     if (QAudio::IdleState == state && m_file && m_file->pos() == m_file->size()) {
         stopPlayback();
     } else {
         if (QAudio::StoppedState == state) {
             // Check error
             QAudio::Error error = QAudio::NoError;
             switch (m_mode) {
             case QAudio::AudioInput:
                 error = m_audioInput->error();
                 break;
             case QAudio::AudioOutput:
                 error = m_audioOutput->error();
                 break;
             }
             if (QAudio::NoError != error) {
                 reset();
                 return;
             }
         }
         setState(state);
     }
 }

 void Engine::audioDataReady()
 {
     Q_ASSERT(0 == m_bufferPosition);
     const qint64 bytesReady = m_audioInput->bytesReady();
     const qint64 bytesSpace = m_buffer.size() - m_dataLength;
     const qint64 bytesToRead = qMin(bytesReady, bytesSpace);

     const qint64 bytesRead = m_audioInputIODevice->read(
                                        m_buffer.data() + m_dataLength,
                                        bytesToRead);

     if (bytesRead) {
         m_dataLength += bytesRead;
         emit dataLengthChanged(dataLength());
     }

     if (m_buffer.size() == m_dataLength)
         stopRecording();
 }

 void Engine::spectrumChanged(const FrequencySpectrum &spectrum)
 {
     ENGINE_DEBUG << "Engine::spectrumChanged" << "pos" << m_spectrumPosition;
     emit spectrumChanged(m_spectrumPosition, m_spectrumBufferLength, spectrum);
 }

 //-----------------------------------------------------------------------------
 // Private functions
 //-----------------------------------------------------------------------------

 void Engine::resetAudioDevices()
 {
     delete m_audioInput;
     m_audioInput = 0;
     m_audioInputIODevice = 0;
     setRecordPosition(0);
     delete m_audioOutput;
     m_audioOutput = 0;
     setPlayPosition(0);
     m_spectrumPosition = 0;
     setLevel(0.0, 0.0, 0);
 }

 void Engine::reset()
 {
     stopRecording();
     stopPlayback();
     setState(QAudio::AudioInput, QAudio::StoppedState);
     setFormat(QAudioFormat());
     m_generateTone = false;
     delete m_file;
     m_file = 0;
     delete m_analysisFile;
     m_analysisFile = 0;
     m_buffer.clear();
     m_bufferPosition = 0;
     m_bufferLength = 0;
     m_dataLength = 0;
     emit dataLengthChanged(0);
     resetAudioDevices();
 }

 bool Engine::initialize()
 {
     bool result = false;

     QAudioFormat format = m_format;

     if (selectFormat()) {
         if (m_format != format) {
             resetAudioDevices();
             if (m_file) {
                 emit bufferLengthChanged(bufferLength());
                 emit dataLengthChanged(dataLength());
                 emit bufferChanged(0, 0, m_buffer);
                 setRecordPosition(bufferLength());
                 result = true;
             } else {
                 m_bufferLength = audioLength(m_format, BufferDurationUs);
                 m_buffer.resize(m_bufferLength);
                 m_buffer.fill(0);
                 emit bufferLengthChanged(bufferLength());
                 if (m_generateTone) {
                     if (0 == m_tone.endFreq) {
                         const qreal nyquist = nyquistFrequency(m_format);
                         m_tone.endFreq = qMin(qreal(SpectrumHighFreq), nyquist);
                     }
                     // Call function defined in utils.h, at global scope
                     ::generateTone(m_tone, m_format, m_buffer);
                     m_dataLength = m_bufferLength;
                     emit dataLengthChanged(dataLength());
                     emit bufferChanged(0, m_dataLength, m_buffer);
                     setRecordPosition(m_bufferLength);
                     result = true;
                 } else {
                     emit bufferChanged(0, 0, m_buffer);
                     m_audioInput = new QAudioInput(m_audioInputDevice, m_format, this);
                     m_audioInput->setNotifyInterval(NotifyIntervalMs);
                     result = true;
                 }
             }
             m_audioOutput = new QAudioOutput(m_audioOutputDevice, m_format, this);
             m_audioOutput->setNotifyInterval(NotifyIntervalMs);
         }
     } else {
         if (m_file)
             emit errorMessage(tr("Audio format not supported"),
                               formatToString(m_format));
         else if (m_generateTone)
             emit errorMessage(tr("No suitable format found"), "");
         else
             emit errorMessage(tr("No common input / output format found"), "");
     }

     ENGINE_DEBUG << "Engine::initialize" << "m_bufferLength" << m_bufferLength;
     ENGINE_DEBUG << "Engine::initialize" << "m_dataLength" << m_dataLength;
     ENGINE_DEBUG << "Engine::initialize" << "format" << m_format;

     return result;
 }

 bool Engine::selectFormat()
 {
     bool foundSupportedFormat = false;

     if (m_file || QAudioFormat() != m_format) {
         QAudioFormat format = m_format;
         if (m_file)
             // Header is read from the WAV file; just need to check whether
             // it is supported by the audio output device
             format = m_file->fileFormat();
         if (m_audioOutputDevice.isFormatSupported(format)) {
             setFormat(format);
             foundSupportedFormat = true;
         }
     } else {

         QList<int> frequenciesList;
     #ifdef Q_OS_WIN
         // The Windows audio backend does not correctly report format support
         // (see QTBUG-9100).  Furthermore, although the audio subsystem captures
         // at 11025Hz, the resulting audio is corrupted.
         frequenciesList += 8000;
     #endif

         if (!m_generateTone)
             frequenciesList += m_audioInputDevice.supportedFrequencies();

         frequenciesList += m_audioOutputDevice.supportedFrequencies();
         frequenciesList = frequenciesList.toSet().toList(); // remove duplicates
         qSort(frequenciesList);
         ENGINE_DEBUG << "Engine::initialize frequenciesList" << frequenciesList;

         QList<int> channelsList;
         channelsList += m_audioInputDevice.supportedChannels();
         channelsList += m_audioOutputDevice.supportedChannels();
         channelsList = channelsList.toSet().toList();
         qSort(channelsList);
         ENGINE_DEBUG << "Engine::initialize channelsList" << channelsList;

         QAudioFormat format;
         format.setByteOrder(QAudioFormat::LittleEndian);
         format.setCodec("audio/pcm");
         format.setSampleSize(16);
         format.setSampleType(QAudioFormat::SignedInt);
         int frequency, channels;
         foreach (frequency, frequenciesList) {
             if (foundSupportedFormat)
                 break;
             format.setFrequency(frequency);
             foreach (channels, channelsList) {
                 format.setChannels(channels);
                 const bool inputSupport = m_generateTone ||
                                           m_audioInputDevice.isFormatSupported(format);
                 const bool outputSupport = m_audioOutputDevice.isFormatSupported(format);
                 ENGINE_DEBUG << "Engine::initialize checking " << format
                              << "input" << inputSupport
                              << "output" << outputSupport;
                 if (inputSupport && outputSupport) {
                     foundSupportedFormat = true;
                     break;
                 }
             }
         }

         if (!foundSupportedFormat)
             format = QAudioFormat();

         setFormat(format);
     }

     return foundSupportedFormat;
 }

 void Engine::stopRecording()
 {
     if (m_audioInput) {
         m_audioInput->stop();
         QCoreApplication::instance()->processEvents();
         m_audioInput->disconnect();
     }
     m_audioInputIODevice = 0;

 #ifdef DUMP_AUDIO
     dumpData();
 #endif
 }

 void Engine::stopPlayback()
 {
     if (m_audioOutput) {
         m_audioOutput->stop();
         QCoreApplication::instance()->processEvents();
         m_audioOutput->disconnect();
         setPlayPosition(0);
     }
 }

 void Engine::setState(QAudio::State state)
 {
     const bool changed = (m_state != state);
     m_state = state;
     if (changed)
         emit stateChanged(m_mode, m_state);
 }

 void Engine::setState(QAudio::Mode mode, QAudio::State state)
 {
     const bool changed = (m_mode != mode || m_state != state);
     m_mode = mode;
     m_state = state;
     if (changed)
         emit stateChanged(m_mode, m_state);
 }

 void Engine::setRecordPosition(qint64 position, bool forceEmit)
 {
     const bool changed = (m_recordPosition != position);
     m_recordPosition = position;
     if (changed || forceEmit)
         emit recordPositionChanged(m_recordPosition);
 }

 void Engine::setPlayPosition(qint64 position, bool forceEmit)
 {
     const bool changed = (m_playPosition != position);
     m_playPosition = position;
     if (changed || forceEmit)
         emit playPositionChanged(m_playPosition);
 }

 void Engine::calculateLevel(qint64 position, qint64 length)
 {
 #ifdef DISABLE_LEVEL
     Q_UNUSED(position)
     Q_UNUSED(length)
 #else
     Q_ASSERT(position + length <= m_bufferPosition + m_dataLength);

     qreal peakLevel = 0.0;

     qreal sum = 0.0;
     const char *ptr = m_buffer.constData() + position - m_bufferPosition;
     const char *const end = ptr + length;
     while (ptr < end) {
         const qint16 value = *reinterpret_cast<const qint16*>(ptr);
         const qreal fracValue = pcmToReal(value);
         peakLevel = qMax(peakLevel, fracValue);
         sum += fracValue * fracValue;
         ptr += 2;
     }
     const int numSamples = length / 2;
     qreal rmsLevel = sqrt(sum / numSamples);

     rmsLevel = qMax(qreal(0.0), rmsLevel);
     rmsLevel = qMin(qreal(1.0), rmsLevel);
     setLevel(rmsLevel, peakLevel, numSamples);

     ENGINE_DEBUG << "Engine::calculateLevel" << "pos" << position << "len" << length
                  << "rms" << rmsLevel << "peak" << peakLevel;
 #endif
 }

 void Engine::calculateSpectrum(qint64 position)
 {
 #ifdef DISABLE_SPECTRUM
     Q_UNUSED(position)
 #else
     Q_ASSERT(position + m_spectrumBufferLength <= m_bufferPosition + m_dataLength);
     Q_ASSERT(0 == m_spectrumBufferLength % 2); // constraint of FFT algorithm

     // QThread::currentThread is marked 'for internal use only', but
     // we're only using it for debug output here, so it's probably OK :)
     ENGINE_DEBUG << "Engine::calculateSpectrum" << QThread::currentThread()
                  << "count" << m_count << "pos" << position << "len" << m_spectrumBufferLength
                  << "spectrumAnalyser.isReady" << m_spectrumAnalyser.isReady();

     if(m_spectrumAnalyser.isReady()) {
         m_spectrumBuffer = QByteArray::fromRawData(m_buffer.constData() + position - m_bufferPosition,
                                                    m_spectrumBufferLength);
         m_spectrumPosition = position;
         m_spectrumAnalyser.calculate(m_spectrumBuffer, m_format);
     }
 #endif
 }

 void Engine::setFormat(const QAudioFormat &format)
 {
     const bool changed = (format != m_format);
     m_format = format;
     m_levelBufferLength = audioLength(m_format, LevelWindowUs);
     m_spectrumBufferLength = SpectrumLengthSamples *
                             (m_format.sampleSize() / 8) * m_format.channels();
     if (changed)
         emit formatChanged(m_format);
 }

 void Engine::setLevel(qreal rmsLevel, qreal peakLevel, int numSamples)
 {
     m_rmsLevel = rmsLevel;
     m_peakLevel = peakLevel;
     emit levelChanged(m_rmsLevel, m_peakLevel, numSamples);
 }

 #ifdef DUMP_DATA
 void Engine::createOutputDir()
 {
     m_outputDir.setPath("output");

     // Ensure output directory exists and is empty
     if (m_outputDir.exists()) {
         const QStringList files = m_outputDir.entryList(QDir::Files);
         QString file;
         foreach (file, files)
             m_outputDir.remove(file);
     } else {
         QDir::current().mkdir("output");
     }
 }
 #endif // DUMP_DATA

 #ifdef DUMP_AUDIO
 void Engine::dumpData()
 {
     const QString txtFileName = m_outputDir.filePath("data.txt");
     QFile txtFile(txtFileName);
     txtFile.open(QFile::WriteOnly | QFile::Text);
     QTextStream stream(&txtFile);
     const qint16 *ptr = reinterpret_cast<const qint16*>(m_buffer.constData());
     const int numSamples = m_dataLength / (2 * m_format.channels());
     for (int i=0; i<numSamples; ++i) {
         stream << i << "\t" << *ptr << "\n";
         ptr += m_format.channels();
     }

     const QString pcmFileName = m_outputDir.filePath("data.pcm");
     QFile pcmFile(pcmFileName);
     pcmFile.open(QFile::WriteOnly);
     pcmFile.write(m_buffer.constData(), m_dataLength);
 }
 #endif // DUMP_AUDIO
Publicité

Best Of

Actualités les plus lues

Semaine
Mois
Année
  1. « Quelque chose ne va vraiment pas avec les développeurs "modernes" », un développeur à "l'ancienne" critique la multiplication des bibliothèques 94
  2. Apercevoir la troisième dimension ou l'utilisation multithreadée d'OpenGL dans Qt, un article des Qt Quarterly traduit par Guillaume Belz 0
  3. Les développeurs ignorent-ils trop les failles découvertes dans leur code ? Prenez-vous en compte les remarques des autres ? 17
  4. Pourquoi les programmeurs sont-ils moins payés que les gestionnaires de programmes ? Manquent-ils de pouvoir de négociation ? 42
  5. Quelles nouveautés de C++11 Visual C++ doit-il rapidement intégrer ? Donnez-nous votre avis 10
  6. Adieu qmake, bienvenue qbs : Qt Building Suite, un outil déclaratif et extensible pour la compilation de projets Qt 17
  7. 2017 : un quinquennat pour une nouvelle version du C++ ? Possible, selon Herb Sutter 9
Page suivante

Le Qt Labs au hasard

Logo

La théorie des chaînes

Les Qt Labs sont les laboratoires des développeurs de Qt, où ils peuvent partager des impressions sur le framework, son utilisation, ce que pourrait être son futur. Lire l'article.

Communauté

Ressources

Liens utiles

Contact

  • Vous souhaitez rejoindre la rédaction ou proposer un tutoriel, une traduction, une question... ? Postez dans le forum Contribuez ou contactez-nous par MP ou par email (voir en bas de page).

Qt dans le magazine

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 4.7-snapshot
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
 
 
 
 
Partenaires

Hébergement Web