summaryrefslogtreecommitdiffstats
path: root/examples/multimedia/audiooutput
diff options
context:
space:
mode:
authorGareth Stockwell <ext-gareth.stockwell@nokia.com>2010-02-16 12:55:23 (GMT)
committerGareth Stockwell <ext-gareth.stockwell@nokia.com>2010-02-16 17:57:39 (GMT)
commit53dc6607cf669b977ff40de995bd9b1b8e395b78 (patch)
treefb83b582460bb91d7a3da9805b6a03a151175cdc /examples/multimedia/audiooutput
parentb03306503cc7de9513aa282b55bda40cea00e128 (diff)
downloadQt-53dc6607cf669b977ff40de995bd9b1b8e395b78.zip
Qt-53dc6607cf669b977ff40de995bd9b1b8e395b78.tar.gz
Qt-53dc6607cf669b977ff40de995bd9b1b8e395b78.tar.bz2
Made data generation in audio output example work for all formats
The previous code only worked correctly for mono PCM16 formats. This meant that: a) If the device did not support mono, but did support stereo PCM16, the tone would be played at the wrong pitch. b) If the device did not support little-endian PCM16 at all (admittedly unlikely), the example would not run. Reviewed-by: trustme
Diffstat (limited to 'examples/multimedia/audiooutput')
-rw-r--r--examples/multimedia/audiooutput/audiooutput.cpp128
-rw-r--r--examples/multimedia/audiooutput/audiooutput.h19
2 files changed, 75 insertions, 72 deletions
diff --git a/examples/multimedia/audiooutput/audiooutput.cpp b/examples/multimedia/audiooutput/audiooutput.cpp
index d4bb294..d459e50e 100644
--- a/examples/multimedia/audiooutput/audiooutput.cpp
+++ b/examples/multimedia/audiooutput/audiooutput.cpp
@@ -44,30 +44,27 @@
#include <QAudioOutput>
#include <QAudioDeviceInfo>
+#include <QtCore/qmath.h>
+#include <QtCore/qendian.h>
#include "audiooutput.h"
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
#define SECONDS 1
#define FREQ 600
#define SYSTEM_FREQ 44100
-Generator::Generator(QObject *parent)
- :QIODevice( parent )
+Generator::Generator(const QAudioFormat &format,
+ qint64 durationUs,
+ int frequency,
+ QObject *parent)
+ : QIODevice(parent)
+ , pos(0)
{
- finished = false;
- buffer = new char[SECONDS*SYSTEM_FREQ*4+1000];
- t=buffer;
- len=fillData(t,FREQ,SECONDS); /* mono FREQHz sine */
- pos = 0;
- total = len;
+ generateData(format, durationUs, frequency);
}
Generator::~Generator()
{
- delete [] buffer;
+
}
void Generator::start()
@@ -75,54 +72,67 @@ void Generator::start()
open(QIODevice::ReadOnly);
}
-qint64 Generator::bytesAvailable() const
-{
- return (SECONDS*SYSTEM_FREQ*2)-pos + QIODevice::bytesAvailable();
-}
-
void Generator::stop()
{
+ pos = 0;
close();
}
-int Generator::putShort(char *t, unsigned int value)
+void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int frequency)
{
- *(unsigned char *)(t++)=value&255;
- *(unsigned char *)(t)=(value/256)&255;
- return 2;
-}
-
-int Generator::fillData(char *start, int frequency, int seconds)
-{
- int i, len=0;
- int value;
- for(i=0; i<seconds*SYSTEM_FREQ; i++) {
- value=(int)(32767.0*sin(2.0*M_PI*((double)(i))*(double)(frequency)/SYSTEM_FREQ));
- putShort(start, value);
- start += 4;
- len+=2;
+ const int channelBytes = format.sampleSize() / 8;
+ const int sampleBytes = format.channels() * channelBytes;
+
+ qint64 length = (format.frequency() * format.channels() * (format.sampleSize() / 8))
+ * durationUs / 100000;
+
+ Q_ASSERT(length % sampleBytes == 0);
+ Q_UNUSED(sampleBytes) // suppress warning in release builds
+
+ buffer.resize(length);
+ unsigned char *ptr = reinterpret_cast<unsigned char *>(buffer.data());
+ int sampleIndex = 0;
+
+ while (length) {
+ const qreal x = qSin(2 * M_PI * frequency * qreal(sampleIndex % format.frequency()) / format.frequency());
+ for (int i=0; i<format.channels(); ++i) {
+ if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::UnSignedInt) {
+ const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255);
+ *reinterpret_cast<quint8*>(ptr) = value;
+ } else if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::SignedInt) {
+ const qint8 value = static_cast<qint8>(x * 127);
+ *reinterpret_cast<quint8*>(ptr) = value;
+ } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::UnSignedInt) {
+ quint16 value = static_cast<quint16>((1.0 + x) / 2 * 65535);
+ if (format.byteOrder() == QAudioFormat::LittleEndian)
+ qToLittleEndian<quint16>(value, ptr);
+ else
+ qToBigEndian<quint16>(value, ptr);
+ } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) {
+ qint16 value = static_cast<qint16>(x * 32767);
+ if (format.byteOrder() == QAudioFormat::LittleEndian)
+ qToLittleEndian<qint16>(value, ptr);
+ else
+ qToBigEndian<qint16>(value, ptr);
+ }
+
+ ptr += channelBytes;
+ length -= channelBytes;
+ }
+ ++sampleIndex;
}
- return len;
}
-qint64 Generator::readData(char *data, qint64 maxlen)
+qint64 Generator::readData(char *data, qint64 len)
{
- int len = maxlen;
- if (len > 16384)
- len = 16384;
-
- if (len < (SECONDS*SYSTEM_FREQ*2)-pos) {
- // Normal
- memcpy(data,t+pos,len);
- pos+=len;
- return len;
- } else {
- // Whats left and reset to start
- qint64 left = (SECONDS*SYSTEM_FREQ*2)-pos;
- memcpy(data,t+pos,left);
- pos=0;
- return left;
+ qint64 total = 0;
+ while (len - total) {
+ const qint64 chunk = qMin((buffer.size() - pos), len - total);
+ memcpy(data, buffer.constData() + pos, chunk);
+ pos = (pos + chunk) % buffer.size();
+ total += chunk;
}
+ return total;
}
qint64 Generator::writeData(const char *data, qint64 len)
@@ -133,6 +143,11 @@ qint64 Generator::writeData(const char *data, qint64 len)
return 0;
}
+qint64 Generator::bytesAvailable() const
+{
+ return buffer.size() + QIODevice::bytesAvailable();
+}
+
AudioTest::AudioTest()
{
QWidget *window = new QWidget;
@@ -160,15 +175,11 @@ AudioTest::AudioTest()
buffer = new char[BUFFER_SIZE];
- gen = new Generator(this);
-
pullMode = true;
timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),SLOT(writeMore()));
- gen->start();
-
settings.setFrequency(SYSTEM_FREQ);
settings.setChannels(1);
settings.setSampleSize(16);
@@ -182,13 +193,8 @@ AudioTest::AudioTest()
settings = info.nearestFormat(settings);
}
- if(settings.sampleSize() != 16) {
- qWarning()<<"audio device doesn't support 16 bit samples, example cannot run";
- button->setDisabled(true);
- button2->setDisabled(true);
- audioOutput = 0;
- return;
- }
+ gen = new Generator(settings, SECONDS*1000000, FREQ, this);
+ gen->start();
audioOutput = new QAudioOutput(settings,this);
connect(audioOutput,SIGNAL(notify()),SLOT(status()));
diff --git a/examples/multimedia/audiooutput/audiooutput.h b/examples/multimedia/audiooutput/audiooutput.h
index eba6446..2c62d84 100644
--- a/examples/multimedia/audiooutput/audiooutput.h
+++ b/examples/multimedia/audiooutput/audiooutput.h
@@ -49,6 +49,7 @@
#include <QTimer>
#include <QPushButton>
#include <QComboBox>
+#include <QByteArray>
#include <QAudioOutput>
@@ -56,27 +57,22 @@ class Generator : public QIODevice
{
Q_OBJECT
public:
- Generator(QObject *parent);
+ Generator(const QAudioFormat &format, qint64 durationUs, int frequency, QObject *parent);
~Generator();
void start();
void stop();
- char *t;
- int len;
- int pos;
- int total;
- char *buffer;
- bool finished;
- int chunk_size;
-
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len);
qint64 bytesAvailable() const;
private:
- int putShort(char *t, unsigned int value);
- int fillData(char *start, int frequency, int seconds);
+ void generateData(const QAudioFormat &format, qint64 durationUs, int frequency);
+
+private:
+ qint64 pos;
+ QByteArray buffer;
};
class AudioTest : public QMainWindow
@@ -86,6 +82,7 @@ public:
AudioTest();
~AudioTest();
+private:
QAudioDeviceInfo device;
Generator* gen;
QAudioOutput* audioOutput;