From 53dc6607cf669b977ff40de995bd9b1b8e395b78 Mon Sep 17 00:00:00 2001 From: Gareth Stockwell Date: Tue, 16 Feb 2010 12:55:23 +0000 Subject: 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 --- examples/multimedia/audiooutput/audiooutput.cpp | 128 +++++++++++++----------- examples/multimedia/audiooutput/audiooutput.h | 19 ++-- 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 #include +#include +#include #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(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((1.0 + x) / 2 * 255); + *reinterpret_cast(ptr) = value; + } else if (format.sampleSize() == 8 && format.sampleType() == QAudioFormat::SignedInt) { + const qint8 value = static_cast(x * 127); + *reinterpret_cast(ptr) = value; + } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::UnSignedInt) { + quint16 value = static_cast((1.0 + x) / 2 * 65535); + if (format.byteOrder() == QAudioFormat::LittleEndian) + qToLittleEndian(value, ptr); + else + qToBigEndian(value, ptr); + } else if (format.sampleSize() == 16 && format.sampleType() == QAudioFormat::SignedInt) { + qint16 value = static_cast(x * 32767); + if (format.byteOrder() == QAudioFormat::LittleEndian) + qToLittleEndian(value, ptr); + else + qToBigEndian(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 #include #include +#include #include @@ -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; -- cgit v0.12