/**************************************************************************** ** ** 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 */