diff options
author | Michael Goddard <michael.goddard@nokia.com> | 2011-06-29 13:38:46 +1000 |
---|---|---|
committer | Michael Goddard <michael.goddard@nokia.com> | 2011-06-29 13:38:46 +1000 |
commit | 2a34e88c1e1ced28e75c487cd13402e1c9cf9fa3 (patch) | |
tree | e6c1b770c5c47212792a1f9344fa034ea3e54c44 /examples/audiooutput |
Initial copy of QtMultimediaKit.
Comes from original repo, with SHA1:
2c82d5611655e5967f5c5095af50c0991c4378b2
Diffstat (limited to 'examples/audiooutput')
-rw-r--r-- | examples/audiooutput/audiooutput.cpp | 314 | ||||
-rw-r--r-- | examples/audiooutput/audiooutput.h | 122 | ||||
-rw-r--r-- | examples/audiooutput/audiooutput.pro | 15 | ||||
-rw-r--r-- | examples/audiooutput/main.cpp | 55 |
4 files changed, 506 insertions, 0 deletions
diff --git a/examples/audiooutput/audiooutput.cpp b/examples/audiooutput/audiooutput.cpp new file mode 100644 index 000000000..df0b226bb --- /dev/null +++ b/examples/audiooutput/audiooutput.cpp @@ -0,0 +1,314 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 Mobility Components. +** +** $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 <QDebug> +#include <QVBoxLayout> + +#include <qaudiooutput.h> +#include <qaudiodeviceinfo.h> +#include <QtCore/qmath.h> +#include <QtCore/qendian.h> +#include "audiooutput.h" + +const QString AudioTest::PushModeLabel(tr("Enable push mode")); +const QString AudioTest::PullModeLabel(tr("Enable pull mode")); +const QString AudioTest::SuspendLabel(tr("Suspend playback")); +const QString AudioTest::ResumeLabel(tr("Resume playback")); + +const int DurationSeconds = 1; +const int ToneFrequencyHz = 600; +const int DataFrequencyHz = 44100; +const int BufferSize = 32768; + + +Generator::Generator(const QAudioFormat &format, + qint64 durationUs, + int frequency, + QObject *parent) + : QIODevice(parent) + , m_pos(0) +{ + generateData(format, durationUs, frequency); +} + +Generator::~Generator() +{ + +} + +void Generator::start() +{ + open(QIODevice::ReadOnly); +} + +void Generator::stop() +{ + m_pos = 0; + close(); +} + +void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int frequency) +{ + 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 + + m_buffer.resize(length); + unsigned char *ptr = reinterpret_cast<unsigned char *>(m_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; + } +} + +qint64 Generator::readData(char *data, qint64 len) +{ + qint64 total = 0; + while (len - total > 0) { + const qint64 chunk = qMin((m_buffer.size() - m_pos), len - total); + memcpy(data + total, m_buffer.constData() + m_pos, chunk); + m_pos = (m_pos + chunk) % m_buffer.size(); + total += chunk; + } + return total; +} + +qint64 Generator::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + Q_UNUSED(len); + + return 0; +} + +qint64 Generator::bytesAvailable() const +{ + return m_buffer.size() + QIODevice::bytesAvailable(); +} + +AudioTest::AudioTest() + : m_pullTimer(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_buffer(BufferSize, 0) +{ + initializeWindow(); + initializeAudio(); +} + +void AudioTest::initializeWindow() +{ + QScopedPointer<QWidget> window(new QWidget); + QScopedPointer<QVBoxLayout> layout(new QVBoxLayout); + + m_deviceBox = new QComboBox(this); + foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) + m_deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo)); + connect(m_deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); + layout->addWidget(m_deviceBox); + + m_modeButton = new QPushButton(this); + m_modeButton->setText(PushModeLabel); + connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode())); + layout->addWidget(m_modeButton); + + m_suspendResumeButton = new QPushButton(this); + m_suspendResumeButton->setText(SuspendLabel); + connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); + layout->addWidget(m_suspendResumeButton); + + window->setLayout(layout.data()); + layout.take(); // ownership transferred + + setCentralWidget(window.data()); + QWidget *const windowPtr = window.take(); // ownership transferred + windowPtr->show(); +} + +void AudioTest::initializeAudio() +{ + connect(m_pullTimer, SIGNAL(timeout()), SLOT(pullTimerExpired())); + + m_pullMode = true; + + m_format.setFrequency(DataFrequencyHz); + m_format.setChannels(1); + m_format.setSampleSize(16); + m_format.setCodec("audio/pcm"); + m_format.setByteOrder(QAudioFormat::LittleEndian); + m_format.setSampleType(QAudioFormat::SignedInt); + + QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); + if (!info.isFormatSupported(m_format)) { + qWarning() << "Default format not supported - trying to use nearest"; + m_format = info.nearestFormat(m_format); + } + + m_generator = new Generator(m_format, DurationSeconds*1000000, ToneFrequencyHz, this); + + createAudioOutput(); +} + +void AudioTest::createAudioOutput() +{ + delete m_audioOutput; + m_audioOutput = 0; + m_audioOutput = new QAudioOutput(m_device, m_format, this); + connect(m_audioOutput, SIGNAL(notify()), SLOT(notified())); + connect(m_audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State))); + m_generator->start(); + m_audioOutput->start(m_generator); +} + +AudioTest::~AudioTest() +{ + +} + +void AudioTest::deviceChanged(int index) +{ + m_pullTimer->stop(); + m_generator->stop(); + m_audioOutput->stop(); + m_audioOutput->disconnect(this); + m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>(); + createAudioOutput(); +} + +void AudioTest::notified() +{ + qWarning() << "bytesFree = " << m_audioOutput->bytesFree() + << ", " << "elapsedUSecs = " << m_audioOutput->elapsedUSecs() + << ", " << "processedUSecs = " << m_audioOutput->processedUSecs(); +} + +void AudioTest::pullTimerExpired() +{ + 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; + } + } +} + +void AudioTest::toggleMode() +{ + m_pullTimer->stop(); + m_audioOutput->stop(); + + if (m_pullMode) { + m_modeButton->setText(PullModeLabel); + m_output = m_audioOutput->start(); + m_pullMode = false; + m_pullTimer->start(20); + } else { + m_modeButton->setText(PushModeLabel); + m_pullMode = true; + m_audioOutput->start(m_generator); + } + + m_suspendResumeButton->setText(SuspendLabel); +} + +void AudioTest::toggleSuspendResume() +{ + if (m_audioOutput->state() == QAudio::SuspendedState) { + qWarning() << "status: Suspended, resume()"; + m_audioOutput->resume(); + m_suspendResumeButton->setText(SuspendLabel); + } else if (m_audioOutput->state() == QAudio::ActiveState) { + qWarning() << "status: Active, suspend()"; + m_audioOutput->suspend(); + m_suspendResumeButton->setText(ResumeLabel); + } else if (m_audioOutput->state() == QAudio::StoppedState) { + qWarning() << "status: Stopped, resume()"; + m_audioOutput->resume(); + m_suspendResumeButton->setText(SuspendLabel); + } else if (m_audioOutput->state() == QAudio::IdleState) { + qWarning() << "status: IdleState"; + } +} + +void AudioTest::stateChanged(QAudio::State state) +{ + qWarning() << "state = " << state; +} diff --git a/examples/audiooutput/audiooutput.h b/examples/audiooutput/audiooutput.h new file mode 100644 index 000000000..805168e7c --- /dev/null +++ b/examples/audiooutput/audiooutput.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 Mobility Components. +** +** $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$ +** +****************************************************************************/ + +#ifndef AUDIOOUTPUT_H +#define AUDIOOUTPUT_H + +#include <math.h> + +#include <QObject> +#include <QMainWindow> +#include <QIODevice> +#include <QTimer> +#include <QPushButton> +#include <QComboBox> +#include <QByteArray> + +#include <qaudiooutput.h> + +class Generator : public QIODevice +{ + Q_OBJECT +public: + Generator(const QAudioFormat &format, qint64 durationUs, int frequency, QObject *parent); + ~Generator(); + + void start(); + void stop(); + + qint64 readData(char *data, qint64 maxlen); + qint64 writeData(const char *data, qint64 len); + qint64 bytesAvailable() const; + +private: + void generateData(const QAudioFormat &format, qint64 durationUs, int frequency); + +private: + qint64 m_pos; + QByteArray m_buffer; +}; + +class AudioTest : public QMainWindow +{ + Q_OBJECT +public: + AudioTest(); + ~AudioTest(); + +private: + void initializeWindow(); + void initializeAudio(); + void createAudioOutput(); + +private: + QTimer* m_pullTimer; + + // Owned by layout + QPushButton* m_modeButton; + QPushButton* m_suspendResumeButton; + QComboBox* m_deviceBox; + + QAudioDeviceInfo m_device; + Generator* m_generator; + QAudioOutput* m_audioOutput; + QIODevice* m_output; // not owned + QAudioFormat m_format; + + bool m_pullMode; + QByteArray m_buffer; + + static const QString PushModeLabel; + static const QString PullModeLabel; + static const QString SuspendLabel; + static const QString ResumeLabel; + +private slots: + void notified(); + void pullTimerExpired(); + void toggleMode(); + void toggleSuspendResume(); + void stateChanged(QAudio::State state); + void deviceChanged(int index); +}; + +#endif + diff --git a/examples/audiooutput/audiooutput.pro b/examples/audiooutput/audiooutput.pro new file mode 100644 index 000000000..63d037f60 --- /dev/null +++ b/examples/audiooutput/audiooutput.pro @@ -0,0 +1,15 @@ +TEMPLATE = app +CONFIG += example + +INCLUDEPATH += ../../src/multimedia ../../src/multimedia/audio +include(../mobility_examples.pri) + +CONFIG += mobility +MOBILITY = multimedia + +QMAKE_RPATHDIR += $$DESTDIR + +HEADERS = audiooutput.h + +SOURCES = audiooutput.cpp \ + main.cpp diff --git a/examples/audiooutput/main.cpp b/examples/audiooutput/main.cpp new file mode 100644 index 000000000..93f972d04 --- /dev/null +++ b/examples/audiooutput/main.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 Mobility Components. +** +** $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 <QtGui> + +#include "audiooutput.h" + +int main(int argv, char **args) +{ + QApplication app(argv, args); + app.setApplicationName("Audio Output Test"); + + AudioTest audio; + audio.show(); + + return app.exec(); +} |