summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/multimedia/audio/audio.pri5
-rw-r--r--src/multimedia/audio/qaudiobuffer.cpp440
-rw-r--r--src/multimedia/audio/qaudiobuffer.h158
-rw-r--r--src/multimedia/audio/qaudiobuffer_p.h90
4 files changed, 692 insertions, 1 deletions
diff --git a/src/multimedia/audio/audio.pri b/src/multimedia/audio/audio.pri
index 8c8daa5d1..a1cfa0b4d 100644
--- a/src/multimedia/audio/audio.pri
+++ b/src/multimedia/audio/audio.pri
@@ -2,6 +2,7 @@ INCLUDEPATH += audio
PUBLIC_HEADERS += \
audio/qaudio.h \
+ audio/qaudiobuffer.h \
audio/qaudioformat.h \
audio/qaudioinput.h \
audio/qaudiooutput.h \
@@ -12,6 +13,7 @@ PUBLIC_HEADERS += \
audio/qsound.h
PRIVATE_HEADERS += \
+ audio/qaudiobuffer_p.h \
audio/qaudiodevicefactory_p.h \
audio/qaudiopluginloader_p.h \
audio/qwavedecoder_p.h \
@@ -30,7 +32,8 @@ SOURCES += \
audio/qsoundeffect.cpp \
audio/qwavedecoder_p.cpp \
audio/qsamplecache_p.cpp \
- audio/qsound.cpp
+ audio/qsound.cpp \
+ audio/qaudiobuffer.cpp
mac {
PRIVATE_HEADERS += audio/qaudioinput_mac_p.h \
diff --git a/src/multimedia/audio/qaudiobuffer.cpp b/src/multimedia/audio/qaudiobuffer.cpp
new file mode 100644
index 000000000..7fa37f81b
--- /dev/null
+++ b/src/multimedia/audio/qaudiobuffer.cpp
@@ -0,0 +1,440 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaudiobuffer.h"
+#include "qaudiobuffer_p.h"
+
+#include <QObject>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ class QAudioBufferPrivateRegisterMetaTypes
+ {
+ public:
+ QAudioBufferPrivateRegisterMetaTypes()
+ {
+ qRegisterMetaType<QAudioBuffer>();
+ }
+ } _registerMetaTypes;
+}
+
+
+class QAudioBufferPrivate : public QSharedData
+{
+public:
+ QAudioBufferPrivate(QAbstractAudioBuffer *provider)
+ : mProvider(provider)
+ , mCount(1)
+ {
+ }
+
+ ~QAudioBufferPrivate()
+ {
+ if (mProvider)
+ mProvider->release();
+ }
+
+ void ref()
+ {
+ mCount.ref();
+ }
+
+ void deref()
+ {
+ if (!mCount.deref())
+ delete this;
+ }
+
+ QAudioBufferPrivate *clone();
+
+ static QAudioBufferPrivate *acquire(QAudioBufferPrivate *other)
+ {
+ if (!other)
+ return 0;
+
+ // Ref the other (if there are extant data() pointers, they will
+ // also point here - it's a feature, not a bug, like QByteArray)
+ other->ref();
+ return other;
+ }
+
+ QAbstractAudioBuffer *mProvider;
+ QAtomicInt mCount;
+};
+
+// Private class to go in .cpp file
+class QMemoryAudioBufferProvider : public QAbstractAudioBuffer {
+public:
+ QMemoryAudioBufferProvider(const void *data, int sampleCount, const QAudioFormat &format, qint64 startTime)
+ : mStartTime(startTime)
+ , mSampleCount(sampleCount)
+ , mFormat(format)
+ {
+ int numBytes = (sampleCount * format.channelCount() * format.sampleSize()) / 8;
+ if (numBytes > 0) {
+ mBuffer = malloc(numBytes);
+ if (!mBuffer) {
+ // OOM, if that's likely
+ mStartTime = -1;
+ mSampleCount = 0;
+ mFormat = QAudioFormat();
+ } else {
+ // Allocated, see if we have data to copy
+ if (data) {
+ memcpy(mBuffer, data, numBytes);
+ } else {
+ // We have to fill with the zero value..
+ switch (format.sampleType()) {
+ case QAudioFormat::SignedInt:
+ // Signed int means 0x80, 0x8000 is zero
+ // XXX this is not right for > 8 bits(0x8080 vs 0x8000)
+ memset(mBuffer, 0x80, numBytes);
+ break;
+ default:
+ memset(mBuffer, 0x0, numBytes);
+ }
+ }
+ }
+ } else
+ mBuffer = 0;
+ }
+
+ ~QMemoryAudioBufferProvider()
+ {
+ if (mBuffer)
+ free(mBuffer);
+ }
+
+ void release() {delete this;}
+ QAudioFormat format() const {return mFormat;}
+ qint64 startTime() const {return mStartTime;}
+ int sampleCount() const {return mSampleCount;}
+
+ void *constData() const {return mBuffer;}
+
+ void *writableData() {return mBuffer;}
+ QAbstractAudioBuffer *clone() const
+ {
+ return new QMemoryAudioBufferProvider(mBuffer, mSampleCount, mFormat, mStartTime);
+ }
+
+ void *mBuffer;
+ qint64 mStartTime;
+ int mSampleCount;
+ QAudioFormat mFormat;
+};
+
+QAudioBufferPrivate *QAudioBufferPrivate::clone()
+{
+ // We want to create a single bufferprivate with a
+ // single qaab
+ // This should only be called when the count is > 1
+ Q_ASSERT(mCount.load() > 1);
+
+ if (mProvider) {
+ QAbstractAudioBuffer *abuf = mProvider->clone();
+
+ if (!abuf) {
+ abuf = new QMemoryAudioBufferProvider(mProvider->constData(), mProvider->sampleCount(), mProvider->format(), mProvider->startTime());
+ }
+
+ if (abuf) {
+ return new QAudioBufferPrivate(abuf);
+ }
+ }
+
+ return 0;
+}
+
+/*!
+ \class QAbstractAudioBuffer
+ \internal
+*/
+
+/*!
+ \class QAudioBuffer
+ \brief A class that represents a collection of audio samples.
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \ingroup multimedia_audio
+
+ The QAudioBuffer class represents a collection of audio samples,
+ with a specific format and sample rate.
+*/
+// ^ Mostly useful with probe or decoder
+
+/*!
+ Create a new, empty, invalid buffer.
+ */
+QAudioBuffer::QAudioBuffer()
+ : d(0)
+{
+}
+
+/*!
+ \internal
+ Create a new audio buffer from the supplied \a provider. This
+ constructor is typically only used when handling certain hardware
+ or media framework specific buffers, and generally isn't useful
+ in application code.
+ */
+QAudioBuffer::QAudioBuffer(QAbstractAudioBuffer *provider)
+ : d(new QAudioBufferPrivate(provider))
+{
+}
+/*!
+ Creates a new audio buffer from \a other. Generally
+ this will have copy-on-write semantics - a copy will
+ only be made when it has to be.
+ */
+QAudioBuffer::QAudioBuffer(const QAudioBuffer &other)
+{
+ d = QAudioBufferPrivate::acquire(other.d);
+}
+
+/*!
+ Creates a new audio buffer from the supplied \a data, in the
+ given \a format. The format will determine how the number
+ and sizes of the samples are interpreted from the \a data.
+
+ If the supplied \a data is not an integer multiple of the
+ calculated sample size, the excess data will not be used.
+
+ This audio buffer will copy the contents of \a data.
+ */
+QAudioBuffer::QAudioBuffer(const QByteArray &data, const QAudioFormat &format)
+{
+ int sampleSize = (format.sampleSize() * format.channelCount()) / 8;
+ int sampleCount = data.size() / sampleSize; // truncate
+ d = new QAudioBufferPrivate(new QMemoryAudioBufferProvider(data.constData(), sampleCount, format, -1));
+}
+
+/*!
+ Creates a new audio buffer with space for \a numSamples samples of
+ the given \a format. The samples will be initialized to the default
+ for the format.
+ */
+QAudioBuffer::QAudioBuffer(int numSamples, const QAudioFormat &format)
+ : d(new QAudioBufferPrivate(new QMemoryAudioBufferProvider(0, numSamples, format, -1)))
+{
+}
+
+/*!
+ Assigns the \a other buffer to this.
+ */
+QAudioBuffer &QAudioBuffer::operator =(const QAudioBuffer &other)
+{
+ if (this->d != other.d) {
+ d = QAudioBufferPrivate::acquire(other.d);
+ }
+ return *this;
+}
+
+/*!
+ Destroys this audio buffer.
+ */
+QAudioBuffer::~QAudioBuffer()
+{
+ if (d)
+ d->deref();
+}
+
+/*!
+ Returns true if this is a valid buffer. A valid buffer
+ has more than zero samples in it and a valid format.
+ */
+bool QAudioBuffer::isValid() const
+{
+ if (!d || !d->mProvider)
+ return false;
+ return d->mProvider->format().isValid() && (d->mProvider->sampleCount() > 0);
+}
+
+/*!
+ Returns the \l {QAudioFormat}{format} of this buffer.
+
+ Several properties of this format influence how
+ the \l duration() or \l byteCount() are calculated
+ from the \l sampleCount().
+ */
+QAudioFormat QAudioBuffer::format() const
+{
+ if (!isValid())
+ return QAudioFormat();
+ return d->mProvider->format();
+}
+
+/*!
+ Returns the number of samples in this buffer.
+
+ If the format of this buffer has multiple channels,
+ then this count includes all channels. This means
+ that a stereo buffer with 1000 samples in total will
+ have 500 left samples and 500 right samples (interleaved),
+ and this function will return 1000.
+ */
+int QAudioBuffer::sampleCount() const
+{
+ if (!isValid())
+ return 0;
+ return d->mProvider->sampleCount();
+}
+
+/*!
+ Returns the size of this buffer, in bytes.
+ */
+int QAudioBuffer::byteCount() const
+{
+ const QAudioFormat f(format());
+ return (f.channelCount() * f.sampleSize() * sampleCount()) / 8; // sampleSize is in bits
+}
+
+/*!
+ Returns the duration of audio in this buffer, in microseconds.
+
+ This depends on the /l format(), and the \l sampleCount().
+*/
+qint64 QAudioBuffer::duration() const
+{
+ int divisor = format().sampleRate() * format().channelCount();
+ if (divisor > 0)
+ return (sampleCount() * 1000000LL) / divisor;
+ else
+ return 0;
+}
+
+/*!
+ Returns the time in a stream that this buffer starts at (in microseconds).
+
+ If this buffer is not part of a stream, this will return -1.
+ */
+qint64 QAudioBuffer::startTime() const
+{
+ if (!isValid())
+ return -1;
+ return d->mProvider->startTime();
+}
+
+/*!
+ Returns a pointer to this buffer's data. You can only read it.
+
+ This method is preferred over the const version of \l data() to
+ prevent unnecessary copying.
+ */
+const void* QAudioBuffer::constData() const
+{
+ if (!isValid())
+ return 0;
+ return d->mProvider->constData();
+}
+
+/*!
+ Returns a pointer to this buffer's data. You can only read it.
+
+ You should use the \l constData() function rather than this
+ to prevent accidental deep copying.
+ */
+const void* QAudioBuffer::data() const
+{
+ if (!isValid())
+ return 0;
+ return d->mProvider->constData();
+}
+
+/*!
+ Returns a pointer to this buffer's data. You can modify the
+ data through the returned pointer.
+
+ Since QAudioBuffers can share the actual sample data, calling
+ this function will result in a deep copy being made if there
+ are any other buffers using the sample. You should avoid calling
+ this unless you really need to modify the data.
+
+ This pointer will remain valid until the underlying storage is
+ detached. In particular, if you obtain a pointer, and then
+ copy this audio buffer, changing data through this pointer may
+ change both buffer instances. Calling \l data() on either instance
+ will again cause a deep copy to be made, which may invalidate
+ the pointers returned from this function previously.
+ */
+void *QAudioBuffer::data()
+{
+ if (!isValid())
+ return 0;
+
+ if (d->mCount.load() != 1) {
+ // Can't share a writable buffer
+ // so we need to detach
+ QAudioBufferPrivate *newd = d->clone();
+
+ // This shouldn't happen
+ if (!newd)
+ return 0;
+
+ d->deref();
+ d = newd;
+ }
+
+ // We're (now) the only user of this qaab, so
+ // see if it's writable directly
+ void *buffer = d->mProvider->writableData();
+ if (buffer) {
+ return buffer;
+ }
+
+ // Wasn't writable, so turn it into a memory provider
+ QAbstractAudioBuffer *memBuffer = new QMemoryAudioBufferProvider(constData(), sampleCount(), format(), startTime());
+
+ if (memBuffer) {
+ d->mProvider->release();
+ d->mCount.store(1);
+ d->mProvider = memBuffer;
+
+ return memBuffer->writableData();
+ }
+
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiobuffer.h b/src/multimedia/audio/qaudiobuffer.h
new file mode 100644
index 000000000..bd95f9d08
--- /dev/null
+++ b/src/multimedia/audio/qaudiobuffer.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAUDIOBUFFER_H
+#define QAUDIOBUFFER_H
+
+#include <QSharedDataPointer>
+
+#include <qtmultimediadefs.h>
+#include <qtmedianamespace.h>
+
+#include <qaudio.h>
+#include <qaudioformat.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+class QAbstractAudioBuffer;
+class QAudioBufferPrivate;
+class Q_MULTIMEDIA_EXPORT QAudioBuffer
+{
+public:
+ QAudioBuffer();
+ QAudioBuffer(QAbstractAudioBuffer *provider);
+ QAudioBuffer(const QAudioBuffer &other);
+ QAudioBuffer(const QByteArray &data, const QAudioFormat &format);
+ QAudioBuffer(int numSamples, const QAudioFormat &format); // Initialized to empty
+
+ QAudioBuffer& operator=(const QAudioBuffer &other);
+
+ ~QAudioBuffer();
+
+ bool isValid() const;
+
+ QAudioFormat format() const;
+
+ int sampleCount() const;
+ int byteCount() const;
+
+ qint64 duration() const;
+ qint64 startTime() const;
+
+ // Data modification
+ // void clear();
+ // Other ideas
+ // operator *=
+ // operator += (need to be careful about different formats)
+
+ // Data access
+ const void* constData() const; // Does not detach, preferred
+ const void* data() const; // Does not detach
+ void *data(); // detaches
+
+ // Structures for easier access to stereo data
+ template <typename T> struct StereoSampleDefault { enum { Default = 0 }; };
+
+ template <typename T> struct StereoSample {
+
+ StereoSample()
+ : left(T(StereoSampleDefault<T>::Default))
+ , right(T(StereoSampleDefault<T>::Default))
+ {
+ }
+
+ StereoSample(T leftSample, T rightSample)
+ : left(leftSample)
+ , right(rightSample)
+ {
+ }
+
+ StereoSample& operator=(const StereoSample &other)
+ {
+ // Two straight assigns is probably
+ // cheaper than a conditional check on
+ // self assignment
+ left = other.left;
+ right = other.right;
+ return *this;
+ }
+
+ T left;
+ T right;
+
+ T average() const {return (left + right) / 2;}
+ void clear() {left = right = T(StereoSampleDefault<T>::Default);}
+ };
+
+ typedef StereoSample<unsigned char> S8U;
+ typedef StereoSample<signed char> S8S;
+ typedef StereoSample<unsigned short> S16U;
+ typedef StereoSample<signed short> S16S;
+ typedef StereoSample<float> S32F;
+
+ template <typename T> const T* constData() const {
+ return static_cast<const T*>(constData());
+ }
+ template <typename T> const T* data() const {
+ return static_cast<const T*>(data());
+ }
+ template <typename T> T* data() {
+ return static_cast<T*>(data());
+ }
+private:
+ QAudioBufferPrivate *d;
+};
+
+template <> struct QAudioBuffer::StereoSampleDefault<unsigned char> { enum { Default = 128 }; };
+template <> struct QAudioBuffer::StereoSampleDefault<unsigned short> { enum { Default = 32768 }; };
+
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QAudioBuffer)
+
+QT_END_HEADER
+
+#endif // QAUDIOBUFFER_H
diff --git a/src/multimedia/audio/qaudiobuffer_p.h b/src/multimedia/audio/qaudiobuffer_p.h
new file mode 100644
index 000000000..af81b7cad
--- /dev/null
+++ b/src/multimedia/audio/qaudiobuffer_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAUDIOBUFFER_P_H
+#define QAUDIOBUFFER_P_H
+
+#include <qtmultimediadefs.h>
+#include <qtmedianamespace.h>
+
+#include "qaudioformat.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+class Q_MULTIMEDIA_EXPORT QAbstractAudioBuffer {
+public:
+ virtual ~QAbstractAudioBuffer() {}
+
+ // Lifetime management
+ virtual void release() = 0;
+
+ // Format related
+ virtual QAudioFormat format() const = 0;
+ virtual qint64 startTime() const = 0;
+ virtual int sampleCount() const = 0;
+
+ // R/O Data
+ virtual void *constData() const = 0;
+
+ // For writable data we do this:
+ // If we only have one reference to the provider,
+ // call writableData(). If that does not return 0,
+ // then we're finished. If it does return 0, then we call
+ // writableClone() to get a new buffer and then release
+ // the old clone if that succeeds. If it fails, we create
+ // a memory clone from the constData and release the old buffer.
+ // If writableClone() succeeds, we then call writableData() on it
+ // and that should be good.
+
+ virtual void *writableData() = 0;
+ virtual QAbstractAudioBuffer *clone() const = 0;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOBUFFER_P_H