@@ -5,13 +5,21 @@ namespace RTE {
5
5
6
6
CONCRETECLASSINFO (SoundContainer, Entity, 0 );
7
7
8
+ const std::unordered_map<std::string, SoundContainer::SoundCycleMode> SoundContainer::c_CycleModeMap = {
9
+ {" Random" , SoundContainer::SoundCycleMode::MODE_RANDOM},
10
+ {" Forwards" , SoundContainer::SoundCycleMode::MODE_FORWARDS}
11
+ };
12
+
8
13
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9
14
10
15
void SoundContainer::Clear () {
11
- m_Sounds.clear ();
12
- m_SelectedSounds.clear ();
16
+ m_SoundSets.clear ();
17
+ m_SelectedSoundSet = 0 ;
18
+ m_SoundSelectionCycleMode = MODE_RANDOM;
19
+
13
20
m_PlayingChannels.clear ();
14
- m_AttenuationStartDistance = 1 ;
21
+
22
+ m_AttenuationStartDistance = c_DefaultAttenuationStartDistance;
15
23
m_Loops = 0 ;
16
24
m_Priority = AudioMan::PRIORITY_NORMAL;
17
25
m_AffectedByGlobalPitch = true ;
@@ -25,10 +33,16 @@ namespace RTE {
25
33
int SoundContainer::Create (const SoundContainer &reference) {
26
34
Entity::Create (reference);
27
35
28
- for (std::vector<std::pair<ContentFile, FMOD::Sound *>>::const_iterator itr = reference.m_Sounds .begin (); itr != reference.m_Sounds .end (); ++itr) {
29
- m_Sounds.push_back (*itr);
36
+ for (std::vector<SoundData> referenceSoundSet : reference.m_SoundSets ) {
37
+ std::vector<SoundData> soundSet;
38
+ for (SoundData referenceData : referenceSoundSet) {
39
+ soundSet.push_back (SoundData {referenceData.SoundFile , referenceData.SoundObject , referenceData.Offset , referenceData.MinimumAudibleDistance , referenceData.AttenuationStartDistance });
40
+ }
41
+ m_SoundSets.push_back (soundSet);
30
42
}
31
- m_SelectedSounds = reference.m_SelectedSounds ;
43
+ m_SelectedSoundSet = reference.m_SelectedSoundSet ;
44
+ m_SoundSelectionCycleMode = reference.m_SoundSelectionCycleMode ;
45
+
32
46
m_PlayingChannels.clear ();
33
47
34
48
m_AttenuationStartDistance = reference.m_AttenuationStartDistance ;
@@ -43,12 +57,15 @@ namespace RTE {
43
57
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
44
58
45
59
int SoundContainer::ReadProperty (std::string propName, Reader &reader) {
46
- if (propName == " AddSound" ) {
47
- ContentFile newFile;
48
- reader >> newFile;
49
- FMOD::Sound *pNewSample = newFile.GetAsSample ();
50
- if (!pNewSample) { reader.ReportError (std::string (" Failed to load the sample from the file" )); }
51
- m_Sounds.push_back (std::pair<ContentFile, FMOD::Sound *>(newFile, pNewSample));
60
+ if (propName == " AddSound" || propName == " AddSoundSet" ) {
61
+ return ReadSoundSet (propName, reader);
62
+ } else if (propName == " CycleMode" ) {
63
+ std::string cycleModeString = reader.ReadPropValue ();
64
+ if (c_CycleModeMap.find (cycleModeString) != c_CycleModeMap.end ()) {
65
+ m_SoundSelectionCycleMode = c_CycleModeMap.find (cycleModeString)->second ;
66
+ } else {
67
+ reader.ReportError (" Cycle mode " + cycleModeString + " is invalid." );
68
+ }
52
69
} else if (propName == " AttenuationStartDistance" ) {
53
70
reader >> m_AttenuationStartDistance;
54
71
} else if (propName == " LoopSetting" ) {
@@ -69,8 +86,66 @@ namespace RTE {
69
86
}
70
87
71
88
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
89
+
90
+ int SoundContainer::ReadSoundSet (std::string propName, Reader &reader) {
91
+ vector<SoundData> soundSet;
92
+ if (propName == " AddSound" ) {
93
+ soundSet.push_back (ReadSound (reader));
94
+ } else if (propName == " AddSoundSet" ) {
95
+ reader.ReadPropValue ();
96
+ while (reader.NextProperty ()) {
97
+ std::string soundSetSubPropertyName = reader.ReadPropName ();
98
+ if (soundSetSubPropertyName == " AddSound" ) {
99
+ soundSet.push_back (ReadSound (reader));
100
+ } else {
101
+ reader.ReportError (soundSetSubPropertyName + " is not a valid property of SoundSets." );
102
+ }
103
+ }
104
+ }
105
+
106
+ m_SoundSets.push_back (soundSet);
107
+ return 0 ;
108
+ }
109
+
110
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
111
+
112
+ SoundContainer::SoundData SoundContainer::ReadSound (Reader &reader) {
113
+ std::string propValue = reader.ReadPropValue ();
114
+ SoundData soundData;
115
+
116
+ auto readSound = [](const std::string &soundPath, Reader &parentReader, SoundData *outSoundData) {
117
+ ContentFile soundFile (soundPath.c_str ());
118
+ FMOD::Sound *soundObject = soundFile.GetAsSample ();
119
+ if (g_AudioMan.IsAudioEnabled () && !soundObject) { parentReader.ReportError (std::string (" Failed to load the sound from the file" )); }
120
+
121
+ outSoundData->SoundFile = soundFile;
122
+ outSoundData->SoundObject = soundObject;
123
+ };
124
+
125
+ if (propValue != " Sound" && propValue != " ContentFile" ) {
126
+ readSound (propValue, reader, &soundData);
127
+ return soundData;
128
+ }
129
+
130
+ while (reader.NextProperty ()) {
131
+ std::string soundSubPropertyName = reader.ReadPropName ();
132
+ if (soundSubPropertyName == " FilePath" || soundSubPropertyName == " Path" ) {
133
+ readSound (reader.ReadPropValue (), reader, &soundData);
134
+ } else if (soundSubPropertyName == " Offset" ) {
135
+ reader >> soundData.Offset ;
136
+ } else if (soundSubPropertyName == " MinimumAudibleDistance" ) {
137
+ reader >> soundData.MinimumAudibleDistance ;
138
+ } else if (soundSubPropertyName == " AttenuationStartDistance" ) {
139
+ reader >> soundData.AttenuationStartDistance ;
140
+ }
141
+ }
72
142
73
- void SoundContainer::AddSound (std::string const &soundFilePath, unsigned int soundSetIndex, const Vector &offset, float attenuationStartDistance, bool abortGameForInvalidSound) {
143
+ return soundData;
144
+ }
145
+
146
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
147
+
148
+ void SoundContainer::AddSound (std::string const &soundFilePath, unsigned int soundSetIndex, const Vector &offset, float minimumAudibleDistance, float attenuationStartDistance, bool abortGameForInvalidSound) {
74
149
vector<SoundData> soundSet;
75
150
if (soundSetIndex < m_SoundSets.size ()) { soundSet = m_SoundSets[soundSetIndex]; }
76
151
@@ -80,7 +155,8 @@ namespace RTE {
80
155
return ;
81
156
}
82
157
83
- soundSet.push_back ({soundFile, soundObject, offset, attenuationStartDistance});
158
+ attenuationStartDistance = attenuationStartDistance < 0 ? c_DefaultAttenuationStartDistance : attenuationStartDistance;
159
+ soundSet.push_back ({soundFile, soundObject, offset, minimumAudibleDistance, attenuationStartDistance});
84
160
if (soundSetIndex >= m_SoundSets.size ()) { m_SoundSets.push_back (soundSet); }
85
161
86
162
m_AllSoundPropertiesUpToDate = false ;
@@ -90,49 +166,59 @@ namespace RTE {
90
166
91
167
std::vector<size_t > SoundContainer::GetSelectedSoundHashes () {
92
168
std::vector<size_t > soundHashes;
93
- for (size_t selectedSoundIndex : m_SelectedSounds ) {
94
- soundHashes.push_back (m_Sounds[selectedSoundIndex]. first .GetHash ());
169
+ for (SoundData selectedSoundData : m_SoundSets[m_SelectedSoundSet] ) {
170
+ soundHashes.push_back (selectedSoundData. SoundFile .GetHash ());
95
171
}
96
172
return soundHashes;
97
173
}
98
174
99
175
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
100
-
101
- std::vector<FMOD::Sound *> SoundContainer::GetSelectedSoundObjects () {
102
- std::vector<FMOD::Sound *> soundObjects;
103
- for (size_t selectedSoundIndex : m_SelectedSounds) {
104
- soundObjects.push_back (m_Sounds[selectedSoundIndex].second );
176
+
177
+ SoundContainer::SoundData *SoundContainer::GetSoundDataForSound (FMOD::Sound *sound) {
178
+ for (std::vector<SoundData> soundSet : m_SoundSets) {
179
+ for (SoundData soundData : soundSet) {
180
+ if (sound == soundData.SoundObject ) {
181
+ return &soundData;
182
+ }
183
+ }
105
184
}
106
- return soundObjects ;
185
+ return NULL ;
107
186
}
108
187
109
188
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
110
189
111
- bool SoundContainer::SelectNextSounds () {
112
- int soundCount = GetSoundCount ();
113
- if (soundCount == 0 ) {
114
- return false ;
115
- }
116
- size_t previouslySelectedSound = (m_SelectedSounds.size () > 0 ) ? m_SelectedSounds[0 ] : 0 ;
190
+ bool SoundContainer::SelectNextSoundSet () {
191
+ int soundSetCount = m_SoundSets.size ();
192
+ switch (soundSetCount) {
193
+ case 0 :
194
+ return false ;
195
+ case 1 :
196
+ return true ;
197
+ case 2 :
198
+ m_SelectedSoundSet = (m_SelectedSoundSet + 1 ) % 2 ;
199
+ break ;
200
+ default :
201
+ auto selectRandomSound = [](int soundSetSize, size_t *outSelectedSoundSet) {
202
+ size_t soundToSelect = floorf (static_cast <float >(soundSetSize) * PosRand ());
203
+ while (soundToSelect == *outSelectedSoundSet) {
204
+ soundToSelect = floorf (static_cast <float >(soundSetSize) * PosRand ());
205
+ }
206
+ *outSelectedSoundSet = soundToSelect;
207
+ };
117
208
118
- if (m_SelectedSounds.empty () || soundCount == 1 ) {
119
- m_SelectedSounds.clear ();
120
- m_SelectedSounds.push_back (previouslySelectedSound);
121
- } else {
122
- m_SelectedSounds.clear ();
123
- if (soundCount == 2 ) {
124
- m_SelectedSounds.push_back ((previouslySelectedSound + 1 ) % soundCount);
125
- } else if (soundCount > 2 ) {
126
- size_t soundToSelect = floorf (static_cast <float >(soundCount) * PosRand ());
127
- // Mix it up again if we got the same sound twice
128
- while (soundToSelect == previouslySelectedSound) {
129
- soundToSelect = floorf (static_cast <float >(soundCount) * PosRand ());
209
+ switch (m_SoundSelectionCycleMode) {
210
+ case MODE_RANDOM:
211
+ selectRandomSound (soundSetCount, &m_SelectedSoundSet);
212
+ break ;
213
+ case MODE_FORWARDS:
214
+ m_SelectedSoundSet = (m_SelectedSoundSet + 1 ) % soundSetCount;
215
+ break ;
216
+ default :
217
+ RTEAbort (" Invalid sound cycle mode " + m_SoundSelectionCycleMode);
218
+ break ;
130
219
}
131
- m_SelectedSounds.push_back (soundToSelect);
132
- }
220
+ RTEAssert (m_SelectedSoundSet >= 0 && m_SelectedSoundSet < soundSetCount, " Failed to select next sound, either none was selected or the selected sound was invalid." );
133
221
}
134
- RTEAssert (m_SelectedSounds.size () > 0 && m_SelectedSounds[0 ] >= 0 && m_SelectedSounds[0 ] < soundCount, " Failed to select next sound, either none was selected or the selected sound was invalid." );
135
-
136
222
return true ;
137
223
}
138
224
@@ -141,19 +227,57 @@ namespace RTE {
141
227
FMOD_RESULT SoundContainer::UpdateSoundProperties () {
142
228
FMOD_RESULT result = FMOD_OK;
143
229
144
- for (std::vector<std::pair<ContentFile, FMOD::Sound * >>::const_iterator itr = m_Sounds.begin (); itr != m_Sounds.end () && result == FMOD_OK; ++itr) {
145
- FMOD_MODE soundMode = (m_Loops == 0 ) ? FMOD_LOOP_OFF : FMOD_LOOP_NORMAL;
146
- if (m_Immobile) {
147
- soundMode |= FMOD_3D_HEADRELATIVE;
148
- m_AttenuationStartDistance = 100000 ;
149
- }
230
+ for (std::vector<SoundData> &soundSet : m_SoundSets) {
231
+ for (SoundData &soundData : soundSet) {
232
+ FMOD_MODE soundMode = (m_Loops == 0 ) ? FMOD_LOOP_OFF : FMOD_LOOP_NORMAL;
233
+ if (m_Immobile) {
234
+ soundMode |= FMOD_3D_HEADRELATIVE;
235
+ m_AttenuationStartDistance = c_SoundMaxAudibleDistance;
236
+ } else {
237
+ soundMode |= FMOD_3D_CUSTOMROLLOFF;
238
+ }
239
+
240
+ result = (result == FMOD_OK) ? soundData.SoundObject ->setMode (soundMode) : result;
241
+ result = (result == FMOD_OK) ? soundData.SoundObject ->setLoopCount (m_Loops) : result;
242
+ if (m_Immobile) {
243
+ result = (result == FMOD_OK) ? soundData.SoundObject ->set3DMinMaxDistance (m_AttenuationStartDistance, c_SoundMaxAudibleDistance) : result;
244
+ } else {
245
+ // FMOD_VECTOR customRolloffPoints[10];
246
+ // CalculateCustomRolloffPoints(soundData, customRolloffPoints, 10);
150
247
151
- result = (result == FMOD_OK) ? itr->second ->setMode (soundMode) : result;
152
- result = (result == FMOD_OK) ? itr->second ->setLoopCount (m_Loops) : result;
153
- result = (result == FMOD_OK) ? itr->second ->set3DMinMaxDistance (m_AttenuationStartDistance, 100000 ) : result;
248
+ // TODO Consider replacing this with normal min and max distance (but keep custom rolloff mode) so we can save some pointing issues. Might need to store min audible distance in audioman if fmod is strict about min and max distance sizes wrt each other.
249
+ soundData.CustomRolloffPoints [0 ] = FMOD_VECTOR{soundData.MinimumAudibleDistance , 0 , 0 };
250
+ soundData.CustomRolloffPoints [1 ] = FMOD_VECTOR{soundData.AttenuationStartDistance < 0 ? m_AttenuationStartDistance : soundData.AttenuationStartDistance , 1 , 0 };
251
+ result = (result == FMOD_OK) ? soundData.SoundObject ->set3DCustomRolloff (soundData.CustomRolloffPoints , 2 ) : result;
252
+ }
253
+ }
154
254
}
155
255
m_AllSoundPropertiesUpToDate = result == FMOD_OK;
156
256
157
257
return result;
158
258
}
259
+
260
+ // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
261
+
262
+ // TODO this needs to be used or be deleted
263
+ void SoundContainer::CalculateCustomRolloffPoints (const SoundData &soundDataToCalculateFor, FMOD_VECTOR *rolloffPoints, int numRolloffPoints) {
264
+ int attenuationStartDistance = soundDataToCalculateFor.AttenuationStartDistance < 0 ? m_AttenuationStartDistance : soundDataToCalculateFor.AttenuationStartDistance ;
265
+ float currentDistance = attenuationStartDistance;
266
+ float currentVolumeLevel = 1 ;
267
+
268
+ int i = 0 ;
269
+ if (soundDataToCalculateFor.MinimumAudibleDistance > 0 ) {
270
+ i = 2 ;
271
+ currentDistance += soundDataToCalculateFor.MinimumAudibleDistance ;
272
+ rolloffPoints[0 ] = FMOD_VECTOR{0 , 0 , 0 };
273
+ rolloffPoints[1 ] = FMOD_VECTOR{soundDataToCalculateFor.MinimumAudibleDistance - 0 .1F , 0 , 0 };
274
+ }
275
+
276
+ for (i = (soundDataToCalculateFor.MinimumAudibleDistance > 0 ? 2 : 0 ); i < numRolloffPoints - 1 ; i++) {
277
+ rolloffPoints[i] = FMOD_VECTOR{currentDistance, currentVolumeLevel, 0 };
278
+ currentDistance += attenuationStartDistance;
279
+ currentVolumeLevel = currentDistance < c_SoundMaxAudibleDistance ? currentVolumeLevel * 0.5 : 0 ;
280
+ }
281
+ rolloffPoints[numRolloffPoints - 1 ] = FMOD_VECTOR{currentDistance, 0 , 0 };
282
+ }
159
283
}
0 commit comments