@@ -4,25 +4,19 @@ namespace RTE {
4
4
5
5
ConcreteClassInfo (SoundContainer, Entity, 50 );
6
6
7
- const std::unordered_map<std::string, SoundContainer::SoundCycleMode> SoundContainer::c_SoundCycleModeMap = {
8
- {" Random" , SoundContainer::SoundCycleMode::MODE_RANDOM},
9
- {" Forwards" , SoundContainer::SoundCycleMode::MODE_FORWARDS}
10
- };
11
7
const std::unordered_map<std::string, SoundContainer::SoundOverlapMode> SoundContainer::c_SoundOverlapModeMap = {
12
- {" Overlap" , SoundContainer::SoundOverlapMode::MODE_OVERLAP },
13
- {" Restart" , SoundContainer::SoundOverlapMode::MODE_RESTART },
14
- {" Ignore Play" , SoundContainer::SoundOverlapMode::MODE_IGNORE_PLAY }
8
+ {" Overlap" , SoundContainer::SoundOverlapMode::OVERLAP },
9
+ {" Restart" , SoundContainer::SoundOverlapMode::RESTART },
10
+ {" Ignore Play" , SoundContainer::SoundOverlapMode::IGNORE_PLAY }
15
11
};
16
12
17
13
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
18
14
19
15
void SoundContainer::Clear () {
20
- m_SoundSets.clear ();
21
- m_SelectedSoundSet = 0 ;
22
- m_SoundSelectionCycleMode = MODE_RANDOM;
16
+ m_TopLevelSoundSet.Destroy ();
23
17
24
18
m_PlayingChannels.clear ();
25
- m_SoundOverlapMode = MODE_OVERLAP ;
19
+ m_SoundOverlapMode = SoundOverlapMode::OVERLAP ;
26
20
27
21
m_Immobile = false ;
28
22
m_AttenuationStartDistance = c_DefaultAttenuationStartDistance;
@@ -42,15 +36,7 @@ namespace RTE {
42
36
int SoundContainer::Create (const SoundContainer &reference) {
43
37
Entity::Create (reference);
44
38
45
- for (const std::vector<SoundData> &referenceSoundSet : reference.m_SoundSets ) {
46
- std::vector<SoundData> soundSet;
47
- for (const SoundData &referenceData : referenceSoundSet) {
48
- soundSet.push_back (SoundData {referenceData.SoundFile , referenceData.SoundObject , referenceData.Offset , referenceData.MinimumAudibleDistance , referenceData.AttenuationStartDistance });
49
- }
50
- m_SoundSets.push_back (soundSet);
51
- }
52
- m_SelectedSoundSet = reference.m_SelectedSoundSet ;
53
- m_SoundSelectionCycleMode = reference.m_SoundSelectionCycleMode ;
39
+ m_TopLevelSoundSet.Create (reference.m_TopLevelSoundSet );
54
40
55
41
m_PlayingChannels.clear ();
56
42
m_SoundOverlapMode = reference.m_SoundOverlapMode ;
@@ -72,15 +58,14 @@ namespace RTE {
72
58
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
73
59
74
60
int SoundContainer::ReadProperty (std::string propName, Reader &reader) {
75
- if (propName == " AddSound" || propName == " AddSoundSet" ) {
76
- return ReadSoundOrSoundSet (propName, reader);
77
- } else if (propName == " CycleMode" ) {
78
- std::string cycleModeString = reader.ReadPropValue ();
79
- if (c_SoundCycleModeMap.find (cycleModeString) != c_SoundCycleModeMap.end ()) {
80
- m_SoundSelectionCycleMode = c_SoundCycleModeMap.find (cycleModeString)->second ;
81
- } else {
82
- reader.ReportError (" Cycle mode " + cycleModeString + " is invalid." );
83
- }
61
+ if (propName == " AddSound" ) {
62
+ m_TopLevelSoundSet.AddSoundData (SoundSet::ReadAndGetSound (reader));
63
+ } else if (propName == " AddSoundSet" ) {
64
+ SoundSet subSoundSet;
65
+ reader >> subSoundSet;
66
+ m_TopLevelSoundSet.AddSubSoundSet (subSoundSet);
67
+ } else if (propName == " SoundSelectionCycleMode" || propName == " CycleMode" ) {
68
+ m_TopLevelSoundSet.SetSoundSelectionCycleMode (SoundSet::ReadSoundSelectionCycleMode (reader));
84
69
} else if (propName == " OverlapMode" ) {
85
70
std::string overlapModeString = reader.ReadPropValue ();
86
71
if (c_SoundOverlapModeMap.find (overlapModeString) != c_SoundOverlapModeMap.end ()) {
@@ -112,110 +97,22 @@ namespace RTE {
112
97
return 0 ;
113
98
}
114
99
115
- // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
116
-
117
- int SoundContainer::ReadSoundOrSoundSet (const std::string &propName, Reader &reader) {
118
- vector<SoundData> soundSet;
119
- if (propName == " AddSound" ) {
120
- soundSet.push_back (ReadAndGetSound (reader));
121
- } else if (propName == " AddSoundSet" ) {
122
- reader.ReadPropValue ();
123
- while (reader.NextProperty ()) {
124
- std::string soundSetSubPropertyName = reader.ReadPropName ();
125
- if (soundSetSubPropertyName == " AddSound" ) {
126
- soundSet.push_back (ReadAndGetSound (reader));
127
- } else {
128
- reader.ReportError (soundSetSubPropertyName + " is not a valid property of SoundSets." );
129
- }
130
- }
131
- }
132
-
133
- m_SoundSets.push_back (soundSet);
134
- return 0 ;
135
- }
136
-
137
- // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
138
-
139
- SoundContainer::SoundData SoundContainer::ReadAndGetSound (Reader &reader) const {
140
- std::string propValue = reader.ReadPropValue ();
141
- SoundData soundData;
142
-
143
- // / <summary>
144
- // / Internal lambda function to load an audio file by path in as a ContentFile, which in turn loads it into FMOD, then returns SoundData for it in the outParam outSoundData.
145
- // / </summary>
146
- // / <param name="soundPath">The path to the sound file.</param>
147
- auto readSound = [&soundData, &reader](const std::string &soundPath) {
148
- ContentFile soundFile (soundPath.c_str ());
149
- soundFile.SetFormattedReaderPosition (" in file " + reader.GetCurrentFilePath () + " on line " + std::to_string (reader.GetCurrentFileLine ()));
150
- FMOD::Sound *soundObject = soundFile.GetAsSound ();
151
- if (g_AudioMan.IsAudioEnabled () && !soundObject) { reader.ReportError (std::string (" Failed to load the sound from the file" )); }
152
-
153
- soundData.SoundFile = soundFile;
154
- soundData.SoundObject = soundObject;
155
- };
156
-
157
- if (propValue != " Sound" && propValue != " ContentFile" ) {
158
- readSound (propValue);
159
- return soundData;
160
- }
161
-
162
- while (reader.NextProperty ()) {
163
- std::string soundSubPropertyName = reader.ReadPropName ();
164
- if (soundSubPropertyName == " FilePath" || soundSubPropertyName == " Path" ) {
165
- readSound (reader.ReadPropValue ());
166
- } else if (soundSubPropertyName == " Offset" ) {
167
- reader >> soundData.Offset ;
168
- } else if (soundSubPropertyName == " MinimumAudibleDistance" ) {
169
- reader >> soundData.MinimumAudibleDistance ;
170
- } else if (soundSubPropertyName == " AttenuationStartDistance" ) {
171
- reader >> soundData.AttenuationStartDistance ;
172
- }
173
- }
174
-
175
- return soundData;
176
- }
177
-
178
100
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
179
101
180
102
int SoundContainer::Save (Writer &writer) const {
181
103
Entity::Save (writer);
182
104
183
- for (const std::vector<SoundData> &soundSet : m_SoundSets) {
184
- writer.NewProperty (" AddSoundSet" );
185
- writer.ObjectStart (" SoundSet" );
105
+ writer << m_TopLevelSoundSet;
186
106
187
- for (const SoundData &soundData : soundSet) {
188
- writer.NewProperty (" AddSound" );
189
- writer.ObjectStart (" ContentFile" );
190
-
191
- writer.NewProperty (" FilePath" );
192
- writer << soundData.SoundFile .GetDataPath ();
193
- writer.NewProperty (" Offset" );
194
- writer << soundData.Offset ;
195
- writer.NewProperty (" MinimumAudibleDistance" );
196
- writer << soundData.MinimumAudibleDistance ;
197
- writer.NewProperty (" AttenuationStartDistance" );
198
- writer << soundData.AttenuationStartDistance ;
199
-
200
- writer.ObjectEnd ();
201
- }
202
- writer.ObjectEnd ();
203
- }
204
-
205
- writer.NewProperty (" CycleMode" );
206
- std::list<std::pair<const std::string, SoundCycleMode>>::const_iterator cycleModeMapEntry = std::find_if (c_SoundCycleModeMap.begin (), c_SoundCycleModeMap.end (), [&soundSelectionCycleMode = m_SoundSelectionCycleMode](auto element) { return element.second == soundSelectionCycleMode; });
207
- if (cycleModeMapEntry != c_SoundCycleModeMap.end ()) {
208
- writer << cycleModeMapEntry->first ;
209
- } else {
210
- writer << m_SoundSelectionCycleMode;
211
- }
107
+ writer.NewProperty (" SoundSelectionCycleMode" );
108
+ SoundSet::SaveSoundSelectionCycleMode (writer, m_TopLevelSoundSet.GetSoundSelectionCycleMode ());
212
109
213
110
writer.NewProperty (" OverlapMode" );
214
111
std::list<std::pair<const std::string, SoundOverlapMode>>::const_iterator overlapModeMapEntry = std::find_if (c_SoundOverlapModeMap.begin (), c_SoundOverlapModeMap.end (), [&soundOverlapMode = m_SoundOverlapMode](auto element) { return element.second == soundOverlapMode; });
215
112
if (overlapModeMapEntry != c_SoundOverlapModeMap.end ()) {
216
113
writer << overlapModeMapEntry->first ;
217
114
} else {
218
- writer << m_SoundOverlapMode ;
115
+ RTEAbort ( " Tried to write invalid SoundOverlapMode when saving SoundContainer. " ) ;
219
116
}
220
117
221
118
writer.NewProperty (" Immobile" );
@@ -242,53 +139,37 @@ namespace RTE {
242
139
243
140
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
244
141
245
- void SoundContainer::AddSound (const std::string &soundFilePath, unsigned int soundSetIndex, const Vector &offset, float minimumAudibleDistance, float attenuationStartDistance, bool abortGameForInvalidSound) {
246
- std::vector<SoundData> soundSet;
247
- if (soundSetIndex < m_SoundSets.size ()) { soundSet = m_SoundSets[soundSetIndex]; }
248
-
249
- ContentFile soundFile (soundFilePath.c_str ());
250
- FMOD::Sound *soundObject = soundFile.GetAsSound (abortGameForInvalidSound, false );
251
- if (!soundObject) {
252
- return ;
253
- }
254
-
255
- soundSet.push_back ({soundFile, soundObject, offset, minimumAudibleDistance, attenuationStartDistance});
256
- if (soundSetIndex >= m_SoundSets.size ()) { m_SoundSets.push_back (soundSet); }
257
-
258
- m_SoundPropertiesUpToDate = false ;
259
- }
260
-
261
- // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
262
-
263
- std::vector<size_t > SoundContainer::GetSelectedSoundHashes () const {
142
+ std::vector<std::size_t > SoundContainer::GetSelectedSoundHashes () const {
264
143
std::vector<size_t > soundHashes;
265
- for (const SoundData &selectedSoundData : m_SoundSets[m_SelectedSoundSet]) {
266
- soundHashes.push_back (selectedSoundData.SoundFile .GetHash ());
144
+ std::vector<SoundSet::SoundData *> flattenedSoundData;
145
+ m_TopLevelSoundSet.GetFlattenedSoundData (flattenedSoundData, false );
146
+ for (const SoundSet::SoundData *selectedSoundData : flattenedSoundData) {
147
+ soundHashes.push_back (selectedSoundData->SoundFile .GetHash ());
267
148
}
268
149
return soundHashes;
269
150
}
270
151
271
152
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
272
153
273
- const SoundContainer ::SoundData *SoundContainer::GetSoundDataForSound (const FMOD::Sound *sound) const {
274
- for ( const std::vector<SoundData> &soundSet : m_SoundSets) {
275
- for ( const SoundData &soundData : soundSet) {
276
- if (sound == soundData. SoundObject ) {
277
- return & soundData;
278
- }
154
+ const SoundSet ::SoundData * SoundContainer::GetSoundDataForSound (const FMOD::Sound *sound) const {
155
+ std::vector<SoundSet:: SoundData *> flattenedSoundData;
156
+ m_TopLevelSoundSet. GetFlattenedSoundData (flattenedSoundData, false );
157
+ for ( const SoundSet::SoundData * soundData : flattenedSoundData ) {
158
+ if (sound == soundData-> SoundObject ) {
159
+ return soundData;
279
160
}
280
161
}
281
- return NULL ;
162
+ return nullptr ;
282
163
}
283
164
284
165
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
285
166
286
167
bool SoundContainer::Play (int player) {
287
168
if (HasAnySounds ()) {
288
169
if (IsBeingPlayed ()) {
289
- if (m_SoundOverlapMode == MODE_RESTART ) {
170
+ if (m_SoundOverlapMode == SoundOverlapMode::RESTART ) {
290
171
Restart (player);
291
- } else if (m_SoundOverlapMode == MODE_IGNORE_PLAY ) {
172
+ } else if (m_SoundOverlapMode == SoundOverlapMode::IGNORE_PLAY ) {
292
173
return false ;
293
174
}
294
175
}
@@ -298,65 +179,25 @@ namespace RTE {
298
179
return false ;
299
180
}
300
181
301
- // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
302
-
303
- bool SoundContainer::SelectNextSoundSet () {
304
- int soundSetCount = m_SoundSets.size ();
305
- switch (soundSetCount) {
306
- case 0 :
307
- return false ;
308
- case 1 :
309
- return true ;
310
- case 2 :
311
- m_SelectedSoundSet = (m_SelectedSoundSet + 1 ) % 2 ;
312
- break ;
313
- default :
314
- // / <summary>
315
- // / Internal lambda function to pick a random sound that's not the previously played sound. Done to avoid scoping issues inside the switch below.
316
- // / </summary>
317
- auto selectRandomSound = [&soundSetCount, this ]() {
318
- size_t soundToSelect = RandomNum (0 , soundSetCount - 1 );
319
- while (soundToSelect == m_SelectedSoundSet) {
320
- soundToSelect = RandomNum (0 , soundSetCount - 1 );
321
- }
322
- m_SelectedSoundSet = soundToSelect;
323
- };
324
-
325
- switch (m_SoundSelectionCycleMode) {
326
- case MODE_RANDOM:
327
- selectRandomSound ();
328
- break ;
329
- case MODE_FORWARDS:
330
- m_SelectedSoundSet = (m_SelectedSoundSet + 1 ) % soundSetCount;
331
- break ;
332
- default :
333
- RTEAbort (" Invalid sound cycle mode " + m_SoundSelectionCycleMode);
334
- break ;
335
- }
336
- RTEAssert (m_SelectedSoundSet >= 0 && m_SelectedSoundSet < soundSetCount, " Failed to select next sound, either none was selected or the selected sound was invalid." );
337
- }
338
- return true ;
339
- }
340
-
341
182
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
342
183
343
184
FMOD_RESULT SoundContainer::UpdateSoundProperties () {
344
185
FMOD_RESULT result = FMOD_OK;
345
186
346
- for (std::vector<SoundData> &soundSet : m_SoundSets) {
347
- for (SoundData &soundData : soundSet) {
348
- FMOD_MODE soundMode = (m_Loops == 0 ) ? FMOD_LOOP_OFF : FMOD_LOOP_NORMAL;
349
- if (m_Immobile) {
350
- soundMode |= FMOD_3D_HEADRELATIVE;
351
- m_AttenuationStartDistance = c_SoundMaxAudibleDistance;
352
- } else {
353
- soundMode |= FMOD_3D_INVERSEROLLOFF;
354
- }
355
-
356
- result = (result == FMOD_OK) ? soundData.SoundObject ->setMode (soundMode) : result;
357
- result = (result == FMOD_OK) ? soundData.SoundObject ->setLoopCount (m_Loops) : result;
358
- result = (result == FMOD_OK) ? soundData.SoundObject ->set3DMinMaxDistance (soundData.MinimumAudibleDistance + std::max (0 .0F , m_AttenuationStartDistance), c_SoundMaxAudibleDistance) : result;
187
+ std::vector<SoundSet::SoundData *> flattenedSoundData;
188
+ m_TopLevelSoundSet.GetFlattenedSoundData (flattenedSoundData, false );
189
+ for (SoundSet::SoundData *soundData : flattenedSoundData) {
190
+ FMOD_MODE soundMode = (m_Loops == 0 ) ? FMOD_LOOP_OFF : FMOD_LOOP_NORMAL;
191
+ if (m_Immobile) {
192
+ soundMode |= FMOD_3D_HEADRELATIVE;
193
+ m_AttenuationStartDistance = c_SoundMaxAudibleDistance;
194
+ } else {
195
+ soundMode |= FMOD_3D_INVERSEROLLOFF;
359
196
}
197
+
198
+ result = (result == FMOD_OK) ? soundData->SoundObject ->setMode (soundMode) : result;
199
+ result = (result == FMOD_OK) ? soundData->SoundObject ->setLoopCount (m_Loops) : result;
200
+ result = (result == FMOD_OK) ? soundData->SoundObject ->set3DMinMaxDistance (soundData->MinimumAudibleDistance + std::max (0 .0F , m_AttenuationStartDistance), c_SoundMaxAudibleDistance) : result;
360
201
}
361
202
m_SoundPropertiesUpToDate = result == FMOD_OK;
362
203
0 commit comments