diff options
author | Gareth Stockwell <ext-gareth.stockwell@nokia.com> | 2010-02-16 16:43:20 (GMT) |
---|---|---|
committer | Gareth Stockwell <ext-gareth.stockwell@nokia.com> | 2010-02-16 17:57:48 (GMT) |
commit | 479e26ab077a9d43e37b0706db4f5cb61964b327 (patch) | |
tree | b8906650d2d326a75e967c71b3e63bb4071da425 /examples | |
parent | d17060663236c0cf4d3eec79f8f76e30edfca636 (diff) | |
download | Qt-479e26ab077a9d43e37b0706db4f5cb61964b327.zip Qt-479e26ab077a9d43e37b0706db4f5cb61964b327.tar.gz Qt-479e26ab077a9d43e37b0706db4f5cb61964b327.tar.bz2 |
Made level calculation in audio input example work for all formats
The previous code only worked correctly for little-endian PCM16 formats.
If the audio input device does not support such a format, the example
previously would not run.
Reviewed-by: trustme
Diffstat (limited to 'examples')
-rw-r--r-- | examples/multimedia/audioinput/audioinput.cpp | 110 | ||||
-rw-r--r-- | examples/multimedia/audioinput/audioinput.h | 12 |
2 files changed, 80 insertions, 42 deletions
diff --git a/examples/multimedia/audioinput/audioinput.cpp b/examples/multimedia/audioinput/audioinput.cpp index d00dd02..36fc5ac 100644 --- a/examples/multimedia/audioinput/audioinput.cpp +++ b/examples/multimedia/audioinput/audioinput.cpp @@ -48,14 +48,42 @@ #include <QAudioDeviceInfo> #include <QAudioInput> + +#include <QtCore/qendian.h> + #include "audioinput.h" #define BUFFER_SIZE 4096 -AudioInfo::AudioInfo(QObject *parent) - :QIODevice(parent) +AudioInfo::AudioInfo(const QAudioFormat &format, QObject *parent) + : QIODevice(parent) + , m_format(format) + , m_maxAmplitude(0) + , m_level(0.0) + { - m_maxValue = 0; + switch (m_format.sampleSize()) { + case 8: + switch (m_format.sampleType()) { + case QAudioFormat::UnSignedInt: + m_maxAmplitude = 255; + break; + case QAudioFormat::SignedInt: + m_maxAmplitude = 127; + break; + } + break; + case 16: + switch (m_format.sampleType()) { + case QAudioFormat::UnSignedInt: + m_maxAmplitude = 65535; + break; + case QAudioFormat::SignedInt: + m_maxAmplitude = 32767; + break; + } + break; + } } AudioInfo::~AudioInfo() @@ -82,41 +110,49 @@ qint64 AudioInfo::readData(char *data, qint64 maxlen) qint64 AudioInfo::writeData(const char *data, qint64 len) { - int samples = len/2; // 2 bytes per sample - int maxAmp = 32768; // max for S16 samples - bool clipping = false; - - m_maxValue = 0; - - qint16 *s = (qint16*)data; - - // sample format is S16LE, only! - - for (int i = 0; i < samples; ++i) { - qint16 sample = *s; - s++; - if (abs(sample) > m_maxValue) m_maxValue = abs(sample); + if (m_maxAmplitude) { + Q_ASSERT(m_format.sampleSize() % 8 == 0); + const int channelBytes = m_format.sampleSize() / 8; + const int sampleBytes = m_format.channels() * channelBytes; + Q_ASSERT(len % sampleBytes == 0); + const int numSamples = len / sampleBytes; + + quint16 maxValue = 0; + const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data); + + for (int i = 0; i < numSamples; ++i) { + for(int j = 0; j < m_format.channels(); ++j) { + quint16 value = 0; + + if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::UnSignedInt) { + value = *reinterpret_cast<const quint8*>(ptr); + } else if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::SignedInt) { + value = qAbs(*reinterpret_cast<const qint8*>(ptr)); + } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::UnSignedInt) { + if (m_format.byteOrder() == QAudioFormat::LittleEndian) + value = qFromLittleEndian<quint16>(ptr); + else + value = qFromBigEndian<quint16>(ptr); + } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::SignedInt) { + if (m_format.byteOrder() == QAudioFormat::LittleEndian) + value = qAbs(qFromLittleEndian<qint16>(ptr)); + else + value = qAbs(qFromBigEndian<qint16>(ptr)); + } + + maxValue = qMax(value, maxValue); + ptr += channelBytes; + } + } + + maxValue = qMin(maxValue, m_maxAmplitude); + m_level = qreal(maxValue) / m_maxAmplitude; } - // check for clipping - if (m_maxValue >= (maxAmp - 1)) - clipping = true; - - float value = ((float)m_maxValue/(float)maxAmp); - if (clipping) - m_maxValue = 100; - else - m_maxValue = (int)(value*100); emit update(); - return len; } -int AudioInfo::LinearMax() -{ - return m_maxValue; -} - RenderArea::RenderArea(QWidget *parent) : QWidget(parent) { @@ -137,12 +173,12 @@ void RenderArea::paintEvent(QPaintEvent * /* event */) painter.viewport().top()+10, painter.viewport().right()-20, painter.viewport().bottom()-20)); - if (level == 0) + if (level == 0.0) return; painter.setPen(Qt::red); - int pos = ((painter.viewport().right()-20)-(painter.viewport().left()+11))*level/100; + int pos = ((painter.viewport().right()-20)-(painter.viewport().left()+11))*level; for (int i = 0; i < 10; ++i) { int x1 = painter.viewport().left()+11; int y1 = painter.viewport().top()+10+i; @@ -155,7 +191,7 @@ void RenderArea::paintEvent(QPaintEvent * /* event */) } } -void RenderArea::setLevel(int value) +void RenderArea::setLevel(qreal value) { level = value; repaint(); @@ -220,7 +256,7 @@ InputTest::InputTest() audioInput = new QAudioInput(format,this); connect(audioInput, SIGNAL(notify()), SLOT(status())); connect(audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(state(QAudio::State))); - audioinfo = new AudioInfo(this); + audioinfo = new AudioInfo(format, this); connect(audioinfo, SIGNAL(update()), SLOT(refreshDisplay())); audioinfo->start(); audioInput->start(audioinfo); @@ -292,7 +328,7 @@ void InputTest::state(QAudio::State state) void InputTest::refreshDisplay() { - canvas->setLevel(audioinfo->LinearMax()); + canvas->setLevel(audioinfo->level()); canvas->repaint(); } diff --git a/examples/multimedia/audioinput/audioinput.h b/examples/multimedia/audioinput/audioinput.h index 6f6c8eb..33b9ac6 100644 --- a/examples/multimedia/audioinput/audioinput.h +++ b/examples/multimedia/audioinput/audioinput.h @@ -52,19 +52,21 @@ class AudioInfo : public QIODevice { Q_OBJECT public: - AudioInfo(QObject *parent); + AudioInfo(const QAudioFormat &format, QObject *parent); ~AudioInfo(); void start(); void stop(); - int LinearMax(); + qreal level() const { return m_level; } qint64 readData(char *data, qint64 maxlen); qint64 writeData(const char *data, qint64 len); private: - int m_maxValue; + const QAudioFormat m_format; + quint16 m_maxAmplitude; + qreal m_level; // 0.0 <= m_level <= 1.0 signals: void update(); @@ -78,13 +80,13 @@ class RenderArea : public QWidget public: RenderArea(QWidget *parent = 0); - void setLevel(int value); + void setLevel(qreal value); protected: void paintEvent(QPaintEvent *event); private: - int level; + qreal level; QPixmap pixmap; }; |