summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorVaL Doroshchuk <valentyn.doroshchuk@qt.io>2017-09-18 11:42:32 +0200
committerVaL Doroshchuk <valentyn.doroshchuk@qt.io>2017-09-28 14:00:55 +0000
commitcd39b3726db7df2d3d8b2ec2584f1aae6255e4aa (patch)
tree1ad09cc22ad5703e749257d20530d92d66f06deb /examples
parent1a8b30c10602aded40bd420614cbc6c7a3d3ba13 (diff)
Modernize the Audio Output example
Changed initialization style. Recoded toggleMode. Removed unneeded defines, function members. Changed signal/slot connection style. Changed foreach to c++11 style. Fixed bug with wrong duration seconds. Task-number: QTBUG-60627 Change-Id: Ib62f7979f2a32d629482026e0d954612b2665d66 Reviewed-by: Christian Stromme <christian.stromme@qt.io>
Diffstat (limited to 'examples')
-rw-r--r--examples/multimedia/audiooutput/audiooutput.cpp242
-rw-r--r--examples/multimedia/audiooutput/audiooutput.h36
2 files changed, 113 insertions, 165 deletions
diff --git a/examples/multimedia/audiooutput/audiooutput.cpp b/examples/multimedia/audiooutput/audiooutput.cpp
index 3e9ec7377..543242a80 100644
--- a/examples/multimedia/audiooutput/audiooutput.cpp
+++ b/examples/multimedia/audiooutput/audiooutput.cpp
@@ -38,6 +38,8 @@
**
****************************************************************************/
+#include "audiooutput.h"
+
#include <QAudioDeviceInfo>
#include <QAudioOutput>
#include <QDebug>
@@ -45,36 +47,14 @@
#include <qmath.h>
#include <qendian.h>
-#include "audiooutput.h"
-
-#define PUSH_MODE_LABEL "Enable push mode"
-#define PULL_MODE_LABEL "Enable pull mode"
-#define SUSPEND_LABEL "Suspend playback"
-#define RESUME_LABEL "Resume playback"
-#define VOLUME_LABEL "Volume:"
-
-const int DurationSeconds = 1;
-const int ToneSampleRateHz = 600;
-const int DataSampleRateHz = 44100;
-const int BufferSize = 32768;
-
-
-Generator::Generator(const QAudioFormat &format,
- qint64 durationUs,
- int sampleRate,
- QObject *parent)
- : QIODevice(parent)
- , m_pos(0)
+Generator::Generator(const QAudioFormat &format
+ , qint64 durationUs
+ , int sampleRate)
{
if (format.isValid())
generateData(format, durationUs, sampleRate);
}
-Generator::~Generator()
-{
-
-}
-
void Generator::start()
{
open(QIODevice::ReadOnly);
@@ -90,10 +70,8 @@ void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int
{
const int channelBytes = format.sampleSize() / 8;
const int sampleBytes = format.channelCount() * channelBytes;
-
qint64 length = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8))
- * durationUs / 100000;
-
+ * durationUs / 1000000;
Q_ASSERT(length % sampleBytes == 0);
Q_UNUSED(sampleBytes) // suppress warning in release builds
@@ -102,32 +80,36 @@ void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int
int sampleIndex = 0;
while (length) {
- const qreal x = qSin(2 * M_PI * sampleRate * qreal(sampleIndex % format.sampleRate()) / format.sampleRate());
+ // Produces value (-1..1)
+ const qreal x = qSin(2 * M_PI * sampleRate * qreal(sampleIndex++ % format.sampleRate()) / format.sampleRate());
for (int i=0; i<format.channelCount(); ++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);
+ if (format.sampleSize() == 8) {
+ if (format.sampleType() == QAudioFormat::UnSignedInt) {
+ const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255);
+ *reinterpret_cast<quint8 *>(ptr) = value;
+ } else if (format.sampleType() == QAudioFormat::SignedInt) {
+ const qint8 value = static_cast<qint8>(x * 127);
+ *reinterpret_cast<qint8 *>(ptr) = value;
+ }
+ } else if (format.sampleSize() == 16) {
+ if (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.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;
}
}
@@ -159,177 +141,149 @@ qint64 Generator::bytesAvailable() const
}
AudioTest::AudioTest()
- : m_pushTimer(new QTimer(this))
- , m_modeButton(0)
- , m_suspendResumeButton(0)
- , m_deviceBox(0)
- , m_device(QAudioDeviceInfo::defaultOutputDevice())
- , m_generator(0)
- , m_audioOutput(0)
- , m_output(0)
- , m_pullMode(true)
- , m_buffer(BufferSize, 0)
+ : m_pushTimer(new QTimer(this))
{
initializeWindow();
- initializeAudio();
+ initializeAudio(QAudioDeviceInfo::defaultOutputDevice());
+}
+
+AudioTest::~AudioTest()
+{
+ m_pushTimer->stop();
}
void AudioTest::initializeWindow()
{
- QScopedPointer<QWidget> window(new QWidget);
- QScopedPointer<QVBoxLayout> layout(new QVBoxLayout);
+ QWidget *window = new QWidget;
+ QVBoxLayout *layout = new QVBoxLayout;
m_deviceBox = new QComboBox(this);
const QAudioDeviceInfo &defaultDeviceInfo = QAudioDeviceInfo::defaultOutputDevice();
m_deviceBox->addItem(defaultDeviceInfo.deviceName(), qVariantFromValue(defaultDeviceInfo));
- foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) {
+ for (auto &deviceInfo: QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) {
if (deviceInfo != defaultDeviceInfo)
m_deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo));
}
- connect(m_deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int)));
+ connect(m_deviceBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::deviceChanged);
layout->addWidget(m_deviceBox);
m_modeButton = new QPushButton(this);
- m_modeButton->setText(tr(PUSH_MODE_LABEL));
- connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode()));
+ connect(m_modeButton, &QPushButton::clicked, this, &AudioTest::toggleMode);
layout->addWidget(m_modeButton);
m_suspendResumeButton = new QPushButton(this);
- m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
- connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume()));
+ connect(m_suspendResumeButton, &QPushButton::clicked, this, &AudioTest::toggleSuspendResume);
layout->addWidget(m_suspendResumeButton);
QHBoxLayout *volumeBox = new QHBoxLayout;
m_volumeLabel = new QLabel;
- m_volumeLabel->setText(tr(VOLUME_LABEL));
+ m_volumeLabel->setText(tr("Volume:"));
m_volumeSlider = new QSlider(Qt::Horizontal);
m_volumeSlider->setMinimum(0);
m_volumeSlider->setMaximum(100);
m_volumeSlider->setSingleStep(10);
- connect(m_volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
+ connect(m_volumeSlider, &QSlider::valueChanged, this, &AudioTest::volumeChanged);
volumeBox->addWidget(m_volumeLabel);
volumeBox->addWidget(m_volumeSlider);
layout->addLayout(volumeBox);
- window->setLayout(layout.data());
- layout.take(); // ownership transferred
+ window->setLayout(layout);
- setCentralWidget(window.data());
- QWidget *const windowPtr = window.take(); // ownership transferred
- windowPtr->show();
+ setCentralWidget(window);
+ window->show();
}
-void AudioTest::initializeAudio()
+void AudioTest::initializeAudio(const QAudioDeviceInfo &deviceInfo)
{
- connect(m_pushTimer, SIGNAL(timeout()), SLOT(pushTimerExpired()));
-
- m_format.setSampleRate(DataSampleRateHz);
- m_format.setChannelCount(1);
- m_format.setSampleSize(16);
- m_format.setCodec("audio/pcm");
- m_format.setByteOrder(QAudioFormat::LittleEndian);
- m_format.setSampleType(QAudioFormat::SignedInt);
-
- QAudioDeviceInfo info(m_device);
- if (!info.isFormatSupported(m_format)) {
+ QAudioFormat format;
+ format.setSampleRate(44100);
+ format.setChannelCount(1);
+ format.setSampleSize(16);
+ format.setCodec("audio/pcm");
+ format.setByteOrder(QAudioFormat::LittleEndian);
+ format.setSampleType(QAudioFormat::SignedInt);
+
+ if (!deviceInfo.isFormatSupported(format)) {
qWarning() << "Default format not supported - trying to use nearest";
- m_format = info.nearestFormat(m_format);
+ format = deviceInfo.nearestFormat(format);
}
- if (m_generator)
- delete m_generator;
- m_generator = new Generator(m_format, DurationSeconds*1000000, ToneSampleRateHz, this);
-
- createAudioOutput();
-}
-
-void AudioTest::createAudioOutput()
-{
- delete m_audioOutput;
- m_audioOutput = 0;
- m_audioOutput = new QAudioOutput(m_device, m_format, this);
+ const int durationSeconds = 1;
+ const int toneSampleRateHz = 600;
+ m_generator.reset(new Generator(format, durationSeconds * 1000000, toneSampleRateHz));
+ m_audioOutput.reset(new QAudioOutput(deviceInfo, format));
m_generator->start();
- m_audioOutput->start(m_generator);
qreal initialVolume = QAudio::convertVolume(m_audioOutput->volume(),
QAudio::LinearVolumeScale,
QAudio::LogarithmicVolumeScale);
m_volumeSlider->setValue(qRound(initialVolume * 100));
-}
-
-AudioTest::~AudioTest()
-{
-
+ toggleMode();
}
void AudioTest::deviceChanged(int index)
{
- m_pushTimer->stop();
m_generator->stop();
m_audioOutput->stop();
m_audioOutput->disconnect(this);
- m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>();
- initializeAudio();
+ initializeAudio(m_deviceBox->itemData(index).value<QAudioDeviceInfo>());
}
void AudioTest::volumeChanged(int value)
{
- if (m_audioOutput) {
- qreal linearVolume = QAudio::convertVolume(value / qreal(100),
- QAudio::LogarithmicVolumeScale,
- QAudio::LinearVolumeScale);
+ qreal linearVolume = QAudio::convertVolume(value / qreal(100),
+ QAudio::LogarithmicVolumeScale,
+ QAudio::LinearVolumeScale);
- m_audioOutput->setVolume(linearVolume);
- }
-}
-
-void AudioTest::pushTimerExpired()
-{
- if (m_audioOutput && m_audioOutput->state() != QAudio::StoppedState) {
- int chunks = m_audioOutput->bytesFree()/m_audioOutput->periodSize();
- while (chunks) {
- const qint64 len = m_generator->read(m_buffer.data(), m_audioOutput->periodSize());
- if (len)
- m_output->write(m_buffer.data(), len);
- if (len != m_audioOutput->periodSize())
- break;
- --chunks;
- }
- }
+ m_audioOutput->setVolume(linearVolume);
}
void AudioTest::toggleMode()
{
m_pushTimer->stop();
m_audioOutput->stop();
+ toggleSuspendResume();
if (m_pullMode) {
+ //switch to pull mode (QAudioOutput pulls from Generator as needed)
+ m_modeButton->setText(tr("Enable push mode"));
+ m_audioOutput->start(m_generator.data());
+ } else {
//switch to push mode (periodically push to QAudioOutput using a timer)
- m_modeButton->setText(tr(PULL_MODE_LABEL));
- m_output = m_audioOutput->start();
- m_pullMode = false;
+ m_modeButton->setText(tr("Enable pull mode"));
+ auto io = m_audioOutput->start();
+ m_pushTimer->disconnect();
+
+ connect(m_pushTimer, &QTimer::timeout, [this, io]() {
+ if (m_audioOutput->state() == QAudio::StoppedState)
+ return;
+
+ QByteArray buffer(32768, 0);
+ int chunks = m_audioOutput->bytesFree() / m_audioOutput->periodSize();
+ while (chunks) {
+ const qint64 len = m_generator->read(buffer.data(), m_audioOutput->periodSize());
+ if (len)
+ io->write(buffer.data(), len);
+ if (len != m_audioOutput->periodSize())
+ break;
+ --chunks;
+ }
+ });
+
m_pushTimer->start(20);
- } else {
- //switch to pull mode (QAudioOutput pulls from Generator as needed)
- m_modeButton->setText(tr(PUSH_MODE_LABEL));
- m_pullMode = true;
- m_audioOutput->start(m_generator);
}
- m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
+ m_pullMode = !m_pullMode;
}
void AudioTest::toggleSuspendResume()
{
- if (m_audioOutput->state() == QAudio::SuspendedState) {
+ if (m_audioOutput->state() == QAudio::SuspendedState || m_audioOutput->state() == QAudio::StoppedState) {
m_audioOutput->resume();
- m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
+ m_suspendResumeButton->setText(tr("Suspend recording"));
} else if (m_audioOutput->state() == QAudio::ActiveState) {
m_audioOutput->suspend();
- m_suspendResumeButton->setText(tr(RESUME_LABEL));
- } else if (m_audioOutput->state() == QAudio::StoppedState) {
- m_audioOutput->resume();
- m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
+ m_suspendResumeButton->setText(tr("Resume playback"));
} else if (m_audioOutput->state() == QAudio::IdleState) {
// no-op
}
diff --git a/examples/multimedia/audiooutput/audiooutput.h b/examples/multimedia/audiooutput/audiooutput.h
index d5c2b4cc2..489624160 100644
--- a/examples/multimedia/audiooutput/audiooutput.h
+++ b/examples/multimedia/audiooutput/audiooutput.h
@@ -53,14 +53,14 @@
#include <QPushButton>
#include <QSlider>
#include <QTimer>
+#include <QScopedPointer>
class Generator : public QIODevice
{
Q_OBJECT
public:
- Generator(const QAudioFormat &format, qint64 durationUs, int sampleRate, QObject *parent);
- ~Generator();
+ Generator(const QAudioFormat &format, qint64 durationUs, int sampleRate);
void start();
void stop();
@@ -73,7 +73,7 @@ private:
void generateData(const QAudioFormat &format, qint64 durationUs, int sampleRate);
private:
- qint64 m_pos;
+ qint64 m_pos = 0;
QByteArray m_buffer;
};
@@ -87,30 +87,24 @@ public:
private:
void initializeWindow();
- void initializeAudio();
- void createAudioOutput();
+ void initializeAudio(const QAudioDeviceInfo &deviceInfo);
private:
- QTimer *m_pushTimer;
+ QTimer *m_pushTimer = nullptr;
// Owned by layout
- QPushButton *m_modeButton;
- QPushButton *m_suspendResumeButton;
- QComboBox *m_deviceBox;
- QLabel *m_volumeLabel;
- QSlider *m_volumeSlider;
-
- QAudioDeviceInfo m_device;
- Generator *m_generator;
- QAudioOutput *m_audioOutput;
- QIODevice *m_output; // not owned
- QAudioFormat m_format;
-
- bool m_pullMode;
- QByteArray m_buffer;
+ QPushButton *m_modeButton = nullptr;
+ QPushButton *m_suspendResumeButton = nullptr;
+ QComboBox *m_deviceBox = nullptr;
+ QLabel *m_volumeLabel = nullptr;
+ QSlider *m_volumeSlider = nullptr;
+
+ QScopedPointer<Generator> m_generator;
+ QScopedPointer<QAudioOutput> m_audioOutput;
+
+ bool m_pullMode = true;
private slots:
- void pushTimerExpired();
void toggleMode();
void toggleSuspendResume();
void deviceChanged(int index);