summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorLev Zelenskiy <lev.zelenskiy@nokia.com>2012-02-24 13:00:35 +1000
committerQt by Nokia <qt-info@nokia.com>2012-02-27 05:26:51 +0100
commitc9b3f247c7b1b2daa5c47dcc2184be186c9613a4 (patch)
treec2f1b5c23e637ed67d0ff739b8aee3d6185622a2 /examples
parent5ed255ead63c0cef1e2881c886da9dfa9c0b1e42 (diff)
Audio decoder example.
Change-Id: I0f9fb755ef8bc6f66696a06996ac7a9f13de69cc Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/audiodecoder/audiodecoder.cpp188
-rw-r--r--examples/audiodecoder/audiodecoder.h92
-rw-r--r--examples/audiodecoder/audiodecoder.pro13
-rw-r--r--examples/audiodecoder/main.cpp93
-rw-r--r--examples/audiodecoder/wavefilewriter.cpp192
-rw-r--r--examples/audiodecoder/wavefilewriter.h69
6 files changed, 647 insertions, 0 deletions
diff --git a/examples/audiodecoder/audiodecoder.cpp b/examples/audiodecoder/audiodecoder.cpp
new file mode 100644
index 000000000..7263a1085
--- /dev/null
+++ b/examples/audiodecoder/audiodecoder.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $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 "audiodecoder.h"
+#include <iostream>
+
+AudioDecoder::AudioDecoder(bool isPlayback, bool isDelete)
+ : m_cout(stdout, QIODevice::WriteOnly)
+{
+ m_isPlayback = isPlayback;
+ m_isDelete = isDelete;
+
+ // Make sure the data we receive is in correct PCM format.
+ // Our wav file writer only supports SignedInt sample type.
+ QAudioFormat format;
+ format.setChannels(2);
+ format.setSampleSize(16);
+ format.setFrequency(48000);
+ format.setCodec("audio/pcm");
+ format.setSampleType(QAudioFormat::SignedInt);
+ m_decoder.setAudioFormat(format);
+
+ connect(&m_decoder, SIGNAL(bufferReady()), this, SLOT(bufferReady()));
+ connect(&m_decoder, SIGNAL(error(QAudioDecoder::Error)), this, SLOT(error(QAudioDecoder::Error)));
+ connect(&m_decoder, SIGNAL(stateChanged(QAudioDecoder::State)), this, SLOT(stateChanged(QAudioDecoder::State)));
+ connect(&m_decoder, SIGNAL(finished()), this, SLOT(finished()));
+ connect(&m_decoder, SIGNAL(positionChanged(qint64)), this, SLOT(updateProgress()));
+ connect(&m_decoder, SIGNAL(durationChanged(qint64)), this, SLOT(updateProgress()));
+
+ connect(&m_soundEffect, SIGNAL(statusChanged()), this, SLOT(playbackStatusChanged()));
+ connect(&m_soundEffect, SIGNAL(playingChanged()), this, SLOT(playingChanged()));
+
+ m_progress = -1.0;
+}
+
+void AudioDecoder::setSourceFilename(const QString &fileName)
+{
+ m_decoder.setSourceFilename(fileName);
+}
+
+void AudioDecoder::start()
+{
+ m_decoder.start();
+}
+
+void AudioDecoder::stop()
+{
+ m_decoder.stop();
+}
+
+void AudioDecoder::setTargetFilename(const QString &fileName)
+{
+ m_targetFilename = fileName;
+}
+
+void AudioDecoder::bufferReady()
+{
+ // read a buffer from audio decoder
+ QAudioBuffer buffer = m_decoder.read();
+ if (!buffer.isValid())
+ return;
+
+ if (!m_fileWriter.isOpen() && !m_fileWriter.open(m_targetFilename, buffer.format())) {
+ m_decoder.stop();
+ return;
+ }
+
+ m_fileWriter.write(buffer);
+}
+
+void AudioDecoder::error(QAudioDecoder::Error error)
+{
+ switch (error) {
+ case QAudioDecoder::NoError:
+ return;
+ case QAudioDecoder::ResourceError:
+ m_cout << "Resource error" << endl;
+ break;
+ case QAudioDecoder::FormatError:
+ m_cout << "Format error" << endl;
+ break;
+ case QAudioDecoder::AccessDeniedError:
+ m_cout << "Access denied error" << endl;
+ break;
+ case QAudioDecoder::ServiceMissingError:
+ m_cout << "Service missing error" << endl;
+ break;
+ }
+
+ emit done();
+}
+
+void AudioDecoder::stateChanged(QAudioDecoder::State newState)
+{
+ switch (newState) {
+ case QAudioDecoder::DecodingState:
+ m_cout << "Decoding..." << endl;
+ break;
+ case QAudioDecoder::StoppedState:
+ m_cout << "Decoding stopped" << endl;
+ break;
+ }
+}
+
+void AudioDecoder::finished()
+{
+ if (!m_fileWriter.close())
+ m_cout << "Failed to finilize output file" << endl;
+
+ m_cout << "Decoding finished" << endl;
+
+ if (m_isPlayback) {
+ m_cout << "Starting playback" << endl;
+ m_soundEffect.setSource(QUrl::fromLocalFile(m_targetFilename));
+ m_soundEffect.play();
+ } else {
+ emit done();
+ }
+}
+
+void AudioDecoder::playbackStatusChanged()
+{
+ if (m_soundEffect.status() == QSoundEffect::Error) {
+ m_cout << "Playback error" << endl;
+ emit done();
+ }
+}
+
+void AudioDecoder::playingChanged()
+{
+ if (!m_soundEffect.isPlaying()) {
+ m_cout << "Playback finished" << endl;
+ if (m_isDelete)
+ QFile::remove(m_targetFilename);
+ emit done();
+ }
+}
+
+void AudioDecoder::updateProgress()
+{
+ qint64 position = m_decoder.position();
+ qint64 duration = m_decoder.duration();
+ qreal progress = m_progress;
+ if (position >= 0 && duration > 0)
+ progress = position / (qreal)duration;
+
+ if (progress > m_progress + 0.1) {
+ m_cout << "Decoding progress: " << (int)(progress * 100.0) << "%" << endl;
+ m_progress = progress;
+ }
+}
diff --git a/examples/audiodecoder/audiodecoder.h b/examples/audiodecoder/audiodecoder.h
new file mode 100644
index 000000000..63dd8233f
--- /dev/null
+++ b/examples/audiodecoder/audiodecoder.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $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 AUDIODECODER_H
+#define AUDIODECODER_H
+
+#include <private/qaudiodecoder_p.h>
+#include "wavefilewriter.h"
+#include <QSoundEffect>
+#include <QTextStream>
+
+QT_USE_NAMESPACE
+
+class AudioDecoder : public QObject
+{
+ Q_OBJECT
+public:
+ AudioDecoder(bool isPlayback, bool isDelete);
+ ~AudioDecoder() { }
+
+ void setSourceFilename(const QString &fileName);
+ void start();
+ void stop();
+
+ void setTargetFilename(const QString &fileName);
+
+Q_SIGNALS:
+ void done();
+
+public slots:
+ void bufferReady();
+ void error(QAudioDecoder::Error error);
+ void stateChanged(QAudioDecoder::State newState);
+ void finished();
+
+ void playbackStatusChanged();
+ void playingChanged();
+
+private slots:
+ void updateProgress();
+
+private:
+ bool m_isPlayback;
+ bool m_isDelete;
+ QAudioDecoder m_decoder;
+ QTextStream m_cout;
+
+ QString m_targetFilename;
+ WaveFileWriter m_fileWriter;
+ QSoundEffect m_soundEffect;
+
+ qreal m_progress;
+};
+
+#endif // AUDIODECODER_H
diff --git a/examples/audiodecoder/audiodecoder.pro b/examples/audiodecoder/audiodecoder.pro
new file mode 100644
index 000000000..20e660bff
--- /dev/null
+++ b/examples/audiodecoder/audiodecoder.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+TARGET = audiodecoder
+
+CONFIG += qt warn_on
+
+HEADERS = \
+ audiodecoder.h \
+ wavefilewriter.h
+SOURCES = main.cpp \
+ audiodecoder.cpp \
+ wavefilewriter.cpp
+
+QT+= multimedia multimedia-private console
diff --git a/examples/audiodecoder/main.cpp b/examples/audiodecoder/main.cpp
new file mode 100644
index 000000000..b4b1700ff
--- /dev/null
+++ b/examples/audiodecoder/main.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $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 <QtCore/QCoreApplication>
+#include <QTextStream>
+#include <iostream>
+
+#include <qfileinfo.h>
+#include <qdir.h>
+#include "audiodecoder.h"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ QTextStream cout(stdout, QIODevice::WriteOnly);
+ if (app.arguments().size() < 2) {
+ cout << "Usage: audiodecoder [-p] [-pd] SOURCEFILE [TARGETFILE]" << endl;
+ cout << "Set -p option if you want to play output file." << endl;
+ cout << "Set -pd option if you want to play output file and delete it after successful playback." << endl;
+ cout << "Default TARGETFILE name is \"out.wav\" in the same directory as the source file." << endl;
+ return 0;
+ }
+
+ bool isPlayback = false;
+ bool isDelete = false;
+
+ if (app.arguments().at(1) == "-p")
+ isPlayback = true;
+ else if (app.arguments().at(1) == "-pd") {
+ isPlayback = true;
+ isDelete = true;
+ }
+
+ QFileInfo sourceFile;
+ QFileInfo targetFile;
+
+ int sourceFileIndex = (isPlayback || isDelete) ? 2 : 1;
+ if (app.arguments().size() <= sourceFileIndex) {
+ cout << "Error: source filename is not specified." << endl;
+ return 0;
+ }
+ sourceFile.setFile(app.arguments().at(sourceFileIndex));
+ if (app.arguments().size() > sourceFileIndex + 1)
+ targetFile.setFile(app.arguments().at(sourceFileIndex + 1));
+ else
+ targetFile.setFile(sourceFile.dir().absoluteFilePath("out.wav"));
+
+ AudioDecoder decoder(isPlayback, isDelete);
+ QObject::connect(&decoder, SIGNAL(done()), &app, SLOT(quit()));
+ decoder.setSourceFilename(sourceFile.absoluteFilePath());
+ decoder.setTargetFilename(targetFile.absoluteFilePath());
+ decoder.start();
+
+ return app.exec();
+};
diff --git a/examples/audiodecoder/wavefilewriter.cpp b/examples/audiodecoder/wavefilewriter.cpp
new file mode 100644
index 000000000..218e68daa
--- /dev/null
+++ b/examples/audiodecoder/wavefilewriter.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $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 "wavefilewriter.h"
+
+struct Q_PACKED chunk
+{
+ char id[4];
+ quint32 size;
+};
+
+struct Q_PACKED RIFFHeader
+{
+ chunk descriptor; // "RIFF"
+ char type[4]; // "WAVE"
+};
+
+struct Q_PACKED WAVEHeader
+{
+ chunk descriptor;
+ quint16 audioFormat;
+ quint16 numChannels;
+ quint32 sampleRate;
+ quint32 byteRate;
+ quint16 blockAlign;
+ quint16 bitsPerSample;
+};
+
+struct Q_PACKED DATAHeader
+{
+ chunk descriptor;
+};
+
+struct Q_PACKED CombinedHeader
+{
+ RIFFHeader riff;
+ WAVEHeader wave;
+ DATAHeader data;
+};
+static const int HeaderLength = sizeof(CombinedHeader);
+
+
+WaveFileWriter::WaveFileWriter(QObject *parent)
+ : QObject(parent)
+ , m_dataLength(0)
+{
+}
+
+WaveFileWriter::~WaveFileWriter()
+{
+ close();
+}
+
+bool WaveFileWriter::open(const QString& fileName, const QAudioFormat& format)
+{
+ if (file.isOpen())
+ return false; // file already open
+
+ if (format.codec() != "audio/pcm" || format.sampleType() != QAudioFormat::SignedInt)
+ return false; // data format is not supported
+
+ file.setFileName(fileName);
+ if (!file.open(QIODevice::WriteOnly))
+ return false; // unable to open file for writing
+
+ if (!writeHeader(format))
+ return false;
+
+ m_format = format;
+ return true;
+}
+
+bool WaveFileWriter::write(const QAudioBuffer& buffer)
+{
+ if (buffer.format() != m_format)
+ return false; // buffer format has changed
+
+ qint64 written = file.write((const char*)buffer.constData(), buffer.byteCount());
+ m_dataLength += written;
+ return written == buffer.byteCount();
+}
+
+bool WaveFileWriter::close()
+{
+ bool result = false;
+ if (file.isOpen()) {
+ Q_ASSERT(m_dataLength < INT_MAX);
+ result = writeDataLength();
+
+ m_dataLength = 0;
+ file.close();
+ }
+ return result;
+}
+
+bool WaveFileWriter::writeHeader(const QAudioFormat& format)
+{
+ // check if format is supported
+ if (format.byteOrder() == QAudioFormat::BigEndian || format.sampleType() != QAudioFormat::SignedInt)
+ return false;
+
+ CombinedHeader header;
+ memset(&header, 0, HeaderLength);
+
+#ifndef Q_LITTLE_ENDIAN
+ // only implemented for LITTLE ENDIAN
+ return false;
+#else
+ // RIFF header
+ memcpy(header.riff.descriptor.id, "RIFF", 4);
+ header.riff.descriptor.size = 0; // this will be updated with correct duration:
+ // m_dataLength + HeaderLength - 8
+ // WAVE header
+ memcpy(header.riff.type, "WAVE", 4);
+ memcpy(header.wave.descriptor.id, "fmt ", 4);
+ header.wave.descriptor.size = quint32(16);
+ header.wave.audioFormat = quint16(1);
+ header.wave.numChannels = quint16(format.channels());
+ header.wave.sampleRate = quint32(format.sampleRate());
+ header.wave.byteRate = quint32(format.sampleRate() * format.channels() * format.sampleSize() / 8);
+ header.wave.blockAlign = quint16(format.channels() * format.sampleSize() / 8);
+ header.wave.bitsPerSample = quint16(format.sampleSize());
+
+ // DATA header
+ memcpy(header.data.descriptor.id,"data", 4);
+ header.data.descriptor.size = 0; // this will be updated with correct data length: m_dataLength
+
+ return (file.write(reinterpret_cast<const char *>(&header), HeaderLength) == HeaderLength);
+#endif
+}
+
+bool WaveFileWriter::writeDataLength()
+{
+#ifndef Q_LITTLE_ENDIAN
+ // only implemented for LITTLE ENDIAN
+ return false;
+#endif
+
+ if (file.isSequential())
+ return false;
+
+ // seek to RIFF header size, see header.riff.descriptor.size above
+ if (!file.seek(4))
+ return false;
+
+ quint32 length = m_dataLength + HeaderLength - 8;
+ if (file.write(reinterpret_cast<const char *>(&length), 4) != 4)
+ return false;
+
+ // seek to DATA header size, see header.data.descriptor.size above
+ if (!file.seek(40))
+ return false;
+
+ return file.write(reinterpret_cast<const char *>(&m_dataLength), 4) == 4;
+}
diff --git a/examples/audiodecoder/wavefilewriter.h b/examples/audiodecoder/wavefilewriter.h
new file mode 100644
index 000000000..a3c2df4c4
--- /dev/null
+++ b/examples/audiodecoder/wavefilewriter.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $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 WAVEFILEWRITER_H
+#define WAVEFILEWRITER_H
+
+#include <QObject>
+#include <qfile.h>
+#include <qaudiobuffer.h>
+
+class WaveFileWriter : public QObject
+{
+ Q_OBJECT
+public:
+ explicit WaveFileWriter(QObject *parent = 0);
+ ~WaveFileWriter();
+
+ bool open(const QString& fileName, const QAudioFormat& format);
+ bool write(const QAudioBuffer& buffer);
+ bool close();
+ bool isOpen() const { return file.isOpen(); }
+
+private:
+ bool writeHeader(const QAudioFormat& format);
+ bool writeDataLength();
+
+ QFile file;
+ QAudioFormat m_format;
+ qint64 m_dataLength;
+};
+
+#endif // WAVEFILEWRITER_H