code:
/*
 * AudioPlayer.h
 *
 *  Created on: Aug 18, 2011
 *      Author: laschweinski
 */

#ifndef AUDIOPLAYER_H_
#define AUDIOPLAYER_H_

namespace CocosDenshion {

class AudioPlayer {
public:
	virtual void close() = 0;

	/**
	 @brief Preload background music
	 @param pszFilePath The path of the background music file,or the FileName of T_SoundResInfo
	 */
	virtual void preloadBackgroundMusic(const char* pszFilePath) = 0;

	/**
	 @brief Play background music
	 @param pszFilePath The path of the background music file,or the FileName of T_SoundResInfo
	 @param bLoop Whether the background music loop or not
	 */
	virtual void playBackgroundMusic(const char* pszFilePath, bool bLoop = false) = 0;

	/**
	 @brief Stop playing background music
	 @param bReleaseData If release the background music data or not.As default value is false
	 */
	virtual void stopBackgroundMusic(bool bReleaseData = false) = 0;

	/**
	 @brief Pause playing background music
	 */
	virtual void pauseBackgroundMusic() = 0;

	/**
	 @brief Resume playing background music
	 */
	virtual void resumeBackgroundMusic() = 0;

	/**
	 @brief Rewind playing background music
	 */
	virtual void rewindBackgroundMusic() = 0;

	virtual bool willPlayBackgroundMusic() = 0;

	/**
	 @brief Whether the background music is playing
	 @return If is playing return true,or return false
	 */
	virtual bool isBackgroundMusicPlaying() = 0;

	// properties
	/**
	 @brief The volume of the background music max value is 1.0,the min value is 0.0
	 */
	virtual float getBackgroundMusicVolume() = 0;

	/**
	 @brief set the volume of background music
	 @param volume must be in 0.0~1.0
	 */
	virtual void setBackgroundMusicVolume(float volume) = 0;

	/**
	 @brief The volume of the effects max value is 1.0,the min value is 0.0
	 */
	virtual float getEffectsVolume() = 0;

	/**
	 @brief set the volume of sound effecs
	 @param volume must be in 0.0~1.0
	 */
	virtual void setEffectsVolume(float volume) = 0;

	// for sound effects
	/**
	 @brief Play sound effect
	 @param pszFilePath The path of the effect file,or the FileName of T_SoundResInfo
	 @bLoop Whether to loop the effect playing, default value is false
	 */
	virtual unsigned int playEffect(const char* pszFilePath, bool bLoop = false) = 0;

	/**
	 @brief Stop playing sound effect
	 @param nSoundId The return value of function playEffect
	 */
	virtual void stopEffect(unsigned int nSoundId) = 0;

	/**
	 @brief  		preload a compressed audio file
	 @details	    the compressed audio will be decode to wave, then write into an
	 internal buffer in SimpleaudioEngine
	 */
	virtual void preloadEffect(const char* pszFilePath) = 0;

	/**
	 @brief  		unload the preloaded effect from internal buffer
	 @param[in]		pszFilePath		The path of the effect file,or the FileName of T_SoundResInfo
	 */
	virtual void unloadEffect(const char* pszFilePath) = 0;

	/**
	 @brief  		pause an effect identified by sound id
	 @param[in]		uSoundId 	sound id
	 */
	virtual void pauseEffect(unsigned int uSoundId) = 0;

	/**
	 @brief  		pause all playing effects
	 */
	virtual void pauseAllEffects() = 0;

	/**
	 @brief  		resume an effect identified by sound id
	 @param[in]		uSoundId 	sound id
	 */
	virtual void resumeEffect(unsigned int uSoundId) = 0;

	/**
	 @brief  		resume a effect identified by sound id
	 */
	virtual void resumeAllEffects() = 0;

	/**
	 @brief  		stop all playing effects
	 */
	virtual void stopAllEffects() = 0;
};
}

#endif /* AUDIOPLAYER_H_ */


code:
/**
* Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* For the applicable distribution terms see the license text file included in
* the distribution.
*/

#include "QtAudioPlayer.h"
#include "pullaudioout.h"
#include "pushaudioout.h"
#include "CCFileUtils.h"
#include "CCApplication.h"
#include <QDebug>

using namespace GE;

namespace CocosDenshion {

static unsigned int _Hash(const char *key)
{
    unsigned int len = strlen(key);
    const char *end=key+len;
    unsigned int hash;

    for (hash = 0; key < end; key++)
    {
        hash *= 16777619;
        hash ^= (unsigned int) (unsigned char) toupper(*key);
    }
    return (hash);
}

static QString fullPathFromRelativePath(const char *pszRelativePath)
{
    QString strRet="";
    int len = strlen(pszRelativePath);
    if (pszRelativePath == NULL || len <= 0)
    {
        return strRet;
    }

    if (len > 1 && pszRelativePath[0] == '/')
    {
        strRet = pszRelativePath;
    }
    else
    {
        strRet = CCFileUtils::fullPathFromRelativePath(pszRelativePath);
    }
    return strRet;
}

QtAudioPlayer* QtAudioPlayer::sharedPlayer()
{
    static QtAudioPlayer s_SharedPlayer;
    return &s_SharedPlayer;
}

QtAudioPlayer::QtAudioPlayer() :
    m_mixer(NULL),
    m_audioOut(NULL),
    m_musicId(NULL),
    m_effectsVolume(0.7f),
    m_musicVolume(0.7f),
    m_music(NULL)
#ifndef USE_VORBIS_SOURCE
   ,m_musicBuffer(NULL)
#endif
{
    init();
}

void QtAudioPlayer::init()
{
    CCApplication::sharedApplication().lock();
    m_mixer = new AudioMixer(this);

#ifdef Q_OS_SYMBIAN
    m_audioOut = new PullAudioOut(m_mixer, this);
#else
    m_audioOut = new PushAudioOut(m_mixer, this);
#endif
    CCApplication::sharedApplication().unlock();
}

void QtAudioPlayer::close()
{
    delete m_mixer;
    m_mixer = NULL;

    delete m_audioOut;
    m_audioOut = NULL;

    foreach (QPointer<AudioBufferPlayInstance> i, m_effectInstances)
    {
        delete i;
    }
    m_effectInstances.clear();

    foreach (AudioBuffer *i, m_effects)
    {
        delete i;
    }
    m_effects.clear();
}

QtAudioPlayer::~QtAudioPlayer()
{
    close();
}

void QtAudioPlayer::checkFinishedEffects()
{
    QHash<unsigned int, QPointer<AudioBufferPlayInstance> >::iterator i =
            m_effectInstances.begin();
    while (i != m_effectInstances.end())
    {
        if (i.value().isNull())
            i = m_effectInstances.erase(i);
        else
            ++i;
    }
}

void QtAudioPlayer::preloadBackgroundMusic(const char* pszFilePath)
{
    if (!m_music.isNull())
    {
        m_mixer->removeAudioSource(m_music);
        delete m_music;
        m_music = NULL;
        m_musicId = 0;
    }

#ifdef USE_VORBIS_SOURCE
    m_music = new VorbisSource(fullPathFromRelativePath(pszFilePath));
    m_mixer->addAudioSource(m_music);
#else
    if (m_musicBuffer)
    {
        delete m_musicBuffer;
        m_musicBuffer = NULL;
    }
    m_musicBuffer = AudioBuffer::load(fullPathFromRelativePath(pszFilePath));
#endif
    m_musicId = _Hash(pszFilePath);
}

void QtAudioPlayer::playBackgroundMusic(const char* pszFilePath, bool bLoop)
{
    unsigned int hash = _Hash(pszFilePath);

#ifdef USE_VORBIS_SOURCE
    if (m_music.isNull() || m_musicId != hash)
    {
        preloadBackgroundMusic(pszFilePath);
    }

    if (m_music.isNull())
    {
        CCLOG("preloadBackgroundMusic failed!");
        return;
    }
    m_music->seek(0);
    m_music->play();
#else
    if (!m_musicBuffer || m_musicId != hash)
    {
        preloadBackgroundMusic(pszFilePath);
    }

    if (!m_musicBuffer)
    {
        CCLOG("preloadBackgroundMusic failed!");
        return;
    }

    if (m_music.isNull())
    {
        m_music = m_musicBuffer->playWithMixer(*m_mixer);
    }
#endif

    m_music->setLeftVolume(m_musicVolume);
    m_music->setRightVolume(m_musicVolume);
    if (bLoop)
        m_music->setLoopCount(1<<30);
}

void QtAudioPlayer::stopBackgroundMusic(bool bReleaseData)
{
    if (m_music.isNull())
        return;

    m_music->seek(0);
    m_music->stop();

    if (bReleaseData)
    {
        m_mixer->removeAudioSource(m_music);
        delete m_music;
        m_music = NULL;
        m_musicId = 0;
    }
}

void QtAudioPlayer::pauseBackgroundMusic()
{
    if (!m_music.isNull())
        m_music->pause();
}

void QtAudioPlayer::resumeBackgroundMusic()
{
    if (!m_music.isNull())
        m_music->resume();
}

void QtAudioPlayer::rewindBackgroundMusic()
{
    if (!m_music.isNull())
        m_music->seek(0);
}

bool QtAudioPlayer::willPlayBackgroundMusic()
{
    return false;
}

bool QtAudioPlayer::isBackgroundMusicPlaying()
{
    if (m_music.isNull())
        return false;

    return (!m_music->isFinished());
}

float QtAudioPlayer::getBackgroundMusicVolume()
{
    return m_musicVolume;
}

void QtAudioPlayer::setBackgroundMusicVolume(float volume)
{
    if (volume > 1.0f)
    {
        volume = 1.0f;
    }
    else if (volume < 0.0f)
    {
        volume = 0.0f;
    }

    m_musicVolume = volume;

    if (!m_music.isNull())
    {
        m_music->setLeftVolume(volume);
        m_music->setRightVolume(volume);
    }
}

// for sound effects
float QtAudioPlayer::getEffectsVolume()
{
    return m_effectsVolume;
}

void QtAudioPlayer::setEffectsVolume(float volume)
{
    if (volume > 1.0f)
    {
        volume = 1.0f;
    }
    else if (volume < 0.0f)
    {
        volume = 0.0f;
    }

    m_effectsVolume = volume;

    checkFinishedEffects();
    foreach (QPointer<AudioBufferPlayInstance> i, m_effectInstances)
    {
        i->setLeftVolume(m_effectsVolume);
        i->setRightVolume(m_effectsVolume);
    }
}

unsigned int QtAudioPlayer::playEffect(const char* pszFilePath, bool bLoop)
{
    unsigned int hash = _Hash(pszFilePath);

    checkFinishedEffects();
    AudioBuffer *buffer = m_effects.value(hash);
    if (!buffer)
    {
        preloadEffect(pszFilePath);
        buffer = m_effects.value(hash);
    }

    // Not loaded successfully
    if (!buffer)
        return 0;

    AudioBufferPlayInstance *inst = buffer->playWithMixer(*m_mixer);
    if (!inst)
    {
        CCLOG("playWithMixer for %s failed", pszFilePath);
        return 0;
    }
    inst->setLeftVolume(m_effectsVolume);
    inst->setRightVolume(m_effectsVolume);
    if (bLoop)
        inst->setLoopCount(1<<30);

    m_effectInstances.insertMulti(hash, QPointer<AudioBufferPlayInstance>(inst));

    return hash;
}

void QtAudioPlayer::stopEffect(unsigned int nSoundId)
{
    checkFinishedEffects();
    QHash<unsigned int, QPointer<AudioBufferPlayInstance> >::const_iterator i =
             m_effectInstances.find(nSoundId);
    while (i != m_effectInstances.end() && i.key() == nSoundId)
    {
        i.value()->stop();
        ++i;
    }
    m_effectInstances.remove(nSoundId);
}

void QtAudioPlayer::pauseEffect(unsigned int uSoundId)
{
    checkFinishedEffects();
    QHash<unsigned int, QPointer<AudioBufferPlayInstance> >::const_iterator i =
             m_effectInstances.find(uSoundId);
    while (i != m_effectInstances.end() && i.key() == uSoundId)
    {
       i.value()->pause();
       ++i;
    }
}

void QtAudioPlayer::pauseAllEffects()
{
    checkFinishedEffects();
    foreach (QPointer<AudioBufferPlayInstance> i, m_effectInstances)
    {
        i->pause();
    }
}

void QtAudioPlayer::resumeEffect(unsigned int uSoundId)
{
    checkFinishedEffects();
    QHash<unsigned int, QPointer<AudioBufferPlayInstance> >::const_iterator i =
             m_effectInstances.find(uSoundId);
    while (i != m_effectInstances.end() && i.key() == uSoundId)
    {
        i.value()->resume();
        ++i;
    }
}

void QtAudioPlayer::resumeAllEffects()
{
    checkFinishedEffects();
    foreach (QPointer<AudioBufferPlayInstance> i, m_effectInstances)
    {
        i->resume();
    }
}

void QtAudioPlayer::stopAllEffects()
{
    checkFinishedEffects();
    foreach (QPointer<AudioBufferPlayInstance> i, m_effectInstances)
    {
        i->stop();
    }

    m_effectInstances.clear();
}

void QtAudioPlayer::preloadEffect(const char* pszFilePath)
{
    unsigned int hash = _Hash(pszFilePath);

    AudioBuffer *buffer = m_effects.value(hash);
    if (!buffer)
    {
        AudioBuffer *buffer = AudioBuffer::load(
                    fullPathFromRelativePath(pszFilePath));
        if (!buffer)
        {
            CCLOG("could not load audio effect %s", pszFilePath);
            return;
        }
        m_effects.insert(hash, buffer);
    }
}

void QtAudioPlayer::unloadEffect(const char* pszFilePath)
{
    unsigned int hash = _Hash(pszFilePath);
    stopEffect(hash);

    checkFinishedEffects();
    AudioBuffer* buffer = m_effects.value(hash);
    delete buffer;
    m_effects.remove(hash);
}

} /* namespace CocosDenshion */

license: mit


code:
/**
* Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* For the applicable distribution terms see the license text file included in
* the distribution.
*/

#ifndef QTAUDIOPLAYER_H_
#define QTAUDIOPLAYER_H_

#include "AudioPlayer.h"
#include "audiomixer.h"
#include "audioout.h"
#include "vorbissource.h"
#include "audiobufferplayinstance.h"

#include <QVariant>
#include <QList>

using namespace GE;

namespace CocosDenshion {

class QtAudioPlayer : public QObject,
                      public AudioPlayer
{
    Q_OBJECT

public:
    QtAudioPlayer();
    virtual ~QtAudioPlayer();

    static QtAudioPlayer* sharedPlayer();

    virtual void close();

    /**
     @brief Preload background music
     @param pszFilePath The path of the background music file,or the FileName of T_SoundResInfo
     */
    virtual void preloadBackgroundMusic(const char* pszFilePath);

    /**
     @brief Play background music
     @param pszFilePath The path of the background music file,or the FileName of T_SoundResInfo
     @param bLoop Whether the background music loop or not
     */
    virtual void playBackgroundMusic(const char* pszFilePath, bool bLoop);

    /**
     @brief Stop playing background music
     @param bReleaseData If release the background music data or not.As default value is false
     */
    virtual void stopBackgroundMusic(bool bReleaseData);

    /**
     @brief Pause playing background music
     */
    virtual void pauseBackgroundMusic();

    /**
     @brief Resume playing background music
     */
    virtual void resumeBackgroundMusic();

    /**
     @brief Rewind playing background music
     */
    virtual void rewindBackgroundMusic();

    virtual bool willPlayBackgroundMusic();

    /**
     @brief Whether the background music is playing
     @return If is playing return true,or return false
     */
    virtual bool isBackgroundMusicPlaying();

    // properties
    /**
     @brief The volume of the background music max value is 1.0,the min value is 0.0
     */
    virtual float getBackgroundMusicVolume();

    /**
     @brief set the volume of background music
     @param volume must be in 0.0~1.0
     */
    virtual void setBackgroundMusicVolume(float volume);

    /**
     @brief The volume of the effects max value is 1.0,the min value is 0.0
     */
    virtual float getEffectsVolume();

    /**
     @brief set the volume of sound effecs
     @param volume must be in 0.0~1.0
     */
    virtual void setEffectsVolume(float volume);

    // for sound effects
    /**
     @brief Play sound effect
     @param pszFilePath The path of the effect file,or the FileName of T_SoundResInfo
     @bLoop Whether to loop the effect playing, default value is false
     */
    virtual unsigned int playEffect(const char* pszFilePath, bool bLoop = false);

    /**
     @brief Stop playing sound effect
     @param nSoundId The return value of function playEffect
     */
    virtual void stopEffect(unsigned int nSoundId);

    /**
     @brief  		preload a compressed audio file
     @details	    the compressed audio will be decode to wave, then write into an
     internal buffer in SimpleaudioEngine
     */
    virtual void preloadEffect(const char* pszFilePath);

    /**
     @brief  		unload the preloaded effect from internal buffer
     @param[in]		pszFilePath		The path of the effect file,or the FileName of T_SoundResInfo
     */
    virtual void unloadEffect(const char* pszFilePath);

    /**
     @brief  		pause an effect identified by sound id
     @param[in]		uSoundId 	sound id
     */
    virtual void pauseEffect(unsigned int uSoundId);

    /**
     @brief  		pause all playing effects
     */
    virtual void pauseAllEffects();

    /**
     @brief  		resume an effect identified by sound id
     @param[in]		uSoundId 	sound id
     */
    virtual void resumeEffect(unsigned int uSoundId);

    /**
     @brief  		resume a effect identified by sound id
     */
    virtual void resumeAllEffects();

    /**
     @brief  		stop all playing effects
     */
    virtual void stopAllEffects();

private:
    void init();
    void checkFinishedEffects();

private:
    AudioMixer *m_mixer;
    AudioOut *m_audioOut;
    QHash<unsigned int, AudioBuffer*> m_effects;
    QHash<unsigned int, QPointer<AudioBufferPlayInstance> > m_effectInstances;
    unsigned int m_musicId;
    float m_effectsVolume;
    float m_musicVolume;
#ifdef USE_VORBIS_SOURCE
    QPointer<VorbisSource> m_music;
#else
    QPointer<AudioBufferPlayInstance> m_music;
    AudioBuffer *m_musicBuffer;
#endif
};

} /* namespace CocosDenshion */

#endif /* QTAUDIOPLAYER_H_ */


code:
/**
* Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* For the applicable distribution terms see the license text file included in
* the distribution.
*/

#include "SimpleAudioEngine.h"
#include "QtAudioPlayer.h"

namespace CocosDenshion {

static AudioPlayer* oAudioPlayer;

SimpleAudioEngine::SimpleAudioEngine()
{
    oAudioPlayer = QtAudioPlayer::sharedPlayer();
}

SimpleAudioEngine::~SimpleAudioEngine()
{
}

SimpleAudioEngine* SimpleAudioEngine::sharedEngine()
{
	static SimpleAudioEngine s_SharedEngine;
	return &s_SharedEngine;
}

void SimpleAudioEngine::end()
{
}

void SimpleAudioEngine::setResource(const char* pszZipFileName)
{
}

//////////////////////////////////////////////////////////////////////////
// BackgroundMusic
//////////////////////////////////////////////////////////////////////////

void SimpleAudioEngine::playBackgroundMusic(const char* pszFilePath,
        bool bLoop)
{
    oAudioPlayer->playBackgroundMusic(pszFilePath, bLoop);
}

void SimpleAudioEngine::stopBackgroundMusic(bool bReleaseData)
{
    oAudioPlayer->stopBackgroundMusic(bReleaseData);
}

void SimpleAudioEngine::pauseBackgroundMusic() {
    oAudioPlayer->pauseBackgroundMusic();
}

void SimpleAudioEngine::resumeBackgroundMusic() {
    oAudioPlayer->resumeBackgroundMusic();
}

void SimpleAudioEngine::rewindBackgroundMusic() {
    oAudioPlayer->rewindBackgroundMusic();
}

bool SimpleAudioEngine::willPlayBackgroundMusic() {
    return oAudioPlayer->willPlayBackgroundMusic();
}

bool SimpleAudioEngine::isBackgroundMusicPlaying() {
    return oAudioPlayer->isBackgroundMusicPlaying();
}

void SimpleAudioEngine::preloadBackgroundMusic(const char* pszFilePath) {
    return oAudioPlayer->preloadBackgroundMusic(pszFilePath);
}

//////////////////////////////////////////////////////////////////////////
// effect function
//////////////////////////////////////////////////////////////////////////

unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath,
        bool bLoop)
{
    return oAudioPlayer->playEffect(pszFilePath, bLoop);
}

void SimpleAudioEngine::stopEffect(unsigned int nSoundId)
{
    return oAudioPlayer->stopEffect(nSoundId);
}

void SimpleAudioEngine::preloadEffect(const char* pszFilePath)
{
    return oAudioPlayer->preloadEffect(pszFilePath);
}

void SimpleAudioEngine::unloadEffect(const char* pszFilePath)
{
    return oAudioPlayer->unloadEffect(pszFilePath);
}

void SimpleAudioEngine::pauseEffect(unsigned int uSoundId)
{
    oAudioPlayer->pauseEffect(uSoundId);
}

void SimpleAudioEngine::pauseAllEffects()
{
    oAudioPlayer->pauseAllEffects();
}

void SimpleAudioEngine::resumeEffect(unsigned int uSoundId)
{
    oAudioPlayer->resumeEffect(uSoundId);
}

void SimpleAudioEngine::resumeAllEffects()
{
    oAudioPlayer->resumeAllEffects();
}

void SimpleAudioEngine::stopAllEffects()
{
    oAudioPlayer->stopAllEffects();
}

//////////////////////////////////////////////////////////////////////////
// volume interface
//////////////////////////////////////////////////////////////////////////

float SimpleAudioEngine::getBackgroundMusicVolume()
{
    return oAudioPlayer->getBackgroundMusicVolume();
}

void SimpleAudioEngine::setBackgroundMusicVolume(float volume)
{
    return oAudioPlayer->setBackgroundMusicVolume(volume);
}

float SimpleAudioEngine::getEffectsVolume()
{
    return oAudioPlayer->getEffectsVolume();
}

void SimpleAudioEngine::setEffectsVolume(float volume)
{
    return oAudioPlayer->setEffectsVolume(volume);
}

} // end of namespace CocosDenshion


code:
Copyright � 2011-2012 Nokia Corporation. All rights reserved.
Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation.
Other product and company names mentioned herein may be trademarks or trade names
of their respective owners.

Subject to the conditions below, you may, without charge:

�  Use, copy, modify and/or merge copies of this software and
   associated content and documentation files (the �Software�)

�  Publish, distribute, sub-licence and/or sell new software
   derived from or incorporating the Software.

Some of the documentation, content and/or software maybe licensed under open source
software or other licenses. To the extent such documentation, content and/or software
are included, licenses and/or other terms and conditions shall apply in addition and/or
instead of this notice. The exact terms of the licenses, disclaimers, acknowledgements
and notices are reproduced in the materials provided.

This file, unmodified, shall be included with all copies or substantial portions
of the Software that are distributed in source code form.

The Software cannot constitute the primary value of any new software derived
from or incorporating the Software.

Any person dealing with the Software shall not misrepresent the source of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


code:
# Copyright (c) 2011-2012 Nokia Corporation.

# Comment the following line out for better performance. Using the definition
# enables debug logging which is convenient for locating problems in the code
# but is also very costly in terms of performance.
#DEFINES += GE_DEBUG

# Support longer audio buffers than 2^20 samples per channel
DEFINES += QTGAMEENABLER_SUPPORT_LONG_SAMPLES

# For enabling Ogg Vorbis support
DEFINES += QTGAMEENABLER_SUPPORT_OGG_VORBIS

# STB's pullmode API is not needed
DEFINES += STB_VORBIS_NO_PULLDATA_API

INCLUDEPATH += $$PWD/src

HEADERS  += \
    $$PWD/src/trace.h \
    $$PWD/src/geglobal.h \
    $$PWD/src/audiobuffer.h \
    $$PWD/src/audiobufferplayinstance.h \
    $$PWD/src/audiomixer.h \
    $$PWD/src/audioout.h \
    $$PWD/src/pushaudioout.h \
    $$PWD/src/pullaudioout.h \
    $$PWD/src/audiosourceif.h \
    $$PWD/src/audioeffect.h \
    $$PWD/src/echoeffect.h \
    $$PWD/src/cutoffeffect.h

SOURCES += \
    $$PWD/src/audiobuffer.cpp \
    $$PWD/src/audiobufferplayinstance.cpp \
    $$PWD/src/audiomixer.cpp \
    $$PWD/src/pushaudioout.cpp \
    $$PWD/src/pullaudioout.cpp \
    $$PWD/src/audiosourceif.cpp \
    $$PWD/src/audioeffect.cpp \
    $$PWD/src/echoeffect.cpp \
    $$PWD/src/cutoffeffect.cpp

contains(DEFINES, QTGAMEENABLER_SUPPORT_OGG_VORBIS) {
    HEADERS += \
        $$PWD/src/stb_vorbis.h \
        $$PWD/src/vorbisdecoder.h \
        $$PWD/src/oggpage.h \
        $$PWD/src/oggconstants.h \
        $$PWD/src/vorbissource.h

    SOURCES += \
        $$PWD/src/stb_vorbis.c \
        $$PWD/src/vorbisdecoder.cpp \
        $$PWD/src/oggpage.cpp \
        $$PWD/src/vorbissource.cpp
}

QT += core gui

symbian {
    message(Symbian build)

    CONFIG += mobility
    MOBILITY += multimedia systeminfo

    # For volume keys
    LIBS += -lremconcoreapi -lremconinterfacebase

    # Uncomment the following define to enable a very ugly hack to set the
    # volume level on Symbian devices higher. By default, on Symbian, the volume
    # level is very low when audio is played using QAudioOutput class. For now,
    # this ugly hack is the only way to set the volume louder.
    #
    # WARNING: The volume hack (see the GEAudioOut.cpp file) is VERY DANGEROUS
    # because the data to access the volume interface is retrieved manually with
    # pointer manipulation. Should the library, in which the interface is
    # implemented, be modified even a tiny bit, the application using this hack
    # might crash.
    #
    #DEFINES += QTGAMEENABLER_USE_VOLUME_HACK

    contains(DEFINES, QTGAMEENABLER_USE_VOLUME_HACK) {
        # Include paths and libraries required for the volume hack.
        message(Symbian volume hack enabled)
        INCLUDEPATH += /epoc32/include/mmf/common
        INCLUDEPATH += /epoc32/include/mmf/server
        LIBS += -lmmfdevsound
    }

    #DEFINES += GE_PULLMODEAUDIO

    INCLUDEPATH += /epoc32/include/mw
    HEADERS += $$PWD/src/volumekeys.h
    SOURCES += $$PWD/src/volumekeys.cpp
}

unix:!symbian {
    maemo5 {
        message(Maemo 5 build)

        QT += multimedia
        CONFIG += mobility
        MOBILITY += systeminfo
    } else {
        contains(MEEGO_EDITION, harmattan) {
            message(Harmattan build)

            DEFINES += MEEGO_EDITION_HARMATTAN
            CONFIG += mobility
            MOBILITY += multimedia systeminfo
        }
        else {
            message(Unix based desktop build)

            CONFIG += mobility
            MOBILITY += multimedia systeminfo
            #DEFINES += GE_PULLMODEAUDIO
        }
    }
}

windows {
    message(Windows desktop build)

    QT += multimedia
    DEFINES += GE_NOMOBILITY
}

# End of file.


code:
Qt GameEnabler
==============

Qt GameEnabler provides a simple framework for game developers, enabling the
use of native OpenGL� ES 2.0 code within a Qt application. Qt GameEnabler does
not utilise QtOpenGL but overrides Qt's own rendering and replaces it with
native OpenGL. This enables applications to achieve maximum performance for
just their own use. An application created with Qt GameEnabler will run on all
devices supporting OpenGL ES 2.0. In addition, Qt GameEnabler provides a
lightweight, easy-to-use audio framework with rich features.

The three main parts of Qt GameEnabler are:

1. GE::GameWindow: A QGLWidget-like class which allows the inheriter to use
   real OpenGL ES 2.0 instead of encapsulated QtOpenGL. The window will always
   be full-screen and without any compositing enabled: Everything is rendered
   directly on the screen. This prevents the user from using Qt's UI
   functionality, but other parts of it are still usable. For example, QImage
   can be used for loading GL textures.

2. Audio framework: A set of classes providing a very simple and easy-to-use
   system for loading WAV files as audio buffers and playing them with dynamic
   attributes (speed, volume, and so on). Audio playback is implemented using
   custom mixing and a single instance of QAudioOutput in either pull or push
   mode.

3. QML audio plug-in: QML extension plug-in which uses the audio framework to
   provide simple AudioBuffer, AudioEffect, and AudioMixer elements for use
   with QML

This framework has been tested on Symbian^3, Maemo 5 (Nokia N900),
and MeeGo 1.2 Harmattan (Nokia N9 and Nokia N950). In addition, the framework
supports desktop platforms with OpenGL ES 2.0 emulation libraries (PowerVR),
and has been tested on Windows XP and Windows 7.

This example application is hosted in Nokia Developer Projects:
- http://projects.developer.nokia.com/qtgameenabler

For more information on implementation and porting, visit the wiki pages:
- http://projects.developer.nokia.com/qtgameenabler/wiki

What's new in 2.1
-----------------

 * Built-in OGG support

1. Prerequisites
-------------------------------------------------------------------------------
 - Qt intermediate
 - Qt Quick basics
 - OpenGL basics

2. Project structure and implementation
-------------------------------------------------------------------------------

2.1 Folders
-----------
 |
 |- examples        The root folder of the example applications demonstrating
 |  |               the use of Qt GameEnabler
 |  |
 |  |- bin          Compiled example binaries
 |  |
 |  |- qtgameenablerqmlaudiotest
 |  |  |
 |  |  |- audio     Contains the audio samples
 |  |  |
 |  |  |- gfx       Contains the graphics
 |  |  |
 |  |  |- qml       Contains QML source code
 |  |  |
 |  |  |- rsc       Contains the resource files
 |  |
 |  |- qtgameenablertest
 |     |
 |     |- graphics  Contains the graphics
 |     |
 |     |- sounds    Contains the audio samples
 |     |
 |     |- test_src  Contains the source code of the example
 |
 |- qtgameenabler   The root folder of the actual Qt GameEnabler source code.
 |  |               Contains the project files, the license information and
 |  |               this file (release notes).
 |  |
 |  |- features
 |  |
 |  |- icons        Contains the project icons
 |  |
 |  |- plugins      Contains the source code of the QML audio plug-in
 |  |
 |  |- src          Contains the source code of the OpenGL ES wrapper and the
 |                  audio framework

2.2 Important files and classes
-------------------------------

| Class                   | Description                                       |
|-------------------------|---------------------------------------------------|
| GameWindow              | The QGLWidget replacement with native             |
|                         | OpenGL ES 2.0                                     |
|-------------------------|---------------------------------------------------|
| AudioSource             | An interface from which audio data can be pulled. |
|                         | All of the playing is done via this class in      |
|                         | GE::Audio. Custom audio sources must also be      |
|                         | inherited from this interface.                    |
|-------------------------|---------------------------------------------------|
| AudioBuffer             | A class to contain a single audio buffer (for     |
|                         | example, a single audio file, such as WAV). The   |
|                         | audio buffer itself is not able to play anything, |
|                         | it only contains the audio data.                  |
|-------------------------|---------------------------------------------------|
| AudioBufferPlayInstance | A class derived from IAudioSource which points to |
|                         | an AudioBuffer and can provide its audio data via |
|                         | IAudioSource's pull functionality                 |
|-------------------------|---------------------------------------------------|
| AudioMixer              | A helper class which contains a list of           |
|                         | IAudioSources and methods to manipulate them. All |
|                         | of the items in this list are mixed together when |
|                         | the mixer's pullAudio is called.                  |
|-------------------------|---------------------------------------------------|
| AudioEffect             | An interface for audio effects, such as echo,     |
|                         | which can be applied to the audio buffer or mixer |
|                         | output. Current implementation includes cut-off   |
|                         | (with resonance) and echo effects.                |                                  |-------------------------|---------------------------------------------------|
| PushAudioOut            | "Push"-based audio output class                   |
|-------------------------|---------------------------------------------------|
| PullAudioOut            | "Pull"-based audio output class                   |
|-------------------------|---------------------------------------------------|
| AudioPlugin             | Use this to register the QML extension plug-in    |
|                         | which provides simple AudioBuffer, AudioEffect,   |
|                         | and AudioMixer elements for QML.                  |
|-------------------------|---------------------------------------------------|
| VorbisSource            | An audiosource capable of playing an OGG stream   |
|-------------------------|---------------------------------------------------|

2.3 Used APIs/QML elements/Qt Quick Components
----------------------------------------------

 - OpenGL ES (1.1 or 2.0)
 - QAudioOut

3. Compatibility
-------------------------------------------------------------------------------

 - Symbian devices with Qt 4.7.3 or higher.
 - MeeGo 1.2 Harmattan.
 - Windows desktop (PowerVR GLES2 emulation)
 - Linux desktop

Tested to work on
 - Nokia C6-01
 - Nokia C7-00
 - Nokia E6-00
 - Nokia E7-00
 - Nokia N8-00
 - Nokia N9
 - Nokia N950
 - Windows XP
 - Windows 7

Developed with Qt SDK 1.2.

3.1 Required Capabilities
-------------------------

None; The application can be self signed on Symbian.

3.2 Known Issues
----------------

None.

4. Building, installing, and running the application
-------------------------------------------------------------------------------

The project contains two examples which demonstrate the use of Qt GameEnabler.
The Qt GameEnabler Test example is a simple application that utilises both the
OpenGL and the audio features of Qt GameEnabler. The example is located in the
folder 'examples/qtgameenablertest'.

The Qt GameEnabler QML Audio Test example demonstrates the use of the QML
audio plug-in. While the application does not utilise OpenGL, the user
interface is implemented with QML code. The example is located in the folder
'examples/qtgameenablerqmlaudiotest'.

4.1 Preparations
----------------

Check that you have the latest Qt/Qt SDK installed in the development
environment and on the device.

Note: The Qt GameEnabler Test example application, which utilises OpenGL, can
be compiled directly on any device with OpenGL ES 2.0 support, for example,
Maemo or Symbian^3 devices. However, if you wish to compile it on some other
platform - desktop Windows, for example - you must have external OpenGL ES 2.0
emulation libraries. With Windows or Linux (32bit) desktop, you can use
Khronos OpenGL ES 2.0 PC-emulation libraries from www.imgtec.com:
http://www.imgtec.com/powervr/insider/sdkdownloads/index.asp#GLES2

The Qt GameEnabler QML Audio Test example compiles and runs also on platforms
without OpenGL ES 2.0 support.

4.2 Using the Qt SDK
--------------------

You can install and run the application on the device by using the Qt SDK.
Open the project in the SDK, set up the correct target (depending on the device
platform), and click the Run button. For more details about this approach,
visit the Qt Getting Started section at Nokia Developer
(http://www.developer.nokia.com/Develop/Qt/Getting_started/).

4.3 Symbian device
------------------

Make sure your device is connected to your computer. Locate the .sis
installation file and open it with Ovi Suite. Accept all requests from Ovi
Suite and the device. Note that you can also install the application by copying
the installation file onto your device and opening it with the Symbian File
Manager application.

After the application is installed, locate the application icon from the
application menu and launch the application by tapping the icon.

4.4 Nokia N9 and Nokia N950
---------------------------

Copy the application Debian package onto the device. Locate the file with the
device and run it; this will install the application. Note that you can also
use the terminal application and install the application by typing the command
'dpkg -i <package name>.deb' on the command line. To install the application
using the terminal application, make sure you have the right privileges
to do so (e.g. root access).

Once the application is installed, locate the application icon from the
application menu and launch the application by tapping the icon.

4.5 Desktop computers
---------------------------

Select a desktop target. Modify the qtgameenabler.pri file's according
section's GLES2 include and library  paths according to where you have
installed the GLES Emulation SDK:
   'INCLUDEPATH += /PowerVRSDK/Builds/OGLES2/Include' and
   'LIBS +=  -L/PowerVRSDK/Builds/OGLES2/WindowsPC/Lib' must point to valid
   locations.

5. License
-------------------------------------------------------------------------------

See the license text file delivered with this project. The license file is also
available online at
http://projects.developer.nokia.com/<identifier>/browser/trunk/Licence.txt

OpenGL is a registered trademark and the OpenGL ES logo is a trademark of
Silicon Graphics Inc. used by permission by Khronos (http://www.khronos.org/).

6. Related documentation
-------------------------------------------------------------------------------
Qt GameEnabler wiki:
- http://projects.developer.nokia.com/qtgameenabler/wiki
- http://projects.developer.nokia.com/qtgameenabler/wiki/graphics
- http://projects.developer.nokia.com/qtgameenabler/wiki/audio
- http://projects.developer.nokia.com/qtgameenabler/wiki/audio_qml
- http://projects.developer.nokia.com/qtgameenabler/wiki/examples

7. Version history
-------------------------------------------------------------------------------

2.1     Built-in OGG support. New documentation.
2.0     Various improvements, QML audio plug-in implementation, and two new
        examples
1.1     Added MeeGo 1.2 Harmattan support
1.0.2   Minor modifications related to Symbian audio handling
1.0.1   Added Debian packaging files for Maemo target
1.0     First version


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#include "audiobuffer.h"

#include <QFile>
#include <stdlib.h>

#include "audiobufferplayinstance.h"
#include "audiomixer.h"
#include "trace.h"
#ifdef QTGAMEENABLER_SUPPORT_OGG_VORBIS
#include "vorbisdecoder.h"
#endif // QTGAMEENABLER_SUPPORT_OGG_VORBIS

using namespace GE;

/*!
  Header for wav data
*/
struct SWavHeader {
    char chunkID[4];
    unsigned int chunkSize;
    char format[4];

    unsigned char subchunk1id[4];
    unsigned int subchunk1size;
    unsigned short audioFormat;
    unsigned short nofChannels;
    unsigned int sampleRate;
    unsigned int byteRate;

    unsigned short blockAlign;
    unsigned short bitsPerSample;

    unsigned char subchunk2id[4];
    unsigned int subchunk2size;
};

/*!
 * \class AudioBuffer
 * \brief A class to hold audio information (a buffer).
 */

/*!
  Constructor.
*/
AudioBuffer::AudioBuffer(QObject *parent)
    : QObject(parent),
      m_sampleFunction(NULL),
      m_data(NULL),
      m_dataLength(0),
      m_nofChannels(0),
      m_bitsPerSample(0),
      m_signedData(false),
      m_samplesPerSec(0)
{
    DEBUG_INFO(this);
}

/*!
  Destructor.
*/
AudioBuffer::~AudioBuffer()
{
    // Deallocate the data.
    reallocate(0);
}

/*!
  (Re)allocates the audio buffer according to \a length.
*/
void AudioBuffer::reallocate(int length)
{
    if (m_data)
        delete [] ((char*)m_data);

    m_dataLength = length;

    if (m_dataLength > 0)
        m_data = new char[m_dataLength];
    else
        m_data = 0;
}

/*!
  Loads a .wav or .ogg file. Can be used for loading from Qt resources as well.
  If \a parent is given, it is set as the parent of the constructed buffer.

  Returns a new buffer if successful, NULL otherwise.
*/
AudioBuffer *AudioBuffer::load(QString fileName, QObject *parent)
{
    AudioBuffer *buffer;

    buffer = AudioBuffer::loadWav(fileName, parent);
    if (!buffer) {
        DEBUG_INFO("Trying to load the file as an ogg file");
        buffer = AudioBuffer::loadOgg(fileName, parent);
    }
    return buffer;
}

/*!
  Loads a .wav file from file with \a fileName. Note that this method can be
  used for loading .wav from Qt resources as well. If \a parent is given, it
  is set as the parent of the constructed buffer.

  Returns a new buffer if successful, NULL otherwise.
*/
AudioBuffer *AudioBuffer::loadWav(QString fileName, QObject *parent)
{
    QFile wavFile(fileName);

    if (wavFile.open(QIODevice::ReadOnly)) {
        AudioBuffer *buffer = loadWav(wavFile, parent);

        if (!buffer)
            DEBUG_INFO("Failed to load data from " << fileName << "!");

        wavFile.close();
        return buffer;
    }

    DEBUG_INFO("Failed to open " << fileName << ": " << wavFile.errorString());
    return NULL;
}

/*!
  Loads a .ogg file from file with \a fileName. Note that this method can be
  used for loading .ogg from Qt resources as well. If \a parent is given, it
  is set as the parent of the constructed buffer.

  Returns a new buffer if successful, NULL otherwise.
*/
AudioBuffer *AudioBuffer::loadOgg(QString fileName, QObject *parent)
{
    AudioBuffer *buffer = new AudioBuffer(parent);

    if (!buffer->readOgg(fileName)) {
        DEBUG_INFO("Failed to read ogg file:" << fileName);
        delete buffer;
        return NULL;
    }
    return buffer;
}

/*!
  Protected method, called from AudioBuffer::loadWav(QString, QObject*).

  Loads a .wav file from a preopened \a wavFile. If \a parent is given, it is
  set as the parent of the constructed buffer.

  Returns a new buffer if successful, NULL otherwise.
*/
AudioBuffer *AudioBuffer::loadWav(QFile &wavFile, QObject *parent)
{
    if (!wavFile.isOpen()) {
        // The file is not open!
        DEBUG_INFO("The given file must be opened before calling this method!");
        return NULL;
    }

    SWavHeader header;

    wavFile.read(header.chunkID, 4);

    if (header.chunkID[0] != 'R' || header.chunkID[1] != 'I' ||
        header.chunkID[2] != 'F' || header.chunkID[3] != 'F') {
        // Incorrect header
        return NULL;
    }

    wavFile.read((char*)&header.chunkSize, 4);
    wavFile.read((char*)&header.format, 4);

    if (header.format[0] != 'W' || header.format[1] != 'A' ||
        header.format[2] != 'V' || header.format[3] != 'E') {
        // Incorrect header
        return NULL;
    }

    wavFile.read((char*)&header.subchunk1id, 4);

    if (header.subchunk1id[0] != 'f' || header.subchunk1id[1] != 'm' ||
        header.subchunk1id[2] != 't' || header.subchunk1id[3] != ' ') {
        // Incorrect header
        return NULL;
    }

    wavFile.read((char*)&header.subchunk1size, 4);
    wavFile.read((char*)&header.audioFormat, 2);
    wavFile.read((char*)&header.nofChannels, 2);
    wavFile.read((char*)&header.sampleRate, 4);
    wavFile.read((char*)&header.byteRate, 4);
    wavFile.read((char*)&header.blockAlign, 2);
    wavFile.read((char*)&header.bitsPerSample, 2);

    while (1) {
        if (wavFile.read((char*)&header.subchunk2id, 4) != 4)
            return NULL;

        if (wavFile.read((char*)&header.subchunk2size, 4) != 4)
            return NULL;

        if (header.subchunk2id[0] == 'd' && header.subchunk2id[1] == 'a' &&
            header.subchunk2id[2] == 't' && header.subchunk2id[3] == 'a') {
            // Found the data chunk.
            break;
        }

        // This was not the data-chunk. Skip it.
        if (header.subchunk2size < 1) {
            // Error in file!
            return NULL;
        }

        char *unused = new char[header.subchunk2size];
        wavFile.read(unused, header.subchunk2size);
        delete [] unused;
    }

    // The data follows.
    if (header.subchunk2size < 1)
        return NULL;

    // Construct the buffer.
    AudioBuffer *buffer = new AudioBuffer(parent);

    buffer->m_nofChannels = header.nofChannels;
    buffer->m_bitsPerSample = header.bitsPerSample;
    buffer->m_samplesPerSec = header.sampleRate;
    buffer->m_signedData = 0; // Where to look for this?
    buffer->reallocate(header.subchunk2size);

    wavFile.read((char*)buffer->m_data, header.subchunk2size);

    // Select a good sampling function.
    if (!setSampleFunction(*buffer)) {
        // Failed to resolve the sample function!
        delete buffer;
        return NULL;
    }

    return buffer;
}

/*!
  Protected method, called from AudioBuffer::loadOgg(QString, QObject*).

  Decodes an entire .ogg file into memory.

  Returns true if if successful.
*/
bool AudioBuffer::readOgg(QString &oggFile)
{
#ifdef QTGAMEENABLER_SUPPORT_OGG_VORBIS
    VorbisDecoder decoder(false, this);

    if (!decoder.load(oggFile))
        return false;

    const stb_vorbis_info *info = decoder.fileInfo();
    m_nofChannels = info->channels;
    m_bitsPerSample = 16;
    m_samplesPerSec = info->sample_rate;
    m_signedData = 0;
    setSampleFunction(*this);

    unsigned int len;
    m_data = decoder.decodeAll(&len);
    if (!m_data)
        return false;

    m_dataLength = len;
    return true;
#else
    return false;
#endif
}

// Mix to  mono versions.

AUDIO_SAMPLE_TYPE AudioBuffer::sampleFunction8bitMono(AudioBuffer *buffer,
                                                      int pos,
                                                      int channel)
{
    Q_UNUSED(channel);
    return (AUDIO_SAMPLE_TYPE)(((quint8*)(buffer->m_data))[pos] - 128) << 8;
}

AUDIO_SAMPLE_TYPE AudioBuffer::sampleFunction16bitMono(AudioBuffer *buffer,
                                                        int pos,
                                                        int channel)
{
    Q_UNUSED(channel);
    return (AUDIO_SAMPLE_TYPE)(((quint16*)(buffer->m_data))[pos]);
}

AUDIO_SAMPLE_TYPE AudioBuffer::sampleFunction32bitMono(AudioBuffer *buffer,
                                                        int pos,
                                                        int channel)
{
    Q_UNUSED(channel); // To prevent compiler warnings.
    return (((float*)(buffer->m_data))[pos * buffer->m_nofChannels]) * 65536.0f / 2.0f;
}

// Mix to stereo versions.

AUDIO_SAMPLE_TYPE AudioBuffer::sampleFunction8bitStereo(AudioBuffer *buffer,
                                                         int pos,
                                                         int channel)
{
    return ((AUDIO_SAMPLE_TYPE)
        (((quint8*)(buffer->m_data))[pos * buffer->m_nofChannels + channel]) << 8);
}

AUDIO_SAMPLE_TYPE AudioBuffer::sampleFunction16bitStereo(AudioBuffer *buffer,
                                                          int pos,
                                                          int channel)
{
    return (AUDIO_SAMPLE_TYPE)
        (((quint16*)(buffer->m_data))[pos * buffer->m_nofChannels + channel]);
}

AUDIO_SAMPLE_TYPE AudioBuffer::sampleFunction32bitStereo(AudioBuffer *buffer,
                                                          int pos,
                                                          int channel)
{
    return (((float*)(buffer->m_data))[pos * buffer->m_nofChannels +
            channel]) * 65536.0f / 2.0f;
}

/*!
  Constructs a new play instance and sets it as an audio source for \a mixer.
  Note that the mixer takes ownership of the constructed instance.
  Returns the constructed instance or NULL in case the mixer refused to add
  the instance.
*/
AudioBufferPlayInstance *AudioBuffer::playWithMixer(AudioMixer &mixer)
{
    AudioBufferPlayInstance *instance = new AudioBufferPlayInstance(this);

    if (!mixer.addAudioSource(instance)) {
        DEBUG_INFO("Failed to add the new audio source to mixer!");
        delete instance;
        return NULL;
    }

    return instance;
}

/*!
  Sets an appropriate sample function for \a buffer depending on the number of
  channels and the bit rate.

  Returns true if successful, false otherwise.
*/
bool AudioBuffer::setSampleFunction(AudioBuffer &buffer)
{
    buffer.m_sampleFunction = 0;

    if (buffer.m_nofChannels == 1) {
        if (buffer.m_bitsPerSample == 8)
            buffer.m_sampleFunction = sampleFunction8bitMono;

        if (buffer.m_bitsPerSample == 16)
            buffer.m_sampleFunction = sampleFunction16bitMono;

        if (buffer.m_bitsPerSample == 32)
            buffer.m_sampleFunction = sampleFunction32bitMono;
    } else {
        if (buffer.m_bitsPerSample == 8)
            buffer.m_sampleFunction = sampleFunction8bitStereo;

        if (buffer.m_bitsPerSample == 16)
            buffer.m_sampleFunction = sampleFunction16bitStereo;

        if (buffer.m_bitsPerSample == 32)
            buffer.m_sampleFunction = sampleFunction32bitStereo;
    }

    if (!buffer.m_sampleFunction) {
        // Unknown bit rate!
        DEBUG_INFO("Unknown bit rate:" << buffer.m_bitsPerSample);
        return false;
    }

    return true;
}


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#ifndef GEAUDIOBUFFER_H
#define GEAUDIOBUFFER_H

#include "geglobal.h"
#include "audiosourceif.h"

// Forward declarations
class QFile;

namespace GE {

// Forward declarations (inside GE namespace)
class AudioBuffer;
class AudioBufferPlayInstance;
class AudioMixer;

// Prototype function for audio sampling
typedef AUDIO_SAMPLE_TYPE(*SAMPLE_FUNCTION_TYPE)(AudioBuffer *buffer,
                                                 int pos,
                                                 int channel);

class Q_GE_EXPORT AudioBuffer : public QObject
{
    Q_OBJECT

public:
    explicit AudioBuffer(QObject *parent = 0);
    virtual ~AudioBuffer();
    static AudioBuffer *load(QString fileName, QObject *parent = 0);
    static AudioBuffer *loadWav(QString fileName, QObject *parent = 0);
    static AudioBuffer *loadOgg(QString fileName, QObject *parent = 0);

public:
    void reallocate(int length);

    // Getters for raw sample data and sample details
    inline void* getRawData() { return m_data; }
    inline int getDataLength() { return m_dataLength; }
    inline int getBytesPerSample() { return (m_bitsPerSample >> 3); }
    inline int getBitsPerSample() { return m_bitsPerSample; }
    inline int getSamplesPerSec() { return m_samplesPerSec; }
    inline short getNofChannels() { return m_nofChannels; }
    inline SAMPLE_FUNCTION_TYPE getSampleFunction() { return m_sampleFunction; }

    // Static implementations of sample functions
    static AUDIO_SAMPLE_TYPE sampleFunction8bitMono(
        AudioBuffer *buffer, int pos, int channel);
    static AUDIO_SAMPLE_TYPE sampleFunction16bitMono(
        AudioBuffer *buffer, int pos, int channel);
    static AUDIO_SAMPLE_TYPE sampleFunction32bitMono(
        AudioBuffer *buffer, int pos, int channel);
    static AUDIO_SAMPLE_TYPE sampleFunction8bitStereo(
        AudioBuffer *buffer, int pos, int channel);
    static AUDIO_SAMPLE_TYPE sampleFunction16bitStereo(
        AudioBuffer *buffer, int pos, int channel);
    static AUDIO_SAMPLE_TYPE sampleFunction32bitStereo(
        AudioBuffer *buffer, int pos, int channel);

    AudioBufferPlayInstance *playWithMixer(GE::AudioMixer &mixer);

protected:
    static AudioBuffer *loadWav(QFile &wavFile, QObject *parent = 0);
    static bool setSampleFunction(AudioBuffer &buffer);

    bool readOgg(QString &fileName);

protected: // Data
    SAMPLE_FUNCTION_TYPE m_sampleFunction;
    void *m_data; // Owned
    int m_dataLength; // In bytes
    short m_nofChannels;
    short m_bitsPerSample;
    bool m_signedData;
    int m_samplesPerSec;
};

} // namespace GE

#endif // GEAUDIOBUFFER_H


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#include "audiobufferplayinstance.h"
#include "audiobuffer.h"
#include "audioeffect.h"
#include "trace.h"

using namespace GE;

// Constants
const float GEMaxAudioSpeedValue(4096.0f);
const float GEDefaultAudioVolume(1.0f); // 1.0 => 100 %
const float GEDefaultAudioSpeed(1.0f); // 1.0 => 100 %

/*!
 * \class AudioBufferPlayInstance
 * \brief An AudioSource instance capable of playing a single audio buffer.
 */

/*!
  Constructor. If \a buffer is not NULL, it is set as the buffer to play.
*/
AudioBufferPlayInstance::AudioBufferPlayInstance(AudioBuffer *buffer /* = 0 */,
                                                 QObject *parent /* = 0 */)
    : AudioSource(parent),
      m_buffer(0),
      m_effect(0),
      m_finished(false),
      m_destroyWhenFinished(true),
      m_paused(false),
      m_fixedPos(0),
      m_fixedInc(0),
      m_fixedLeftVolume((int)GEMaxAudioVolumeValue),
      m_fixedRightVolume((int)GEMaxAudioVolumeValue),
      m_loopCount(0)
{
    DEBUG_POINT;
    if (buffer) {
        // Start playing the given buffer.
        playBuffer(buffer, GEDefaultAudioVolume, GEDefaultAudioSpeed);
    }
}

/*!
  Destructor.
*/
AudioBufferPlayInstance::~AudioBufferPlayInstance()
{
    DEBUG_POINT;
}

/*!
  Returns true if the buffer is set, false otherwise.
*/
bool AudioBufferPlayInstance::isPlaying() const
{
    if (!m_buffer.isNull())
        return true;

    return false;
}

/*!
  From AudioSource.

  The framework will use this to know whether this AudioSource can be
  destroyed or not.
*/
bool AudioBufferPlayInstance::canBeDestroyed()
{
    if (m_finished && m_destroyWhenFinished)
        return true;

    return false;
}

/*!
  From AudioSource.

  Returns an audio stream from the current sample.
*/
int AudioBufferPlayInstance::pullAudio(AUDIO_SAMPLE_TYPE *target,
                                       int bufferLength)
{
    if (m_buffer.isNull() || m_paused) {
        return 0;
    }

    unsigned int divider(m_buffer->getNofChannels() * m_buffer->getBytesPerSample());
    unsigned int channelLength(0);

    // Check in case of division by zero.
    if (divider) {
        channelLength = m_buffer->getDataLength() / divider - 2;
    }
    else {
        DEBUG_INFO("Warning: Catched division by zero error!");
    }

    unsigned int samplesToWrite(bufferLength / 2);
    unsigned int amount(0);
    unsigned int totalMixed(0);

    while (samplesToWrite > 0) {
        unsigned int samplesLeft;

        if (m_fixedInc == 0) {
            // No speed set. Will lead to division by zero error if not set.
            setSpeed(GEDefaultAudioSpeed);
        }

        samplesLeft = m_fixedInc > 0 ? channelLength - (m_fixedPos >> 12) :
            (m_fixedPos >> 12);

        // This is how much we can mix at least.
        unsigned int maxMixAmount = (int)(((long long int)(samplesLeft) << 12) /
                                 qAbs(m_fixedInc));

        if (maxMixAmount > samplesToWrite) {
            maxMixAmount = samplesToWrite;
        }

        if (maxMixAmount > 0) {
            amount = mixBlock(target+totalMixed * 2, maxMixAmount);

            if (amount == 0) {
                // Error!
                break;
            }

            totalMixed += amount;
        }
        else {
            amount = 0;
            m_fixedPos = m_fixedInc > 0 ? channelLength<<12 : 0;
        }

        // The sample ended. Check the looping variables and see what to do.
        if ((m_fixedPos >> 12) >= channelLength || m_fixedPos <= 0) {
            m_fixedPos += m_fixedInc > 0 ? -((qint64)channelLength << 12) :
                ((qint64)channelLength << 12);
            if (m_loopCount > 0)
                m_loopCount--;

            if (m_loopCount == 0) {
                // No more loops, stop the sample and return the amount of
                // samples already mixed.
                stop();
                break;
            }
        }

        samplesToWrite -= amount;

        if (samplesToWrite < 1)
            break;
    }

    if (!m_effect.isNull())
        return m_effect->process(target, totalMixed * 2);

    return totalMixed * 2;
}

/*!
  Sets \a buffer as the audio buffer and will repeat the buffer according to
  \a loopCount. Note: If the given loop count is -1, the buffer will be
  repeated forever.
*/
void AudioBufferPlayInstance::playBuffer(AudioBuffer *buffer,
                                         int loopCount /* = 0 */)
{
    m_buffer = buffer;
    m_loopCount = loopCount;
    m_fixedPos = 0;
}

/*!
  For convenience.

  In addition to playBuffer(AudioBuffer*, int) method, will also set \a volume
  and \a speed.
*/
void AudioBufferPlayInstance::playBuffer(AudioBuffer *buffer,
                                         float volume,
                                         float speed,
                                         int loopCount /* = 0 */)
{
    setLeftVolume(volume);
    m_fixedRightVolume = m_fixedLeftVolume;
    setSpeed(speed);
    playBuffer(buffer, loopCount);
}

/*!
  Resets the local buffer i.e. gets rid of the set buffer.
*/
void AudioBufferPlayInstance::stop()
{
    m_buffer = 0;
    m_finished = true;
    emit finished();
}

/*!
  Sets the loop count to \a count. If the argument value is -1, the
  buffer is looped forever.
*/
void AudioBufferPlayInstance::setLoopCount(int count)
{
    DEBUG_INFO("Setting the loop count to " << count);
    m_loopCount = count;
}

/*!
  Sets \a speed as the speed of which the buffer is played in. The given
  argument value should not be zero. 1.0 indicates 100 % forward speed, -1.0
  100 % reverse speed.
*/
void AudioBufferPlayInstance::setSpeed(float speed)
{
    if (m_buffer.isNull())
        return;

    m_fixedInc = (int)(((float)m_buffer->getSamplesPerSec() *
        GEMaxAudioSpeedValue * speed) / (float)AUDIO_FREQUENCY);

    if (!m_fixedInc)
        m_fixedInc = 1;
}

/*
  Sets playback position to given value. The given argument is in units of PCM
  audio samples per channel. 0 indicates beginning of the buffer and -1 the
  end of the buffer.
*/
void AudioBufferPlayInstance::seek(unsigned int samplePos)
{
    if (m_buffer.isNull())
        return;

    const unsigned int channelLength = m_buffer->getDataLength() /
        m_buffer->getNofChannels() * m_buffer->getBytesPerSample();

    if (samplePos > channelLength)
        samplePos = channelLength;
#ifdef QTGAMEENABLER_SUPPORT_LONG_SAMPLES
    m_fixedPos = (quint64)samplePos << 12;
#else
    m_fixedPos = samplePos << 12;
#endif
}

/*
  Return the current playback position in units of PCM audio samples per
  channel.
*/
unsigned int AudioBufferPlayInstance::position()
{
    if (m_buffer.isNull())
        return 0;

    return (m_fixedPos >> 12);
}

/*!
  Sets \a volume for the left channel. The given argument value should be
  between 0.0 and 1.0 since 1.0 indicates 100 %.
*/
void AudioBufferPlayInstance::setLeftVolume(float volume)
{
    m_fixedLeftVolume = (int)(GEMaxAudioVolumeValue * volume);
}

/*!
  Sets \a volume for the right channel. The given argument value should be
  between 0.0 and 1.0 since 1.0 indicates 100 %.
*/
void AudioBufferPlayInstance::setRightVolume(float volume)
{
    m_fixedRightVolume = (int)(GEMaxAudioVolumeValue * volume);
}

/*!
  TODO: Document this method.

  Note: Does not do any bound checking, must be checked before called!
*/
int AudioBufferPlayInstance::mixBlock(AUDIO_SAMPLE_TYPE *target,
                                      int samplesToMix)
{
    SAMPLE_FUNCTION_TYPE sampleFunction = m_buffer->getSampleFunction();

    if (!sampleFunction) {
        // Unsupported sample type.
        return 0;
    }

    AUDIO_SAMPLE_TYPE *t_target = target + samplesToMix * 2;
    unsigned int sourcepos(0);

    if (m_buffer->getNofChannels() == 2) {
        // Stereo
        while (target != t_target) {
            sourcepos = m_fixedPos >> 12;

            target[0] = (((((sampleFunction)
                            (m_buffer, sourcepos, 0) *
                            (4096 - (m_fixedPos & 4095)) +
                            (sampleFunction)(m_buffer, sourcepos + 1, 0) *
                            (m_fixedPos & 4095)) >> 12) *
                          m_fixedLeftVolume) >> 12);

            target[1] = (((((sampleFunction)
                            (m_buffer, sourcepos, 1) *
                            (4096 - (m_fixedPos & 4095)) +
                            (sampleFunction)(m_buffer, sourcepos + 1, 1) *
                            (m_fixedPos & 4095) ) >> 12) *
                          m_fixedRightVolume) >> 12);

            m_fixedPos += m_fixedInc;
            target += 2;
        }
    }
    else {
        // Mono
        int temp(0);

        while (target != t_target) {
            sourcepos = m_fixedPos >> 12;

            temp = (((sampleFunction)(m_buffer, sourcepos, 0 ) *
                     (4096 - (m_fixedPos & 4095)) +
                     (sampleFunction)(m_buffer, sourcepos + 1, 0) *
                     (m_fixedPos & 4095)) >> 12);

            target[0] = ((temp * m_fixedLeftVolume) >> 12);
            target[1] = ((temp * m_fixedRightVolume) >> 12);

            m_fixedPos += m_fixedInc;
            target += 2;
        }
    }

    return samplesToMix;
}


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#ifndef GEAUDIOBUFFERPLAYINSTANCE_H
#define GEAUDIOBUFFERPLAYINSTANCE_H

#include <QPointer>
#include "geglobal.h"
#include "audiosourceif.h"
#include "audioeffect.h"

namespace GE {

// Forward declarations
class AudioBuffer;

class Q_GE_EXPORT AudioBufferPlayInstance : public AudioSource
{
    Q_OBJECT

public:
    AudioBufferPlayInstance(AudioBuffer *buffer = 0, QObject *parent = 0);
    virtual ~AudioBufferPlayInstance();

public:
    bool isPlaying() const;
    inline bool isFinished() const { return m_finished; }
    inline void setDestroyWhenFinished(bool set) { m_destroyWhenFinished = set; }
    inline bool destroyWhenFinished() const { return m_destroyWhenFinished; }

public: // From AudioSource
    bool canBeDestroyed();
    int pullAudio(AUDIO_SAMPLE_TYPE *target, int bufferLength);

public slots:
    void playBuffer(AudioBuffer *buffer, int loopCount = 0);
    void playBuffer(AudioBuffer *buffer,
                    float volume,
                    float speed,
                    int loopCount = 0);
    void stop();
    void setLoopCount(int count);
    void setSpeed(float speed);
    void seek(unsigned int samplePos);
    unsigned int position();
    void setLeftVolume(float volume);
    void setRightVolume(float volume);
    float leftVolume() { return m_fixedLeftVolume / 4096.0f; }
    float rightVolume() { return m_fixedRightVolume / 4096.0f; }
    void setEffect(AudioEffect *effect) { m_effect = effect; }
    void pause() { m_paused = true; }
    void resume() { m_paused = false; }

protected:
    int mixBlock(AUDIO_SAMPLE_TYPE *target, int bufferLength);

signals:
    void finished();

protected: // Data
    QPointer<AudioBuffer> m_buffer; // Not owned
    QPointer<AudioEffect> m_effect; // Not owned
    bool m_finished;
    bool m_destroyWhenFinished;
    bool m_paused;
#ifdef QTGAMEENABLER_SUPPORT_LONG_SAMPLES
    quint64 m_fixedPos;
#else
    unsigned int m_fixedPos;
#endif
    int m_fixedInc;
    int m_fixedLeftVolume;
    int m_fixedRightVolume;
    int m_loopCount;
};

} // namespace GE

#endif // GEAUDIOBUFFERPLAYINSTANCE_H


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#include "audioeffect.h"
#include "trace.h"

using namespace GE;

AudioEffect::AudioEffect(QObject *parent)
    : QObject(parent),
      m_next(NULL)
{
    DEBUG_INFO(this);
}

AudioEffect::~AudioEffect()
{
    DEBUG_POINT;
}

AudioEffect *AudioEffect::next()
{
    return m_next;
}

void AudioEffect::linkTo(AudioEffect *next)
{
    DEBUG_POINT;

    if (!m_next.isNull()) {
        m_next->linkTo(next);
        return;
    }

   m_next = next;
}

void AudioEffect::flush()
{
    if (!m_next.isNull())
        m_next->flush();
}

int AudioEffect::process(AUDIO_SAMPLE_TYPE *target, int bufferLength)
{
    if (!m_next.isNull())
        bufferLength = m_next->process(target, bufferLength);

    return bufferLength;
}


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#ifndef AUDIOEFFECT_H
#define AUDIOEFFECT_H

#include <QObject>
#include <QPointer>
#include "geglobal.h"
#include "audiosourceif.h"
#include "audiobuffer.h"

namespace GE {

class Q_GE_EXPORT AudioEffect : public QObject
{
    Q_OBJECT

public:
    explicit AudioEffect(QObject *parent = 0);
    virtual ~AudioEffect();

    AudioEffect *next();
    void linkTo(AudioEffect *next);

public:
    virtual void flush();
    virtual int process(AUDIO_SAMPLE_TYPE *target, int bufferLength);

protected:
    QPointer<GE::AudioEffect> m_next; // Not owned
};

} // namespace GE

#endif // AUDIOEFFECT_H


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#include "audiomixer.h"
#include <memory.h>
#include "trace.h" // For debug macros

using namespace GE;

/*!
  \class AudioMixer
  \brief An AudioSource capable of combining all of its child sources into
         a single audio stream.
*/

/*!
  Constructor.
*/
AudioMixer::AudioMixer(QObject *parent)
    : AudioSource(parent),
      m_mixingBuffer(0),
      m_effect(0),
      m_mixingBufferLength(0),
      m_fixedGeneralVolume((int)GEMaxAudioVolumeValue)
{
    DEBUG_INFO(this);
}

/*!
  Destructor.
*/
AudioMixer::~AudioMixer()
{
    destroyList();

    if (m_mixingBuffer) {
        delete [] m_mixingBuffer;
        m_mixingBuffer = 0;
    }
}

/*!
  Returns the absolute volume.
*/
float AudioMixer::absoluteVolume() const
{
    return (float)m_fixedGeneralVolume / 4096.0f;
}

/*!
  Returns the general volume.
*/
float AudioMixer::generalVolume()
{
    return (float)m_fixedGeneralVolume *
           (float)audioSourceCount() / GEMaxAudioVolumeValue;
}

/*!
  Adds \a source to the list of audio sources. Returns true if the given audio
  source was added into the list, false otherwise.
*/
bool AudioMixer::addAudioSource(AudioSource *source)
{
    if (!source) {
        // Invalid argument!
        DEBUG_INFO("The given source is NULL!");
        return false;
    }

    QMutexLocker locker(&m_mutex);
    Q_UNUSED(locker); // To prevent warnings.
    m_sourceList.push_back(source);
    return true;
}

/*!
  Removes \a source from the list of audio sources. Returns true if
  found and removed, false otherwise.

  Note: The removed item is not deleted!
*/
bool AudioMixer::removeAudioSource(AudioSource *source)
{
    QMutexLocker locker(&m_mutex);
    Q_UNUSED(locker); // To prevent warnings
    return m_sourceList.removeOne(source);
}

/*!
  Destroys all the sources in the list.
*/
void AudioMixer::destroyList()
{
    QMutexLocker locker(&m_mutex);
    Q_UNUSED(locker); // To prevent warnings

    QList<AudioSource*>::iterator iter;

    for (iter = m_sourceList.begin(); iter != m_sourceList.end(); iter++) {
        delete *iter;
    }

    m_sourceList.clear();
}

/*!
  Returns the audio source list count.
*/
int AudioMixer::audioSourceCount()
{
    QMutexLocker locker(&m_mutex);
    Q_UNUSED(locker); // To prevent warnings
    return m_sourceList.count();
}

/*!
  From AudioSource.

  Mix the requested amount of samples from all mixer's audiosources
  into a single buffer.
*/
int AudioMixer::pullAudio(AUDIO_SAMPLE_TYPE *target, int bufferLength)
{
    QMutexLocker locker(&m_mutex);
    Q_UNUSED(locker); // To prevent warnings

    if ((m_sourceList.isEmpty() && m_effect.isNull())
             || bufferLength <= 0) {
        return 0;
    }

    if (m_mixingBufferLength < bufferLength) {
        if (m_mixingBuffer) {
            delete [] m_mixingBuffer;
        }

        m_mixingBufferLength = bufferLength;
        m_mixingBuffer = new AUDIO_SAMPLE_TYPE[m_mixingBufferLength];
    }

    memset(target, 0, sizeof(AUDIO_SAMPLE_TYPE) * bufferLength);

    AUDIO_SAMPLE_TYPE *t;
    AUDIO_SAMPLE_TYPE *t_target;
    AUDIO_SAMPLE_TYPE *s;

    QList<AudioSource*>::iterator iter(m_sourceList.begin());

    while (iter != m_sourceList.end()) {
        if (!(*iter)) {
            // NULL pointer!
            DEBUG_INFO("Warning: stumbled on a null pointer!");
            continue;
        }

        // Process the list item.
        int mixed = (*iter)->pullAudio(m_mixingBuffer, bufferLength);

        if (mixed > 0) {
            // Mix to main.
            t = target;
            t_target = t + mixed;
            s = m_mixingBuffer;

            while (t != t_target) {
                *t += (((*s) * m_fixedGeneralVolume) >> 12);
                t++;
                s++;
            }
        }

        if ((*iter)->canBeDestroyed()) {
            // Auto-destroy the current audio source.
            //
            // Note: The auto-destroy feature is undergoing testing and may
            // cause unpredictable crashes with some use cases!
            delete *iter;
            iter = m_sourceList.erase(iter);
        }
        else {
            iter++;
        }
    }

    if (!m_effect.isNull()) {
        return m_effect->process(target, bufferLength);
    }

    //DEBUG_INFO("Done, will return buffer length: " << bufferLength);
    return bufferLength;
}

/*!
  Sets \a volume as the absolute volume.
*/
void AudioMixer::setAbsoluteVolume(float volume)
{
    DEBUG_INFO(volume);
    m_fixedGeneralVolume = GEMaxAudioVolumeValue * volume;
    emit absoluteVolumeChanged(m_fixedGeneralVolume);
}

/*!
  Sets \a volume as the general volume, relative to the channel count
  (audio source count).
*/
void AudioMixer::setGeneralVolume(float volume)
{
    const int sourceCount(audioSourceCount());

    DEBUG_INFO(volume);

    // Safety checks for possible division by zero error.
    if (volume == 0) {
        m_fixedGeneralVolume = 0.0f;
    }
    else if (sourceCount) {
        m_fixedGeneralVolume =
            (GEMaxAudioVolumeValue / (float)audioSourceCount() * volume);
    }

    emit generalVolumeChanged(m_fixedGeneralVolume);
}


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#ifndef GEAUDIOMIXER_H
#define GEAUDIOMIXER_H

#include <QMutex>
#include "geglobal.h"
#include "audiosourceif.h"
#include "audioeffect.h"

namespace GE {

class Q_GE_EXPORT AudioMixer : public AudioSource
{
    Q_OBJECT

public:
    explicit AudioMixer(QObject *parent = 0);
    virtual ~AudioMixer();

public:
    float absoluteVolume() const;
    float generalVolume();
    bool addAudioSource(AudioSource *source);
    bool removeAudioSource(AudioSource *source);
    void destroyList();
    int audioSourceCount();
    void setEffect(AudioEffect *effect) { m_effect = effect; }

public: // From AudioSource
    int pullAudio(AUDIO_SAMPLE_TYPE *target, int bufferLength);

public slots:
    void setAbsoluteVolume(float volume);
    void setGeneralVolume(float volume);

signals:
    void absoluteVolumeChanged(float volume);
    void generalVolumeChanged(float volume);

protected: // Data
    QList<AudioSource*> m_sourceList; // Owned
    AUDIO_SAMPLE_TYPE *m_mixingBuffer; // Owned
    QPointer<AudioEffect> m_effect; // Not owned
    QMutex m_mutex;
    int m_mixingBufferLength;
    int m_fixedGeneralVolume;
};

} // namespace GE

#endif // GEAUDIOMIXER_H


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#ifndef GEAUDIOOUT_H
#define GEAUDIOOUT_H

#include <QAudioFormat>
#include "audiosourceif.h"

namespace GE {

const QString GEDefaultAudioCodec("audio/pcm");
const QAudioFormat::Endian GEByteOrder(QAudioFormat::LittleEndian);
const QAudioFormat::SampleType GESampleType(QAudioFormat::SignedInt);

class AudioOut
{
public:
    AudioOut() {}
    virtual ~AudioOut() {}

public:
    virtual bool needsManualTick() const { return false; };
    virtual void tick() {};
};

} // namespace GE

#endif // GEAUDIOOUT_H


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#include "audiosourceif.h"

using namespace GE;

/*!
  \class AudioSource
  \brief An abstract interface for an audio source.
*/

/*!
  Constructor.
*/
AudioSource::AudioSource(QObject *parent /* = 0 */)
    : QObject(parent)
{
}

/*!
  Destructor.
*/
AudioSource::~AudioSource()
{
}

/*!
  This method is used to check whether this instance can be (auto-)destroyed
  or not.

  To be implemented in the derived class. This default implementation always
  returns false.
*/
bool AudioSource::canBeDestroyed()
{
    return false;
}


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#ifndef GEINTERFACES_H
#define GEINTERFACES_H

#include <QObject>

namespace GE {

#define AUDIO_FREQUENCY 22050
#define AUDIO_SAMPLE_TYPE short
#define AUDIO_SAMPLE_BITS 16
#define AUDIO_CHANNELS 2

// Constants
const float GEMaxAudioVolumeValue(4096.0f);

class AudioSource : public QObject
{
    Q_OBJECT

public:
    explicit AudioSource(QObject *parent = 0);
    virtual ~AudioSource();

public:
    virtual bool canBeDestroyed();
    virtual int pullAudio(AUDIO_SAMPLE_TYPE *target, int bufferLength ) = 0;
};

} // namespace GE

#endif // GEINTERFACES_H


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#include "cutoffeffect.h"

#include <QMutexLocker>
#include <math.h>

#include "trace.h"

using namespace GE;

CutOffEffect::CutOffEffect(QObject *parent)
    : AudioEffect(parent),
      m_lp(NULL),
      m_hp(NULL),
      m_bp(NULL)
{
    DEBUG_INFO(this);
    setResonance(1.0f);
    setCutOff(1.0f);
    setup();
}

CutOffEffect::~CutOffEffect()
{
    DEBUG_POINT;
    delete []m_lp;
    delete []m_hp;
    delete []m_bp;
}

void CutOffEffect::setCutOff(float value)
{
    m_cutOff = value;
    m_fixedCutOff = value * 4096.0f;
}

float CutOffEffect::cutOff()
{
    return m_cutOff;
}

void CutOffEffect::setResonance(float value)
{
    m_resonance = value;
    m_fixedResonance = value * 4096.0f;
}

float CutOffEffect::resonance()
{
    return m_resonance;
}

void CutOffEffect::flush()
{
    setup();
    AudioEffect::flush();
}

void CutOffEffect::setup()
{
    QMutexLocker locker(&m_mutex);
    Q_UNUSED(locker);

    delete []m_lp;
    m_lp = new int[AUDIO_CHANNELS];
    memset(m_lp, 0, sizeof(int) * AUDIO_CHANNELS);
    delete []m_bp;
    m_bp = new int[AUDIO_CHANNELS];
    memset(m_bp, 0, sizeof(int) * AUDIO_CHANNELS);
    delete []m_hp;
    m_hp = new int[AUDIO_CHANNELS];
    memset(m_hp, 0, sizeof(int) * AUDIO_CHANNELS);
}

int CutOffEffect::process(AUDIO_SAMPLE_TYPE *target, int bufferLength)
{
    QMutexLocker locker(&m_mutex);
    Q_UNUSED(locker);

    AUDIO_SAMPLE_TYPE *p_max = target + bufferLength;
    AUDIO_SAMPLE_TYPE *p = target;
    int i, input;
    qint64 pos = 0;

    while (p < p_max) {
        for (i = 0; i < AUDIO_CHANNELS; i++) {
            input = ((*p * (2047^(pos & 2047)) +
                    *(p + AUDIO_CHANNELS) *
                    (pos & 2047)) >> 11);
            m_lp[i] += ((m_bp[i] * m_fixedCutOff) >> 12);
            m_hp[i] = input - m_lp[i] - ((m_bp[i] * m_fixedResonance) >> 12);
            m_bp[i] += ((m_hp[i] * m_fixedCutOff) >> 12);

            input = m_lp[i];

            if (input < -32767) {
                input = -32767;
            }

            if (input > 32767) {
                input = 32767;
            }

            *(p++) = input;
        }

        pos += 2048;
    }

    return AudioEffect::process(target, bufferLength);
}


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#ifndef CUTOFFEFFECT_H
#define CUTOFFEFFECT_H

#include <QObject>
#include <QMutex>
#include "geglobal.h"
#include "audioeffect.h"

namespace GE {

class Q_GE_EXPORT CutOffEffect : public AudioEffect
{
    Q_OBJECT

public:
    explicit CutOffEffect(QObject *parent = 0);
    virtual ~CutOffEffect();

    void setCutOff(float value);
    float cutOff();

    void setResonance(float value);
    float resonance();

public:
    void flush();
    int process(AUDIO_SAMPLE_TYPE *target, int bufferLength);

private:
    void setup();

private:
    QMutex m_mutex;
    float m_cutOff;
    int m_fixedCutOff;
    float m_resonance;
    int m_fixedResonance;
    int *m_lp;
    int *m_hp;
    int *m_bp;
};

} // namespace GE

#endif // CUTOFFEFFECT_H


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#include "echoeffect.h"

#include <QMutexLocker>
#include <math.h>

#include "trace.h"

using namespace GE;

EchoEffect::EchoEffect(QObject *parent)
    : AudioEffect(parent),
      m_delayBuffer(NULL)
{
    DEBUG_INFO(this);

    setDelay(1.0f);
    setDecay(1.0f);
    setupBuffer();
}

EchoEffect::~EchoEffect()
{
    delete []m_delayBuffer;
}

void EchoEffect::setDelay(float value)
{
    m_delay = value;
    setupBuffer();
}

float EchoEffect::delay()
{
    return m_delay;
}

void EchoEffect::setDecay(float value)
{
    m_decay = value;
    m_fixedDecay = value * 4096;
}

float EchoEffect::decay()
{
    return m_decay;
}

void EchoEffect::flush()
{
    setupBuffer();
    AudioEffect::flush();
}

void EchoEffect::setupBuffer()
{
    DEBUG_POINT;

    QMutexLocker locker(&m_mutex);
    Q_UNUSED(locker);

    m_delayInSamples = AUDIO_CHANNELS * (int)(AUDIO_FREQUENCY * m_delay);

    DEBUG_INFO("Setting delay to" << m_delayInSamples << "samples");

    delete []m_delayBuffer;
    m_delayBuffer = new AUDIO_SAMPLE_TYPE[m_delayInSamples];
    memset(m_delayBuffer, 0, m_delayInSamples * sizeof(AUDIO_SAMPLE_TYPE));
    m_index = 0;
}

int EchoEffect::process(AUDIO_SAMPLE_TYPE *target, int bufferLength)
{
    QMutexLocker locker(&m_mutex);
    Q_UNUSED(locker);

    if (!m_delayBuffer) {
        setupBuffer();

        if (!m_delayBuffer) {
            return 0;
        }
    }

    AUDIO_SAMPLE_TYPE *max_p = target + bufferLength;
    AUDIO_SAMPLE_TYPE *p = target;

    while (p < max_p) {
        *p += (AUDIO_SAMPLE_TYPE)((int)m_delayBuffer[m_index]
                                  * m_fixedDecay >> 12);
        m_delayBuffer[m_index++] = *p;

        if (m_index >= m_delayInSamples) {
            m_index = 0;
        }

        p++;
    }

    return AudioEffect::process(target, bufferLength);
}


code:
/**
 * Copyright (c) 2011-2012 Nokia Corporation.
 * All rights reserved.
 *
 * Part of the Qt GameEnabler.
 *
 * For the applicable distribution terms see the license text file included in
 * the distribution.
 */

#ifndef ECHOEFFECT_H
#define ECHOEFFECT_H

#include <QObject>
#include <QMutex>
#include "geglobal.h"
#include "audioeffect.h"

namespace GE {

class Q_GE_EXPORT EchoEffect : public AudioEffect
{
    Q_OBJECT

public:
    explicit EchoEffect(QObject *parent = 0);
    virtual ~EchoEffect();

    void setDelay(float value);
    float delay();

    void setDecay(float value);
    float decay();

public:
    void flush();
    int process(AUDIO_SAMPLE_TYPE *target, int bufferLength);

private:
    void setupBuffer();

private:
    QMutex m_mutex;
    AUDIO_SAMPLE_TYPE *m_delayBuffer;
    float m_delay;
    float m_decay;
    int m_fixedDecay;
    int m_delayInSamples;
    int m_index;
};

} // namespace GE

#endif // ECHOEFFECT_H