Added: #1459 Group controllers for sound sources

--HG--
branch : sound_dev
This commit is contained in:
kaetemi 2012-04-10 15:24:35 +02:00
parent 57411c0a7b
commit 0b64102ab8
21 changed files with 510 additions and 103 deletions

View file

@ -204,9 +204,9 @@ public:
* pass a callback function that will be called (if not NULL) just before deleting the spawned * pass a callback function that will be called (if not NULL) just before deleting the spawned
* source. * source.
*/ */
virtual USource *createSource( const NLMISC::TStringId &name, bool spawn=false, TSpawnEndCallback cb=NULL, void *cbUserParam = NULL, NL3D::CCluster *cluster = 0, CSoundContext *context = 0 ); virtual USource *createSource( const NLMISC::TStringId &name, bool spawn=false, TSpawnEndCallback cb=NULL, void *cbUserParam = NULL, NL3D::CCluster *cluster = 0, CSoundContext *context = 0, UGroupController *groupController = NULL);
/// Add a logical sound source (by sound id). To remove a source, just delete it. See createSource(const char*) /// Add a logical sound source (by sound id). To remove a source, just delete it. See createSource(const char*)
virtual USource *createSource( TSoundId id, bool spawn=false, TSpawnEndCallback cb=NULL, void *cbUserParam = NULL, NL3D::CCluster *cluster = 0, CSoundContext *context = 0 ); virtual USource *createSource( TSoundId id, bool spawn=false, TSpawnEndCallback cb=NULL, void *cbUserParam = NULL, NL3D::CCluster *cluster = 0, CSoundContext *context = 0, UGroupController *groupController = NULL);
/// Add a source which was created by an EnvSound /// Add a source which was created by an EnvSound
void addSource( CSourceCommon *source ); void addSource( CSourceCommon *source );
/** Delete a logical sound source. If you don't call it, the source will be auto-deleted /** Delete a logical sound source. If you don't call it, the source will be auto-deleted
@ -431,8 +431,9 @@ private:
// utility function for automatic sample bank loading. // utility function for automatic sample bank loading.
bool tryToLoadSampleBank(const std::string &sampleName); bool tryToLoadSampleBank(const std::string &sampleName);
public:
typedef CHashSet<CSourceCommon*, THashPtr<CSourceCommon*> > TSourceContainer; typedef CHashSet<CSourceCommon*, THashPtr<CSourceCommon*> > TSourceContainer;
private:
typedef CHashSet<IMixerUpdate*, THashPtr<IMixerUpdate*> > TMixerUpdateContainer; typedef CHashSet<IMixerUpdate*, THashPtr<IMixerUpdate*> > TMixerUpdateContainer;
typedef CHashMap<IBuffer*, std::vector<class CSound*>, THashPtr<IBuffer*> > TBufferToSourceContainer; typedef CHashMap<IBuffer*, std::vector<class CSound*>, THashPtr<IBuffer*> > TBufferToSourceContainer;
// typedef std::multimap<NLMISC::TTime, IMixerEvent*> TTimedEventContainer; // typedef std::multimap<NLMISC::TTime, IMixerEvent*> TTimedEventContainer;

View file

@ -36,7 +36,7 @@ class CBackgroundSource : public CSourceCommon , public CAudioMixerUser::IMixerU
{ {
public: public:
/// Constructor /// Constructor
CBackgroundSource (CBackgroundSound *backgroundSound=NULL, bool spawn=false, TSpawnEndCallback cb=0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0); CBackgroundSource (CBackgroundSound *backgroundSound=NULL, bool spawn=false, TSpawnEndCallback cb=0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0, CGroupController *groupController = NULL);
/// Destructor /// Destructor
~CBackgroundSource (); ~CBackgroundSource ();

View file

@ -34,7 +34,7 @@ class CComplexSource : public CSourceCommon, public CAudioMixerUser::IMixerEvent
{ {
public: public:
/// Constructor /// Constructor
CComplexSource (CComplexSound *soundPattern=NULL, bool spawn=false, TSpawnEndCallback cb=0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0); CComplexSource (CComplexSound *soundPattern=NULL, bool spawn=false, TSpawnEndCallback cb=0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0, CGroupController *groupController = NULL);
/// Destructor /// Destructor
~CComplexSource (); ~CComplexSource ();

View file

@ -0,0 +1,100 @@
/**
* \file group_controller.h
* \brief CGroupController
* \date 2012-04-10 09:29GMT
* \author Jan Boon (Kaetemi)
* CGroupController
*/
/*
* Copyright (C) 2012 by authors
*
* This file is part of RYZOM CORE.
* RYZOM CORE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* RYZOM CORE is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with RYZOM CORE. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef NLSOUND_GROUP_CONTROLLER_H
#define NLSOUND_GROUP_CONTROLLER_H
#include <nel/misc/types_nl.h>
// STL includes
#include <string>
#include <map>
// NeL includes
#include <nel/misc/common.h>
#include <nel/sound/audio_mixer_user.h>
#include <nel/sound/u_group_controller.h>
// Project includes
namespace NLSOUND {
class CSourceCommon;
class CGroupControllerRoot;
/**
* \brief CGroupController
* \date 2012-04-10 09:29GMT
* \author Jan Boon (Kaetemi)
* CGroupController
*/
class CGroupController : public UGroupController
{
public:
friend CGroupControllerRoot;
private:
CGroupController *m_Parent;
std::map<std::string, CGroupController *> m_Children;
float m_DevGain;
float m_UserGain;
float m_FinalGain;
int m_NbSourcesInclChild;
CAudioMixerUser::TSourceContainer m_Sources;
public:
CGroupController(CGroupController *parent);
/// \name UGroupController
//@{
virtual void setDevGain(float gain) { NLMISC::clamp(gain, 0.0f, 1.0f); m_DevGain = gain; updateSourceGain(); }
virtual float getDevGain() { return m_DevGain; }
virtual void setUserGain(float gain) { NLMISC::clamp(gain, 0.0f, 1.0f); m_UserGain = gain; updateSourceGain(); }
virtual float getUserGain() { return m_UserGain; }
//@}
inline float getFinalGain() const { return m_FinalGain; }
void addSource(CSourceCommon *source);
void removeSource(CSourceCommon *source);
private:
virtual ~CGroupController(); // subnodes can only be deleted by the root
inline float calculateTotalGain() { return m_DevGain * m_UserGain; }
virtual void calculateFinalGain();
virtual void increaseSources();
virtual void decreaseSources();
void updateSourceGain();
}; /* class CGroupController */
} /* namespace NLSOUND */
#endif /* #ifndef NLSOUND_GROUP_CONTROLLER_H */
/* end of file */

View file

@ -0,0 +1,67 @@
/**
* \file group_controller_root.h
* \brief CGroupControllerRoot
* \date 2012-04-10 09:44GMT
* \author Jan Boon (Kaetemi)
* CGroupControllerRoot
*/
/*
* Copyright (C) 2012 by authors
*
* This file is part of RYZOM CORE.
* RYZOM CORE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* RYZOM CORE is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with RYZOM CORE. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef NLSOUND_GROUP_CONTROLLER_ROOT_H
#define NLSOUND_GROUP_CONTROLLER_ROOT_H
#include <nel/misc/types_nl.h>
// STL includes
// NeL includes
// Project includes
#include <nel/sound/group_controller.h>
namespace NLSOUND {
/**
* \brief CGroupControllerRoot
* \date 2012-04-10 09:44GMT
* \author Jan Boon (Kaetemi)
* CGroupControllerRoot
*/
class CGroupControllerRoot : public CGroupController
{
public:
CGroupControllerRoot();
virtual ~CGroupControllerRoot();
/// Gets the group controller in a certain path with separator '/', if it doesn't exist yet it will be created.
CGroupController *getGroupController(const std::string &path);
protected:
virtual void calculateFinalGain();
virtual void increaseSources();
virtual void decreaseSources();
}; /* class CGroupControllerRoot */
} /* namespace NLSOUND */
#endif /* #ifndef NLSOUND_GROUP_CONTROLLER_ROOT_H */
/* end of file */

View file

@ -35,7 +35,7 @@ class CMusicSource : public CSourceCommon
{ {
public: public:
/// Constructor /// Constructor
CMusicSource (class CMusicSound *sound=NULL, bool spawn=false, TSpawnEndCallback cb=0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0); CMusicSource (class CMusicSound *sound=NULL, bool spawn=false, TSpawnEndCallback cb=0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0, CGroupController *groupController = NULL);
/// Destructor /// Destructor
~CMusicSource (); ~CMusicSource ();

View file

@ -40,7 +40,7 @@ class CSimpleSource : public CSourceCommon, public CAudioMixerUser::IMixerEvent
{ {
public: public:
/// Constructor /// Constructor
CSimpleSource(CSimpleSound *simpleSound = NULL, bool spawn = false, TSpawnEndCallback cb = 0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0); CSimpleSource(CSimpleSound *simpleSound = NULL, bool spawn = false, TSpawnEndCallback cb = 0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0, CGroupController *groupController = NULL);
/// Destructor /// Destructor
virtual ~CSimpleSource(); virtual ~CSimpleSource();
@ -97,14 +97,7 @@ public:
* 1.0 -> no attenuation * 1.0 -> no attenuation
* values > 1 (amplification) not supported by most drivers * values > 1 (amplification) not supported by most drivers
*/ */
virtual void setGain( float gain ); virtual void updateFinalGain();
/** Set the gain amount (value inside [0, 1]) to map between 0 and the nominal gain
* (which is getSource()->getGain()). Does nothing if getSource() is null.
*/
virtual void setRelativeGain( float gain );
/** Shift the frequency. 1.0f equals identity, each reduction of 50% equals a pitch shift
* of one octave. 0 is not a legal value.
*/
virtual void setPitch( float pitch ); virtual void setPitch( float pitch );
/// Set the source relative mode. If true, positions are interpreted relative to the listener position (default: false) /// Set the source relative mode. If true, positions are interpreted relative to the listener position (default: false)
virtual void setSourceRelativeMode( bool mode ); virtual void setSourceRelativeMode( bool mode );

View file

@ -30,6 +30,7 @@ namespace NLSOUND {
class ISoundDriver; class ISoundDriver;
class IBuffer; class IBuffer;
class CSound; class CSound;
class CGroupController;
/// Sound names hash map /// Sound names hash map
@ -104,6 +105,8 @@ public:
/// Return the max distance (if detailed()) /// Return the max distance (if detailed())
virtual float getMaxDistance() const { return _MaxDist; } virtual float getMaxDistance() const { return _MaxDist; }
inline CGroupController *getGroupController() const { return NULL; } // TODO, RETURN THE GROUP CONTROLLER
/// Set looping /// Set looping
void setLooping( bool looping ) { _Looping = looping; } void setLooping( bool looping ) { _Looping = looping; }

View file

@ -22,7 +22,7 @@
#include "nel/sound/u_stream_source.h" #include "nel/sound/u_stream_source.h"
#include "nel/3d/cluster.h" #include "nel/3d/cluster.h"
#include "nel/sound/sound.h" #include "nel/sound/sound.h"
#include "nel/sound/group_controller.h"
namespace NLSOUND { namespace NLSOUND {
@ -36,11 +36,12 @@ public:
SOURCE_SIMPLE, SOURCE_SIMPLE,
SOURCE_COMPLEX, SOURCE_COMPLEX,
SOURCE_BACKGROUND, SOURCE_BACKGROUND,
SOURCE_MUSIC, SOURCE_MUSIC, // DEPRECATED
SOURCE_STREAM SOURCE_STREAM
}; };
CSourceCommon(TSoundId id, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster); /// When groupController is NULL it will use the groupcontroller specified in the TSoundId. You should manually specify the groupController if this source is a child of another source, so that the parent source controller of the user-specified .sound file is the one that will be used.
CSourceCommon(TSoundId id, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController);
~CSourceCommon(); ~CSourceCommon();
@ -63,6 +64,8 @@ public:
void setGain( float gain ); void setGain( float gain );
void setRelativeGain( float gain ); void setRelativeGain( float gain );
float getRelativeGain() const; float getRelativeGain() const;
/// Called whenever the gain is changed trough setGain, setRelativeGain or the group controller's gain settings change.
virtual void updateFinalGain() { }
void setSourceRelativeMode( bool mode ); void setSourceRelativeMode( bool mode );
/// return the user param for the user callback /// return the user param for the user callback
void *getCallbackUserParam(void) const { return _CbUserParam; } void *getCallbackUserParam(void) const { return _CbUserParam; }
@ -74,6 +77,8 @@ public:
virtual void getDirection( NLMISC::CVector& dir ) const { dir = _Direction; } virtual void getDirection( NLMISC::CVector& dir ) const { dir = _Direction; }
/// Get the gain /// Get the gain
virtual float getGain() const { return _Gain; } virtual float getGain() const { return _Gain; }
/// Get the final gain, including group controller changes. Use this when setting the physical source output gain.
inline float getFinalGain() const { return _Gain * _GroupController->getFinalGain(); }
/// Get the pitch /// Get the pitch
virtual float getPitch() const { return _Pitch; } virtual float getPitch() const { return _Pitch; }
/// Get the source relative mode /// Get the source relative mode
@ -145,6 +150,9 @@ protected:
/// An optional user var controler. /// An optional user var controler.
NLMISC::TStringId _UserVarControler; NLMISC::TStringId _UserVarControler;
/// Group controller for gain
CGroupController *_GroupController;
}; };
} // NLSOUND } // NLSOUND

View file

@ -41,7 +41,7 @@ namespace NLSOUND {
class CStreamSource : public CSourceCommon class CStreamSource : public CSourceCommon
{ {
public: public:
CStreamSource(CStreamSound *streamSound = NULL, bool spawn = false, TSpawnEndCallback cb = 0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0); CStreamSource(CStreamSound *streamSound = NULL, bool spawn = false, TSpawnEndCallback cb = 0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0, CGroupController *groupController = NULL);
virtual ~CStreamSource(); virtual ~CStreamSource();
/// Return the sound binded to the source (or NULL if there is no sound) /// Return the sound binded to the source (or NULL if there is no sound)
@ -80,18 +80,7 @@ public:
virtual void setVelocity(const NLMISC::CVector& vel); virtual void setVelocity(const NLMISC::CVector& vel);
/// Set the direction vector (3D mode only, ignored in stereo mode) (default: (0,0,0) as non-directional) /// Set the direction vector (3D mode only, ignored in stereo mode) (default: (0,0,0) as non-directional)
virtual void setDirection(const NLMISC::CVector& dir); virtual void setDirection(const NLMISC::CVector& dir);
/** Set the gain (volume value inside [0 , 1]). (default: 1) virtual void updateFinalGain();
* 0.0 -> silence
* 0.5 -> -6dB
* 1.0 -> no attenuation
* values > 1 (amplification) not supported by most drivers
*/
virtual void setGain(float gain);
/** Set the gain amount (value inside [0, 1]) to map between 0 and the nominal gain
* (which is getSource()->getGain()). Does nothing if getSource() is null.
*/
virtual void setRelativeGain(float gain);
/** Shift the frequency. 1.0f equals identity, each reduction of 50% equals a pitch shift /** Shift the frequency. 1.0f equals identity, each reduction of 50% equals a pitch shift
* of one octave. 0 is not a legal value. * of one octave. 0 is not a legal value.
*/ */

View file

@ -20,6 +20,7 @@
#include "nel/misc/types_nl.h" #include "nel/misc/types_nl.h"
#include "nel/misc/string_mapper.h" #include "nel/misc/string_mapper.h"
#include "nel/sound/u_source.h" #include "nel/sound/u_source.h"
#include "nel/sound/u_group_controller.h"
#include "nel/ligo/primitive.h" #include "nel/ligo/primitive.h"
#include <vector> #include <vector>
@ -291,9 +292,9 @@ public:
* pass a callback function that will be called (if not NULL) just before deleting the spawned * pass a callback function that will be called (if not NULL) just before deleting the spawned
* source. * source.
*/ */
virtual USource *createSource( const NLMISC::TStringId &name, bool spawn=false, TSpawnEndCallback cb=NULL, void *callbackUserParam = NULL, NL3D::CCluster *cluster = 0, CSoundContext *context=0) = 0; virtual USource *createSource(const NLMISC::TStringId &name, bool spawn=false, TSpawnEndCallback cb=NULL, void *callbackUserParam = NULL, NL3D::CCluster *cluster = 0, CSoundContext *context = 0, UGroupController *groupController = NULL) = 0;
/// Add a logical sound source (by sound id). To remove a source, just delete it. See createSource(const char*) /// Add a logical sound source (by sound id). To remove a source, just delete it. See createSource(const char*)
virtual USource *createSource( TSoundId id, bool spawn=false, TSpawnEndCallback cb=NULL, void *callbackUserParam = NULL, NL3D::CCluster *cluster = 0, CSoundContext *context=0 ) = 0; virtual USource *createSource(TSoundId id, bool spawn=false, TSpawnEndCallback cb=NULL, void *callbackUserParam = NULL, NL3D::CCluster *cluster = 0, CSoundContext *context = 0, UGroupController *groupController = NULL) = 0;
/** Use this method to set the listener position instead of using getListener->setPos(); /** Use this method to set the listener position instead of using getListener->setPos();
* It's because we have to update the background sounds in this case. * It's because we have to update the background sounds in this case.

View file

@ -0,0 +1,63 @@
/**
* \file u_group_controller.h
* \brief UGroupController
* \date 2012-04-10 12:49GMT
* \author Jan Boon (Kaetemi)
* UGroupController
*/
/*
* Copyright (C) 2012 by authors
*
* This file is part of RYZOM CORE.
* RYZOM CORE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* RYZOM CORE is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with RYZOM CORE. If not, see
* <http://www.gnu.org/licenses/>.
*/
#ifndef NLSOUND_U_GROUP_CONTROLLER_H
#define NLSOUND_U_GROUP_CONTROLLER_H
#include <nel/misc/types_nl.h>
// STL includes
// NeL includes
// Project includes
namespace NLSOUND {
/**
* \brief UGroupController
* \date 2012-04-10 12:49GMT
* \author Jan Boon (Kaetemi)
* UGroupController
*/
class UGroupController
{
virtual void setDevGain(float gain) = 0;
virtual float getDevGain() = 0;
virtual void setUserGain(float gain) = 0;
virtual float getUserGain() = 0;
protected:
virtual ~UGroupController();
}; /* class UGroupController */
} /* namespace NLSOUND */
#endif /* #ifndef NLSOUND_U_GROUP_CONTROLLER_H */
/* end of file */

View file

@ -51,6 +51,7 @@
#include "nel/sound/sample_bank_manager.h" #include "nel/sound/sample_bank_manager.h"
#include "nel/sound/sample_bank.h" #include "nel/sound/sample_bank.h"
#include "nel/sound/sound_bank.h" #include "nel/sound/sound_bank.h"
#include "nel/sound/group_controller.h"
using namespace std; using namespace std;
using namespace NLMISC; using namespace NLMISC;
@ -1689,7 +1690,7 @@ void CAudioMixerUser::update()
// _Tracks[i]->DrvSource->setPos(source->getPos() * (1-css->PosAlpha) + css->Position*(css->PosAlpha)); // _Tracks[i]->DrvSource->setPos(source->getPos() * (1-css->PosAlpha) + css->Position*(css->PosAlpha));
_Tracks[i]->getPhysicalSource()->setPos(source->getPos() * (1-css->PosAlpha) + vpos*(css->PosAlpha)); _Tracks[i]->getPhysicalSource()->setPos(source->getPos() * (1-css->PosAlpha) + vpos*(css->PosAlpha));
// update the relative gain // update the relative gain
_Tracks[i]->getPhysicalSource()->setGain(source->getRelativeGain()*source->getGain()*css->Gain); _Tracks[i]->getPhysicalSource()->setGain(source->getFinalGain() * css->Gain);
#if EAX_AVAILABLE == 1 #if EAX_AVAILABLE == 1
if (_UseEax) if (_UseEax)
{ {
@ -1829,7 +1830,7 @@ bool CAudioMixerUser::tryToLoadSampleBank(const std::string &sampleName)
// ****************************************************************** // ******************************************************************
USource *CAudioMixerUser::createSource( TSoundId id, bool spawn, TSpawnEndCallback cb, void *userParam, NL3D::CCluster *cluster, CSoundContext *context ) USource *CAudioMixerUser::createSource( TSoundId id, bool spawn, TSpawnEndCallback cb, void *userParam, NL3D::CCluster *cluster, CSoundContext *context, UGroupController *groupController )
{ {
#if NL_PROFILE_MIXER #if NL_PROFILE_MIXER
TTicks start = CTime::getPerformanceTime(); TTicks start = CTime::getPerformanceTime();
@ -1915,7 +1916,7 @@ retrySound:
} }
// Create source // Create source
CSimpleSource *source = new CSimpleSource( simpleSound, spawn, cb, userParam, cluster); CSimpleSource *source = new CSimpleSource( simpleSound, spawn, cb, userParam, cluster, static_cast<CGroupController *>(groupController));
// nldebug("Mixer : source %p created", source); // nldebug("Mixer : source %p created", source);
@ -1939,28 +1940,28 @@ retrySound:
{ {
CStreamSound *streamSound = static_cast<CStreamSound *>(id); CStreamSound *streamSound = static_cast<CStreamSound *>(id);
// This is a stream thingy. // This is a stream thingy.
ret = new CStreamSource(streamSound, spawn, cb, userParam, cluster); ret = new CStreamSource(streamSound, spawn, cb, userParam, cluster, static_cast<CGroupController *>(groupController));
} }
break; break;
case CSound::SOUND_COMPLEX: case CSound::SOUND_COMPLEX:
{ {
CComplexSound *complexSound = static_cast<CComplexSound *>(id); CComplexSound *complexSound = static_cast<CComplexSound *>(id);
// This is a pattern sound. // This is a pattern sound.
ret = new CComplexSource(complexSound, spawn, cb, userParam, cluster); ret = new CComplexSource(complexSound, spawn, cb, userParam, cluster, static_cast<CGroupController *>(groupController));
} }
break; break;
case CSound::SOUND_BACKGROUND: case CSound::SOUND_BACKGROUND:
{ {
// This is a background sound. // This is a background sound.
CBackgroundSound *bgSound = static_cast<CBackgroundSound *>(id); CBackgroundSound *bgSound = static_cast<CBackgroundSound *>(id);
ret = new CBackgroundSource(bgSound, spawn, cb, userParam, cluster); ret = new CBackgroundSource(bgSound, spawn, cb, userParam, cluster, static_cast<CGroupController *>(groupController));
} }
break; break;
case CSound::SOUND_MUSIC: case CSound::SOUND_MUSIC:
{ {
// This is a background music sound // This is a background music sound
CMusicSound *music_sound= static_cast<CMusicSound *>(id); CMusicSound *music_sound= static_cast<CMusicSound *>(id);
ret = new CMusicSource(music_sound, spawn, cb, userParam, cluster); ret = new CMusicSource(music_sound, spawn, cb, userParam, cluster, static_cast<CGroupController *>(groupController));
} }
break; break;
case CSound::SOUND_CONTEXT: case CSound::SOUND_CONTEXT:
@ -1974,7 +1975,7 @@ retrySound:
CSound *sound = ctxSound->getContextSound(*context); CSound *sound = ctxSound->getContextSound(*context);
if (sound != 0) if (sound != 0)
{ {
ret = createSource(sound, spawn, cb, userParam, cluster); ret = createSource(sound, spawn, cb, userParam, cluster, NULL, static_cast<CGroupController *>(groupController));
// Set the volume of the source according to the context volume // Set the volume of the source according to the context volume
if (ret != 0) if (ret != 0)
{ {
@ -2007,9 +2008,9 @@ retrySound:
// ****************************************************************** // ******************************************************************
USource *CAudioMixerUser::createSource( const NLMISC::TStringId &name, bool spawn, TSpawnEndCallback cb, void *userParam, NL3D::CCluster *cluster, CSoundContext *context) USource *CAudioMixerUser::createSource( const NLMISC::TStringId &name, bool spawn, TSpawnEndCallback cb, void *userParam, NL3D::CCluster *cluster, CSoundContext *context, UGroupController *groupController)
{ {
return createSource( getSoundId( name ), spawn, cb, userParam, cluster, context); return createSource( getSoundId( name ), spawn, cb, userParam, cluster, context, groupController);
} }

View file

@ -26,8 +26,8 @@ namespace NLSOUND
{ {
CBackgroundSource::CBackgroundSource(CBackgroundSound *backgroundSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster) CBackgroundSource::CBackgroundSource(CBackgroundSound *backgroundSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController)
: CSourceCommon(backgroundSound, spawn, cb, cbUserParam, cluster) : CSourceCommon(backgroundSound, spawn, cb, cbUserParam, cluster, groupController)
{ {
_BackgroundSound = backgroundSound; _BackgroundSound = backgroundSound;
} }
@ -119,7 +119,7 @@ void CBackgroundSource::play()
for (; first != last; ++first) for (; first != last; ++first)
{ {
TSubSource subSource; TSubSource subSource;
subSource.Source = mixer->createSource(first->SoundName, false, 0, 0, _Cluster, 0); subSource.Source = mixer->createSource(first->SoundName, false, 0, 0, _Cluster, NULL, _GroupController);
if (subSource.Source != NULL) if (subSource.Source != NULL)
subSource.Source->setPriority(_Priority); subSource.Source->setPriority(_Priority);
subSource.Filter = first->Filter; subSource.Filter = first->Filter;

View file

@ -25,8 +25,8 @@ using namespace NLMISC;
namespace NLSOUND namespace NLSOUND
{ {
CComplexSource::CComplexSource (CComplexSound *soundPattern, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster) CComplexSource::CComplexSource (CComplexSound *soundPattern, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController)
: CSourceCommon(soundPattern, spawn, cb, cbUserParam, cluster), : CSourceCommon(soundPattern, spawn, cb, cbUserParam, cluster, groupController),
_Source1(NULL), _Source1(NULL),
_Source2(NULL) _Source2(NULL)
{ {
@ -117,7 +117,7 @@ void CComplexSource::playStuf()
else else
_FadeLength = 0; _FadeLength = 0;
_Source2 = mixer->createSource(sound, false, 0, 0, _Cluster); _Source2 = mixer->createSource(sound, false, 0, 0, _Cluster, NULL, _GroupController);
if (_Source2 == NULL) if (_Source2 == NULL)
return; return;
_Source2->setPriority(_Priority); _Source2->setPriority(_Priority);
@ -155,7 +155,7 @@ void CComplexSource::playStuf()
{ {
CSound *sound = mixer->getSoundId(_PatternSound->getSound(soundSeq[_SoundSeqIndex++])); CSound *sound = mixer->getSoundId(_PatternSound->getSound(soundSeq[_SoundSeqIndex++]));
_Source1 = mixer->createSource(sound, false, 0, 0, _Cluster); _Source1 = mixer->createSource(sound, false, 0, 0, _Cluster, NULL, _GroupController);
if (_Source1 == NULL) if (_Source1 == NULL)
return; return;
_Source1->setPriority(_Priority); _Source1->setPriority(_Priority);
@ -202,7 +202,7 @@ void CComplexSource::playStuf()
CSound *sound = mixer->getSoundId(*first); CSound *sound = mixer->getSoundId(*first);
if (sound != NULL) if (sound != NULL)
{ {
USource *source = mixer->createSource(sound, false, 0, 0, _Cluster); USource *source = mixer->createSource(sound, false, 0, 0, _Cluster, NULL, _GroupController);
if (source != NULL) if (source != NULL)
{ {
source->setPriority(_Priority); source->setPriority(_Priority);
@ -512,7 +512,7 @@ void CComplexSource::onUpdate()
// determine the XFade length (if next sound is too short. // determine the XFade length (if next sound is too short.
_FadeLength = minof<uint32>(uint32(_PatternSound->getFadeLength()/_TickPerSecond), (sound2->getDuration()) / 2, (_Source1->getSound()->getDuration())/2); _FadeLength = minof<uint32>(uint32(_PatternSound->getFadeLength()/_TickPerSecond), (sound2->getDuration()) / 2, (_Source1->getSound()->getDuration())/2);
_Source2 = mixer->createSource(sound2, false, 0, 0, _Cluster); _Source2 = mixer->createSource(sound2, false, 0, 0, _Cluster, NULL, _GroupController);
if (_Source2) if (_Source2)
{ {
_Source2->setPriority(_Priority); _Source2->setPriority(_Priority);
@ -641,7 +641,7 @@ void CComplexSource::onEvent()
CSound *sound = mixer->getSoundId(_PatternSound->getSound(soundSeq[_SoundSeqIndex++])); CSound *sound = mixer->getSoundId(_PatternSound->getSound(soundSeq[_SoundSeqIndex++]));
_Source1 = mixer->createSource(sound, false, 0, 0, _Cluster); _Source1 = mixer->createSource(sound, false, 0, 0, _Cluster, NULL, _GroupController);
if (_Source1 == NULL) if (_Source1 == NULL)
{ {
stop(); stop();

View file

@ -0,0 +1,112 @@
/**
* \file group_controller.cpp
* \brief CGroupController
* \date 2012-04-10 09:29GMT
* \author Jan Boon (Kaetemi)
* CGroupController
*/
/*
* Copyright (C) 2012 by authors
*
* This file is part of RYZOM CORE.
* RYZOM CORE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* RYZOM CORE is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with RYZOM CORE. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "stdsound.h"
#include <nel/sound/group_controller.h>
// STL includes
// NeL includes
// #include <nel/misc/debug.h>
#include <nel/sound/source_common.h>
// Project includes
using namespace std;
// using namespace NLMISC;
namespace NLSOUND {
CGroupController::CGroupController(CGroupController *parent) :
m_Parent(parent), m_DevGain(1.0f), m_UserGain(1.0f), m_NbSourcesInclChild(0)
{
}
CGroupController::~CGroupController()
{
// If m_Sources is not empty, a crash is very likely.
nlassert(m_Sources.empty());
for (std::map<std::string, CGroupController *>::iterator it(m_Children.begin()), end(m_Children.end()); it != end; ++it)
{
delete it->second;
it->second = NULL;
}
m_Parent = NULL;
}
void CGroupController::addSource(CSourceCommon *source)
{
m_Sources.insert(source);
increaseSources();
}
void CGroupController::removeSource(CSourceCommon *source)
{
decreaseSources();
m_Sources.erase(source);
}
void CGroupController::calculateFinalGain() // overridden by root
{
m_FinalGain = calculateTotalGain() * m_Parent->getFinalGain();
}
void CGroupController::updateSourceGain()
{
// Dont update source gain when this controller is inactive.
if (m_NbSourcesInclChild)
{
calculateFinalGain();
for (CAudioMixerUser::TSourceContainer::iterator it(m_Sources.begin()), end(m_Sources.end()); it != end; ++it)
(*it)->updateFinalGain();
for (std::map<std::string, CGroupController *>::iterator it(m_Children.begin()), end(m_Children.end()); it != end; ++it)
(*it).second->updateSourceGain();
}
}
void CGroupController::increaseSources() // overridden by root
{
++m_NbSourcesInclChild;
m_Parent->increaseSources();
// Update source gain when this controller was inactive before but the parent was active before.
// Thus, when this controller was the root of inactive controllers.
if (m_NbSourcesInclChild == 1 && m_Parent->m_NbSourcesInclChild > 1)
updateSourceGain();
}
void CGroupController::decreaseSources() // overridden by root
{
--m_NbSourcesInclChild;
m_Parent->decreaseSources();
}
} /* namespace NLSOUND */
/* end of file */

View file

@ -0,0 +1,99 @@
/**
* \file group_controller_root.cpp
* \brief CGroupControllerRoot
* \date 2012-04-10 09:44GMT
* \author Jan Boon (Kaetemi)
* CGroupControllerRoot
*/
/*
* Copyright (C) 2012 by authors
*
* This file is part of RYZOM CORE.
* RYZOM CORE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* RYZOM CORE is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with RYZOM CORE. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include "stdsound.h"
#include <nel/sound/group_controller_root.h>
// STL includes
// NeL includes
// #include <nel/misc/debug.h>
#include <nel/misc/algo.h>
// Project includes
using namespace std;
// using namespace NLMISC;
namespace NLSOUND {
CGroupControllerRoot::CGroupControllerRoot() : CGroupController(NULL)
{
}
CGroupControllerRoot::~CGroupControllerRoot()
{
}
void CGroupControllerRoot::calculateFinalGain()
{
m_FinalGain = calculateTotalGain();
}
void CGroupController::increaseSources()
{
++m_NbSourcesInclChild;
// Update source gain when this controller was inactive before.
if (m_NbSourcesInclChild == 1)
updateSourceGain();
}
void CGroupController::decreaseSources()
{
--m_NbSourcesInclChild;
}
CGroupController *CGroupControllerRoot::getGroupController(const std::string &path)
{
std::vector<std::string> pathNodes;
NLMISC::splitString(NLMISC::toLower(path), "/", pathNodes);
CGroupController *active = this;
for (std::vector<std::string>::iterator it(pathNodes.begin()), end(pathNodes.end()); it != end; ++it)
{
if (!(*it).empty())
{
std::map<std::string, CGroupController *>::iterator found = active->m_Children.find(*it);
if (found == active->m_Children.end())
{
active = new CGroupController(active);
active->m_Parent->m_Children[*it] = active;
}
else
{
active = (*found).second;
}
}
}
return active;
}
} /* namespace NLSOUND */
/* end of file */

View file

@ -26,8 +26,8 @@ namespace NLSOUND {
// *************************************************************************** // ***************************************************************************
CMusicSource::CMusicSource(CMusicSound *musicSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster) CMusicSource::CMusicSource(CMusicSound *musicSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController)
: CSourceCommon(musicSound, spawn, cb, cbUserParam, cluster) : CSourceCommon(musicSound, spawn, cb, cbUserParam, cluster, groupController)
{ {
_MusicSound= musicSound; _MusicSound= musicSound;
} }

View file

@ -28,8 +28,8 @@ using namespace NLMISC;
namespace NLSOUND { namespace NLSOUND {
CSimpleSource::CSimpleSource(CSimpleSound *simpleSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster) CSimpleSource::CSimpleSource(CSimpleSound *simpleSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController)
: CSourceCommon(simpleSound, spawn, cb, cbUserParam, cluster), : CSourceCommon(simpleSound, spawn, cb, cbUserParam, cluster, groupController),
_SimpleSound(simpleSound), _SimpleSound(simpleSound),
_Track(NULL), _Track(NULL),
_PlayMuted(false) _PlayMuted(false)
@ -166,7 +166,7 @@ void CSimpleSource::play()
setDirection(_Direction); // because there is a workaround inside setDirection(_Direction); // because there is a workaround inside
pSource->setVelocity(_Velocity); pSource->setVelocity(_Velocity);
} }
pSource->setGain(_Gain); pSource->setGain(getFinalGain());
pSource->setSourceRelativeMode(_RelativeMode); pSource->setSourceRelativeMode(_RelativeMode);
pSource->setLooping(_Looping); pSource->setLooping(_Looping);
pSource->setPitch(_Pitch); pSource->setPitch(_Pitch);
@ -312,36 +312,13 @@ void CSimpleSource::setDirection(const NLMISC::CVector& dir)
} }
} }
void CSimpleSource::updateFinalGain()
/* Set the gain (volume value inside [0 , 1]). (default: 1)
* 0.0 -> silence
* 0.5 -> -6dB
* 1.0 -> no attenuation
* values > 1 (amplification) not supported by most drivers
*/
void CSimpleSource::setGain(float gain)
{ {
CSourceCommon::setGain(gain);
// Set the gain // Set the gain
if (hasPhysicalSource()) if (hasPhysicalSource())
{ getPhysicalSource()->setGain(getFinalGain());
getPhysicalSource()->setGain(gain);
}
} }
void CSimpleSource::setRelativeGain(float gain)
{
CSourceCommon::setRelativeGain(gain);
// Set the gain
if (hasPhysicalSource())
{
getPhysicalSource()->setGain(_Gain);
}
}
/* Shift the frequency. 1.0f equals identity, each reduction of 50% equals a pitch shift /* Shift the frequency. 1.0f equals identity, each reduction of 50% equals a pitch shift
* of one octave. 0 is not a legal value. * of one octave. 0 is not a legal value.
*/ */

View file

@ -25,7 +25,7 @@ using namespace NLMISC;
namespace NLSOUND namespace NLSOUND
{ {
CSourceCommon::CSourceCommon(TSoundId id, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster) CSourceCommon::CSourceCommon(TSoundId id, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController)
: _Priority(MidPri), : _Priority(MidPri),
_Playing(false), _Playing(false),
_Looping(false), _Looping(false),
@ -41,9 +41,11 @@ CSourceCommon::CSourceCommon(TSoundId id, bool spawn, TSpawnEndCallback cb, void
_SpawnEndCb(cb), _SpawnEndCb(cb),
_CbUserParam(cbUserParam), _CbUserParam(cbUserParam),
_Cluster(cluster), _Cluster(cluster),
_UserVarControler(id->getUserVarControler()) _UserVarControler(id->getUserVarControler()),
_GroupController(groupController ? groupController : id->getGroupController())
{ {
CAudioMixerUser::instance()->addSource(this); CAudioMixerUser::instance()->addSource(this);
groupController->addSource(this);
// get a local copy of the sound parameter // get a local copy of the sound parameter
_InitialGain = _Gain = id->getGain(); _InitialGain = _Gain = id->getGain();
@ -51,11 +53,11 @@ CSourceCommon::CSourceCommon(TSoundId id, bool spawn, TSpawnEndCallback cb, void
_Looping = id->getLooping(); _Looping = id->getLooping();
_Priority = id->getPriority(); _Priority = id->getPriority();
_Direction = id->getDirectionVector(); _Direction = id->getDirectionVector();
} }
CSourceCommon::~CSourceCommon() CSourceCommon::~CSourceCommon()
{ {
_GroupController->removeSource(this);
CAudioMixerUser::instance()->removeSource(this); CAudioMixerUser::instance()->removeSource(this);
} }
@ -177,6 +179,7 @@ void CSourceCommon::setGain( float gain )
{ {
clamp(gain, 0.0f, 1.0f); clamp(gain, 0.0f, 1.0f);
_InitialGain = _Gain = gain; _InitialGain = _Gain = gain;
updateFinalGain();
} }
/* Set the gain amount (value inside [0, 1]) to map between 0 and the nominal gain /* Set the gain amount (value inside [0, 1]) to map between 0 and the nominal gain
@ -185,8 +188,8 @@ void CSourceCommon::setGain( float gain )
void CSourceCommon::setRelativeGain( float gain ) void CSourceCommon::setRelativeGain( float gain )
{ {
clamp(gain, 0.0f, 1.0f); clamp(gain, 0.0f, 1.0f);
_Gain = _InitialGain * gain; _Gain = _InitialGain * gain;
updateFinalGain();
} }
/* /*

View file

@ -28,8 +28,8 @@ using namespace NLMISC;
namespace NLSOUND { namespace NLSOUND {
CStreamSource::CStreamSource(CStreamSound *streamSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster) CStreamSource::CStreamSource(CStreamSound *streamSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController)
: CSourceCommon(streamSound, spawn, cb, cbUserParam, cluster), : CSourceCommon(streamSound, spawn, cb, cbUserParam, cluster, groupController),
m_StreamSound(streamSound), m_StreamSound(streamSound),
m_Alpha(0.0f), m_Alpha(0.0f),
m_Track(NULL), m_Track(NULL),
@ -177,7 +177,7 @@ void CStreamSource::play()
setDirection(_Direction); // because there is a workaround inside setDirection(_Direction); // because there is a workaround inside
pSource->setVelocity(_Velocity); pSource->setVelocity(_Velocity);
} }
pSource->setGain(_Gain); pSource->setGain(getFinalGain());
pSource->setSourceRelativeMode(_RelativeMode); pSource->setSourceRelativeMode(_RelativeMode);
// pSource->setLooping(_Looping); // pSource->setLooping(_Looping);
pSource->setPitch(_Pitch); pSource->setPitch(_Pitch);
@ -294,22 +294,12 @@ void CStreamSource::setDirection(const NLMISC::CVector& dir)
} }
} }
void CStreamSource::setGain(float gain) void CStreamSource::updateFinalGain()
{ {
CAutoMutex<CMutex> autoMutex(m_BufferMutex); CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CSourceCommon::setGain(gain);
if (hasPhysicalSource()) if (hasPhysicalSource())
getPhysicalSource()->setGain(gain); getPhysicalSource()->setGain(getFinalGain());
}
void CStreamSource::setRelativeGain(float gain)
{
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
CSourceCommon::setRelativeGain(gain);
if (hasPhysicalSource())
getPhysicalSource()->setGain(_Gain);
} }
void CStreamSource::setPitch(float pitch) void CStreamSource::setPitch(float pitch)