Add AudioEngine with new implementation

Change-Id: I5eebe662ecbce9814ed3e763db56df9be737d11f
Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
This commit is contained in:
Ling Hu
2012-01-18 17:17:54 +10:00
committed by Qt by Nokia
parent 262f397e3e
commit 809bbc35c6
39 changed files with 6592 additions and 6 deletions

View File

@@ -0,0 +1,47 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 <AL/al.h>
int main(int argc, char** argv)
{
return 0;
}

View File

@@ -0,0 +1,11 @@
TEMPLATE = app
DEPENDPATH += .
INCLUDEPATH += .
SOURCES += main.cpp
win32 {
LIBS += -lOpenAL32
}else {
LIBS += -lopenal
}

View File

@@ -0,0 +1,7 @@
TEMPLATE = subdirs
# These examples contain no C++ and can simply be copied
SUBDIRS =
sources.files = qml/*
sources.path = $$[QT_INSTALL_EXAMPLES]/qtmultimedia/declarative/audioengine
INSTALLS += sources

View File

@@ -0,0 +1,193 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
import QtAudioEngine 1.0
import QtQuick 2.0
import "content"
Rectangle {
color:"white"
id: root
width: 300
height: 500
property int radius : 100
property real twoPi : Math.PI + Math.PI
MyAudioEngine {
id:audioEngine
listener.position : Qt.vector3d(observer.x, observer.y, 0);
}
Item {
id: circle
x: root.width / 2
y: root.height / 2
property real percent: 0
SequentialAnimation on percent {
id: circleAnim1
loops: Animation.Infinite
running: true
NumberAnimation {
duration: 8000
from: 0
to: 1
}
}
}
Item {
id: holder
x: circle.x - Math.sin(circle.percent * root.twoPi) * root.radius - 50
y: circle.y + Math.cos(circle.percent * root.twoPi) * root.radius + 50
}
Rectangle {
color:"green"
id: observer
width: 16
height: 16
x: circle.x - width / 2
y: circle.y - height / 2
}
Rectangle {
color:"red"
id: starship
width: 32
height: 32
x: holder.x - width / 2
y: holder.y - height / 2
}
MouseArea {
anchors.fill: parent
onClicked: {
audioEngine.sounds["effects"].play(Qt.vector3d(holder.x, holder.y, 0));
}
}
SoundInstance {
id: shipSound
engine:audioEngine
sound:"shipengine"
position: Qt.vector3d(holder.x, holder.y, 0)
direction: {
var a = (starship.rotation / 360) * root.twoPi;
return Qt.vector3d(Math.sin(a), -Math.cos(a), 0);
}
velocity: {
var speed = root.twoPi * root.radius / 4;
return shipSound.direction * speed;
}
Component.onCompleted: shipSound.play()
}
//Category Volume Control
Rectangle {
property variant volumeCtrl: audioEngine.categories["sfx"];
id: volumeBar
x: 10
y: 10
width: 280
height: 22
color: "darkgray"
Rectangle {
id: volumeTracker
x: 0
y: 0
width: volumeBar.volumeCtrl.volume * parent.width;
height: parent.height
color: "lightgreen"
}
Text {
text: " volume:" + volumeBar.volumeCtrl.volume * 100 +"%";
font.pointSize: 16;
font.italic: true;
color: "black"
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
property bool m:false
onPressed: {
m = true;
updateVolume(mouse);
}
onReleased: {
m = false;
}
onPositionChanged: {
if (m) {
updateVolume(mouse);
}
}
function updateVolume(mouse) {
volumeBar.volumeCtrl.volume = Math.min(1, Math.max(0, mouse.x / (volumeBar.width - 1)));
}
}
}
//Information display
Item {
x:10
y:32
Text {
text: " [live instances] = " + audioEngine.liveInstances;
font.pointSize: 14;
font.italic: true;
color: "black"
anchors.fill: parent
}
}
Item {
x:10
y:60
Text {
text: " [loading]=" + (audioEngine.loading ? "true" : "false");
font.pointSize: 16;
font.italic: true;
color: "black"
anchors.fill: parent
}
}
}

View File

@@ -0,0 +1,16 @@
import QmlProject 1.1
Project {
mainFile: "audioengine.qml"
/* Include .qml, .js, and image files from current directory and subdirectories */
QmlFiles {
directory: "."
}
JavaScriptFiles {
directory: "."
}
ImageFiles {
directory: "."
}
}

View File

@@ -0,0 +1,131 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
import QtAudioEngine 1.0
import QtQuick 2.0
AudioEngine {
AudioCategory {
name:"sfx"
volume: 1
}
AudioCategory {
name:"music"
volume: 1
}
AttenuationModelInverse {
name:"default"
start: 20
end: 1000
rolloff: 1
}
AttenuationModelLinear {
name:"shipengine"
start: 20
end: 180
}
AudioSample {
name:"fire"
source: "fire-03-loop.wav"
preloaded:true
}
AudioSample {
name:"explosion"
source: "explosion-02.wav"
}
AudioSample {
name:"lava"
source: "lava-bubbling-01.wav"
}
AudioSample {
name:"water"
source: "running-water-01.wav"
}
Sound {
name:"shipengine"
attenuationModel:"shipengine"
category:"sfx"
PlayVariation {
looping:true
sample:"fire"
maxGain:0.9
minGain:0.8
}
}
Sound {
name:"effects"
category:"sfx"
PlayVariation {
sample:"lava"
maxGain:1.5
minGain:1.2
maxPitch:2.0
minPitch:0.5
}
PlayVariation {
sample:"explosion"
maxGain:1.1
minGain:0.7
maxPitch:1.5
minPitch:0.5
}
PlayVariation {
sample:"water"
maxGain:1.5
minGain:1.2
}
}
dopplerFactor: 1
speedOfSound: 343.33
listener.up:"0,0,1"
listener.position:"0,0,0"
listener.velocity:"0,0,0"
listener.direction:"0,1,0"
}

View File

@@ -24,3 +24,4 @@ TEMPLATE = subdirs
QT += widgets
}
contains(config_test_openal, yes): SUBDIRS += audioengine

View File

@@ -0,0 +1,85 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 <QtDeclarative/qdeclarativeextensionplugin.h>
#include <QtDeclarative/qdeclarative.h>
#include <QtDeclarative/qdeclarativeengine.h>
#include <QtDeclarative/qdeclarativecomponent.h>
#include "qdeclarative_audioengine_p.h"
#include "qdeclarative_soundinstance_p.h"
#include "qdeclarative_sound_p.h"
#include "qdeclarative_playvariation_p.h"
#include "qdeclarative_audiocategory_p.h"
#include "qdeclarative_audiolistener_p.h"
#include "qdeclarative_audiosample_p.h"
#include "qdeclarative_attenuationmodel_p.h"
QT_BEGIN_NAMESPACE
class QAudioEngineDeclarativeModule : public QDeclarativeExtensionPlugin
{
Q_OBJECT
public:
virtual void registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("QtAudioEngine"));
qmlRegisterType<QDeclarativeAudioEngine>(uri, 1, 0, "AudioEngine");
qmlRegisterType<QDeclarativeAudioSample>(uri, 1, 0, "AudioSample");
qmlRegisterType<QDeclarativeAudioCategory>(uri, 1, 0, "AudioCategory");
qmlRegisterType<QDeclarativeSoundCone>(uri, 1, 0, "");
qmlRegisterType<QDeclarativeSound>(uri, 1, 0, "Sound");
qmlRegisterType<QDeclarativePlayVariation>(uri, 1, 0, "PlayVariation");
qmlRegisterType<QDeclarativeAudioListener>(uri, 1, 0, "AudioListener");
qmlRegisterType<QDeclarativeSoundInstance>(uri, 1, 0, "SoundInstance");
qmlRegisterType<QDeclarativeAttenuationModelLinear>(uri, 1, 0, "AttenuationModelLinear");
qmlRegisterType<QDeclarativeAttenuationModelInverse>(uri, 1, 0, "AttenuationModelInverse");
}
};
QT_END_NAMESPACE
#include "audioengine.moc"
Q_EXPORT_PLUGIN2("QtAudioEngine", QT_PREPEND_NAMESPACE(QAudioEngineDeclarativeModule));

View File

@@ -0,0 +1,51 @@
TARGET = declarative_audioengine
TARGETPATH = QtAudioEngine
include(../qimportbase.pri)
QT += declarative quick multimedia-private
win32 {
LIBS += -lOpenAL32
}else {
LIBS += -lopenal
}
DESTDIR = $$QT.multimedia.imports/$$TARGETPATH
target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
INCLUDEPATH += ../../multimedia/audio
HEADERS += \
qdeclarative_attenuationmodel_p.h \
qdeclarative_audioengine_p.h \
qdeclarative_soundinstance_p.h \
qdeclarative_audiocategory_p.h \
qdeclarative_audiolistener_p.h \
qdeclarative_playvariation_p.h \
qdeclarative_audiosample_p.h \
qdeclarative_sound_p.h \
qsoundinstance_p.h \
qaudioengine_p.h \
qsoundsource_p.h \
qsoundbuffer_p.h \
qaudioengine_openal_p.h
SOURCES += \
audioengine.cpp \
qdeclarative_attenuationmodel_p.cpp \
qdeclarative_audioengine_p.cpp \
qdeclarative_soundinstance_p.cpp \
qdeclarative_audiocategory_p.cpp \
qdeclarative_audiolistener_p.cpp \
qdeclarative_playvariation_p.cpp \
qdeclarative_audiosample_p.cpp \
qdeclarative_sound_p.cpp \
qsoundinstance_p.cpp \
qaudioengine_p.cpp \
qsoundsource_openal_p.cpp \
qaudioengine_openal_p.cpp
qmldir.files += $$PWD/qmldir
qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH
INSTALLS += target qmldir

View File

@@ -0,0 +1,448 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 <QtCore/QThread>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkAccessManager>
#include <QtCore/QUrl>
#include <QtCore/QThread>
#include <QtCore/QMutex>
#include "qsamplecache_p.h"
#include "qaudioengine_openal_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
class StaticSoundBufferAL : public QSoundBufferPrivateAL
{
Q_OBJECT
public:
StaticSoundBufferAL(QObject *parent, const QUrl& url, QSampleCache *sampleLoader)
: QSoundBufferPrivateAL(parent)
, m_ref(1)
, m_url(url)
, m_alBuffer(0)
, m_isReady(false)
, m_sample(0)
, m_sampleLoader(sampleLoader)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "creating new StaticSoundBufferOpenAL";
#endif
}
void load()
{
if (m_sample)
return;
m_sample = m_sampleLoader->requestSample(m_url);
connect(m_sample, SIGNAL(error()), this, SLOT(decoderError()));
connect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady()));
switch (m_sample->state()) {
case QSample::Ready:
sampleReady();
break;
case QSample::Error:
decoderError();
break;
default:
break;
}
}
~StaticSoundBufferAL()
{
if (m_sample)
m_sample->release();
alDeleteBuffers(1, &m_alBuffer);
}
void bindToSource(ALuint alSource)
{
Q_ASSERT(m_alBuffer != 0);
alSourcei(alSource, AL_BUFFER, m_alBuffer);
}
void unbindFromSource(ALuint alSource)
{
alSourcei(alSource, AL_BUFFER, 0);
}
//called in application
bool isReady() const
{
return m_isReady;
}
long addRef()
{
return ++m_ref;
}
long release()
{
return --m_ref;
}
long refCount() const
{
return m_ref;
}
public Q_SLOTS:
void sampleReady()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "StaticSoundBufferOpenAL:sample[" << m_url << "] loaded";
#endif
disconnect(m_sample, SIGNAL(error()), this, SLOT(decoderError()));
disconnect(m_sample, SIGNAL(ready()), this, SLOT(sampleReady()));
if (m_sample->data().size() > 1024 * 1024 * 4) {
qWarning() << "source [" << m_url << "] size too large!";
decoderError();
return;
}
if (m_sample->format().channelCount() > 2) {
qWarning() << "source [" << m_url << "] channel > 2!";
decoderError();
return;
}
ALenum alFormat = 0;
if (m_sample->format().sampleSize() == 8) {
alFormat = m_sample->format().channelCount() == 1 ? AL_FORMAT_MONO8 : AL_FORMAT_STEREO8;
} else if (m_sample->format().sampleSize() == 16) {
alFormat = m_sample->format().channelCount() == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
} else {
qWarning() << "source [" << m_url << "] invalid sample size:"
<< m_sample->format().sampleSize() << "(should be 8 or 16)";
decoderError();
return;
}
alGenBuffers(1, &m_alBuffer);
if (!QAudioEnginePrivate::checkNoError("create buffer")) {
return;
}
alBufferData(m_alBuffer, alFormat, m_sample->data().data(),
m_sample->data().size(), m_sample->format().frequency());
if (!QAudioEnginePrivate::checkNoError("fill buffer")) {
return;
}
m_isReady = true;
emit ready();
m_sample->release();
m_sample = 0;
}
void decoderError()
{
qWarning() << "loading [" << m_url << "] failed";
disconnect(m_sample, SIGNAL(error()), this, SLOT(decoderError()));
emit error();
}
private:
long m_ref;
QUrl m_url;
ALuint m_alBuffer;
bool m_isReady;
QSample *m_sample;
QSampleCache *m_sampleLoader;
};
QSoundBufferPrivateAL::QSoundBufferPrivateAL(QObject *parent)
: QSoundBuffer(parent)
{
}
/////////////////////////////////////////////////////////////////
QAudioEnginePrivate::QAudioEnginePrivate(QObject *parent)
: QObject(parent)
{
m_updateTimer.setInterval(200);
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateSoundSources()));
m_sampleLoader = new QSampleCache(this);
m_sampleLoader->setCapacity(0);
connect(m_sampleLoader, SIGNAL(isLoadingChanged()), this, SIGNAL(isLoadingChanged()));
#ifdef DEBUG_AUDIOENGINE
qDebug() << "default openal device = " << alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
const ALCchar* devNames = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
int cc = 0;
qDebug() << "device list:";
while (true) {
qDebug() << " " << devNames + cc;
while (devNames[cc] != 0)
++cc;
++cc;
if (devNames[cc] == 0)
break;
}
#endif
ALCdevice *device = alcOpenDevice(0);
if (!device) {
qWarning() << "Can not create openal device!";
return;
}
ALCcontext* context = alcCreateContext(device, 0);
if (!context) {
qWarning() << "Can not create openal context!";
return;
}
alcMakeContextCurrent(context);
alDistanceModel(AL_NONE);
alDopplerFactor(0);
}
QAudioEnginePrivate::~QAudioEnginePrivate()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QAudioEnginePrivate::dtor";
#endif
delete m_sampleLoader;
QObjectList children = this->children();
foreach (QObject *child, children) {
QSoundSourcePrivate* s = qobject_cast<QSoundSourcePrivate*>(child);
if (!s)
continue;
s->release();
}
foreach (QSoundBufferPrivateAL *buffer, m_staticBufferPool) {
delete buffer;
}
m_staticBufferPool.clear();
ALCcontext* context = alcGetCurrentContext();
ALCdevice *device = alcGetContextsDevice(context);
alcDestroyContext(context);
alcCloseDevice(device);
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QAudioEnginePrivate::dtor: all done";
#endif
}
bool QAudioEnginePrivate::isLoading() const
{
return m_sampleLoader->isLoading();
}
QSoundSource* QAudioEnginePrivate::createSoundSource()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QAudioEnginePrivate::createSoundSource()";
#endif
QSoundSourcePrivate *instance = NULL;
if (m_instancePool.count() == 0) {
instance = new QSoundSourcePrivate(this);
} else {
instance = m_instancePool.front();
m_instancePool.pop_front();
}
connect(instance, SIGNAL(activate(QObject*)), this, SLOT(soundSourceActivate(QObject*)));
return instance;
}
void QAudioEnginePrivate::releaseSoundSource(QSoundSource *soundInstance)
{
QSoundSourcePrivate *privInstance = static_cast<QSoundSourcePrivate*>(soundInstance);
#ifdef DEBUG_AUDIOENGINE
qDebug() << "recycle soundInstance" << privInstance;
#endif
privInstance->unbindBuffer();
m_instancePool.push_front(privInstance);
m_activeInstances.removeOne(privInstance);
}
QSoundBuffer* QAudioEnginePrivate::getStaticSoundBuffer(const QUrl& url)
{
StaticSoundBufferAL *staticBuffer = NULL;
QMap<QUrl, QSoundBufferPrivateAL*>::iterator it = m_staticBufferPool.find(url);
if (it == m_staticBufferPool.end()) {
staticBuffer = new StaticSoundBufferAL(this, url, m_sampleLoader);
m_staticBufferPool.insert(url, staticBuffer);
} else {
staticBuffer = static_cast<StaticSoundBufferAL*>(*it);
staticBuffer->addRef();
}
return staticBuffer;
}
void QAudioEnginePrivate::releaseSoundBuffer(QSoundBuffer *buffer)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QAudioEnginePrivate: recycle sound buffer";
#endif
if (buffer->inherits("StaticSoundBufferOpenAL")) {
StaticSoundBufferAL *staticBuffer = static_cast<StaticSoundBufferAL*>(buffer);
//decrement the reference count, still kept in memory for reuse
staticBuffer->release();
//TODO implement some resource recycle strategy
} else {
//TODO
Q_ASSERT(0);
qWarning() << "Unknown soundbuffer type for recycle" << buffer;
}
}
bool QAudioEnginePrivate::checkNoError(const char *msg)
{
ALenum error = alGetError();
if (error != AL_NO_ERROR) {
qWarning() << "Failed on" << msg << "[OpenAL error code =" << error << "]";
return false;
}
return true;
}
QVector3D QAudioEnginePrivate::listenerPosition() const
{
ALfloat x, y, z;
alGetListener3f(AL_POSITION, &x, &y, &z);
checkNoError("get listener position");
return QVector3D(x, y, z);
}
QVector3D QAudioEnginePrivate::listenerVelocity() const
{
ALfloat x, y, z;
alGetListener3f(AL_VELOCITY, &x, &y, &z);
checkNoError("get listener velocity");
return QVector3D(x, y, z);
}
qreal QAudioEnginePrivate::listenerGain() const
{
ALfloat gain;
alGetListenerf(AL_GAIN, &gain);
checkNoError("get listener gain");
return gain;
}
void QAudioEnginePrivate::setListenerPosition(const QVector3D& position)
{
alListener3f(AL_POSITION, position.x(), position.y(), position.z());
checkNoError("set listener position");
}
void QAudioEnginePrivate::setListenerOrientation(const QVector3D& direction, const QVector3D& up)
{
ALfloat orientation[6];
orientation[0] = direction.x();
orientation[1] = direction.y();
orientation[2] = direction.z();
orientation[3] = up.x();
orientation[4] = up.y();
orientation[5] = up.z();
alListenerfv(AL_ORIENTATION, orientation);
checkNoError("set listener orientation");
}
void QAudioEnginePrivate::setListenerVelocity(const QVector3D& velocity)
{
alListener3f(AL_VELOCITY, velocity.x(), velocity.y(), velocity.z());
checkNoError("set listener velocity");
}
void QAudioEnginePrivate::setListenerGain(qreal gain)
{
alListenerf(AL_GAIN, gain);
checkNoError("set listener gain");
}
void QAudioEnginePrivate::setDopplerFactor(qreal dopplerFactor)
{
alDopplerFactor(dopplerFactor);
}
void QAudioEnginePrivate::setSpeedOfSound(qreal speedOfSound)
{
alSpeedOfSound(speedOfSound);
}
void QAudioEnginePrivate::soundSourceActivate(QObject *soundSource)
{
QSoundSourcePrivate *ss = qobject_cast<QSoundSourcePrivate*>(soundSource);
ss->checkState();
if (ss->isLooping())
return;
if (!m_activeInstances.contains(ss))
m_activeInstances.push_back(ss);
if (!m_updateTimer.isActive())
m_updateTimer.start();
}
void QAudioEnginePrivate::updateSoundSources()
{
for (QList<QSoundSourcePrivate*>::Iterator it = m_activeInstances.begin();
it != m_activeInstances.end();) {
QSoundSourcePrivate *instance = *it;
instance->checkState();
if (instance->state() == QSoundSource::StoppedState) {
it = m_activeInstances.erase(it);
} else {
++it;
}
}
if (m_activeInstances.count() == 0) {
m_updateTimer.stop();
}
}
#include "qaudioengine_openal_p.moc"
//#include "moc_qaudioengine_openal_p.cpp"

View File

@@ -0,0 +1,168 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QAUDIOENGINE_OPENAL_P_H
#define QAUDIOENGINE_OPENAL_P_H
#include <QObject>
#include <QList>
#include <QMap>
#include <QTimer>
#include <AL/al.h>
#include <AL/alc.h>
#include "qsoundsource_p.h"
#include "qsoundbuffer_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QSoundBufferPrivateAL : public QSoundBuffer
{
Q_OBJECT
public:
QSoundBufferPrivateAL(QObject* parent);
virtual void bindToSource(ALuint alSource) = 0;
virtual void unbindFromSource(ALuint alSource) = 0;
};
class QSoundSourcePrivate : public QSoundSource
{
Q_OBJECT
public:
QSoundSourcePrivate(QObject *parent);
~QSoundSourcePrivate();
void play();
void pause();
void stop();
QSoundSource::State state() const;
bool isLooping() const;
void setLooping(bool looping);
void setPosition(const QVector3D& position);
void setDirection(const QVector3D& direction);
void setVelocity(const QVector3D& velocity);
QVector3D velocity() const;
QVector3D position() const;
QVector3D direction() const;
void setGain(qreal gain);
void setPitch(qreal pitch);
void setCone(qreal innerAngle, qreal outerAngle, qreal outerGain);
void bindBuffer(QSoundBuffer*);
void unbindBuffer();
void checkState();
void release();
Q_SIGNALS:
void activate(QObject*);
private:
void sourcePlay();
void sourcePause();
ALuint m_alSource;
QSoundBufferPrivateAL *m_bindBuffer;
bool m_isReady; //true if the sound source is already bound to some sound buffer
QSoundSource::State m_state;
qreal m_gain;
qreal m_pitch;
qreal m_coneInnerAngle;
qreal m_coneOuterAngle;
qreal m_coneOuterGain;
};
class QSampleCache;
class QAudioEnginePrivate : public QObject
{
Q_OBJECT
public:
QAudioEnginePrivate(QObject *parent);
~QAudioEnginePrivate();
bool isLoading() const;
QSoundSource* createSoundSource();
void releaseSoundSource(QSoundSource *soundInstance);
QSoundBuffer* getStaticSoundBuffer(const QUrl& url);
void releaseSoundBuffer(QSoundBuffer *buffer);
QVector3D listenerPosition() const;
QVector3D listenerVelocity() const;
qreal listenerGain() const;
void setListenerPosition(const QVector3D& position);
void setListenerVelocity(const QVector3D& velocity);
void setListenerOrientation(const QVector3D& direction, const QVector3D& up);
void setListenerGain(qreal gain);
void setDopplerFactor(qreal dopplerFactor);
void setSpeedOfSound(qreal speedOfSound);
static bool checkNoError(const char *msg);
Q_SIGNALS:
void isLoadingChanged();
private Q_SLOTS:
void updateSoundSources();
void soundSourceActivate(QObject *soundSource);
private:
QList<QSoundSourcePrivate*> m_activeInstances;
QList<QSoundSourcePrivate*> m_instancePool;
QMap<QUrl, QSoundBufferPrivateAL*> m_staticBufferPool;
QSampleCache *m_sampleLoader;
QTimer m_updateTimer;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1,198 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qaudioengine_p.h"
#include "qsoundsource_p.h"
#include "qdebug.h"
#include "qaudioengine_openal_p.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
QSoundSource::QSoundSource(QObject *parent)
: QObject(parent)
{
}
QSoundBuffer::QSoundBuffer(QObject *parent)
: QObject(parent)
{
}
QAudioEngine* QAudioEngine::create(QObject *parent)
{
return new QAudioEngine(parent);
}
QAudioEngine::QAudioEngine(QObject *parent)
: QObject(parent)
, m_listenerUp(0, 0, 1)
, m_listenerDirection(0, 1, 0)
{
d = new QAudioEnginePrivate(this);
connect(d, SIGNAL(isLoadingChanged()), this, SIGNAL(isLoadingChanged()));
setDopplerFactor(1);
setSpeedOfSound(qreal(343.33));
updateListenerOrientation();
}
QAudioEngine::~QAudioEngine()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QAudioEngine::dtor";
#endif
}
QSoundBuffer* QAudioEngine::getStaticSoundBuffer(const QUrl& url)
{
return d->getStaticSoundBuffer(url);
}
void QAudioEngine::releaseSoundBuffer(QSoundBuffer *buffer)
{
d->releaseSoundBuffer(buffer);
}
QSoundSource* QAudioEngine::createSoundSource()
{
return d->createSoundSource();
}
void QAudioEngine::releaseSoundSource(QSoundSource *soundInstance)
{
d->releaseSoundSource(soundInstance);
}
bool QAudioEngine::isLoading() const
{
return d->isLoading();
}
QVector3D QAudioEngine::listenerPosition() const
{
return d->listenerPosition();
}
QVector3D QAudioEngine::listenerDirection() const
{
return m_listenerDirection;
}
QVector3D QAudioEngine::listenerUp() const
{
return m_listenerUp;
}
qreal QAudioEngine::listenerGain() const
{
return d->listenerGain();
}
QVector3D QAudioEngine::listenerVelocity() const
{
return d->listenerVelocity();
}
void QAudioEngine::setListenerPosition(const QVector3D& position)
{
d->setListenerPosition(position);
}
void QAudioEngine::setListenerVelocity(const QVector3D& velocity)
{
d->setListenerVelocity(velocity);
}
void QAudioEngine::setListenerDirection(const QVector3D& direction)
{
if (m_listenerDirection == direction)
return;
m_listenerDirection = direction;
updateListenerOrientation();
}
void QAudioEngine::setListenerUp(const QVector3D& up)
{
if (m_listenerUp == up)
return;
m_listenerUp = up;
updateListenerOrientation();
}
void QAudioEngine::updateListenerOrientation()
{
QVector3D dir = m_listenerDirection;
QVector3D up = m_listenerUp;
dir.normalize();
up.normalize();
QVector3D u = up - dir * QVector3D::dotProduct(dir, up);
u.normalize();
d->setListenerOrientation(dir, u);
}
void QAudioEngine::setListenerGain(qreal gain)
{
d->setListenerGain(gain);
}
qreal QAudioEngine::dopplerFactor() const
{
return m_dopplerFactor;
}
void QAudioEngine::setDopplerFactor(qreal dopplerFactor)
{
m_dopplerFactor = dopplerFactor;
d->setDopplerFactor(dopplerFactor);
}
qreal QAudioEngine::speedOfSound() const
{
return m_speedOfSound;
}
void QAudioEngine::setSpeedOfSound(qreal speedOfSound)
{
m_speedOfSound = speedOfSound;
d->setSpeedOfSound(speedOfSound);
}

View File

@@ -0,0 +1,110 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QAUDIOENGINE_P_H
#define QAUDIOENGINE_P_H
#include <QtCore/QObject>
#include <QtCore/QMap>
#include <QtCore/QUrl>
#include <QtGui/qvector3d.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QSoundSource;
class QSoundBuffer;
class QAudioEnginePrivate;
class QAudioEngine : public QObject
{
Q_OBJECT
public:
~QAudioEngine();
virtual QSoundSource* createSoundSource();
virtual void releaseSoundSource(QSoundSource *soundInstance);
virtual QSoundBuffer* getStaticSoundBuffer(const QUrl& url);
virtual void releaseSoundBuffer(QSoundBuffer *buffer);
virtual bool isLoading() const;
virtual QVector3D listenerPosition() const;
virtual QVector3D listenerDirection() const;
virtual QVector3D listenerVelocity() const;
virtual QVector3D listenerUp() const;
virtual qreal listenerGain() const;
virtual void setListenerPosition(const QVector3D& position);
virtual void setListenerDirection(const QVector3D& direction);
virtual void setListenerVelocity(const QVector3D& velocity);
virtual void setListenerUp(const QVector3D& up);
virtual void setListenerGain(qreal gain);
virtual qreal dopplerFactor() const;
virtual void setDopplerFactor(qreal dopplerFactor);
virtual qreal speedOfSound() const;
virtual void setSpeedOfSound(qreal speedOfSound);
static QAudioEngine* create(QObject *parent);
Q_SIGNALS:
void isLoadingChanged();
private:
QAudioEngine(QObject *parent);
QAudioEnginePrivate *d;
void updateListenerOrientation();
qreal m_dopplerFactor;
qreal m_speedOfSound;
QVector3D m_listenerUp;
QVector3D m_listenerDirection;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1,379 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qdeclarative_attenuationmodel_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
QDeclarativeAttenuationModel::QDeclarativeAttenuationModel(QObject *parent)
: QObject(parent)
, m_complete(false)
{
}
QDeclarativeAttenuationModel::~QDeclarativeAttenuationModel()
{
}
void QDeclarativeAttenuationModel::classBegin()
{
if (!parent() || !parent()->inherits("QDeclarativeAudioEngine")) {
qWarning("AttenuationModel must be defined inside AudioEngine!");
//TODO: COMPILE_EXCEPTION ?
return;
}
}
void QDeclarativeAttenuationModel::componentComplete()
{
if (m_name.isEmpty()) {
qWarning("AttenuationModel must have a name!");
return;
}
m_complete = true;
}
QString QDeclarativeAttenuationModel::name() const
{
return m_name;
}
void QDeclarativeAttenuationModel::setName(const QString& name)
{
if (m_complete) {
qWarning("AttenuationModel: you can not change name after initialization.");
return;
}
m_name = name;
}
//////////////////////////////////////////////////////////////////////////////////////////
/*!
\qmlclass AttenuationModelLinear QDeclarativeAttenuationModelLinear
\since 5.0
\brief The AttenuationModelLinear element allows you to define a linear attenuation curve for
Sound element.
\ingroup qml-multimedia
\inherits Item
This element is part of the \bold{QtAudioEngine 1.0} module.
AttenuationModelLinear must be defined inside AudioEngine.
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
AttenuationModelLinear {
name:"linear"
start: 20
end: 180
}
AudioSample {
name:"explosion"
source: "explosion-02.wav"
}
Sound {
name:"explosion"
attenuationModel: "linear"
PlayVariation {
sample:"explosion"
}
}
}
}
\endqml
*/
/*!
\qmlproperty string AttenuationModelLinear::name
This property holds the name of AttenuationModelLinear, must be unique among all attenuation
models and only defined once.
*/
QDeclarativeAttenuationModelLinear::QDeclarativeAttenuationModelLinear(QObject *parent)
: QDeclarativeAttenuationModel(parent)
, m_start(0)
, m_end(1)
{
}
void QDeclarativeAttenuationModelLinear::componentComplete()
{
if (m_start > m_end) {
qSwap(m_start, m_end);
qWarning() << "AttenuationModelLinear[" << m_name << "]: start must be less or equal than end.";
}
QDeclarativeAttenuationModel::componentComplete();
}
/*!
\qmlproperty real AttenuationModelLinear::start
This property holds the start distance. There will be no attenuation if the distance from sound
to listener is within this range.
The default value is 0.
*/
qreal QDeclarativeAttenuationModelLinear::startDistance() const
{
return m_start;
}
void QDeclarativeAttenuationModelLinear::setStartDistance(qreal startDist)
{
if (m_complete) {
qWarning() << "AttenuationModelLinear[" << m_name << "]: you can not change properties after initialization.";
return;
}
if (startDist < 0) {
qWarning() << "AttenuationModelLinear[" << m_name << "]: start must be no less than 0.";
return;
}
m_start = startDist;
}
/*!
\qmlproperty real AttenuationModelLinear::end
This property holds the end distance. There will be no sound hearable if the distance from sound
to listener is larger than this.
The default value is 1.
*/
qreal QDeclarativeAttenuationModelLinear::endDistance() const
{
return m_end;
}
void QDeclarativeAttenuationModelLinear::setEndDistance(qreal endDist)
{
if (m_complete) {
qWarning() << "AttenuationModelLinear[" << m_name << "]: you can not change properties after initialization.";
return;
}
if (endDist < 0) {
qWarning() << "AttenuationModelLinear[" << m_name << "]: end must be no greater than 0.";
return;
}
m_end = endDist;
}
qreal QDeclarativeAttenuationModelLinear::calculateGain(const QVector3D &listenerPosition, const QVector3D &sourcePosition) const
{
qreal md = m_end - m_start;
if (md == 0)
return 1;
qreal d = qBound(qreal(0), (listenerPosition - sourcePosition).length() - m_start, md);
return qreal(1) - (d / md);
}
//////////////////////////////////////////////////////////////////////////////////////////
/*!
\qmlclass AttenuationModelInverse QDeclarativeAttenuationModelInverse
\since 5.0
\brief The AttenuationModelInverse element allows you to define a non-linear attenuation curve
for Sound element.
\ingroup qml-multimedia
\inherits Item
This element is part of the \bold{QtAudioEngine 1.0} module.
AttenuationModelInverse must be defined inside AudioEngine.
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
AttenuationModelInverse {
name:"linear"
start: 20
end: 500
rolloff: 1.5
}
AudioSample {
name:"explosion"
source: "explosion-02.wav"
}
Sound {
name:"explosion"
attenuationModel: "linear"
PlayVariation {
sample:"explosion"
}
}
}
}
\endqml
Attenuation factor is calculated as below:
distance: distance from sound to listener
d = min(max(distance, start), end);
attenuation = start / (start + (d - start) * rolloff);
*/
/*!
\qmlproperty string AttenuationModelInverse::name
This property holds the name of AttenuationModelInverse, must be unique among all attenuation
models and only defined once.
*/
/*!
\qmlproperty real AttenuationModelInverse::start
This property holds the start distance. There will be no attenuation if the distance from sound
to listener is within this range.
The default value is 1.
*/
/*!
\qmlproperty real AttenuationModelInverse::end
This property holds the end distance. There will be no further attenuation if the distance from
sound to listener is larger than this.
The default value is 1000.
*/
/*!
\qmlproperty real AttenuationModelInverse::rolloff
This property holds the rolloff factor. The bigger the value is, the faster the sound attenuates.
The default value is 1.
*/
QDeclarativeAttenuationModelInverse::QDeclarativeAttenuationModelInverse(QObject *parent)
: QDeclarativeAttenuationModel(parent)
, m_ref(1)
, m_max(1000)
, m_rolloff(1)
{
}
void QDeclarativeAttenuationModelInverse::componentComplete()
{
if (m_ref > m_max) {
qSwap(m_ref, m_max);
qWarning() << "AttenuationModelInverse[" << m_name << "]: referenceDistance must be less or equal than maxDistance.";
}
QDeclarativeAttenuationModel::componentComplete();
}
qreal QDeclarativeAttenuationModelInverse::referenceDistance() const
{
return m_ref;
}
void QDeclarativeAttenuationModelInverse::setReferenceDistance(qreal referenceDistance)
{
if (m_complete) {
qWarning() << "AttenuationModelInverse[" << m_name << "]: you can not change properties after initialization.";
return;
}
if (referenceDistance <= 0) {
qWarning() << "AttenuationModelInverse[" << m_name << "]: referenceDistance must be greater than 0.";
return;
}
m_ref = referenceDistance;
}
qreal QDeclarativeAttenuationModelInverse::maxDistance() const
{
return m_max;
}
void QDeclarativeAttenuationModelInverse::setMaxDistance(qreal maxDistance)
{
if (m_complete) {
qWarning() << "AttenuationModelInverse[" << m_name << "]: you can not change properties after initialization.";
return;
}
if (maxDistance <= 0) {
qWarning() << "AttenuationModelInverse[" << m_name << "]: maxDistance must be greater than 0.";
return;
}
m_max = maxDistance;
}
qreal QDeclarativeAttenuationModelInverse::rolloffFactor() const
{
return m_rolloff;
}
void QDeclarativeAttenuationModelInverse::setRolloffFactor(qreal rolloffFactor)
{
if (m_complete) {
qWarning() << "AttenuationModelInverse[" << m_name << "]: you can not change properties after initialization.";
return;
}
m_rolloff = rolloffFactor;
}
qreal QDeclarativeAttenuationModelInverse::calculateGain(const QVector3D &listenerPosition, const QVector3D &sourcePosition) const
{
Q_ASSERT(m_ref > 0);
return m_ref / (m_ref + (qBound(m_ref, (listenerPosition - sourcePosition).length(), m_max) - m_ref) * m_rolloff);
}

View File

@@ -0,0 +1,138 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QDECLARATIVEATTENUATIONMODEL_P_H
#define QDECLARATIVEATTENUATIONMODEL_P_H
#include <QtDeclarative/qdeclarative.h>
#include <QtDeclarative/qdeclarativecomponent.h>
#include <QVector3D>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QDeclarativeAttenuationModel : public QObject, public QDeclarativeParserStatus
{
Q_OBJECT
Q_INTERFACES(QDeclarativeParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
public:
QDeclarativeAttenuationModel(QObject *parent = 0);
~QDeclarativeAttenuationModel();
void classBegin();
void componentComplete();
QString name() const;
void setName(const QString& name);
virtual qreal calculateGain(const QVector3D &listenerPosition, const QVector3D &sourcePosition) const = 0;
protected:
bool m_complete;
QString m_name;
private:
Q_DISABLE_COPY(QDeclarativeAttenuationModel);
};
class QDeclarativeAttenuationModelLinear : public QDeclarativeAttenuationModel
{
Q_OBJECT
Q_PROPERTY(qreal start READ startDistance WRITE setStartDistance CONSTANT)
Q_PROPERTY(qreal end READ endDistance WRITE setEndDistance CONSTANT)
public:
QDeclarativeAttenuationModelLinear(QObject *parent = 0);
void componentComplete();
qreal startDistance() const;
void setStartDistance(qreal startDist);
qreal endDistance() const;
void setEndDistance(qreal endDist);
qreal calculateGain(const QVector3D &listenerPosition, const QVector3D &sourcePosition) const;
private:
Q_DISABLE_COPY(QDeclarativeAttenuationModelLinear);
qreal m_start;
qreal m_end;
};
class QDeclarativeAttenuationModelInverse : public QDeclarativeAttenuationModel
{
Q_OBJECT
Q_PROPERTY(qreal start READ referenceDistance WRITE setReferenceDistance CONSTANT)
Q_PROPERTY(qreal end READ maxDistance WRITE setMaxDistance CONSTANT)
Q_PROPERTY(qreal rolloff READ rolloffFactor WRITE setRolloffFactor CONSTANT)
public:
QDeclarativeAttenuationModelInverse(QObject *parent = 0);
void componentComplete();
qreal referenceDistance() const;
void setReferenceDistance(qreal referenceDistance);
qreal maxDistance() const;
void setMaxDistance(qreal maxDistance);
qreal rolloffFactor() const;
void setRolloffFactor(qreal rolloffFactor);
qreal calculateGain(const QVector3D &listenerPosition, const QVector3D &sourcePosition) const;
private:
Q_DISABLE_COPY(QDeclarativeAttenuationModelInverse);
qreal m_ref;
qreal m_max;
qreal m_rolloff;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1,207 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qdeclarative_audiocategory_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
/*!
\qmlclass AudioCategory QDeclarativeAudioCategory
\since 5.0
\brief The AudioCategory element allows you to control all active sound instances by group
\ingroup qml-multimedia
\inherits Item
This element is part of the \bold{QtAudioEngine 1.0} module.
AudioCategory element can be accessed through AudioEngine::categories with its unique name and
must be defined inside AudioEngine.
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
AudioCategory {
name: "sfx"
volume: 0.8
}
AudioSample {
name:"explosion"
source: "explosion-02.wav"
}
Sound {
name:"explosion"
category: "sfx"
PlayVariation {
sample:"explosion"
}
}
}
MouseArea {
anchors.fill: parent
onPressed: {
audioengine.categories["sfx"].volume = 0.5;
}
}
}
\endqml
Sound elements can be grouped togather by specifying the category property. When you change the
volume of a category, all audio output from related elements will be affected as well.
Note: there will always be an AudioCategory named \c default whether you explicitly define it or
not. If you do not specify any category for a Sound element, it will be grouped into the \c default
category.
*/
QDeclarativeAudioCategory::QDeclarativeAudioCategory(QObject *parent)
: QObject(parent)
, m_complete(false)
, m_volume(1)
{
}
QDeclarativeAudioCategory::~QDeclarativeAudioCategory()
{
}
void QDeclarativeAudioCategory::classBegin()
{
if (!parent() || !parent()->inherits("QDeclarativeAudioEngine")) {
qWarning("AudioCategory must be defined inside AudioEngine!");
return;
}
}
void QDeclarativeAudioCategory::componentComplete()
{
if (m_name.isEmpty()) {
qWarning("AudioCategory must have a name!");
return;
}
m_complete = true;
}
/*!
\qmlproperty real AudioCategory::volume
This property holds the volume of the category and will modulate all audio output from the
element which belongs to this category.
*/
qreal QDeclarativeAudioCategory::volume() const
{
return m_volume;
}
void QDeclarativeAudioCategory::setVolume(qreal volume)
{
if (m_volume == volume)
return;
m_volume = volume;
emit volumeChanged(m_volume);
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeAudioCategory[" << m_name << "] setVolume(" << volume << ")";
#endif
}
/*!
\qmlproperty string AudioCategory::name
This property holds the name of AudioCategory. The name must be unique among all categories and only
defined once.
*/
void QDeclarativeAudioCategory::setName(const QString& name)
{
if (m_complete) {
qWarning("AudioCategory: you can not change name after initialization.");
return;
}
m_name = name;
}
QString QDeclarativeAudioCategory::name() const
{
return m_name;
}
/*!
\qmlmethod AudioCategory::stop()
Stops all active sound instances which belong to this category.
*/
void QDeclarativeAudioCategory::stop()
{
emit stopped();
}
/*!
\qmlmethod AudioCategory::pause()
Pauses all active sound instances which belong to this category.
*/
void QDeclarativeAudioCategory::pause()
{
emit paused();
}
/*!
\qmlmethod AudioCategory::pause()
Resumes all active sound instances from paused state which belong to this category.
*/
void QDeclarativeAudioCategory::resume()
{
emit resumed();
}

View File

@@ -0,0 +1,94 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QDECLARATIVEAUDIOCATEGORY_P_H
#define QDECLARATIVEAUDIOCATEGORY_P_H
#include <QtDeclarative/qdeclarative.h>
#include <QtDeclarative/qdeclarativecomponent.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QDeclarativeAudioCategory : public QObject, public QDeclarativeParserStatus
{
Q_OBJECT
Q_INTERFACES(QDeclarativeParserStatus)
Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
Q_PROPERTY(QString name READ name WRITE setName)
public:
QDeclarativeAudioCategory(QObject *parent = 0);
~QDeclarativeAudioCategory();
void classBegin();
void componentComplete();
qreal volume() const;
void setVolume(qreal volume);
QString name() const;
void setName(const QString& name);
Q_SIGNALS:
void volumeChanged(qreal newVolume);
void stopped();
void paused();
void resumed();
public Q_SLOTS:
void stop();
void pause();
void resume();
private:
Q_DISABLE_COPY(QDeclarativeAudioCategory);
bool m_complete;
QString m_name;
qreal m_volume;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1,519 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qdeclarative_audioengine_p.h"
#include "qdeclarative_audiolistener_p.h"
#include "qdeclarative_audiocategory_p.h"
#include "qdeclarative_audiosample_p.h"
#include "qdeclarative_sound_p.h"
#include "qdeclarative_playvariation_p.h"
#include "qdeclarative_attenuationmodel_p.h"
#include "qdeclarative_soundinstance_p.h"
#include "qsoundinstance_p.h"
#include <QtDeclarative/qdeclarativeengine.h>
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
/*!
\qmlclass AudioEngine QDeclarativeAudioEngine
\since 5.0
\brief The AudioEngine element allows you to organize all your 3d audio content in one place.
\ingroup qml-multimedia
\inherits Item
This element is part of the \bold{QtAudioEngine 1.0} module.
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
AudioSample {
name:"explosion"
source: "explosion-02.wav"
}
Sound {
name:"explosion"
PlayVariation {
sample:"explosion"
}
}
dopplerFactor: 1
speedOfSound: 343.33
listener.up:"0,0,1"
listener.position:"0,0,0"
listener.velocity:"0,0,0"
listener.direction:"0,1,0"
}
MouseArea {
anchors.fill: parent
onPressed: {
audioengine.sounds["explosion"].play();
}
}
}
\endqml
The \c AudioEngine element acts as a central library for configuring all 3d audio content in an
app, so you should define only one such element in your app.
It is mostly used as a container to access other elements such as AudioCategory, AudioSample and
Sound.
\sa AudioCategory, AudioSample, Sound, SoundInstance, AttenuationModelLinear, AttenuationModelInverse
*/
QDeclarativeAudioEngine::QDeclarativeAudioEngine(QObject *parent)
: QObject(parent)
, m_complete(false)
, m_defaultCategory(0)
, m_defaultAttenuationModel(0)
, m_audioEngine(0)
{
m_audioEngine = QAudioEngine::create(this);
connect(m_audioEngine, SIGNAL(isLoadingChanged()), this, SIGNAL(isLoadingChanged()));
connect(m_audioEngine, SIGNAL(isLoadingChanged()), this, SLOT(handleLoadingChanged()));
m_listener = new QDeclarativeAudioListener(this);
m_updateTimer.setInterval(100);
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateSoundInstances()));
}
QDeclarativeAudioEngine::~QDeclarativeAudioEngine()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeAudioEngine::dtor"
<< "active = " << m_activeSoundInstances.count()
<< "pool = " << m_soundInstancePool.count();
#endif
qDeleteAll(m_activeSoundInstances);
m_activeSoundInstances.clear();
#ifdef DEBUG_AUDIOENGINE
qDebug() << "for pool";
#endif
qDeleteAll(m_soundInstancePool);
m_soundInstancePool.clear();
}
void QDeclarativeAudioEngine::classBegin()
{
}
bool QDeclarativeAudioEngine::isReady() const
{
return m_complete;
}
QAudioEngine* QDeclarativeAudioEngine::engine() const
{
return m_audioEngine;
}
QDeclarativeSoundInstance* QDeclarativeAudioEngine::newDeclarativeSoundInstance(bool managed)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeAudioEngine::newDeclarativeSoundInstance(" << managed << ")";
#endif
QDeclarativeSoundInstance *instance = 0;
if (managed) {
if (m_managedDeclSndInstancePool.count() > 0) {
instance = m_managedDeclSndInstancePool.last();
m_managedDeclSndInstancePool.pop_back();
} else {
instance = new QDeclarativeSoundInstance(this);
qmlEngine(instance)->setObjectOwnership(instance, QDeclarativeEngine::CppOwnership);
instance->setEngine(this);
}
m_managedDeclSoundInstances.push_back(instance);
} else {
instance = new QDeclarativeSoundInstance();
instance->setEngine(this);
qmlEngine(instance)->setObjectOwnership(instance, QDeclarativeEngine::JavaScriptOwnership);
}
return instance;
}
void QDeclarativeAudioEngine::releaseManagedDeclarativeSoundInstance(QDeclarativeSoundInstance* declSndInstance)
{
declSndInstance->setSound(QString());
m_managedDeclSndInstancePool.push_back(declSndInstance);
}
/*!
\qmlproperty int AudioEngine::liveInstances
This property indicates how many live sound instances there are at the moment.
*/
int QDeclarativeAudioEngine::liveInstanceCount() const
{
return m_activeSoundInstances.count();
}
QSoundInstance* QDeclarativeAudioEngine::newSoundInstance(const QString &name)
{
QSoundInstance *instance = 0;
if (m_soundInstancePool.count() > 0) {
instance = m_soundInstancePool.last();
m_soundInstancePool.pop_back();
} else {
instance = new QSoundInstance(this);
}
instance->bindSoundDescription(qobject_cast<QDeclarativeSound*>(qvariant_cast<QObject*>(m_sounds.value(name))));
m_activeSoundInstances.push_back(instance);
if (!m_updateTimer.isActive())
m_updateTimer.start();
emit liveInstanceCountChanged();
return instance;
}
void QDeclarativeAudioEngine::releaseSoundInstance(QSoundInstance* instance)
{
instance->bindSoundDescription(0);
m_activeSoundInstances.removeOne(instance);
m_soundInstancePool.push_back(instance);
emit liveInstanceCountChanged();
}
void QDeclarativeAudioEngine::componentComplete()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "AudioEngine begin initialization";
#endif
if (!m_defaultCategory) {
#ifdef DEBUG_AUDIOENGINE
qDebug() << "creating default category";
#endif
m_defaultCategory = new QDeclarativeAudioCategory(this);
m_defaultCategory->classBegin();
m_defaultCategory->setName(QString::fromLatin1("default"));
m_defaultCategory->setVolume(1);
m_defaultCategory->componentComplete();
}
#ifdef DEBUG_AUDIOENGINE
qDebug() << "init samples" << m_samples.keys().count();
#endif
foreach (const QString& key, m_samples.keys()) {
QDeclarativeAudioSample *sample = qobject_cast<QDeclarativeAudioSample*>(
qvariant_cast<QObject*>(m_samples[key]));
if (!sample) {
qWarning() << "accessing invalid sample[" << key << "]";
continue;
}
sample->init();
}
#ifdef DEBUG_AUDIOENGINE
qDebug() << "init sounds" << m_sounds.keys().count();
#endif
foreach (const QString& key, m_sounds.keys()) {
QDeclarativeSound *sound = qobject_cast<QDeclarativeSound*>(
qvariant_cast<QObject*>(m_sounds[key]));
if (!sound) {
qWarning() << "accessing invalid sound[" << key << "]";
continue;
}
QDeclarativeAudioCategory *category = m_defaultCategory;
if (m_categories.contains(sound->category())) {
category = qobject_cast<QDeclarativeAudioCategory*>(
qvariant_cast<QObject*>(m_categories[sound->category()]));
}
sound->setCategoryObject(category);
QDeclarativeAttenuationModel *attenuationModel = 0;
if (sound->attenuationModel().isEmpty()) {
if (m_defaultAttenuationModel)
attenuationModel = m_defaultAttenuationModel;
} else if (m_attenuationModels.contains(sound->attenuationModel())){
attenuationModel = m_attenuationModels[sound->attenuationModel()];
} else {
qWarning() << "Sound[" << sound->name() << "] contains invalid attenuationModel["
<< sound->attenuationModel() << "]";
}
sound->setAttenuationModelObject(attenuationModel);
foreach (QDeclarativePlayVariation* playVariation, sound->playlist()) {
if (m_samples.contains(playVariation->sample())) {
playVariation->setSampleObject(
qobject_cast<QDeclarativeAudioSample*>(
qvariant_cast<QObject*>(m_samples[playVariation->sample()])));
} else {
qWarning() << "Sound[" << sound->name() << "] contains invalid sample["
<< playVariation->sample() << "] for its playVarations";
}
}
}
m_complete = true;
#ifdef DEBUG_AUDIOENGINE
qDebug() << "AudioEngine ready.";
#endif
emit ready();
}
void QDeclarativeAudioEngine::updateSoundInstances()
{
for (QList<QDeclarativeSoundInstance*>::Iterator it = m_managedDeclSoundInstances.begin();
it != m_managedDeclSoundInstances.end();) {
QDeclarativeSoundInstance *declSndInstance = *it;
if (declSndInstance->state() == QDeclarativeSoundInstance::StopppedState) {
it = m_managedDeclSoundInstances.erase(it);
releaseManagedDeclarativeSoundInstance(declSndInstance);
#ifdef DEBUG_AUDIOENGINE
qDebug() << "AudioEngine removed managed sounce instance";
#endif
} else {
declSndInstance->updatePosition(qreal(0.1));
++it;
}
}
QVector3D listenerPosition = this->listener()->position();
foreach (QSoundInstance *instance, m_activeSoundInstances) {
if (instance->state() == QSoundInstance::PlayingState
&& instance->attenuationEnabled()) {
instance->update3DVolume(listenerPosition);
}
}
if (m_activeSoundInstances.count() == 0)
m_updateTimer.stop();
}
void QDeclarativeAudioEngine::appendFunction(QDeclarativeListProperty<QObject> *property, QObject *value)
{
QDeclarativeAudioEngine* engine = static_cast<QDeclarativeAudioEngine*>(property->object);
if (engine->m_complete) {
qWarning("AudioEngine: cannot add child after initialization!");
return;
}
QDeclarativeSound *sound = qobject_cast<QDeclarativeSound*>(value);
if (sound) {
#ifdef DEBUG_AUDIOENGINE
qDebug() << "add QDeclarativeSound[" << sound->name() << "]";
#endif
if (engine->m_sounds.contains(sound->name())) {
qWarning() << "Failed to add Sound[" << sound->name() << "], already exists!";
return;
}
engine->m_sounds.insert(sound->name(), QVariant::fromValue(value));
return;
}
QDeclarativeAudioSample *sample = qobject_cast<QDeclarativeAudioSample*>(value);
if (sample) {
#ifdef DEBUG_AUDIOENGINE
qDebug() << "add QDeclarativeAudioSample[" << sample->name() << "]";
#endif
if (engine->m_samples.contains(sample->name())) {
qWarning() << "Failed to add AudioSample[" << sample->name() << "], already exists!";
return;
}
engine->m_samples.insert(sample->name(), QVariant::fromValue(value));
return;
}
QDeclarativeAudioCategory *category = qobject_cast<QDeclarativeAudioCategory*>(value);
if (category) {
#ifdef DEBUG_AUDIOENGINE
qDebug() << "add QDeclarativeAudioCategory[" << category->name() << "]";
#endif
if (engine->m_categories.contains(category->name())) {
qWarning() << "Failed to add AudioCategory[" << category->name() << "], already exists!";
return;
}
engine->m_categories.insert(category->name(), QVariant::fromValue(value));
if (category->name() == QLatin1String("default")) {
engine->m_defaultCategory = category;
}
}
QDeclarativeAttenuationModel *attenModel = qobject_cast<QDeclarativeAttenuationModel*>(value);
if (attenModel) {
#ifdef DEBUG_AUDIOENGINE
qDebug() << "add AttenuationModel[" << attenModel->name() << "]";
#endif
if (attenModel->name() == QLatin1String("default")) {
engine->m_defaultAttenuationModel = attenModel;
}
if (engine->m_attenuationModels.contains(attenModel->name())) {
qWarning() << "Failed to add AttenuationModel[" << attenModel->name() << "], already exists!";
return;
}
engine->m_attenuationModels.insert(attenModel->name(), attenModel);
return;
}
qWarning("Unknown child type for AudioEngine!");
}
QDeclarativeListProperty<QObject> QDeclarativeAudioEngine::bank()
{
return QDeclarativeListProperty<QObject>(this, 0, appendFunction);
}
/*!
\qmlproperty map AudioEngine::categories
Container of all AudioCategory elements.
*/
QObject* QDeclarativeAudioEngine::categories()
{
return &m_categories;
}
/*!
\qmlproperty map AudioEngine::samples
Container of all AudioSample elements.
*/
QObject* QDeclarativeAudioEngine::samples()
{
return &m_samples;
}
/*!
\qmlproperty map AudioEngine::sounds
Container of all Sound elements.
*/
QObject* QDeclarativeAudioEngine::sounds()
{
return &m_sounds;
}
/*!
\qmlproperty AudioListener AudioEngine::listener
This property holds the listener object. You can change various
properties to affect the 3D positioning of sounds.
\sa AudioListener
*/
QDeclarativeAudioListener* QDeclarativeAudioEngine::listener() const
{
return m_listener;
}
/*!
\qmlproperty real AudioEngine::dopplerFactor
This property holds a simple scaling for the effect of doppler shift.
*/
qreal QDeclarativeAudioEngine::dopplerFactor() const
{
return m_audioEngine->dopplerFactor();
}
void QDeclarativeAudioEngine::setDopplerFactor(qreal dopplerFactor)
{
m_audioEngine->setDopplerFactor(dopplerFactor);
}
/*!
\qmlproperty real AudioEngine::speedOfSound
This property holds the reference value of the sound speed which will be used in doppler shift
calculation.
*/
qreal QDeclarativeAudioEngine::speedOfSound() const
{
return m_audioEngine->speedOfSound();
}
void QDeclarativeAudioEngine::setSpeedOfSound(qreal speedOfSound)
{
m_audioEngine->setSpeedOfSound(speedOfSound);
}
/*!
\qmlproperty real AudioEngine::loading
This property indicates if the audio engine is loading any audio sample at the moment. This may
be useful if you specified the preloaded property in AudioSample and would like to show a loading screen
to the user before all audio samples are loaded.
/sa finishedLoading, AudioSample::preloaded
*/
bool QDeclarativeAudioEngine::isLoading() const
{
return m_audioEngine->isLoading();
}
void QDeclarativeAudioEngine::handleLoadingChanged()
{
if (!isLoading())
emit finishedLoading();
}
/*!
\qmlsignal AudioEngine::onLiveInstancesChanged()
This handler is called when \l liveInstances is changed
*/
/*!
\qmlsignal AudioEngine::onLoadingChanged()
This handler is called when \l loading is changed
*/
/*!
\qmlsignal AudioEngine::finishedLoading()
This handler is called when \l loading is finished
*/
QT_END_NAMESPACE

View File

@@ -0,0 +1,168 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QDECLARATIVEAUDIOENGINE_P_H
#define QDECLARATIVEAUDIOENGINE_P_H
#include <QtDeclarative/qdeclarative.h>
#include <QtDeclarative/qdeclarativecomponent.h>
#include <QtDeclarative/qdeclarativepropertymap.h>
#include <QtCore/QMap>
#include <QtCore/QList>
#include <QTimer>
#include "qaudioengine_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QDeclarativeSoundInstance;
class QDeclarativeAudioListener;
class QDeclarativeAudioCategory;
class QDeclarativeAudioSample;
class QDeclarativeSound;
class QDeclarativePlayVariation;
class QAudioCategory;
class QDeclarativeAttenuationModel;
class QSoundInstance;
class QDeclarativeAudioEngine : public QObject, public QDeclarativeParserStatus
{
Q_OBJECT
Q_INTERFACES(QDeclarativeParserStatus)
Q_PROPERTY(QDeclarativeListProperty<QObject> bank READ bank CONSTANT)
Q_PROPERTY(QObject* categories READ categories CONSTANT)
Q_PROPERTY(QObject* samples READ samples CONSTANT)
Q_PROPERTY(QObject* sounds READ sounds CONSTANT)
Q_PROPERTY(bool loading READ isLoading NOTIFY isLoadingChanged)
Q_PROPERTY(int liveInstances READ liveInstanceCount NOTIFY liveInstanceCountChanged)
Q_PROPERTY(QDeclarativeAudioListener* listener READ listener CONSTANT)
Q_PROPERTY(qreal dopplerFactor READ dopplerFactor WRITE setDopplerFactor)
Q_PROPERTY(qreal speedOfSound READ speedOfSound WRITE setSpeedOfSound)
Q_CLASSINFO("DefaultProperty", "bank")
public:
QDeclarativeAudioEngine(QObject *parent = 0);
~QDeclarativeAudioEngine();
void classBegin();
void componentComplete();
//This is used for tracking all objects declared inside AudioEngine
//see appendFunction
QDeclarativeListProperty<QObject> bank();
QObject* categories();
QObject* samples();
QObject* sounds();
QDeclarativeAudioListener* listener() const;
qreal dopplerFactor() const;
void setDopplerFactor(qreal dopplerFactor);
qreal speedOfSound() const;
void setSpeedOfSound(qreal speedOfSound);
bool isLoading() const;
int liveInstanceCount() const;
//for child elements
bool isReady() const;
QAudioEngine* engine() const;
//if managed, then the instance should start playing immediately and will be collected
//when the playback finished
QDeclarativeSoundInstance* newDeclarativeSoundInstance(bool managed);
//internal sound instance is different from declarativeSoundInstance
//declarative instance is more like a soundInstance helper which can
//switch to different sound instance conveniently while sound instance
//must be mapped to one sound definition.
QSoundInstance* newSoundInstance(const QString &name);
void releaseSoundInstance(QSoundInstance* instance);
Q_SIGNALS:
void ready();
void liveInstanceCountChanged();
void isLoadingChanged();
void finishedLoading();
private Q_SLOTS:
void updateSoundInstances();
void handleLoadingChanged();
private:
Q_DISABLE_COPY(QDeclarativeAudioEngine);
bool m_complete;
//see bank()
static void appendFunction(QDeclarativeListProperty<QObject> *property, QObject *value);
QDeclarativeAudioListener *m_listener;
QDeclarativeAudioCategory* m_defaultCategory;
QDeclarativePropertyMap m_categories;
QDeclarativePropertyMap m_samples;
QDeclarativePropertyMap m_sounds;
//Use strong type here since no need to for AttenuationModel to be accessible directly by user
//after config stage
QDeclarativeAttenuationModel *m_defaultAttenuationModel;
QMap<QString, QDeclarativeAttenuationModel*> m_attenuationModels;
QAudioEngine *m_audioEngine;
//for execution stage management
QList<QSoundInstance*> m_soundInstancePool;
QList<QSoundInstance*> m_activeSoundInstances;
QTimer m_updateTimer;
QList<QDeclarativeSoundInstance*> m_managedDeclSoundInstances;
QList<QDeclarativeSoundInstance*> m_managedDeclSndInstancePool;
void releaseManagedDeclarativeSoundInstance(QDeclarativeSoundInstance* declSndInstance);
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1,263 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qdeclarative_audiolistener_p.h"
#include "qdeclarative_audioengine_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
/*!
\qmlclass AudioListener QDeclarativeAudioListener
\since 5.0
\brief The AudioListener element allows you to control global listener parameters.
\ingroup qml-multimedia
\inherits Item
This element is part of the \bold{QtAudioEngine 1.0} module.
AudioListener will have only one global instance and you can either access it through the
listener property of AudioEngine:
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
listener.up:"0,0,1"
listener.velocity:"0,0,0"
listener.direction:"0,1,0"
listener.position:Qt.vector3d(observer.x, observer.y, 0);
}
Item {
id: observer
x: 10 + observer.percent * 100
y: 20 + observer.percent * 80
property real percent: 0
SequentialAnimation on percent {
loops: Animation.Infinite
running: true
NumberAnimation {
duration: 8000
from: 0
to: 1
}
}
}
}
\endqml
or alternatively, by defining an AudioListener element outside AudioEngine:
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
listener.up:"0,0,1"
listener.velocity:"0,0,0"
listener.direction:"0,1,0"
}
AudioListener {
engine:audioengine
position: Qt.vector3d(observer.x, observer.y, 0);
}
Item {
id: observer
x: 10 + observer.percent * 100
y: 20 + observer.percent * 80
property real percent: 0
SequentialAnimation on percent {
loops: Animation.Infinite
running: true
NumberAnimation {
duration: 8000
from: 0
to: 1
}
}
}
}
\endqml
This separate AudioListener definition is allowed to make qml bindings easier in some case.
*/
QDeclarativeAudioListener::QDeclarativeAudioListener(QObject *parent)
: QObject(parent)
, m_engine(0)
{
m_engine = qobject_cast<QDeclarativeAudioEngine*>(parent);
}
QDeclarativeAudioListener::~QDeclarativeAudioListener()
{
}
/*!
\qmlproperty AudioEngine AudioListener::engine
This property holds the reference to AudioEngine, must be set only once.
*/
QDeclarativeAudioEngine* QDeclarativeAudioListener::engine() const
{
return m_engine;
}
void QDeclarativeAudioListener::setEngine(QDeclarativeAudioEngine *engine)
{
setParent(engine);
m_engine = engine;
}
/*!
\qmlproperty vector3d AudioListener::position
This property holds the 3d position of the listener.
*/
QVector3D QDeclarativeAudioListener::position() const
{
return m_engine->engine()->listenerPosition();
}
void QDeclarativeAudioListener::setPosition(const QVector3D &position)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeAudioListener::setPosition";
#endif
m_engine->engine()->setListenerPosition(position);
emit positionChanged();
}
/*!
\qmlproperty vector3d AudioListener::direction
This property holds the normalized 3d direction vector of the listener.
*/
QVector3D QDeclarativeAudioListener::direction() const
{
return m_engine->engine()->listenerDirection();
}
void QDeclarativeAudioListener::setDirection(const QVector3D &direction)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeAudioListener::setDirection";
#endif
m_engine->engine()->setListenerDirection(direction);
emit directionChanged();
}
/*!
\qmlproperty vector3d AudioListener::velocity
This property holds the 3d velocity vector of the listener.
*/
QVector3D QDeclarativeAudioListener::velocity() const
{
return m_engine->engine()->listenerVelocity();
}
void QDeclarativeAudioListener::setVelocity(const QVector3D &velocity)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeAudioListener::setVelocity";
#endif
m_engine->engine()->setListenerVelocity(velocity);
emit velocityChanged();
}
/*!
\qmlproperty vector3d AudioListener::up
This property holds the normalized 3d up vector of the listener.
*/
QVector3D QDeclarativeAudioListener::up() const
{
return m_engine->engine()->listenerUp();
}
void QDeclarativeAudioListener::setUp(const QVector3D &up)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeAudioListener::setUp";
#endif
m_engine->engine()->setListenerUp(up);
emit upChanged();
}
/*!
\qmlproperty real AudioListener::gain
This property will modulate all audio output from audio engine elements.
*/
qreal QDeclarativeAudioListener::gain() const
{
return m_engine->engine()->listenerGain();
}
void QDeclarativeAudioListener::setGain(qreal gain)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeAudioListener::setGain";
#endif
m_engine->engine()->setListenerGain(gain);
emit gainChanged();
}

View File

@@ -0,0 +1,102 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QDECLARATIVEAUDIOLISTENER_P_H
#define QDECLARATIVEAUDIOLISTENER_P_H
#include <QtCore/QObject>
#include <QtGui/qvector3d.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QDeclarativeAudioEngine;
class QDeclarativeAudioListener : public QObject
{
Q_OBJECT
Q_PROPERTY(QDeclarativeAudioEngine* engine READ engine WRITE setEngine)
Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
Q_PROPERTY(QVector3D direction READ direction WRITE setDirection NOTIFY directionChanged)
Q_PROPERTY(QVector3D velocity READ velocity WRITE setVelocity NOTIFY velocityChanged)
Q_PROPERTY(QVector3D up READ up WRITE setUp NOTIFY upChanged)
Q_PROPERTY(qreal gain READ gain WRITE setGain NOTIFY gainChanged)
public:
QDeclarativeAudioListener(QObject *parent = 0);
~QDeclarativeAudioListener();
QDeclarativeAudioEngine* engine() const;
void setEngine(QDeclarativeAudioEngine *engine);
QVector3D position() const;
void setPosition(const QVector3D &position);
QVector3D direction() const;
void setDirection(const QVector3D &direction);
QVector3D up() const;
void setUp(const QVector3D &up);
QVector3D velocity() const;
void setVelocity(const QVector3D &velocity);
qreal gain() const;
void setGain(qreal gain);
Q_SIGNALS:
void positionChanged();
void directionChanged();
void velocityChanged();
void upChanged();
void gainChanged();
private:
Q_DISABLE_COPY(QDeclarativeAudioListener);
QDeclarativeAudioEngine *m_engine;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1,242 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qdeclarative_audiosample_p.h"
#include "qdeclarative_audioengine_p.h"
#include "qdebug.h"
#include "qsoundbuffer_p.h"
#include "qaudioengine_p.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
/*!
\qmlclass AudioSample QDeclarativeAudioSample
\since 5.0
\brief The AudioSample element allows you to load audio samples, mostly wav file.
\ingroup qml-multimedia
\inherits Item
This element is part of the \bold{QtAudioEngine 1.0} module.
AudioSample element can be accessed through AudioEngine::samples with its unique name and must
be defined inside AudioEngine.
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
AudioSample {
name:"explosion"
source: "explosion-02.wav"
}
}
}
\endqml
*/
QDeclarativeAudioSample::QDeclarativeAudioSample(QObject *parent)
: QObject(parent)
, m_complete(false)
, m_streaming(false)
, m_preloaded(false)
, m_soundBuffer(0)
{
}
QDeclarativeAudioSample::~QDeclarativeAudioSample()
{
}
void QDeclarativeAudioSample::classBegin()
{
if (!parent() || !parent()->inherits("QDeclarativeAudioEngine")) {
qWarning("AudioSample must be defined inside AudioEngine!");
return;
}
}
void QDeclarativeAudioSample::componentComplete()
{
if (m_name.isEmpty()) {
qWarning("AudioSample must have a name!");
return;
}
m_complete = true;
}
QUrl QDeclarativeAudioSample::source() const
{
return m_url;
}
void QDeclarativeAudioSample::setSource(const QUrl& url)
{
if (m_complete) {
qWarning("AudioSample: source not changable after initialization.");
return;
}
m_url = url;
}
bool QDeclarativeAudioSample::isStreaming() const
{
return m_streaming;
}
/*!
\qmlproperty bool AudioSample::preloaded
This property holds indicates whether this sample needs to be preloaded or not.
If true, the audio engine will start loading the sample file immediately when the app started,
otherwise the sample will not be loaded untill be used by other element.
*/
bool QDeclarativeAudioSample::isPreloaded() const
{
return m_preloaded;
}
/*!
\qmlproperty bool AudioSample::isLoaded
This property holds indicates whether this sample has been loaded into memory or not.
*/
bool QDeclarativeAudioSample::isLoaded() const
{
if (!m_soundBuffer)
return false;
return m_soundBuffer->isReady();
}
/*!
\qmlproperty AudioSample::load()
Starts loading the sample into memory if not loaded.
*/
void QDeclarativeAudioSample::load()
{
if (isLoaded())
return;
if (!m_soundBuffer) {
m_preloaded = true;
return;
}
m_soundBuffer->load();
}
void QDeclarativeAudioSample::setPreloaded(bool preloaded)
{
if (m_complete) {
qWarning("AudioSample: preloaded not changable after initialization.");
return;
}
m_preloaded = preloaded;
}
void QDeclarativeAudioSample::setStreaming(bool streaming)
{
if (m_complete) {
qWarning("AudioSample: streaming not changable after initialization.");
return;
}
m_streaming = streaming;
}
/*!
\qmlproperty string AudioSample::name
This property holds the name of AudioSample, must be unique among all samples and only
defined once.
*/
QString QDeclarativeAudioSample::name() const
{
return m_name;
}
void QDeclarativeAudioSample::setName(const QString& name)
{
if (m_complete) {
qWarning("AudioSample: name not changable after initialization.");
return;
}
m_name = name;
}
void QDeclarativeAudioSample::init()
{
if (m_streaming) {
//TODO
} else {
m_soundBuffer =
qobject_cast<QDeclarativeAudioEngine*>(parent())->engine()->getStaticSoundBuffer(m_url);
if (m_soundBuffer->isReady()) {
emit loadedChanged();
} else {
connect(m_soundBuffer, SIGNAL(ready()), this, SIGNAL(loadedChanged()));
}
if (m_preloaded) {
m_soundBuffer->load();
}
}
}
QSoundBuffer* QDeclarativeAudioSample::soundBuffer() const
{
return m_soundBuffer;
}
/*!
\qmlsignal AudioSample::onLoadedChanged()
This handler is called when \l loaded is changed
*/

View File

@@ -0,0 +1,111 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QDECLARATIVEAUDIOSAMPLE_P_H
#define QDECLARATIVEAUDIOSAMPLE_P_H
#include <QtDeclarative/qdeclarative.h>
#include <QtDeclarative/qdeclarativecomponent.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QSoundBuffer;
class QDeclarativeAudioSample : public QObject, public QDeclarativeParserStatus
{
Q_OBJECT
Q_INTERFACES(QDeclarativeParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QUrl source READ source WRITE setSource)
Q_PROPERTY(bool preloaded READ isPreloaded WRITE setPreloaded)
Q_PROPERTY(bool streaming READ isStreaming WRITE setStreaming)
Q_PROPERTY(bool loaded READ isLoaded NOTIFY loadedChanged)
public:
QDeclarativeAudioSample(QObject *parent = 0);
~QDeclarativeAudioSample();
void classBegin();
void componentComplete();
QString name() const;
void setName(const QString& name);
QUrl source() const;
void setSource(const QUrl& url);
bool isStreaming() const;
void setStreaming(bool streaming);
bool isPreloaded() const;
void setPreloaded(bool preloaded);
bool isLoaded() const;
QSoundBuffer* soundBuffer() const;
//called by QDeclarativeAudioEngine
void init();
Q_SIGNALS:
void loadedChanged();
public Q_SLOTS:
void load();
private:
Q_DISABLE_COPY(QDeclarativeAudioSample);
bool m_complete;
QString m_name;
QUrl m_url;
bool m_streaming;
bool m_preloaded;
QSoundBuffer *m_soundBuffer;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1,287 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qdeclarative_playvariation_p.h"
#include "qdeclarative_audioengine_p.h"
#include "qsoundinstance_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
/*!
\qmlclass PlayVariation QDeclarativePlayVariation
\since 5.0
\brief The PlayVariation element allows you to define a playback variation for \l Sound element.
So each time the playback of the same sound can be a slightly different even with the same
AudioSample.
\ingroup qml-multimedia
\inherits Item
This element is part of the \bold{QtAudioEngine 1.0} module.
PlayVariation must be defined inside \l Sound element.
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
AudioSample {
name:"explosion01"
source: "explosion-01.wav"
}
AudioSample {
name:"explosion02"
source: "explosion-02.wav"
}
Sound {
name:"explosion"
PlayVariation {
sample:"explosion01"
minPitch: 0.8
maxPitch: 1.1
}
PlayVariation {
sample:"explosion01"
minGain: 1.1
maxGain: 1.5
}
}
}
}
\endqml
*/
QDeclarativePlayVariation::QDeclarativePlayVariation(QObject *parent)
: QObject(parent)
, m_complete(false)
, m_looping(false)
, m_maxGain(1)
, m_minGain(1)
, m_maxPitch(1)
, m_minPitch(1)
, m_sampleObject(0)
{
}
QDeclarativePlayVariation::~QDeclarativePlayVariation()
{
}
void QDeclarativePlayVariation::classBegin()
{
if (!parent() || !parent()->inherits("QDeclarativeSound")) {
qWarning("PlayVariation must be defined inside Sound!");
return;
}
}
void QDeclarativePlayVariation::componentComplete()
{
if (m_maxGain < m_minGain) {
qWarning("PlayVariation: maxGain must be no less than minGain");
qSwap(m_minGain, m_maxGain);
}
if (m_maxPitch < m_minPitch) {
qWarning("PlayVariation: maxPitch must be no less than minPitch");
qSwap(m_minPitch, m_maxPitch);
}
m_complete = true;
}
/*!
\qmlproperty string PlayVariation::sample
This property specifies which \l AudioSample this variation will use.
*/
QString QDeclarativePlayVariation::sample() const
{
return m_sample;
}
void QDeclarativePlayVariation::setSample(const QString& sample)
{
if (m_complete) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
m_sample = sample;
}
/*!
\qmlproperty bool PlayVariation::looping
This property indicates whether the playback will be looped or not.
*/
bool QDeclarativePlayVariation::isLooping() const
{
return m_looping;
}
void QDeclarativePlayVariation::setLooping(bool looping)
{
if (m_complete) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
m_looping = looping;
}
/*!
\qmlproperty real PlayVariation::maxGain
This property specifies the maximum gain adjustment that can be applied in any playback.
*/
qreal QDeclarativePlayVariation::maxGain() const
{
return m_maxGain;
}
void QDeclarativePlayVariation::setMaxGain(qreal maxGain)
{
if (m_complete) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
if (maxGain <= 0) {
qWarning("PlayVariation: maxGain must be greater than 0");
return;
}
m_maxGain = maxGain;
}
/*!
\qmlproperty real PlayVariation::minGain
This property specifies the minimum gain adjustment that can be applied in any playback.
*/
qreal QDeclarativePlayVariation::minGain() const
{
return m_minGain;
}
void QDeclarativePlayVariation::setMinGain(qreal minGain)
{
if (m_complete) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
if (minGain < 0) {
qWarning("PlayVariation: minGain must be no less than 0");
return;
}
m_minGain = minGain;
}
/*!
\qmlproperty real PlayVariation::maxPitch
This property specifies the maximum pitch adjustment that can be applied in any playback.
*/
qreal QDeclarativePlayVariation::maxPitch() const
{
return m_maxPitch;
}
void QDeclarativePlayVariation::setMaxPitch(qreal maxPitch)
{
if (m_complete) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
if (maxPitch < 0) {
qWarning("PlayVariation: maxPitch must be no less than 0");
return;
}
m_maxPitch = maxPitch;
}
/*!
\qmlproperty real PlayVariation::minPitch
This property specifies the minimum pitch adjustment that can be applied in any playback.
*/
qreal QDeclarativePlayVariation::minPitch() const
{
return m_minPitch;
}
void QDeclarativePlayVariation::setMinPitch(qreal minPitch)
{
if (m_complete) {
qWarning("PlayVariation: cannot change properties after initialization.");
return;
}
if (m_minPitch < 0) {
qWarning("PlayVariation: m_minPitch must be no less than 0");
return;
}
m_minPitch = minPitch;
}
QDeclarativeAudioSample* QDeclarativePlayVariation::sampleObject() const
{
return m_sampleObject;
}
void QDeclarativePlayVariation::setSampleObject(QDeclarativeAudioSample *sampleObject)
{
m_sampleObject = sampleObject;
}
void QDeclarativePlayVariation::applyParameters(QSoundInstance *soundInstance)
{
qreal pitch = qreal(qrand() % 1001) * 0.001f * (m_maxPitch - m_minPitch) + m_minPitch;
qreal gain = qreal(qrand() % 1001) * 0.001f * (m_maxGain - m_minGain) + m_minGain;
soundInstance->updateVariationParameters(pitch, gain, m_looping);
}

View File

@@ -0,0 +1,111 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QDECLARATIVEPLAYVARIATION_P_H
#define QDECLARATIVEPLAYVARIATION_P_H
#include <QtDeclarative/qdeclarative.h>
#include <QtDeclarative/qdeclarativecomponent.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QDeclarativeAudioSample;
class QSoundInstance;
class QDeclarativePlayVariation : public QObject, public QDeclarativeParserStatus
{
Q_OBJECT
Q_INTERFACES(QDeclarativeParserStatus)
Q_PROPERTY(QString sample READ sample WRITE setSample)
Q_PROPERTY(bool looping READ isLooping WRITE setLooping)
Q_PROPERTY(qreal maxGain READ maxGain WRITE setMaxGain)
Q_PROPERTY(qreal minGain READ minGain WRITE setMinGain)
Q_PROPERTY(qreal maxPitch READ maxPitch WRITE setMaxPitch)
Q_PROPERTY(qreal minPitch READ minPitch WRITE setMinPitch)
public:
QDeclarativePlayVariation(QObject *parent = 0);
~QDeclarativePlayVariation();
void classBegin();
void componentComplete();
QString sample() const;
void setSample(const QString& sample);
bool isLooping() const;
void setLooping(bool looping);
qreal maxGain() const;
void setMaxGain(qreal maxGain);
qreal minGain() const;
void setMinGain(qreal minGain);
qreal maxPitch() const;
void setMaxPitch(qreal maxPitch);
qreal minPitch() const;
void setMinPitch(qreal minPitch);
//called by QDeclarativeAudioEngine
void setSampleObject(QDeclarativeAudioSample *sampleObject);
QDeclarativeAudioSample* sampleObject() const;
void applyParameters(QSoundInstance *soundInstance);
private:
Q_DISABLE_COPY(QDeclarativePlayVariation);
bool m_complete;
QString m_sample;
bool m_looping;
qreal m_maxGain;
qreal m_minGain;
qreal m_maxPitch;
qreal m_minPitch;
QDeclarativeAudioSample *m_sampleObject;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1,558 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qdeclarative_sound_p.h"
#include "qdeclarative_audiocategory_p.h"
#include "qdeclarative_attenuationmodel_p.h"
#include "qdeclarative_soundinstance_p.h"
#include "qdeclarative_audioengine_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
QDeclarativeSoundCone::QDeclarativeSoundCone(QObject *parent)
: QObject(parent)
, m_innerAngle(360)
, m_outerAngle(360)
, m_outerGain(0)
{
}
/*!
\qmlproperty real Sound::cone.innerAngle
This property holds the innerAngle for Sound definition.
The range is [0, 360] degree. There is no directional attenuation within innerAngle.
*/
qreal QDeclarativeSoundCone::innerAngle() const
{
return m_innerAngle;
}
void QDeclarativeSoundCone::setInnerAngle(qreal innerAngle)
{
QDeclarativeSound *s = qobject_cast<QDeclarativeSound*>(parent());
if (s && s->m_complete)
return;
if (innerAngle < 0 || innerAngle > 360) {
qWarning() << "innerAngle should be within[0, 360] degrees";
return;
}
m_innerAngle = innerAngle;
}
/*!
\qmlproperty real Sound::cone.outerAngle
This property holds the outerAngle for Sound definition.
The range is [0, 360] degree. All audio output from this sound will be attenuated by \l outerGain
outside outerAngle.
*/
qreal QDeclarativeSoundCone::outerAngle() const
{
return m_outerAngle;
}
void QDeclarativeSoundCone::setOuterAngle(qreal outerAngle)
{
QDeclarativeSound *s = qobject_cast<QDeclarativeSound*>(parent());
if (s && s->m_complete)
return;
if (outerAngle < 0 || outerAngle > 360) {
qWarning() << "outerAngle should be within[0, 360] degrees";
return;
}
m_outerAngle = outerAngle;
}
/*!
\qmlproperty real Sound::cone.outerGain
This property holds attenuation value for directional attenuation of this sound.
The range is [0, 1]. All audio output from this sound will be attenuated by outerGain
outside \l outerAngle.
*/
qreal QDeclarativeSoundCone::outerGain() const
{
return m_outerGain;
}
void QDeclarativeSoundCone::setOuterGain(qreal outerGain)
{
QDeclarativeSound *s = qobject_cast<QDeclarativeSound*>(parent());
if (s && s->m_complete)
return;
if (outerGain < 0 || outerGain > 1) {
qWarning() << "outerGain should no less than 0 and no more than 1";
return;
}
m_outerGain = outerGain;
}
void QDeclarativeSoundCone::componentComplete()
{
if (m_outerAngle < m_innerAngle) {
m_outerAngle = m_innerAngle;
}
}
////////////////////////////////////////////////////////////
/*!
\qmlclass Sound QDeclarativeSound
\since 5.0
\brief The Sound element allows you to define a variety of samples and parameters to be used for
SoundInstance.
\ingroup qml-multimedia
\inherits Item
This element is part of the \bold{QtAudioEngine 1.0} module.
Sound element can be accessed through AudioEngine::sounds with its unique name and must be
defined inside AudioEngine.
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
AudioSample {
name:"explosion01"
source: "explosion-01.wav"
}
AudioSample {
name:"explosion02"
source: "explosion-02.wav"
}
Sound {
name:"explosion"
PlayVariation {
sample:"explosion01"
minPitch: 0.8
maxPitch: 1.1
}
PlayVariation {
sample:"explosion01"
minGain: 1.1
maxGain: 1.5
}
}
}
MouseArea {
anchors.fill: parent
onPressed: {
audioengine.sounds["explosion"].play();
}
}
}
\endqml
*/
QDeclarativeSound::QDeclarativeSound(QObject *parent)
: QObject(parent)
, m_complete(false)
, m_playType(Random)
, m_attenuationModelObject(0)
, m_categoryObject(0)
{
m_cone = new QDeclarativeSoundCone(this);
}
QDeclarativeSound::~QDeclarativeSound()
{
}
void QDeclarativeSound::classBegin()
{
if (!parent() || !parent()->inherits("QDeclarativeAudioEngine")) {
qWarning("Sound must be defined inside AudioEngine!");
return;
}
}
void QDeclarativeSound::componentComplete()
{
m_complete = true;
m_cone->componentComplete();
}
/*!
\qmlproperty enueration Sound::playType
This property holds the playType. It can be one of:
\list
\o Random - randomly picks up a play variation when playback is triggered
\o Sequential - plays each variation in sequence when playback is triggered
\endlist
The default value is Random.
*/
QDeclarativeSound::PlayType QDeclarativeSound::playType() const
{
return m_playType;
}
void QDeclarativeSound::setPlayType(PlayType playType)
{
if (m_complete) {
qWarning("Sound: playType not changable after initialization.");
return;
}
m_playType = playType;
}
/*!
\qmlproperty string Sound::category
This property specifies which AudioCategory this sound belongs to.
*/
QString QDeclarativeSound::category() const
{
return m_category;
}
void QDeclarativeSound::setCategory(const QString& category)
{
if (m_complete) {
qWarning("Sound: category not changable after initialization.");
return;
}
m_category = category;
}
/*!
\qmlproperty string Sound::name
This property holds the name of Sound, must be unique among all sounds and only
defined once.
*/
QString QDeclarativeSound::name() const
{
return m_name;
}
void QDeclarativeSound::setName(const QString& name)
{
if (m_complete) {
qWarning("Sound: category not changable after initialization.");
return;
}
m_name = name;
}
/*!
\qmlproperty string Sound::attenuationModel
This property specifies which attenuation model this sound will apply.
*/
QString QDeclarativeSound::attenuationModel() const
{
return m_attenuationModel;
}
int QDeclarativeSound::genVariationIndex(int oldVariationIndex)
{
if (m_playlist.count() == 0)
return -1;
if (m_playlist.count() == 1)
return 0;
switch (m_playType) {
case QDeclarativeSound::Random: {
if (oldVariationIndex < 0)
oldVariationIndex = 0;
return (oldVariationIndex + (qrand() % (m_playlist.count() + 1))) % m_playlist.count();
}
default:
return (oldVariationIndex + 1) % m_playlist.count();
}
}
QDeclarativePlayVariation* QDeclarativeSound::getVariation(int index)
{
Q_ASSERT(index >= 0 && index < m_playlist.count());
return m_playlist[index];
}
void QDeclarativeSound::setAttenuationModel(QString attenuationModel)
{
if (m_complete) {
qWarning("Sound: attenuationModel not changable after initialization.");
return;
}
m_attenuationModel = attenuationModel;
}
QDeclarativeSoundCone* QDeclarativeSound::cone() const
{
return m_cone;
}
QDeclarativeAttenuationModel* QDeclarativeSound::attenuationModelObject() const
{
return m_attenuationModelObject;
}
void QDeclarativeSound::setAttenuationModelObject(QDeclarativeAttenuationModel *attenuationModelObject)
{
m_attenuationModelObject = attenuationModelObject;
}
QDeclarativeAudioCategory* QDeclarativeSound::categoryObject() const
{
return m_categoryObject;
}
void QDeclarativeSound::setCategoryObject(QDeclarativeAudioCategory *categoryObject)
{
m_categoryObject = categoryObject;
}
QDeclarativeListProperty<QDeclarativePlayVariation> QDeclarativeSound::playVariationlist()
{
return QDeclarativeListProperty<QDeclarativePlayVariation>(this, 0, appendFunction);
}
QList<QDeclarativePlayVariation*>& QDeclarativeSound::playlist()
{
return m_playlist;
}
void QDeclarativeSound::appendFunction(QDeclarativeListProperty<QDeclarativePlayVariation> *property, QDeclarativePlayVariation *value)
{
QDeclarativeSound *sound = static_cast<QDeclarativeSound*>(property->object);
if (sound->m_complete) {
qWarning("Sound: PlayVariation not addable after initialization.");
return;
}
sound->m_playlist.append(value);
}
/*!
\qmlmethod Sound::play()
Creates a new \l SoundInstance and starts playing.
Position, direction and velocity are all set to \c "0,0,0".
*/
void QDeclarativeSound::play()
{
play(QVector3D(), QVector3D(), QVector3D(), 1, 1);
}
/*!
\qmlmethod Sound::play(gain)
Creates a new SoundInstance and starts playing with the adjusted \a gain.
Position, direction and velocity are all set to \c "0,0,0".
*/
void QDeclarativeSound::play(qreal gain)
{
play(QVector3D(), QVector3D(), QVector3D(), gain, 1);
}
/*!
\qmlmethod Sound::play(gain, pitch)
Creates a new SoundInstance and starts playing with the adjusted \a gain and \a pitch.
Position, direction and velocity are all set to \c "0,0,0".
*/
void QDeclarativeSound::play(qreal gain, qreal pitch)
{
play(QVector3D(), QVector3D(), QVector3D(), gain, pitch);
}
/*!
\qmlmethod Sound::play(position)
Creates a new SoundInstance and starts playing with specified \a position.
Direction and velocity are all set to \c "0,0,0".
*/
void QDeclarativeSound::play(const QVector3D& position)
{
play(position, QVector3D(), QVector3D(), 1, 1);
}
/*!
\qmlmethod Sound::play(position, velocity)
Creates a new SoundInstance and starts playing with specified \a position and \a velocity.
Direction is set to \c "0,0,0".
*/
void QDeclarativeSound::play(const QVector3D& position, const QVector3D& velocity)
{
play(position, velocity, QVector3D(), 1, 1);
}
/*!
\qmlmethod Sound::play(position, velocity, direction)
Creates a new SoundInstance and starts playing with specified \a position, \a velocity and
\a direction.
*/
void QDeclarativeSound::play(const QVector3D& position, const QVector3D& velocity,
const QVector3D& direction)
{
play(position, velocity, direction, 1, 1);
}
/*!
\qmlmethod Sound::play(position, gain)
Creates a new SoundInstance and starts playing with specified \a position and adjusted \a gain.
Direction and velocity are all set to \c "0,0,0".
*/
void QDeclarativeSound::play(const QVector3D& position, qreal gain)
{
play(position, QVector3D(), QVector3D(), gain, 1);
}
/*!
\qmlmethod Sound::play(position, velocity, gain)
Creates a new SoundInstance and starts playing with specified \a position, \a velocity and
adjusted \a gain.
Direction is set to \c "0,0,0".
*/
void QDeclarativeSound::play(const QVector3D& position, const QVector3D& velocity, qreal gain)
{
play(position, velocity, QVector3D(), gain, 1);
}
/*!
\qmlmethod Sound::play(position, velocity, direction, gain)
Creates a new SoundInstance and starts playing with specified \a position, \a velocity,
\a direction and adjusted \a gain.
*/
void QDeclarativeSound::play(const QVector3D& position, const QVector3D& velocity, const QVector3D& direction, qreal gain)
{
play(position, velocity, direction, gain, 1);
}
/*!
\qmlmethod Sound::play(position, gain, pitch)
Creates a new SoundInstance and starts playing with specified \a position, adjusted \a gain and
\a pitch.
Direction and velocity are all set to \c "0,0,0".
*/
void QDeclarativeSound::play(const QVector3D& position, qreal gain, qreal pitch)
{
play(position, QVector3D(), QVector3D(), gain, pitch);
}
/*!
\qmlmethod Sound::play(position, velocity, gain, pitch)
Creates a new SoundInstance and starts playing with specified \a position, \a velocity,
adjusted \a gain and \a pitch.
Direction is set to \c "0,0,0".
*/
void QDeclarativeSound::play(const QVector3D& position, const QVector3D& velocity, qreal gain, qreal pitch)
{
play(position, velocity, QVector3D(), gain, pitch);
}
/*!
\qmlmethod Sound::play(position, velocity, direction, gain, pitch)
Creates a new SoundInstance and starts playing with specified \a position, \a velocity,
\a direction, adjusted \a gain and \a pitch.
*/
void QDeclarativeSound::play(const QVector3D& position, const QVector3D& velocity, const QVector3D& direction, qreal gain, qreal pitch)
{
if (!m_complete) {
qWarning() << "AudioEngine::play not ready!";
return;
}
QDeclarativeSoundInstance *instance = this->newInstance(true);
if (!instance)
return;
instance->setPosition(position);
instance->setVelocity(velocity);
instance->setDirection(direction);
instance->setGain(gain);
instance->setPitch(pitch);
instance->setConeInnerAngle(cone()->innerAngle());
instance->setConeOuterAngle(cone()->outerAngle());
instance->setConeOuterGain(cone()->outerGain());
instance->play();
#ifdef DEBUG_AUDIOENGINE
qDebug() << "Sound[" << m_name << "] play ("
<< position << ","
<< velocity <<","
<< direction << ","
<< gain << ","
<< pitch << ")triggered";
#endif
}
/*!
\qmlmethod SoundInstance Sound::newInstance()
Returns a new \l SoundInstance.
*/
QDeclarativeSoundInstance* QDeclarativeSound::newInstance()
{
return newInstance(false);
}
QDeclarativeSoundInstance* QDeclarativeSound::newInstance(bool managed)
{
QDeclarativeSoundInstance *instance =
qobject_cast<QDeclarativeAudioEngine*>(this->parent())->newDeclarativeSoundInstance(managed);
instance->setSound(m_name);
return instance;
}

View File

@@ -0,0 +1,176 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QDECLARATIVESOUND_P_H
#define QDECLARATIVESOUND_P_H
#include <QtDeclarative/qdeclarative.h>
#include <QtDeclarative/qdeclarativecomponent.h>
#include <QtCore/qlist.h>
#include "qdeclarative_playvariation_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QDeclarativeAudioCategory;
class QDeclarativeAttenuationModel;
class QDeclarativeSoundInstance;
class QDeclarativeSoundCone : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal innerAngle READ innerAngle WRITE setInnerAngle)
Q_PROPERTY(qreal outerAngle READ outerAngle WRITE setOuterAngle)
Q_PROPERTY(qreal outerGain READ outerGain WRITE setOuterGain)
public:
QDeclarativeSoundCone(QObject *parent = 0);
//by degree
qreal innerAngle() const;
void setInnerAngle(qreal innerAngle);
//by degree
qreal outerAngle() const;
void setOuterAngle(qreal outerAngle);
qreal outerGain() const;
void setOuterGain(qreal outerGain);
void componentComplete();
private:
Q_DISABLE_COPY(QDeclarativeSoundCone)
qreal m_innerAngle;
qreal m_outerAngle;
qreal m_outerGain;
};
class QDeclarativeSound : public QObject, public QDeclarativeParserStatus
{
friend class QDeclarativeSoundCone;
Q_OBJECT
Q_INTERFACES(QDeclarativeParserStatus)
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(PlayType playType READ playType WRITE setPlayType)
Q_PROPERTY(QString category READ category WRITE setCategory)
Q_PROPERTY(QDeclarativeSoundCone* cone READ cone CONSTANT)
Q_PROPERTY(QString attenuationModel READ attenuationModel WRITE setAttenuationModel)
Q_PROPERTY(QDeclarativeListProperty<QDeclarativePlayVariation> playVariationlist READ playVariationlist CONSTANT)
Q_CLASSINFO("DefaultProperty", "playVariationlist")
Q_ENUMS(PlayType)
public:
enum PlayType
{
Random,
Sequential
};
QDeclarativeSound(QObject *parent = 0);
~QDeclarativeSound();
void classBegin();
void componentComplete();
PlayType playType() const;
void setPlayType(PlayType playType);
QString category() const;
void setCategory(const QString& category);
QString name() const;
void setName(const QString& name);
QString attenuationModel() const;
void setAttenuationModel(QString attenuationModel);
QDeclarativeSoundCone* cone() const;
QDeclarativeAttenuationModel* attenuationModelObject() const;
void setAttenuationModelObject(QDeclarativeAttenuationModel *attenuationModelObject);
QDeclarativeAudioCategory* categoryObject() const;
void setCategoryObject(QDeclarativeAudioCategory *categoryObject);
int genVariationIndex(int oldVariationIndex);
QDeclarativePlayVariation* getVariation(int index);
//This is used for tracking new PlayVariation declared inside Sound
QDeclarativeListProperty<QDeclarativePlayVariation> playVariationlist();
QList<QDeclarativePlayVariation*>& playlist();
public Q_SLOTS:
void play();
void play(qreal gain);
void play(qreal gain, qreal pitch);
void play(const QVector3D& position);
void play(const QVector3D& position, const QVector3D& velocity);
void play(const QVector3D& position, const QVector3D& velocity, const QVector3D& direction);
void play(const QVector3D& position, qreal gain);
void play(const QVector3D& position, const QVector3D& velocity, qreal gain);
void play(const QVector3D& position, const QVector3D& velocity, const QVector3D& direction, qreal gain);
void play(const QVector3D& position, qreal gain, qreal pitch);
void play(const QVector3D& position, const QVector3D& velocity, qreal gain, qreal pitch);
void play(const QVector3D& position, const QVector3D& velocity, const QVector3D& direction, qreal gain, qreal pitch);
QDeclarativeSoundInstance* newInstance();
private:
Q_DISABLE_COPY(QDeclarativeSound)
QDeclarativeSoundInstance* newInstance(bool managed);
static void appendFunction(QDeclarativeListProperty<QDeclarativePlayVariation> *property, QDeclarativePlayVariation *value);
bool m_complete;
PlayType m_playType;
QString m_name;
QString m_category;
QString m_attenuationModel;
QList<QDeclarativePlayVariation*> m_playlist;
QDeclarativeSoundCone *m_cone;
QDeclarativeAttenuationModel *m_attenuationModelObject;
QDeclarativeAudioCategory *m_categoryObject;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1,560 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qdeclarative_soundinstance_p.h"
#include "qdeclarative_sound_p.h"
#include "qdeclarative_audioengine_p.h"
#include "qaudioengine_p.h"
#include "qsoundinstance_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
/*!
\qmlclass SoundInstance QDeclarativeSoundInstance
\since 5.0
\brief The SoundInstance element allows you to play 3d audio content.
\ingroup qml-multimedia
\inherits Item
This element is part of the \bold{QtAudioEngine 1.0} module.
There are two ways to create SoundInstance objects. You can obtain it by calling newInstance
method of Sound element:
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
id:root
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
AudioSample {
name:"explosion01"
source: "explosion-01.wav"
}
Sound {
name:"explosion"
PlayVariation {
sample:"explosion01"
}
}
}
property variant soundEffect: audioengine.sounds["explosion"].newInstance();
MouseArea {
anchors.fill: parent
onPressed: {
root.soundEffect.play();
}
}
}
\endqml
Or alternatively, you can explicitly define SoundInstance element outside of AudioEngine for
easier qml bindings:
\qml
import QtQuick 2.0
import QtAudioEngine 1.0
Rectangle {
id:root
color:"white"
width: 300
height: 500
AudioEngine {
id:audioengine
AudioSample {
name:"explosion01"
source: "explosion-01.wav"
}
Sound {
name:"explosion"
PlayVariation {
sample:"explosion01"
}
}
}
Item {
id: animator
x: 10 + observer.percent * 100
y: 20 + observer.percent * 80
property real percent: 0
SequentialAnimation on percent {
loops: Animation.Infinite
running: true
NumberAnimation {
duration: 8000
from: 0
to: 1
}
}
}
SoundInstance {
id:soundEffect
engine:audioengine
sound:"explosion"
position:Qt.vector3d(animator.x, animator.y, 0);
}
MouseArea {
anchors.fill: parent
onPressed: {
soundEffect.play();
}
}
}
\endqml
*/
QDeclarativeSoundInstance::QDeclarativeSoundInstance(QObject *parent)
: QObject(parent)
, m_position(0, 0, 0)
, m_direction(0, 1, 0)
, m_velocity(0, 0, 0)
, m_gain(1)
, m_pitch(1)
, m_requestState(QDeclarativeSoundInstance::StopppedState)
, m_coneInnerAngle(360)
, m_coneOuterAngle(360)
, m_coneOuterGain(0)
, m_instance(0)
, m_engine(0)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeSoundInstance::ctor()";
#endif
}
/*!
\qmlproperty AudioEngine SoundInstance::engine
This property holds the reference to AudioEngine, must be set only once.
*/
QDeclarativeAudioEngine* QDeclarativeSoundInstance::engine() const
{
return m_engine;
}
void QDeclarativeSoundInstance::setEngine(QDeclarativeAudioEngine *engine)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeSoundInstance::setEngine(" << engine << ")";
#endif
if (!engine)
return;
if (m_engine) {
qWarning("SoundInstance: you can not set different value for engine property");
return;
}
m_engine = engine;
if (!m_engine->isReady()) {
connect(m_engine, SIGNAL(ready()), this, SLOT(engineComplete()));
} else {
engineComplete();
}
}
void QDeclarativeSoundInstance::engineComplete()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeSoundInstance::engineComplete()";
#endif
disconnect(m_engine, SIGNAL(ready()), this, SLOT(engineComplete()));
if (m_sound.isEmpty())
return;
//rebind to actual engine resource
QString sound = m_sound;
m_sound.clear();
setSound(sound);
}
QDeclarativeSoundInstance::~QDeclarativeSoundInstance()
{
}
/*!
\qmlproperty string SoundInstance::sound
This property specifies which Sound this SoundInstance will use. Unlike some properties in
other elements, this property can be changed dynamically.
*/
QString QDeclarativeSoundInstance::sound() const
{
return m_sound;
}
void QDeclarativeSoundInstance::setSound(const QString& sound)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeSoundInstance::setSound(" << sound << ")";
#endif
if (m_sound == sound)
return;
if (!m_engine || !m_engine->isReady()) {
m_sound = sound;
emit soundChanged();
return;
}
#ifdef DEBUG_AUDIOENGINE
qDebug() << "SoundInstance Element switch sound from [" << m_sound << "] to [" << sound << "]";
#endif
stop();
dropInstance();
m_sound = sound;
if (!m_sound.isEmpty()) {
m_instance = m_engine->newSoundInstance(m_sound);
connect(m_instance, SIGNAL(stateChanged(QSoundInstance::State)), this, SLOT(handleStateChanged()));
m_instance->setPosition(m_position);
m_instance->setDirection(m_direction);
m_instance->setVelocity(m_velocity);
m_instance->setGain(m_gain);
m_instance->setPitch(m_pitch);
m_instance->setCone(m_coneInnerAngle, m_coneOuterAngle, m_coneOuterGain);
if (m_requestState == QDeclarativeSoundInstance::PlayingState) {
m_instance->play();
} else if (m_requestState == QDeclarativeSoundInstance::PausedState) {
m_instance->pause();
}
}
emit soundChanged();
}
void QDeclarativeSoundInstance::dropInstance()
{
if (m_instance) {
disconnect(m_instance, SIGNAL(stateChanged(QSoundInstance::State)), this, SLOT(handleStateChanged()));
m_engine->releaseSoundInstance(m_instance);
m_instance = 0;
}
}
/*!
\qmlproperty enumeration SoundInstance::state
This property holds the current playback state. It can be one of:
\list
\o StopppedState
\o PlayingState
\o PausedState
\endlist
*/
QDeclarativeSoundInstance::State QDeclarativeSoundInstance::state() const
{
if (m_instance)
return State(m_instance->state());
return m_requestState;
}
/*!
\qmlmethod SoundInstance::play()
Starts playback.
*/
void QDeclarativeSoundInstance::play()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeSoundInstance::play()";
#endif
if (!m_instance) {
m_requestState = QDeclarativeSoundInstance::PlayingState;
return;
}
m_instance->play();
}
/*!
\qmlmethod SoundInstance::play()
Stops current playback.
*/
void QDeclarativeSoundInstance::stop()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeSoundInstance::stop()";
#endif
m_requestState = QDeclarativeSoundInstance::StopppedState;
if (!m_instance)
return;
m_instance->stop();
}
/*!
\qmlmethod SoundInstance::play()
Pauses current playback.
*/
void QDeclarativeSoundInstance::pause()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QDeclarativeSoundInstance::pause()";
#endif
if (!m_instance) {
m_requestState = QDeclarativeSoundInstance::PausedState;
return;
}
m_instance->pause();
}
void QDeclarativeSoundInstance::updatePosition(qreal deltaTime)
{
if (!m_instance || deltaTime == 0 || m_velocity.lengthSquared() == 0)
return;
setPosition(m_position + m_velocity * deltaTime);
}
/*!
\qmlproperty vector3d SoundInstance::position
This property holds the current 3d position.
*/
QVector3D QDeclarativeSoundInstance::position() const
{
return m_position;
}
void QDeclarativeSoundInstance::setPosition(const QVector3D& position)
{
if (m_position == position)
return;
m_position = position;
emit positionChanged();
if (!m_instance) {
return;
}
m_instance->setPosition(m_position);
}
/*!
\qmlproperty vector3d SoundInstance::direction
This property holds the current 3d direction.
*/
QVector3D QDeclarativeSoundInstance::direction() const
{
return m_direction;
}
void QDeclarativeSoundInstance::setDirection(const QVector3D& direction)
{
if (m_direction == direction)
return;
m_direction = direction;
emit directionChanged();
if (!m_instance) {
return;
}
m_instance->setDirection(m_direction);
}
/*!
\qmlproperty vector3d SoundInstance::velocity
This property holds the current 3d velocity.
*/
QVector3D QDeclarativeSoundInstance::velocity() const
{
return m_velocity;
}
void QDeclarativeSoundInstance::setVelocity(const QVector3D& velocity)
{
if (m_velocity == velocity)
return;
m_velocity = velocity;
emit velocityChanged();
if (!m_instance)
return;
m_instance->setVelocity(m_velocity);
}
/*!
\qmlproperty vector3d SoundInstance::gain
This property holds the gain adjustment which will be used to modulate the audio ouput level
from this SoundInstance.
*/
qreal QDeclarativeSoundInstance::gain() const
{
return m_gain;
}
void QDeclarativeSoundInstance::setGain(qreal gain)
{
if (gain == m_gain)
return;
if (gain < 0) {
qWarning("gain must be a positive value!");
return;
}
m_gain = gain;
emit gainChanged();
if (!m_instance)
return;
m_instance->setGain(m_gain);
}
/*!
\qmlproperty vector3d SoundInstance::gain
This property holds the pitch adjustment which will be used to modulate the audio pitch
from this SoundInstance.
*/
qreal QDeclarativeSoundInstance::pitch() const
{
return m_pitch;
}
void QDeclarativeSoundInstance::setPitch(qreal pitch)
{
if (pitch == m_pitch)
return;
if (pitch < 0) {
qWarning("pitch must be a positive value!");
return;
}
m_pitch = pitch;
emit pitchChanged();
if (!m_instance)
return;
m_instance->setPitch(m_pitch);
}
void QDeclarativeSoundInstance::setConeInnerAngle(qreal innerAngle)
{
if (m_coneInnerAngle == innerAngle)
return;
m_coneInnerAngle = innerAngle;
if (!m_instance)
return;
m_instance->setCone(m_coneInnerAngle, m_coneOuterAngle, m_coneOuterGain);
}
void QDeclarativeSoundInstance::setConeOuterAngle(qreal outerAngle)
{
if (m_coneOuterAngle == outerAngle)
return;
m_coneOuterAngle = outerAngle;
if (!m_instance)
return;
m_instance->setCone(m_coneInnerAngle, m_coneOuterAngle, m_coneOuterGain);
}
void QDeclarativeSoundInstance::setConeOuterGain(qreal outerGain)
{
if (m_coneOuterGain == outerGain)
return;
m_coneOuterGain = outerGain;
if (!m_instance)
return;
m_instance->setCone(m_coneInnerAngle, m_coneOuterAngle, m_coneOuterGain);
}
void QDeclarativeSoundInstance::handleStateChanged()
{
emit stateChanged();
}
/*!
\qmlsignal SoundInstance::onStateChanged(state)
This handler is called when \l state is changed
*/
/*!
\qmlsignal SoundInstance::onPositionChanged()
This handler is called when \l position is changed
*/
/*!
\qmlsignal SoundInstance::onDirectionChanged()
This handler is called when \l direction is changed
*/
/*!
\qmlsignal SoundInstance::onVelocityChanged()
This handler is called when \l velocity is changed
*/
/*!
\qmlsignal SoundInstance::onGainChanged()
This handler is called when \l gain is changed
*/
/*!
\qmlsignal SoundInstance::onPitchChanged()
This handler is called when \l pitch is changed
*/
/*!
\qmlsignal SoundInstance::onSoundChanged()
This handler is called when \l sound is changed
*/

View File

@@ -0,0 +1,155 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QDECLARATIVE_SOUNDINSTANCE_P_H
#define QDECLARATIVE_SOUNDINSTANCE_P_H
#include <QtCore/QObject>
#include <QtGui/qvector3d.h>
#include "qsoundinstance_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QDeclarativeSound;
class QAudioEngine;
class QDeclarativeAudioEngine;
class QDeclarativeSoundInstance : public QObject
{
Q_OBJECT
Q_PROPERTY(QDeclarativeAudioEngine* engine READ engine WRITE setEngine)
Q_PROPERTY(QString sound READ sound WRITE setSound NOTIFY soundChanged)
Q_PROPERTY(State state READ state NOTIFY stateChanged)
Q_PROPERTY(QVector3D position READ position WRITE setPosition NOTIFY positionChanged)
Q_PROPERTY(QVector3D direction READ direction WRITE setDirection NOTIFY directionChanged)
Q_PROPERTY(QVector3D velocity READ velocity WRITE setVelocity NOTIFY velocityChanged)
Q_PROPERTY(qreal gain READ gain WRITE setGain NOTIFY gainChanged)
Q_PROPERTY(qreal pitch READ pitch WRITE setPitch NOTIFY pitchChanged)
Q_ENUMS(State)
public:
enum State
{
StopppedState = QSoundInstance::StopppedState,
PlayingState = QSoundInstance::PlayingState,
PausedState = QSoundInstance::PausedState
};
QDeclarativeSoundInstance(QObject *parent = 0);
~QDeclarativeSoundInstance();
QDeclarativeAudioEngine* engine() const;
void setEngine(QDeclarativeAudioEngine *engine);
QString sound() const;
void setSound(const QString& sound);
State state() const;
QVector3D position() const;
void setPosition(const QVector3D& position);
QVector3D direction() const;
void setDirection(const QVector3D& direction);
QVector3D velocity() const;
void setVelocity(const QVector3D& velocity);
qreal gain() const;
void setGain(qreal gain);
qreal pitch() const;
void setPitch(qreal pitch);
void setConeInnerAngle(qreal innerAngle);
void setConeOuterAngle(qreal outerAngle);
void setConeOuterGain(qreal outerGain);
Q_SIGNALS:
void stateChanged();
void positionChanged();
void directionChanged();
void velocityChanged();
void gainChanged();
void pitchChanged();
void soundChanged();
public Q_SLOTS:
void play();
void stop();
void pause();
void updatePosition(qreal deltaTime);
private Q_SLOTS:
void handleStateChanged();
private:
Q_DISABLE_COPY(QDeclarativeSoundInstance);
QString m_sound;
QVector3D m_position;
QVector3D m_direction;
QVector3D m_velocity;
qreal m_gain;
qreal m_pitch;
State m_requestState;
qreal m_coneInnerAngle;
qreal m_coneOuterAngle;
qreal m_coneOuterGain;
void dropInstance();
QSoundInstance *m_instance;
QDeclarativeAudioEngine *m_engine;
private Q_SLOTS:
void engineComplete();
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -0,0 +1 @@
plugin declarative_audioengine

View File

@@ -0,0 +1,70 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QSOUNDBUFFER_P_H
#define QSOUNDBUFFER_P_H
#include <QObject>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QSoundBuffer : public QObject
{
Q_OBJECT
public:
virtual bool isReady() const = 0;
virtual void load() = 0;
Q_SIGNALS:
void ready();
void error();
protected:
QSoundBuffer(QObject *parent);
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QSOUNDBUFFER_P_H

View File

@@ -0,0 +1,387 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qsoundinstance_p.h"
#include "qsoundsource_p.h"
#include "qsoundbuffer_p.h"
#include "qdeclarative_sound_p.h"
#include "qdeclarative_audiocategory_p.h"
#include "qdeclarative_audiosample_p.h"
#include "qdeclarative_attenuationmodel_p.h"
#include "qdeclarative_playvariation_p.h"
#include "qdeclarative_audioengine_p.h"
#include "qdeclarative_audiolistener_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
QSoundInstance::QSoundInstance(QObject *parent)
: QObject(parent)
, m_soundSource(0)
, m_bindBuffer(0)
, m_sound(0)
, m_variationIndex(-1)
, m_isReady(false)
, m_gain(1)
, m_attenuationGain(1)
, m_varGain(1)
, m_pitch(1)
, m_varPitch(1)
, m_state(QSoundInstance::StopppedState)
, m_coneOuterGain(0)
, m_engine(0)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "creating new QSoundInstance";
#endif
m_engine = qobject_cast<QDeclarativeAudioEngine*>(parent);
}
void QSoundInstance::bindSoundDescription(QDeclarativeSound *sound)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundInstance::bindSoundDescription" << sound;
#endif
if (m_sound == sound)
return;
if (m_sound && m_sound->categoryObject()) {
disconnect(m_sound->categoryObject(), SIGNAL(volumeChanged(qreal)), this, SLOT(categoryVolumeChanged()));
disconnect(m_sound->categoryObject(), SIGNAL(paused()), this, SLOT(pause()));
disconnect(m_sound->categoryObject(), SIGNAL(stopped()), this, SLOT(stop()));
disconnect(m_sound->categoryObject(), SIGNAL(resumed()), this, SLOT(resume()));
}
m_attenuationGain = 1;
m_gain = 1;
m_sound = sound;
if (sound) {
if (!m_soundSource) {
m_soundSource = m_engine->engine()->createSoundSource();
connect(m_soundSource, SIGNAL(stateChanged(QSoundSource::State)),
this, SLOT(handleSourceStateChanged(QSoundSource::State)));
}
} else {
if (m_soundSource) {
detach();
m_engine->engine()->releaseSoundSource(m_soundSource);
m_soundSource = 0;
}
}
if (m_sound) {
if (m_sound->categoryObject()) {
connect(m_sound->categoryObject(), SIGNAL(volumeChanged(qreal)), this, SLOT(categoryVolumeChanged()));
connect(m_sound->categoryObject(), SIGNAL(paused()), this, SLOT(pause()));
connect(m_sound->categoryObject(), SIGNAL(stopped()), this, SLOT(stop()));
connect(m_sound->categoryObject(), SIGNAL(resumed()), this, SLOT(resume()));
}
prepareNewVariation();
} else {
m_variationIndex = -1;
}
}
QSoundInstance::~QSoundInstance()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundInstance::dtor()";
#endif
if (m_soundSource) {
detach();
m_engine->engine()->releaseSoundSource(m_soundSource);
}
}
void QSoundInstance::prepareNewVariation()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundInstance::prepareNewVariation()";
#endif
int newVariationIndex = m_sound->genVariationIndex(m_variationIndex);
if (newVariationIndex == m_variationIndex)
return;
QDeclarativePlayVariation *playVar = m_sound->getVariation(newVariationIndex);
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundInstance: generate new play variation [old:" << m_variationIndex << ", new:" << newVariationIndex << "-" << playVar->sample() << "]";
#endif
m_variationIndex = newVariationIndex;
playVar->applyParameters(this);
detach();
m_bindBuffer = playVar->sampleObject()->soundBuffer();
if (m_bindBuffer->isReady()) {
Q_ASSERT(m_soundSource);
m_soundSource->bindBuffer(m_bindBuffer);
m_isReady = true;
} else {
m_bindBuffer->load();
connect(m_bindBuffer, SIGNAL(ready()), this, SLOT(bufferReady()));
}
}
void QSoundInstance::bufferReady()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundInstance::bufferReady()";
#endif
if (!m_soundSource)
return;
m_soundSource->bindBuffer(m_bindBuffer);
disconnect(m_bindBuffer, SIGNAL(ready()), this, SLOT(bufferReady()));
m_isReady = true;
if (m_state == QSoundInstance::PlayingState) {
sourcePlay();
} else if (m_state == QSoundInstance::PausedState) {
sourcePause();
}
}
void QSoundInstance::categoryVolumeChanged()
{
updateGain();
}
void QSoundInstance::handleSourceStateChanged(QSoundSource::State newState)
{
State ns = State(newState);
if (ns == m_state)
return;
if (ns == QSoundInstance::StopppedState) {
prepareNewVariation();
}
setState(ns);
}
void QSoundInstance::setState(State state)
{
if (state == m_state)
return;
m_state = state;
emit stateChanged(m_state);
}
qreal QSoundInstance::categoryVolume() const
{
if (!m_sound)
return 1;
if (!m_sound->categoryObject())
return 1;
return m_sound->categoryObject()->volume();
}
void QSoundInstance::sourceStop()
{
Q_ASSERT(m_soundSource);
m_soundSource->stop();
setState(QSoundInstance::StopppedState);
}
void QSoundInstance::detach()
{
sourceStop();
m_isReady = false;
if (m_soundSource)
m_soundSource->unbindBuffer();
if (m_bindBuffer) {
disconnect(m_bindBuffer, SIGNAL(ready()), this, SLOT(bufferReady()));
m_engine->engine()->releaseSoundBuffer(m_bindBuffer);
m_bindBuffer = 0;
}
}
void QSoundInstance::play()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundInstancePrivate::play()";
#endif
if (!m_soundSource || m_state == QSoundInstance::PlayingState)
return;
if (!m_isReady) {
setState(QSoundInstance::PlayingState);
return;
}
sourcePlay();
setState(QSoundInstance::PlayingState);
}
void QSoundInstance::sourcePlay()
{
update3DVolume(m_engine->listener()->position());
Q_ASSERT(m_soundSource);
m_soundSource->play();
}
void QSoundInstance::resume()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundInstancePrivate::resume()";
#endif
if (m_state != QSoundInstance::PausedState)
return;
play();
}
void QSoundInstance::pause()
{
if (!m_soundSource || m_state == QSoundInstance::PausedState)
return;
if (!m_isReady) {
setState(QSoundInstance::PausedState);
return;
}
sourcePause();
setState(QSoundInstance::PausedState);
}
void QSoundInstance::sourcePause()
{
Q_ASSERT(m_soundSource);
m_soundSource->pause();
}
void QSoundInstance::stop()
{
if (!m_isReady || !m_soundSource || m_state == QSoundInstance::StopppedState) {
setState(QSoundInstance::StopppedState);
return;
}
sourceStop();
prepareNewVariation();
}
QSoundInstance::State QSoundInstance::state() const
{
return m_state;
}
void QSoundInstance::setPosition(const QVector3D& position)
{
if (!m_soundSource)
return;
m_soundSource->setPosition(position);
}
void QSoundInstance::setDirection(const QVector3D& direction)
{
if (!m_soundSource)
return;
m_soundSource->setDirection(direction);
}
void QSoundInstance::setVelocity(const QVector3D& velocity)
{
if (!m_soundSource)
return;
m_soundSource->setVelocity(velocity);
}
void QSoundInstance::setGain(qreal gain)
{
if (!m_soundSource)
return;
m_gain = gain;
updateGain();
}
void QSoundInstance::setPitch(qreal pitch)
{
if (!m_soundSource)
return;
m_pitch = pitch;
updatePitch();
}
void QSoundInstance::setCone(qreal innerAngle, qreal outerAngle, qreal outerGain)
{
if (!m_soundSource)
return;
m_soundSource->setCone(innerAngle, outerAngle, outerGain);
}
bool QSoundInstance::attenuationEnabled() const
{
if (!m_sound || !m_sound->attenuationModelObject())
return false;
return true;
}
void QSoundInstance::update3DVolume(const QVector3D& listenerPosition)
{
if (!m_sound || !m_soundSource)
return;
QDeclarativeAttenuationModel *attenModel = m_sound->attenuationModelObject();
if (!attenModel)
return;
m_attenuationGain = attenModel->calculateGain(listenerPosition, m_soundSource->position());
updateGain();
}
void QSoundInstance::updateVariationParameters(qreal varPitch, qreal varGain, bool looping)
{
if (!m_soundSource)
return;
m_soundSource->setLooping(looping);
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundInstance::updateVariationParameters" << varPitch << varGain << looping;
#endif
m_varPitch = varPitch;
m_varGain = varGain;
updatePitch();
updateGain();
}
void QSoundInstance::updatePitch()
{
m_soundSource->setPitch(m_pitch * m_varPitch);
}
void QSoundInstance::updateGain()
{
m_soundSource->setGain(m_gain * m_varGain * m_attenuationGain * categoryVolume());
}
QT_END_NAMESPACE

View File

@@ -0,0 +1,139 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QSOUNDINSTANCE_P_H
#define QSOUNDINSTANCE_P_H
#include <QVector3D>
#include <QObject>
#include "qsoundsource_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QDeclarativeSound;
class QDeclarativeAudioEngine;
class QSoundInstance : public QObject
{
Q_OBJECT
public:
explicit QSoundInstance(QObject *parent);
~QSoundInstance();
void play();
enum State
{
StopppedState = QSoundSource::StoppedState,
PlayingState = QSoundSource::PlayingState,
PausedState = QSoundSource::PausedState
};
State state() const;
void setPosition(const QVector3D& position);
void setDirection(const QVector3D& direction);
void setVelocity(const QVector3D& velocity);
//this gain and pitch is used for dynamic user control during execution
void setGain(qreal gain);
void setPitch(qreal pitch);
void setCone(qreal innerAngle, qreal outerAngle, qreal outerGain);
//this varPitch and varGain is calculated from config in PlayVariation
void updateVariationParameters(qreal varPitch, qreal varGain, bool looping);
void bindSoundDescription(QDeclarativeSound *sound);
void update3DVolume(const QVector3D& listenerPosition);
bool attenuationEnabled() const;
Q_SIGNALS:
void stateChanged(QSoundInstance::State state);
public Q_SLOTS:
void pause();
void stop();
private Q_SLOTS:
void resume();
void bufferReady();
void categoryVolumeChanged();
void handleSourceStateChanged(QSoundSource::State);
private:
void setState(State state);
void prepareNewVariation();
void detach();
qreal categoryVolume() const;
void updatePitch();
void updateGain();
void updateConeOuterGain();
void sourcePlay();
void sourcePause();
void sourceStop();
QSoundSource *m_soundSource;
QSoundBuffer *m_bindBuffer;
QDeclarativeSound *m_sound;
int m_variationIndex;
bool m_isReady; //true if the sound source is already bound to some sound buffer
qreal m_gain;
qreal m_attenuationGain;
qreal m_varGain;
qreal m_pitch;
qreal m_varPitch;
State m_state;
qreal m_coneOuterGain;
QDeclarativeAudioEngine *m_engine;
};
QT_END_NAMESPACE
QT_END_HEADER
#endif // QSOUNDINSTANCE_P_H

View File

@@ -0,0 +1,314 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 "qaudioengine_openal_p.h"
#include "qdebug.h"
#define DEBUG_AUDIOENGINE
QT_USE_NAMESPACE
QSoundSourcePrivate::QSoundSourcePrivate(QObject *parent)
: QSoundSource(parent)
, m_alSource(0)
, m_bindBuffer(0)
, m_isReady(false)
, m_state(QSoundSource::StoppedState)
, m_gain(0)
, m_pitch(0)
, m_coneInnerAngle(0)
, m_coneOuterAngle(0)
, m_coneOuterGain(1)
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "creating new QSoundSourcePrivate";
#endif
alGenSources(1, &m_alSource);
QAudioEnginePrivate::checkNoError("create source");
setGain(1);
setPitch(1);
setCone(360, 360, 0);
}
QSoundSourcePrivate::~QSoundSourcePrivate()
{
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundSourcePrivate::dtor";
#endif
release();
}
void QSoundSourcePrivate::release()
{
if (m_alSource) {
#ifdef DEBUG_AUDIOENGINE
qDebug() << "QSoundSourcePrivate::release";
#endif
stop();
unbindBuffer();
alDeleteSources(1, &m_alSource);
QAudioEnginePrivate::checkNoError("delete source");
m_alSource = 0;
}
}
void QSoundSourcePrivate::bindBuffer(QSoundBuffer* soundBuffer)
{
unbindBuffer();
Q_ASSERT(soundBuffer->isReady());
m_bindBuffer = qobject_cast<QSoundBufferPrivateAL*>(soundBuffer);
m_bindBuffer->bindToSource(m_alSource);
m_isReady = true;
}
void QSoundSourcePrivate::unbindBuffer()
{
if (m_bindBuffer) {
m_bindBuffer->unbindFromSource(m_alSource);
m_bindBuffer = 0;
}
m_isReady = false;
if (m_state != QSoundSource::StoppedState) {
m_state = QSoundSource::StoppedState;
emit stateChanged(m_state);
}
}
void QSoundSourcePrivate::play()
{
if (!m_alSource || !m_isReady)
return;
alSourcePlay(m_alSource);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("play");
#endif
emit activate(this);
}
bool QSoundSourcePrivate::isLooping() const
{
if (!m_alSource)
return false;
ALint looping = 0;
alGetSourcei(m_alSource, AL_LOOPING, &looping);
return looping == AL_TRUE ? true : false;
}
void QSoundSourcePrivate::pause()
{
if (!m_alSource || !m_isReady)
return;
alSourcePause(m_alSource);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("pause");
#endif
}
void QSoundSourcePrivate::stop()
{
if (!m_alSource)
return;
alSourceStop(m_alSource);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("stop");
#endif
}
QSoundSource::State QSoundSourcePrivate::state() const
{
return m_state;
}
void QSoundSourcePrivate::checkState()
{
QSoundSource::State st;
st = QSoundSource::StoppedState;
if (m_alSource && m_isReady) {
ALint s;
alGetSourcei(m_alSource, AL_SOURCE_STATE, &s);
switch (s) {
case AL_PLAYING:
st = QSoundSource::PlayingState;
break;
case AL_PAUSED:
st = QSoundSource::PausedState;
break;
}
}
if (st == m_state)
return;
m_state = st;
emit stateChanged(m_state);
}
void QSoundSourcePrivate::setLooping(bool looping)
{
if (!m_alSource)
return;
alSourcei(m_alSource, AL_LOOPING, looping ? AL_TRUE : AL_FALSE);
}
void QSoundSourcePrivate::setPosition(const QVector3D& position)
{
if (!m_alSource)
return;
alSource3f(m_alSource, AL_POSITION, position.x(), position.y(), position.z());
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set position");
#endif
}
void QSoundSourcePrivate::setDirection(const QVector3D& direction)
{
if (!m_alSource)
return;
alSource3f(m_alSource, AL_DIRECTION, direction.x(), direction.y(), direction.z());
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set direction");
#endif
}
void QSoundSourcePrivate::setVelocity(const QVector3D& velocity)
{
if (!m_alSource)
return;
alSource3f(m_alSource, AL_VELOCITY, velocity.x(), velocity.y(), velocity.z());
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set velocity");
#endif
}
QVector3D QSoundSourcePrivate::velocity() const
{
if (!m_alSource)
return QVector3D(0, 0, 0);
ALfloat x, y, z;
alGetSource3f(m_alSource, AL_VELOCITY, &x, &y, &z);
return QVector3D(x, y, z);
}
QVector3D QSoundSourcePrivate::position() const
{
if (!m_alSource)
return QVector3D(0, 0, 0);
ALfloat x, y, z;
alGetSource3f(m_alSource, AL_POSITION, &x, &y, &z);
return QVector3D(x, y, z);
}
QVector3D QSoundSourcePrivate::direction() const
{
if (!m_alSource)
return QVector3D(0, 1, 0);
ALfloat x, y, z;
alGetSource3f(m_alSource, AL_DIRECTION, &x, &y, &z);
return QVector3D(x, y, z);
}
void QSoundSourcePrivate::setGain(qreal gain)
{
if (!m_alSource || gain == m_gain)
return;
alSourcef(m_alSource, AL_GAIN, gain);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set gain");
#endif
m_gain = gain;
}
void QSoundSourcePrivate::setPitch(qreal pitch)
{
if (!m_alSource || m_pitch == pitch)
return;
alSourcef(m_alSource, AL_PITCH, pitch);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set pitch");
#endif
m_pitch = pitch;
}
void QSoundSourcePrivate::setCone(qreal innerAngle, qreal outerAngle, qreal outerGain)
{
if (innerAngle > outerAngle)
outerAngle = innerAngle;
Q_ASSERT(outerAngle <= 360 && innerAngle >= 0);
//make sure the setting order will always keep outerAngle >= innerAngle in openAL
if (outerAngle >= m_coneInnerAngle) {
if (m_coneOuterAngle != outerAngle) {
alSourcef(m_alSource, AL_CONE_OUTER_ANGLE, outerAngle);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set cone outerAngle");
#endif
m_coneOuterAngle = outerAngle;
}
if (m_coneInnerAngle != innerAngle) {
alSourcef(m_alSource, AL_CONE_INNER_ANGLE, innerAngle);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set cone innerAngle");
#endif
m_coneInnerAngle = innerAngle;
}
} else {
if (m_coneInnerAngle != innerAngle) {
alSourcef(m_alSource, AL_CONE_INNER_ANGLE, innerAngle);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set cone innerAngle");
#endif
m_coneInnerAngle = innerAngle;
}
if (m_coneOuterAngle != outerAngle) {
alSourcef(m_alSource, AL_CONE_OUTER_ANGLE, outerAngle);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set cone outerAngle");
#endif
m_coneOuterAngle = outerAngle;
}
}
if (outerGain != m_coneOuterGain) {
alSourcef(m_alSource, AL_CONE_OUTER_GAIN, outerGain);
#ifdef DEBUG_AUDIOENGINE
QAudioEnginePrivate::checkNoError("source set cone outerGain");
#endif
m_coneOuterGain = outerGain;
}
}

View File

@@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the plugins 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 QSOUNDSOURCE_P_H
#define QSOUNDSOURCE_P_H
#include <QVector3D>
#include <QObject>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QSoundBuffer;
class QSoundSource : public QObject
{
Q_OBJECT
public:
enum State
{
StoppedState,
PlayingState,
PausedState
};
virtual void play() = 0;
virtual void pause() = 0;
virtual void stop() = 0;
virtual QSoundSource::State state() const = 0;
virtual void setLooping(bool looping) = 0;
virtual void setDirection(const QVector3D& direction) = 0;
virtual void setPosition(const QVector3D& position) = 0;
virtual void setVelocity(const QVector3D& velocity) = 0;
virtual QVector3D velocity() const = 0;
virtual QVector3D position() const = 0;
virtual QVector3D direction() const = 0;
virtual void setGain(qreal gain) = 0;
virtual void setPitch(qreal pitch) = 0;
virtual void setCone(qreal innerAngle, qreal outerAngle, qreal outerGain) = 0;
virtual void bindBuffer(QSoundBuffer*) = 0;
virtual void unbindBuffer() = 0;
Q_SIGNALS:
void stateChanged(QSoundSource::State newState);
protected:
QSoundSource(QObject *parent);
};
QT_END_NAMESPACE
QT_END_HEADER
#endif

View File

@@ -1,5 +1,5 @@
TEMPLATE = subdirs
SUBDIRS += multimedia
contains(config_test_openal, yes): SUBDIRS += audioengine

View File

@@ -93,13 +93,17 @@ QT_BEGIN_NAMESPACE
\endcode
*/
QSampleCache::QSampleCache()
: m_networkAccessManager(0)
QSampleCache::QSampleCache(QObject *parent)
: QObject(parent)
, m_networkAccessManager(0)
, m_mutex(QMutex::Recursive)
, m_capacity(0)
, m_usage(0)
, m_loadingRefCount(0)
{
m_loadingThread.setObjectName(QLatin1String("QSampleCache::LoadingThread"));
connect(&m_loadingThread, SIGNAL(finished()), this, SIGNAL(isLoadingChanged()));
connect(&m_loadingThread, SIGNAL(started()), this, SIGNAL(isLoadingChanged()));
}
QNetworkAccessManager& QSampleCache::networkAccessManager()
@@ -128,10 +132,31 @@ QSampleCache::~QSampleCache()
delete m_networkAccessManager;
}
void QSampleCache::loadingRelease()
{
QMutexLocker locker(&m_loadingMutex);
m_loadingRefCount--;
if (m_loadingRefCount == 0) {
if (m_loadingThread.isRunning())
m_loadingThread.exit();
}
}
bool QSampleCache::isLoading() const
{
return m_loadingThread.isRunning();
}
QSample* QSampleCache::requestSample(const QUrl& url)
{
//lock and add first to make sure live loadingThread will not be killed during this function call
m_loadingMutex.lock();
m_loadingRefCount++;
m_loadingMutex.unlock();
if (!m_loadingThread.isRunning())
m_loadingThread.start();
#ifdef QT_SAMPLECACHE_DEBUG
qDebug() << "QSampleCache: request sample [" << url << "]";
#endif
@@ -250,6 +275,8 @@ void QSample::loadIfNecessary()
if (m_state == QSample::Error || m_state == QSample::Creating) {
m_state = QSample::Loading;
QMetaObject::invokeMethod(this, "load", Qt::QueuedConnection);
} else {
qobject_cast<QSampleCache*>(m_parent)->loadingRelease();
}
}
@@ -367,6 +394,7 @@ void QSample::decoderError()
#endif
cleanup();
m_state = QSample::Error;
qobject_cast<QSampleCache*>(m_parent)->loadingRelease();
emit error();
}
@@ -380,6 +408,7 @@ void QSample::onReady()
m_audioFormat = m_waveDecoder->audioFormat();
cleanup();
m_state = QSample::Ready;
qobject_cast<QSampleCache*>(m_parent)->loadingRelease();
emit ready();
}

View File

@@ -74,7 +74,7 @@ class QSampleCache;
class QWaveDecoder;
// Lives in application thread
class QSample : public QObject
class Q_MULTIMEDIA_EXPORT QSample : public QObject
{
Q_OBJECT
public:
@@ -127,17 +127,23 @@ private:
int m_ref;
};
class QSampleCache
class Q_MULTIMEDIA_EXPORT QSampleCache : public QObject
{
Q_OBJECT
public:
friend class QSample;
QSampleCache();
QSampleCache(QObject *parent = 0);
~QSampleCache();
QSample* requestSample(const QUrl& url);
void setCapacity(qint64 capacity);
bool isLoading() const;
Q_SIGNALS:
void isLoadingChanged();
private:
QMap<QUrl, QSample*> m_samples;
QSet<QSample*> m_staleSamples;
@@ -152,6 +158,10 @@ private:
bool notifyUnreferencedSample(QSample* sample);
void removeUnreferencedSample(QSample* sample);
void unloadSample(QSample* sample);
void loadingRelease();
int m_loadingRefCount;
QMutex m_loadingMutex;
};
QT_END_NAMESPACE

View File

@@ -52,4 +52,6 @@
"pulseaudio" => {},
"resourcepolicy" => {},
"xvideo" => {},
"openal" => {},
);