/**************************************************************************** ** ** 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_BEGIN_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::StoppedState) , 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::StoppedState) { 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::StoppedState); } 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::StoppedState) { setState(QSoundInstance::StoppedState); 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