diff --git a/source/sound/SoundGroup.cpp b/source/sound/SoundGroup.cpp index c837b4addf..417b712447 100644 --- a/source/sound/SoundGroup.cpp +++ b/source/sound/SoundGroup.cpp @@ -8,6 +8,19 @@ * Author : Gavin Fowler * ========================================================================= */ + +/* +* Copyright (c) 2005-2006 Gavin Fowler +* +* Redistribution and/or modification are also permitted under the +* terms of the GNU General Public License as published by the +* Free Software Foundation (version 2 or later, at your option). +* +* This program 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. +*/ + #include "precompiled.h" #include @@ -28,6 +41,9 @@ CSoundGroup::CSoundGroup() { m_index = 0; m_Flags = 0; + m_Intensity = 0; + m_CurTime = 0.0f; + } @@ -35,6 +51,8 @@ CSoundGroup::CSoundGroup(const char *XMLfile) { m_index = 0; m_Flags = 0; + m_Intensity = 0; + m_CurTime = 0.0f; LoadSoundGroup(XMLfile); } @@ -47,59 +65,122 @@ CSoundGroup::~CSoundGroup() void CSoundGroup::PlayNext() { + if(m_Intensity >= m_IntensityThreshold) + { + if(!is_playing(m_hReplacement)) + { + // load up replacement file + m_hReplacement = snd_open(m_filepath + m_intensity_file); + snd_set_gain(m_hReplacement, m_Gain); + snd_set_pitch(m_hReplacement, m_Pitch); + snd_set_cone(m_hReplacement, m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain); - //if(this->m_intensity_threshold) - //for(size_t i = 0; i < m_index; i++) - //{ - // //H_USER_DATA(snd_group[i], H_Sound); - //} - //check for randomization of pitch and gain - if(TestFlag(eRandPitch)) - snd_set_pitch(snd_group[m_index], (float)((rand(m_PitchLower * 100.0f, m_PitchUpper * 100.0f) / 100.0f))); - if(TestFlag(eRandGain)) - snd_set_gain(snd_group[m_index], (float)((rand(m_GainLower * 100.0f, m_GainUpper * 100.0f) / 100.0f))); + //check for randomization of pitch and gain + if(TestFlag(eRandPitch)) + snd_set_pitch(snd_group[m_index], (float)((rand(m_PitchLower * 100.0f, m_PitchUpper * 100.0f) / 100.0f))); + if(TestFlag(eRandGain)) + snd_set_gain(snd_group[m_index], (float)((rand(m_GainLower * 100.0f, m_GainUpper * 100.0f) / 100.0f))); + + snd_play(m_hReplacement, m_Priority); + + } + } + else + { + // try loading on the fly only when we need the sound to see if that fixes release problems... + if(TestFlag(eRandOrder)) + m_index = (size_t)rand(0, filenames.size()); + Handle temp; + temp = snd_open(m_filepath + filenames[m_index]); + snd_set_gain(temp, m_Gain); + snd_set_pitch(temp, m_Pitch); + snd_set_cone(temp, m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain); + + + //check for randomization of pitch and gain + if(TestFlag(eRandPitch)) + snd_set_pitch(temp, (float)((rand(m_PitchLower * 100.0f, m_PitchUpper * 100.0f) / 100.0f))); + //snd_set_pitch(snd_group[m_index], (float)((rand(m_PitchLower * 100.0f, m_PitchUpper * 100.0f) / 100.0f))); + + if(TestFlag(eRandGain)) + snd_set_gain(temp, (float)((rand(m_GainLower * 100.0f, m_GainUpper * 100.0f) / 100.0f))); + //snd_set_gain(snd_group[m_index], (float)((rand(m_GainLower * 100.0f, m_GainUpper * 100.0f) / 100.0f))); - snd_play(snd_group[m_index], m_Priority); + snd_play(temp, m_Priority); + //snd_play(snd_group[m_index], m_Priority); + + + + + } + + playtimes[m_index] = 0.0f; m_index++; - if(m_index >= snd_group.size()) + m_Intensity++; + if(m_Intensity > m_IntensityThreshold) + m_Intensity = m_IntensityThreshold; + + + if(m_index >= filenames.size()) Reload(); } void CSoundGroup::Reload() { - m_index = 0; // reset our static index + m_index = 0; // reset our index // get rid of the used handles snd_group.clear(); + // clear out the old timers + playtimes.clear(); //Reload the sounds - for(size_t i = 0; i < filenames.size(); i++) + /*for(size_t i = 0; i < filenames.size(); i++) { string szTemp = m_filepath + filenames[i]; Handle temp = snd_open(m_filepath + filenames[i]); snd_set_gain(temp, m_Gain); snd_set_pitch(temp, m_Pitch); snd_set_cone(temp, m_ConeInnerAngle, m_ConeOuterAngle, m_ConeOuterGain); - snd_group.push_back(temp); - } - if(TestFlag(eRandOrder)) - random_shuffle(snd_group.begin(), snd_group.end()); - - - + snd_group.push_back(temp); + }*/ + while(playtimes.size() < filenames.size()) + playtimes.push_back(-1.0f); + //if(TestFlag(eRandOrder)) + //random_shuffle(snd_group.begin(), snd_group.end()); } void CSoundGroup::ReleaseGroup() { for(size_t i = m_index; i= 0.0f) + playtimes[i] += TimeSinceLastFrame; + if(playtimes[i] >= m_Decay) + { + playtimes[i] = -1.0f; + m_Intensity--; + } + } +} bool CSoundGroup::LoadSoundGroup(const char *XMLfile) { @@ -132,6 +213,7 @@ bool CSoundGroup::LoadSoundGroup(const char *XMLfile) EL(pitchlower); EL(path); EL(threshold); + EL(decay); EL(replacement); #undef AT #undef EL @@ -239,9 +321,16 @@ bool CSoundGroup::LoadSoundGroup(const char *XMLfile) } if(child_name == el_threshold) { - m_intensity_threshold = CStr(child.getText()).ToFloat(); - + //m_intensity_threshold = CStr(child.getText()).ToFloat(); + m_IntensityThreshold = CStr(child.getText()).ToFloat(); } + + if(child_name == el_decay) + { + //m_intensity_threshold = CStr(child.getText()).ToFloat(); + m_Decay = CStr(child.getText()).ToFloat(); + } + if(child_name == el_replacement) { m_intensity_file = child.getText(); diff --git a/source/sound/SoundGroup.h b/source/sound/SoundGroup.h index 9af6091150..dd6f4e9fbe 100644 --- a/source/sound/SoundGroup.h +++ b/source/sound/SoundGroup.h @@ -8,13 +8,22 @@ * Author : Gavin Fowler * ========================================================================= */ -/* -Example usage: -CSoundGroup s; -s.LoadSoundGroup("SoundGroup.xml"); // only needs to be called once (or not at all if filename is passed to ctor) -s.PlayNext(); // call each time you want to play another sound from the group. -s.ReleaseGroup(); // If you want to free up the resources early, but this happens in dtor. +/* +* Copyright (c) 2005-2006 Gavin Fowler +* +* Redistribution and/or modification are also permitted under the +* terms of the GNU General Public License as published by the +* Free Software Foundation (version 2 or later, at your option). +* +* This program 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. +*/ + +/* +Example usage: (SEE SOUNDGROUPMGR.H) + Example SoundGroup.xml @@ -55,20 +64,26 @@ enum eSndGrpFlags eLoop = 0x08 }; + class CSoundGroup { size_t m_index; // index of the next sound to play + Handle m_hReplacement; + vector snd_group; // we store the handles so we can load now and play later vector filenames; // we need the filenames so we can reload when necessary. + vector playtimes; // it would be better to store this in with the Handles perhaps? CStr m_filepath; // the file path for the list of sound file resources - CStr m_intensity_file; // this will be either the name of a new sound file or new sound group - - size_t m_intensity_threshold; - + CStr m_intensity_file; // the replacement aggregate 'intense' sound + float m_CurTime; // Time elapsed since soundgroup was created + float m_TimeWindow; // The Intensity Threshold Window + size_t m_IntensityThreshold; // the allowable intensity before a sound switch + size_t m_Intensity; // our current intensity(number of sounds played since m_CurTime - m_TimeWindow) + float m_Decay; // unsigned char m_Flags; // up to eight individual parameters, use with eSndGrpFlags. - + float m_Gain; float m_Pitch; float m_Priority; @@ -95,6 +110,9 @@ public: // Release all remaining loaded handles void ReleaseGroup(); + + // Update SoundGroup, remove dead sounds from intensity count + void Update(float TimeSinceLastFrame); // Set a flag using a value from eSndGrpFlags inline void SetFlag(int flag){ m_Flags |= flag; } diff --git a/source/sound/SoundGroupMgr.cpp b/source/sound/SoundGroupMgr.cpp new file mode 100644 index 0000000000..401ee56abe --- /dev/null +++ b/source/sound/SoundGroupMgr.cpp @@ -0,0 +1,156 @@ +/** +* ========================================================================= +* File : SoundGroupMgr.h +* Project : 0 A.D. +* Description : Manages and updates SoundGroups +* +* Author : Gavin Fowler +* ========================================================================= +*/ + +/* +* Copyright (c) 2005-2006 Gavin Fowler +* +* Redistribution and/or modification are also permitted under the +* terms of the GNU General Public License as published by the +* Free Software Foundation (version 2 or later, at your option). +* +* This program 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. +*/ + +// Example usage: + +// size_t index; +// CSoundGroupMgr *sgm = CSoundGroupMgr::GetInstance(); +// index = sgm->AddGroup("SoundGroup.xml"); + +// sgm->UpdateSoundGroups(TimeSinceLastFrame); // call in Frame() + +// sgm->PlayNext(index); // wash-rinse-repeat + + +// sgm->RemoveGroup(index); // Remove the group if you like + +// sgm->DeleteInstance(); // Delete instance in shutdown + + +#include "precompiled.h" +#include "SoundGroupMgr.h" + + +CSoundGroupMgr *CSoundGroupMgr::m_pInstance = 0; + +CSoundGroupMgr::CSoundGroupMgr() +{ + +} + +CSoundGroupMgr *CSoundGroupMgr::GetInstance() +{ + if(!m_pInstance) + m_pInstance = new CSoundGroupMgr(); + + return m_pInstance; + +} + +void CSoundGroupMgr::DeleteInstance() +{ + if(m_pInstance) + { + + vector::iterator vIter = m_pInstance->m_Groups.begin(); + while(vIter != m_pInstance->m_Groups.end()) + vIter = m_pInstance->RemoveGroup(vIter); + + delete m_pInstance; + } + m_pInstance = 0; + +} + +/////////////////////////////////////////// +// AddGroup() +// in: const char *XMLFile - the filename of the SoundGroup.xml to open +// out: size_t index into m_Groups +// Loads the given XML file and returns an index for later use +/////////////////////////////////////////// +size_t CSoundGroupMgr::AddGroup(const char *XMLFile) +{ + CSoundGroup* newGroup = new CSoundGroup(XMLFile); + m_Groups.push_back(newGroup); + + return m_Groups.size() - 1; +} + +/////////////////////////////////////////// +// RemoveGroup() +// in: size_t index into m_Groups +// out: vector::iterator - one past the index removed (sometimes useful) +// Removes and Releases a given soundgroup +/////////////////////////////////////////// +vector::iterator CSoundGroupMgr::RemoveGroup(size_t index) +{ + + vector::iterator vIter = m_Groups.begin(); + if(index >= m_Groups.size()) + return vIter; + + + + CSoundGroup *temp = (*vIter); + (*vIter)->ReleaseGroup(); + vIter = m_Groups.erase(vIter+index); + + delete temp; + + return vIter; + +} + +/////////////////////////////////////////// +// RemoveGroup() +// in: vector::iterator - item to remove +// out: vector::iterator - one past the index removed (sometimes useful) +// Removes and Releases a given soundgroup +/////////////////////////////////////////// +vector::iterator CSoundGroupMgr::RemoveGroup(vector::iterator iter) +{ + + (*iter)->ReleaseGroup(); + + CSoundGroup *temp = (*iter); + + iter = m_Groups.erase(iter); + + delete temp; + + return iter; + +} + +/////////////////////////////////////////// +// UpdateSoundGroups() +// updates all soundgroups, call in Frame() +/////////////////////////////////////////// +void CSoundGroupMgr::UpdateSoundGroups(float TimeSinceLastFrame) +{ + vector::iterator vIter = m_Groups.begin(); + while(vIter != m_Groups.end()) + { + (*vIter)->Update(TimeSinceLastFrame); + vIter++; + } +} + +/////////////////////////////////////////// +// PlayNext() +// in: size_t index - index into m_Groups +// Plays the next queued sound in an indexed group +/////////////////////////////////////////// +void CSoundGroupMgr::PlayNext(size_t index) +{ + m_Groups[index]->PlayNext(); +} \ No newline at end of file diff --git a/source/sound/SoundGroupMgr.h b/source/sound/SoundGroupMgr.h new file mode 100644 index 0000000000..ba5c5533c7 --- /dev/null +++ b/source/sound/SoundGroupMgr.h @@ -0,0 +1,79 @@ +/** +* ========================================================================= +* File : SoundGroupMgr.h +* Project : 0 A.D. +* Description : Manages and updates SoundGroups +* +* Author : Gavin Fowler +* ========================================================================= +*/ + + +/* +* Copyright (c) 2005-2006 Gavin Fowler +* +* Redistribution and/or modification are also permitted under the +* terms of the GNU General Public License as published by the +* Free Software Foundation (version 2 or later, at your option). +* +* This program 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. +*/ + +#include "SoundGroup.h" +#include +using namespace std; + +class CSoundGroupMgr +{ +public: + vector m_Groups; // a collection of sound groups + static CSoundGroupMgr *m_pInstance; // our static instance of the manager + static CSoundGroupMgr *GetInstance(); + static void DeleteInstance(); + + /////////////////////////////////////////// + // UpdateSoundGroups() + // updates all soundgroups, call in Frame() + /////////////////////////////////////////// + void UpdateSoundGroups(float TimeSinceLastFrame); + + /////////////////////////////////////////// + // PlayNext() + // in: size_t index - index into m_Groups + // Plays the next queued sound in an indexed group + /////////////////////////////////////////// + void PlayNext(size_t index); + + /////////////////////////////////////////// + // AddGroup() + // in: const char *XMLFile - the filename of the SoundGroup.xml to open + // out: size_t index into m_Groups + // Loads the given XML file and returns an index for later use + /////////////////////////////////////////// + size_t AddGroup(const char *XMLFile); + + /////////////////////////////////////////// + // RemoveGroup() + // in: size_t index into m_Groups + // out: vector::iterator - one past the index removed (sometimes useful) + // Removes and Releases a given soundgroup + /////////////////////////////////////////// + vector::iterator RemoveGroup(size_t index); + + /////////////////////////////////////////// + // RemoveGroup() + // in: vector::iterator - item to remove + // out: vector::iterator - one past the index removed (sometimes useful) + // Removes and Releases a given soundgroup + /////////////////////////////////////////// + vector::iterator RemoveGroup(vector::iterator iter); + + +private: + CSoundGroupMgr(); + CSoundGroupMgr(const CSoundGroupMgr &ref); + CSoundGroupMgr &operator=(const CSoundGroupMgr &ref); + +};