From 809bbc35c67f085e91db9202795cccab0a5ae548 Mon Sep 17 00:00:00 2001 From: Ling Hu Date: Wed, 18 Jan 2012 17:17:54 +1000 Subject: Add AudioEngine with new implementation Change-Id: I5eebe662ecbce9814ed3e763db56df9be737d11f Reviewed-by: Michael Goddard --- config.tests/openal/main.cpp | 47 ++ config.tests/openal/openal.pro | 11 + examples/audioengine/audioengine.pro | 7 + examples/audioengine/qml/audioengine.qml | 193 +++++++ examples/audioengine/qml/audioengine.qmlproject | 16 + examples/audioengine/qml/content/MyAudioEngine.qml | 131 +++++ examples/examples.pro | 1 + src/imports/audioengine/audioengine.cpp | 85 ++++ src/imports/audioengine/audioengine.pro | 51 ++ src/imports/audioengine/qaudioengine_openal_p.cpp | 448 +++++++++++++++++ src/imports/audioengine/qaudioengine_openal_p.h | 168 +++++++ src/imports/audioengine/qaudioengine_p.cpp | 198 ++++++++ src/imports/audioengine/qaudioengine_p.h | 110 ++++ .../qdeclarative_attenuationmodel_p.cpp | 379 ++++++++++++++ .../audioengine/qdeclarative_attenuationmodel_p.h | 138 +++++ .../audioengine/qdeclarative_audiocategory_p.cpp | 207 ++++++++ .../audioengine/qdeclarative_audiocategory_p.h | 94 ++++ .../audioengine/qdeclarative_audioengine_p.cpp | 519 +++++++++++++++++++ .../audioengine/qdeclarative_audioengine_p.h | 168 +++++++ .../audioengine/qdeclarative_audiolistener_p.cpp | 263 ++++++++++ .../audioengine/qdeclarative_audiolistener_p.h | 102 ++++ .../audioengine/qdeclarative_audiosample_p.cpp | 242 +++++++++ .../audioengine/qdeclarative_audiosample_p.h | 111 ++++ .../audioengine/qdeclarative_playvariation_p.cpp | 287 +++++++++++ .../audioengine/qdeclarative_playvariation_p.h | 111 ++++ src/imports/audioengine/qdeclarative_sound_p.cpp | 558 ++++++++++++++++++++ src/imports/audioengine/qdeclarative_sound_p.h | 176 +++++++ .../audioengine/qdeclarative_soundinstance_p.cpp | 560 +++++++++++++++++++++ .../audioengine/qdeclarative_soundinstance_p.h | 155 ++++++ src/imports/audioengine/qmldir | 1 + src/imports/audioengine/qsoundbuffer_p.h | 70 +++ src/imports/audioengine/qsoundinstance_p.cpp | 387 ++++++++++++++ src/imports/audioengine/qsoundinstance_p.h | 139 +++++ src/imports/audioengine/qsoundsource_openal_p.cpp | 314 ++++++++++++ src/imports/audioengine/qsoundsource_p.h | 98 ++++ src/imports/imports.pro | 2 +- src/multimedia/audio/qsamplecache_p.cpp | 33 +- src/multimedia/audio/qsamplecache_p.h | 16 +- sync.profile | 2 + 39 files changed, 6592 insertions(+), 6 deletions(-) create mode 100644 config.tests/openal/main.cpp create mode 100644 config.tests/openal/openal.pro create mode 100644 examples/audioengine/audioengine.pro create mode 100644 examples/audioengine/qml/audioengine.qml create mode 100644 examples/audioengine/qml/audioengine.qmlproject create mode 100644 examples/audioengine/qml/content/MyAudioEngine.qml create mode 100644 src/imports/audioengine/audioengine.cpp create mode 100644 src/imports/audioengine/audioengine.pro create mode 100644 src/imports/audioengine/qaudioengine_openal_p.cpp create mode 100644 src/imports/audioengine/qaudioengine_openal_p.h create mode 100644 src/imports/audioengine/qaudioengine_p.cpp create mode 100644 src/imports/audioengine/qaudioengine_p.h create mode 100644 src/imports/audioengine/qdeclarative_attenuationmodel_p.cpp create mode 100644 src/imports/audioengine/qdeclarative_attenuationmodel_p.h create mode 100644 src/imports/audioengine/qdeclarative_audiocategory_p.cpp create mode 100644 src/imports/audioengine/qdeclarative_audiocategory_p.h create mode 100644 src/imports/audioengine/qdeclarative_audioengine_p.cpp create mode 100644 src/imports/audioengine/qdeclarative_audioengine_p.h create mode 100644 src/imports/audioengine/qdeclarative_audiolistener_p.cpp create mode 100644 src/imports/audioengine/qdeclarative_audiolistener_p.h create mode 100644 src/imports/audioengine/qdeclarative_audiosample_p.cpp create mode 100644 src/imports/audioengine/qdeclarative_audiosample_p.h create mode 100644 src/imports/audioengine/qdeclarative_playvariation_p.cpp create mode 100644 src/imports/audioengine/qdeclarative_playvariation_p.h create mode 100644 src/imports/audioengine/qdeclarative_sound_p.cpp create mode 100644 src/imports/audioengine/qdeclarative_sound_p.h create mode 100644 src/imports/audioengine/qdeclarative_soundinstance_p.cpp create mode 100644 src/imports/audioengine/qdeclarative_soundinstance_p.h create mode 100644 src/imports/audioengine/qmldir create mode 100644 src/imports/audioengine/qsoundbuffer_p.h create mode 100644 src/imports/audioengine/qsoundinstance_p.cpp create mode 100644 src/imports/audioengine/qsoundinstance_p.h create mode 100644 src/imports/audioengine/qsoundsource_openal_p.cpp create mode 100644 src/imports/audioengine/qsoundsource_p.h diff --git a/config.tests/openal/main.cpp b/config.tests/openal/main.cpp new file mode 100644 index 000000000..695306270 --- /dev/null +++ b/config.tests/openal/main.cpp @@ -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 + +int main(int argc, char** argv) +{ + return 0; +} diff --git a/config.tests/openal/openal.pro b/config.tests/openal/openal.pro new file mode 100644 index 000000000..58ce529ed --- /dev/null +++ b/config.tests/openal/openal.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +DEPENDPATH += . +INCLUDEPATH += . + +SOURCES += main.cpp + +win32 { + LIBS += -lOpenAL32 +}else { + LIBS += -lopenal +} diff --git a/examples/audioengine/audioengine.pro b/examples/audioengine/audioengine.pro new file mode 100644 index 000000000..d054115c6 --- /dev/null +++ b/examples/audioengine/audioengine.pro @@ -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 diff --git a/examples/audioengine/qml/audioengine.qml b/examples/audioengine/qml/audioengine.qml new file mode 100644 index 000000000..7b1980a66 --- /dev/null +++ b/examples/audioengine/qml/audioengine.qml @@ -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 + } + } +} diff --git a/examples/audioengine/qml/audioengine.qmlproject b/examples/audioengine/qml/audioengine.qmlproject new file mode 100644 index 000000000..15b002b1a --- /dev/null +++ b/examples/audioengine/qml/audioengine.qmlproject @@ -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: "." + } +} diff --git a/examples/audioengine/qml/content/MyAudioEngine.qml b/examples/audioengine/qml/content/MyAudioEngine.qml new file mode 100644 index 000000000..219485fa5 --- /dev/null +++ b/examples/audioengine/qml/content/MyAudioEngine.qml @@ -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" +} diff --git a/examples/examples.pro b/examples/examples.pro index 3f2aaca97..164200f58 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -24,3 +24,4 @@ TEMPLATE = subdirs QT += widgets } +contains(config_test_openal, yes): SUBDIRS += audioengine diff --git a/src/imports/audioengine/audioengine.cpp b/src/imports/audioengine/audioengine.cpp new file mode 100644 index 000000000..495a11a42 --- /dev/null +++ b/src/imports/audioengine/audioengine.cpp @@ -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 +#include +#include +#include + +#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(uri, 1, 0, "AudioEngine"); + qmlRegisterType(uri, 1, 0, "AudioSample"); + qmlRegisterType(uri, 1, 0, "AudioCategory"); + qmlRegisterType(uri, 1, 0, ""); + qmlRegisterType(uri, 1, 0, "Sound"); + qmlRegisterType(uri, 1, 0, "PlayVariation"); + qmlRegisterType(uri, 1, 0, "AudioListener"); + qmlRegisterType(uri, 1, 0, "SoundInstance"); + + qmlRegisterType(uri, 1, 0, "AttenuationModelLinear"); + qmlRegisterType(uri, 1, 0, "AttenuationModelInverse"); + } +}; + +QT_END_NAMESPACE + +#include "audioengine.moc" + +Q_EXPORT_PLUGIN2("QtAudioEngine", QT_PREPEND_NAMESPACE(QAudioEngineDeclarativeModule)); + diff --git a/src/imports/audioengine/audioengine.pro b/src/imports/audioengine/audioengine.pro new file mode 100644 index 000000000..d3cc2bafc --- /dev/null +++ b/src/imports/audioengine/audioengine.pro @@ -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 diff --git a/src/imports/audioengine/qaudioengine_openal_p.cpp b/src/imports/audioengine/qaudioengine_openal_p.cpp new file mode 100644 index 000000000..4818cf595 --- /dev/null +++ b/src/imports/audioengine/qaudioengine_openal_p.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +#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(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(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::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(*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(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(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::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" diff --git a/src/imports/audioengine/qaudioengine_openal_p.h b/src/imports/audioengine/qaudioengine_openal_p.h new file mode 100644 index 000000000..bac62189a --- /dev/null +++ b/src/imports/audioengine/qaudioengine_openal_p.h @@ -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 +#include +#include +#include + +#include +#include + +#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 m_activeInstances; + QList m_instancePool; + QMap m_staticBufferPool; + + QSampleCache *m_sampleLoader; + QTimer m_updateTimer; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/imports/audioengine/qaudioengine_p.cpp b/src/imports/audioengine/qaudioengine_p.cpp new file mode 100644 index 000000000..0c23910e6 --- /dev/null +++ b/src/imports/audioengine/qaudioengine_p.cpp @@ -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); +} diff --git a/src/imports/audioengine/qaudioengine_p.h b/src/imports/audioengine/qaudioengine_p.h new file mode 100644 index 000000000..12b5bbd30 --- /dev/null +++ b/src/imports/audioengine/qaudioengine_p.h @@ -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 +#include +#include +#include + +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 diff --git a/src/imports/audioengine/qdeclarative_attenuationmodel_p.cpp b/src/imports/audioengine/qdeclarative_attenuationmodel_p.cpp new file mode 100644 index 000000000..6624773b6 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_attenuationmodel_p.cpp @@ -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); +} + diff --git a/src/imports/audioengine/qdeclarative_attenuationmodel_p.h b/src/imports/audioengine/qdeclarative_attenuationmodel_p.h new file mode 100644 index 000000000..57b96fec7 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_attenuationmodel_p.h @@ -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 +#include +#include + +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 diff --git a/src/imports/audioengine/qdeclarative_audiocategory_p.cpp b/src/imports/audioengine/qdeclarative_audiocategory_p.cpp new file mode 100644 index 000000000..a7379c24b --- /dev/null +++ b/src/imports/audioengine/qdeclarative_audiocategory_p.cpp @@ -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(); +} diff --git a/src/imports/audioengine/qdeclarative_audiocategory_p.h b/src/imports/audioengine/qdeclarative_audiocategory_p.h new file mode 100644 index 000000000..fa8eb5140 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_audiocategory_p.h @@ -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 +#include + +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 diff --git a/src/imports/audioengine/qdeclarative_audioengine_p.cpp b/src/imports/audioengine/qdeclarative_audioengine_p.cpp new file mode 100644 index 000000000..a2763e021 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_audioengine_p.cpp @@ -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 +#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(qvariant_cast(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( + qvariant_cast(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( + qvariant_cast(m_sounds[key])); + + if (!sound) { + qWarning() << "accessing invalid sound[" << key << "]"; + continue; + } + QDeclarativeAudioCategory *category = m_defaultCategory; + if (m_categories.contains(sound->category())) { + category = qobject_cast( + qvariant_cast(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( + qvariant_cast(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::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 *property, QObject *value) +{ + QDeclarativeAudioEngine* engine = static_cast(property->object); + if (engine->m_complete) { + qWarning("AudioEngine: cannot add child after initialization!"); + return; + } + + QDeclarativeSound *sound = qobject_cast(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(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(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(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 QDeclarativeAudioEngine::bank() +{ + return QDeclarativeListProperty(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 + diff --git a/src/imports/audioengine/qdeclarative_audioengine_p.h b/src/imports/audioengine/qdeclarative_audioengine_p.h new file mode 100644 index 000000000..4b1364d82 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_audioengine_p.h @@ -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 +#include +#include +#include +#include +#include +#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 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 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 *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 m_attenuationModels; + + QAudioEngine *m_audioEngine; + + //for execution stage management + QList m_soundInstancePool; + QList m_activeSoundInstances; + + QTimer m_updateTimer; + QList m_managedDeclSoundInstances; + QList m_managedDeclSndInstancePool; + void releaseManagedDeclarativeSoundInstance(QDeclarativeSoundInstance* declSndInstance); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/imports/audioengine/qdeclarative_audiolistener_p.cpp b/src/imports/audioengine/qdeclarative_audiolistener_p.cpp new file mode 100644 index 000000000..97c424f97 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_audiolistener_p.cpp @@ -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(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(); +} diff --git a/src/imports/audioengine/qdeclarative_audiolistener_p.h b/src/imports/audioengine/qdeclarative_audiolistener_p.h new file mode 100644 index 000000000..97f1e7384 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_audiolistener_p.h @@ -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 +#include + +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 diff --git a/src/imports/audioengine/qdeclarative_audiosample_p.cpp b/src/imports/audioengine/qdeclarative_audiosample_p.cpp new file mode 100644 index 000000000..24a88ae76 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_audiosample_p.cpp @@ -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(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 +*/ + + diff --git a/src/imports/audioengine/qdeclarative_audiosample_p.h b/src/imports/audioengine/qdeclarative_audiosample_p.h new file mode 100644 index 000000000..d854efd34 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_audiosample_p.h @@ -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 +#include + +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 diff --git a/src/imports/audioengine/qdeclarative_playvariation_p.cpp b/src/imports/audioengine/qdeclarative_playvariation_p.cpp new file mode 100644 index 000000000..ec0682723 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_playvariation_p.cpp @@ -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); +} diff --git a/src/imports/audioengine/qdeclarative_playvariation_p.h b/src/imports/audioengine/qdeclarative_playvariation_p.h new file mode 100644 index 000000000..1438aa5b5 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_playvariation_p.h @@ -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 +#include + +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 diff --git a/src/imports/audioengine/qdeclarative_sound_p.cpp b/src/imports/audioengine/qdeclarative_sound_p.cpp new file mode 100644 index 000000000..37912732b --- /dev/null +++ b/src/imports/audioengine/qdeclarative_sound_p.cpp @@ -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(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(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(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 QDeclarativeSound::playVariationlist() +{ + return QDeclarativeListProperty(this, 0, appendFunction); +} + +QList& QDeclarativeSound::playlist() +{ + return m_playlist; +} + +void QDeclarativeSound::appendFunction(QDeclarativeListProperty *property, QDeclarativePlayVariation *value) +{ + QDeclarativeSound *sound = static_cast(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(this->parent())->newDeclarativeSoundInstance(managed); + instance->setSound(m_name); + return instance; +} + diff --git a/src/imports/audioengine/qdeclarative_sound_p.h b/src/imports/audioengine/qdeclarative_sound_p.h new file mode 100644 index 000000000..9784b04f8 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_sound_p.h @@ -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 +#include +#include +#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 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 playVariationlist(); + QList& 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 *property, QDeclarativePlayVariation *value); + bool m_complete; + PlayType m_playType; + QString m_name; + QString m_category; + QString m_attenuationModel; + QList m_playlist; + QDeclarativeSoundCone *m_cone; + + QDeclarativeAttenuationModel *m_attenuationModelObject; + QDeclarativeAudioCategory *m_categoryObject; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/imports/audioengine/qdeclarative_soundinstance_p.cpp b/src/imports/audioengine/qdeclarative_soundinstance_p.cpp new file mode 100644 index 000000000..4f3ade9ea --- /dev/null +++ b/src/imports/audioengine/qdeclarative_soundinstance_p.cpp @@ -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 +*/ diff --git a/src/imports/audioengine/qdeclarative_soundinstance_p.h b/src/imports/audioengine/qdeclarative_soundinstance_p.h new file mode 100644 index 000000000..0fd8c9a20 --- /dev/null +++ b/src/imports/audioengine/qdeclarative_soundinstance_p.h @@ -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 +#include +#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 diff --git a/src/imports/audioengine/qmldir b/src/imports/audioengine/qmldir new file mode 100644 index 000000000..94335c03a --- /dev/null +++ b/src/imports/audioengine/qmldir @@ -0,0 +1 @@ +plugin declarative_audioengine diff --git a/src/imports/audioengine/qsoundbuffer_p.h b/src/imports/audioengine/qsoundbuffer_p.h new file mode 100644 index 000000000..024fc622e --- /dev/null +++ b/src/imports/audioengine/qsoundbuffer_p.h @@ -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 + +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 diff --git a/src/imports/audioengine/qsoundinstance_p.cpp b/src/imports/audioengine/qsoundinstance_p.cpp new file mode 100644 index 000000000..9c5fc7ad9 --- /dev/null +++ b/src/imports/audioengine/qsoundinstance_p.cpp @@ -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(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 diff --git a/src/imports/audioengine/qsoundinstance_p.h b/src/imports/audioengine/qsoundinstance_p.h new file mode 100644 index 000000000..627862728 --- /dev/null +++ b/src/imports/audioengine/qsoundinstance_p.h @@ -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 +#include +#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 diff --git a/src/imports/audioengine/qsoundsource_openal_p.cpp b/src/imports/audioengine/qsoundsource_openal_p.cpp new file mode 100644 index 000000000..8f5bd19c5 --- /dev/null +++ b/src/imports/audioengine/qsoundsource_openal_p.cpp @@ -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(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; + } +} diff --git a/src/imports/audioengine/qsoundsource_p.h b/src/imports/audioengine/qsoundsource_p.h new file mode 100644 index 000000000..8f2fb63a0 --- /dev/null +++ b/src/imports/audioengine/qsoundsource_p.h @@ -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 +#include + +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 diff --git a/src/imports/imports.pro b/src/imports/imports.pro index 669064baa..443940739 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -1,5 +1,5 @@ - TEMPLATE = subdirs SUBDIRS += multimedia +contains(config_test_openal, yes): SUBDIRS += audioengine diff --git a/src/multimedia/audio/qsamplecache_p.cpp b/src/multimedia/audio/qsamplecache_p.cpp index aca08955b..addc03da3 100644 --- a/src/multimedia/audio/qsamplecache_p.cpp +++ b/src/multimedia/audio/qsamplecache_p.cpp @@ -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(m_parent)->loadingRelease(); } } @@ -367,6 +394,7 @@ void QSample::decoderError() #endif cleanup(); m_state = QSample::Error; + qobject_cast(m_parent)->loadingRelease(); emit error(); } @@ -380,6 +408,7 @@ void QSample::onReady() m_audioFormat = m_waveDecoder->audioFormat(); cleanup(); m_state = QSample::Ready; + qobject_cast(m_parent)->loadingRelease(); emit ready(); } diff --git a/src/multimedia/audio/qsamplecache_p.h b/src/multimedia/audio/qsamplecache_p.h index d5997b9cc..0c1bc5e7e 100644 --- a/src/multimedia/audio/qsamplecache_p.h +++ b/src/multimedia/audio/qsamplecache_p.h @@ -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 m_samples; QSet 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 diff --git a/sync.profile b/sync.profile index 31fff9e3f..46b32a093 100644 --- a/sync.profile +++ b/sync.profile @@ -52,4 +52,6 @@ "pulseaudio" => {}, "resourcepolicy" => {}, "xvideo" => {}, + + "openal" => {}, ); -- cgit v1.2.3