Change-Id: I5eebe662ecbce9814ed3e763db56df9be737d11f Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
388 lines
10 KiB
C++
388 lines
10 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
|
** Contact: http://www.qt-project.org/
|
|
**
|
|
** This file is part of the plugins of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** GNU Lesser General Public License Usage
|
|
** This file may be used under the terms of the GNU Lesser General Public
|
|
** License version 2.1 as published by the Free Software Foundation and
|
|
** appearing in the file LICENSE.LGPL included in the packaging of this
|
|
** file. Please review the following information to ensure the GNU Lesser
|
|
** General Public License version 2.1 requirements will be met:
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU General
|
|
** Public License version 3.0 as published by the Free Software Foundation
|
|
** and appearing in the file LICENSE.GPL included in the packaging of this
|
|
** file. Please review the following information to ensure the GNU General
|
|
** Public License version 3.0 requirements will be met:
|
|
** http://www.gnu.org/copyleft/gpl.html.
|
|
**
|
|
** Other Usage
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
**
|
|
**
|
|
**
|
|
**
|
|
**
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "qsoundinstance_p.h"
|
|
#include "qsoundsource_p.h"
|
|
#include "qsoundbuffer_p.h"
|
|
#include "qdeclarative_sound_p.h"
|
|
#include "qdeclarative_audiocategory_p.h"
|
|
#include "qdeclarative_audiosample_p.h"
|
|
#include "qdeclarative_attenuationmodel_p.h"
|
|
#include "qdeclarative_playvariation_p.h"
|
|
#include "qdeclarative_audioengine_p.h"
|
|
#include "qdeclarative_audiolistener_p.h"
|
|
|
|
#include "qdebug.h"
|
|
|
|
#define DEBUG_AUDIOENGINE
|
|
|
|
QT_USE_NAMESPACE
|
|
|
|
QSoundInstance::QSoundInstance(QObject *parent)
|
|
: QObject(parent)
|
|
, m_soundSource(0)
|
|
, m_bindBuffer(0)
|
|
, m_sound(0)
|
|
, m_variationIndex(-1)
|
|
, m_isReady(false)
|
|
, m_gain(1)
|
|
, m_attenuationGain(1)
|
|
, m_varGain(1)
|
|
, m_pitch(1)
|
|
, m_varPitch(1)
|
|
, m_state(QSoundInstance::StopppedState)
|
|
, m_coneOuterGain(0)
|
|
, m_engine(0)
|
|
{
|
|
#ifdef DEBUG_AUDIOENGINE
|
|
qDebug() << "creating new QSoundInstance";
|
|
#endif
|
|
m_engine = qobject_cast<QDeclarativeAudioEngine*>(parent);
|
|
}
|
|
|
|
void QSoundInstance::bindSoundDescription(QDeclarativeSound *sound)
|
|
{
|
|
#ifdef DEBUG_AUDIOENGINE
|
|
qDebug() << "QSoundInstance::bindSoundDescription" << sound;
|
|
#endif
|
|
if (m_sound == sound)
|
|
return;
|
|
|
|
if (m_sound && m_sound->categoryObject()) {
|
|
disconnect(m_sound->categoryObject(), SIGNAL(volumeChanged(qreal)), this, SLOT(categoryVolumeChanged()));
|
|
disconnect(m_sound->categoryObject(), SIGNAL(paused()), this, SLOT(pause()));
|
|
disconnect(m_sound->categoryObject(), SIGNAL(stopped()), this, SLOT(stop()));
|
|
disconnect(m_sound->categoryObject(), SIGNAL(resumed()), this, SLOT(resume()));
|
|
}
|
|
m_attenuationGain = 1;
|
|
m_gain = 1;
|
|
|
|
m_sound = sound;
|
|
|
|
if (sound) {
|
|
if (!m_soundSource) {
|
|
m_soundSource = m_engine->engine()->createSoundSource();
|
|
connect(m_soundSource, SIGNAL(stateChanged(QSoundSource::State)),
|
|
this, SLOT(handleSourceStateChanged(QSoundSource::State)));
|
|
}
|
|
} else {
|
|
if (m_soundSource) {
|
|
detach();
|
|
m_engine->engine()->releaseSoundSource(m_soundSource);
|
|
m_soundSource = 0;
|
|
}
|
|
}
|
|
|
|
if (m_sound) {
|
|
if (m_sound->categoryObject()) {
|
|
connect(m_sound->categoryObject(), SIGNAL(volumeChanged(qreal)), this, SLOT(categoryVolumeChanged()));
|
|
connect(m_sound->categoryObject(), SIGNAL(paused()), this, SLOT(pause()));
|
|
connect(m_sound->categoryObject(), SIGNAL(stopped()), this, SLOT(stop()));
|
|
connect(m_sound->categoryObject(), SIGNAL(resumed()), this, SLOT(resume()));
|
|
}
|
|
prepareNewVariation();
|
|
} else {
|
|
m_variationIndex = -1;
|
|
}
|
|
}
|
|
|
|
QSoundInstance::~QSoundInstance()
|
|
{
|
|
#ifdef DEBUG_AUDIOENGINE
|
|
qDebug() << "QSoundInstance::dtor()";
|
|
#endif
|
|
if (m_soundSource) {
|
|
detach();
|
|
m_engine->engine()->releaseSoundSource(m_soundSource);
|
|
}
|
|
}
|
|
|
|
void QSoundInstance::prepareNewVariation()
|
|
{
|
|
#ifdef DEBUG_AUDIOENGINE
|
|
qDebug() << "QSoundInstance::prepareNewVariation()";
|
|
#endif
|
|
int newVariationIndex = m_sound->genVariationIndex(m_variationIndex);
|
|
if (newVariationIndex == m_variationIndex)
|
|
return;
|
|
QDeclarativePlayVariation *playVar = m_sound->getVariation(newVariationIndex);
|
|
#ifdef DEBUG_AUDIOENGINE
|
|
qDebug() << "QSoundInstance: generate new play variation [old:" << m_variationIndex << ", new:" << newVariationIndex << "-" << playVar->sample() << "]";
|
|
#endif
|
|
m_variationIndex = newVariationIndex;
|
|
playVar->applyParameters(this);
|
|
detach();
|
|
|
|
m_bindBuffer = playVar->sampleObject()->soundBuffer();
|
|
if (m_bindBuffer->isReady()) {
|
|
Q_ASSERT(m_soundSource);
|
|
m_soundSource->bindBuffer(m_bindBuffer);
|
|
m_isReady = true;
|
|
} else {
|
|
m_bindBuffer->load();
|
|
connect(m_bindBuffer, SIGNAL(ready()), this, SLOT(bufferReady()));
|
|
}
|
|
}
|
|
|
|
void QSoundInstance::bufferReady()
|
|
{
|
|
#ifdef DEBUG_AUDIOENGINE
|
|
qDebug() << "QSoundInstance::bufferReady()";
|
|
#endif
|
|
if (!m_soundSource)
|
|
return;
|
|
m_soundSource->bindBuffer(m_bindBuffer);
|
|
disconnect(m_bindBuffer, SIGNAL(ready()), this, SLOT(bufferReady()));
|
|
m_isReady = true;
|
|
|
|
if (m_state == QSoundInstance::PlayingState) {
|
|
sourcePlay();
|
|
} else if (m_state == QSoundInstance::PausedState) {
|
|
sourcePause();
|
|
}
|
|
}
|
|
|
|
void QSoundInstance::categoryVolumeChanged()
|
|
{
|
|
updateGain();
|
|
}
|
|
|
|
void QSoundInstance::handleSourceStateChanged(QSoundSource::State newState)
|
|
{
|
|
State ns = State(newState);
|
|
if (ns == m_state)
|
|
return;
|
|
if (ns == QSoundInstance::StopppedState) {
|
|
prepareNewVariation();
|
|
}
|
|
setState(ns);
|
|
}
|
|
|
|
void QSoundInstance::setState(State state)
|
|
{
|
|
if (state == m_state)
|
|
return;
|
|
m_state = state;
|
|
emit stateChanged(m_state);
|
|
}
|
|
|
|
qreal QSoundInstance::categoryVolume() const
|
|
{
|
|
if (!m_sound)
|
|
return 1;
|
|
if (!m_sound->categoryObject())
|
|
return 1;
|
|
return m_sound->categoryObject()->volume();
|
|
}
|
|
|
|
void QSoundInstance::sourceStop()
|
|
{
|
|
Q_ASSERT(m_soundSource);
|
|
m_soundSource->stop();
|
|
setState(QSoundInstance::StopppedState);
|
|
}
|
|
|
|
void QSoundInstance::detach()
|
|
{
|
|
sourceStop();
|
|
m_isReady = false;
|
|
if (m_soundSource)
|
|
m_soundSource->unbindBuffer();
|
|
if (m_bindBuffer) {
|
|
disconnect(m_bindBuffer, SIGNAL(ready()), this, SLOT(bufferReady()));
|
|
m_engine->engine()->releaseSoundBuffer(m_bindBuffer);
|
|
m_bindBuffer = 0;
|
|
}
|
|
}
|
|
|
|
void QSoundInstance::play()
|
|
{
|
|
#ifdef DEBUG_AUDIOENGINE
|
|
qDebug() << "QSoundInstancePrivate::play()";
|
|
#endif
|
|
if (!m_soundSource || m_state == QSoundInstance::PlayingState)
|
|
return;
|
|
if (!m_isReady) {
|
|
setState(QSoundInstance::PlayingState);
|
|
return;
|
|
}
|
|
sourcePlay();
|
|
setState(QSoundInstance::PlayingState);
|
|
}
|
|
|
|
void QSoundInstance::sourcePlay()
|
|
{
|
|
update3DVolume(m_engine->listener()->position());
|
|
Q_ASSERT(m_soundSource);
|
|
m_soundSource->play();
|
|
}
|
|
|
|
void QSoundInstance::resume()
|
|
{
|
|
#ifdef DEBUG_AUDIOENGINE
|
|
qDebug() << "QSoundInstancePrivate::resume()";
|
|
#endif
|
|
if (m_state != QSoundInstance::PausedState)
|
|
return;
|
|
play();
|
|
}
|
|
|
|
void QSoundInstance::pause()
|
|
{
|
|
if (!m_soundSource || m_state == QSoundInstance::PausedState)
|
|
return;
|
|
if (!m_isReady) {
|
|
setState(QSoundInstance::PausedState);
|
|
return;
|
|
}
|
|
sourcePause();
|
|
setState(QSoundInstance::PausedState);
|
|
}
|
|
|
|
void QSoundInstance::sourcePause()
|
|
{
|
|
Q_ASSERT(m_soundSource);
|
|
m_soundSource->pause();
|
|
}
|
|
|
|
void QSoundInstance::stop()
|
|
{
|
|
if (!m_isReady || !m_soundSource || m_state == QSoundInstance::StopppedState) {
|
|
setState(QSoundInstance::StopppedState);
|
|
return;
|
|
}
|
|
sourceStop();
|
|
prepareNewVariation();
|
|
}
|
|
|
|
QSoundInstance::State QSoundInstance::state() const
|
|
{
|
|
return m_state;
|
|
}
|
|
|
|
void QSoundInstance::setPosition(const QVector3D& position)
|
|
{
|
|
if (!m_soundSource)
|
|
return;
|
|
m_soundSource->setPosition(position);
|
|
}
|
|
|
|
void QSoundInstance::setDirection(const QVector3D& direction)
|
|
{
|
|
if (!m_soundSource)
|
|
return;
|
|
m_soundSource->setDirection(direction);
|
|
}
|
|
|
|
void QSoundInstance::setVelocity(const QVector3D& velocity)
|
|
{
|
|
if (!m_soundSource)
|
|
return;
|
|
m_soundSource->setVelocity(velocity);
|
|
}
|
|
|
|
void QSoundInstance::setGain(qreal gain)
|
|
{
|
|
if (!m_soundSource)
|
|
return;
|
|
m_gain = gain;
|
|
updateGain();
|
|
}
|
|
|
|
void QSoundInstance::setPitch(qreal pitch)
|
|
{
|
|
if (!m_soundSource)
|
|
return;
|
|
m_pitch = pitch;
|
|
updatePitch();
|
|
}
|
|
|
|
void QSoundInstance::setCone(qreal innerAngle, qreal outerAngle, qreal outerGain)
|
|
{
|
|
if (!m_soundSource)
|
|
return;
|
|
m_soundSource->setCone(innerAngle, outerAngle, outerGain);
|
|
}
|
|
|
|
bool QSoundInstance::attenuationEnabled() const
|
|
{
|
|
if (!m_sound || !m_sound->attenuationModelObject())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void QSoundInstance::update3DVolume(const QVector3D& listenerPosition)
|
|
{
|
|
if (!m_sound || !m_soundSource)
|
|
return;
|
|
QDeclarativeAttenuationModel *attenModel = m_sound->attenuationModelObject();
|
|
if (!attenModel)
|
|
return;
|
|
m_attenuationGain = attenModel->calculateGain(listenerPosition, m_soundSource->position());
|
|
updateGain();
|
|
}
|
|
|
|
void QSoundInstance::updateVariationParameters(qreal varPitch, qreal varGain, bool looping)
|
|
{
|
|
if (!m_soundSource)
|
|
return;
|
|
m_soundSource->setLooping(looping);
|
|
#ifdef DEBUG_AUDIOENGINE
|
|
qDebug() << "QSoundInstance::updateVariationParameters" << varPitch << varGain << looping;
|
|
#endif
|
|
m_varPitch = varPitch;
|
|
m_varGain = varGain;
|
|
updatePitch();
|
|
updateGain();
|
|
}
|
|
|
|
void QSoundInstance::updatePitch()
|
|
{
|
|
m_soundSource->setPitch(m_pitch * m_varPitch);
|
|
}
|
|
|
|
void QSoundInstance::updateGain()
|
|
{
|
|
m_soundSource->setGain(m_gain * m_varGain * m_attenuationGain * categoryVolume());
|
|
}
|
|
|
|
QT_END_NAMESPACE
|