Skyscraper 2.0
soundsystem.cpp
Go to the documentation of this file.
1/*
2 Scalable Building Simulator - Sound System
3 The Skyscraper Project - Version 2.0
4 Copyright (C)2004-2024 Ryan Thoryk
5 https://www.skyscrapersim.net
6 https://sourceforge.net/projects/skyscraper/
7 Contact - ryan@skyscrapersim.net
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22*/
23
24#ifndef DISABLE_SOUND
25 #include <fmod.hpp>
26 #include <fmod_errors.h>
27#endif
28
29#include "globals.h"
30#include "sbs.h"
31#include "camera.h"
32#include "sound.h"
33#include "profiler.h"
34#include "soundsystem.h"
35
36namespace SBS {
37
38SoundSystem::SoundSystem(Object *parent, FMOD::System *fmodsystem) : Object(parent)
39{
40 SetValues("SoundSystem", "Sound System", true, false);
41
42#ifndef DISABLE_SOUND
43 soundsys = fmodsystem;
44#endif
45
46 listener_position = Vector3::ZERO;
47 listener_velocity = Vector3::ZERO;
48 listener_forward = Vector3::ZERO;
49 listener_up = Vector3::ZERO;
50 Position = Vector3::ZERO;
51
52#ifndef DISABLE_SOUND
53 //set up sound options (mainly to set sound distance factor to feet instead of meters)
54 soundsys->set3DSettings(1.0f, 3.28f, 1.0f);
55#endif
56}
57
59{
60 SetValues("SoundSystem", "Sound System", true, false);
61
62 listener_position = Vector3::ZERO;
63 listener_velocity = Vector3::ZERO;
64 listener_forward = Vector3::ZERO;
65 listener_up = Vector3::ZERO;
66 Position = Vector3::ZERO;
67}
68
70{
71 for (size_t i = 0; i < sounds.size(); i++)
72 delete sounds[i];
73
74 //for (size_t i = 0; i < reverbs.size(); i++)
75 //delete reverbs[i].object;
76}
77
79{
80#ifndef DISABLE_SOUND
81 //update sound
82 if (enable_advanced_profiling == false)
84 else
86
87 //sync sound listener object to camera position
88 if (sbs->camera->IsActive() == true)
90
91 //set direction of listener to camera's direction
92 Vector3 front = Vector3::ZERO;
93 Vector3 top = Vector3::ZERO;
94 sbs->camera->GetDirection(front, top, true);
95 SetListenerDirection(front, top);
96
97 //update FMOD
98 soundsys->update();
99
101#endif
102}
103
105{
106 //set position of sound listener object
107
108#ifndef DISABLE_SOUND
109
110 unsigned int timing;
111 if (sbs->SmoothFrames > 0)
112 timing = sbs->GetAverageTime();
113 else
114 timing = sbs->GetElapsedTime();
115
116 //calculate sound velocity
117 if (timing > 0)
118 {
119 listener_velocity.x = (float)(position.x - Position.x) * (1000 / timing);
120 listener_velocity.y = (float)(position.y - Position.y) * (1000 / timing);
121 listener_velocity.z = (float)(position.z - Position.z) * (1000 / timing);
122 }
123
124 Position = position;
125
126 Vector3 global_position = sbs->ToGlobal(position);
127
128 listener_position.x = (float)global_position.x;
129 listener_position.y = (float)global_position.y;
130 listener_position.z = (float)global_position.z;
131
132 //copy data structures
133 FMOD_VECTOR pos;
134 pos.x = listener_position.x;
135 pos.y = listener_position.y;
136 pos.z = listener_position.z;
137 FMOD_VECTOR vel;
138 vel.x = listener_velocity.x;
139 vel.y = listener_velocity.y;
140 vel.z = listener_velocity.z;
141 FMOD_VECTOR forward;
142 forward.x = listener_forward.x;
143 forward.y = listener_forward.y;
144 forward.z = listener_forward.z;
145 FMOD_VECTOR up;
146 up.x = listener_up.x;
147 up.y = listener_up.y;
148 up.z = listener_up.z;
149
150 //set attributes
151 soundsys->set3DListenerAttributes(0, &pos, &vel, &forward, &up);
152#endif
153}
154
156{
157 //set direction of sound listener object
158
159 #ifndef DISABLE_SOUND
160
161 listener_forward.x = (float)front.x;
162 listener_forward.y = (float)front.y;
163 listener_forward.z = (float)front.z;
164 listener_up.x = (float)top.x;
165 listener_up.y = (float)top.y;
166 listener_up.z = (float)top.z;
167
168 //copy data structures
169 FMOD_VECTOR pos;
170 pos.x = listener_position.x;
171 pos.y = listener_position.y;
172 pos.z = listener_position.z;
173 FMOD_VECTOR vel;
174 vel.x = listener_velocity.x;
175 vel.y = listener_velocity.y;
176 vel.z = listener_velocity.z;
177 FMOD_VECTOR forward;
178 forward.x = listener_forward.x;
179 forward.y = listener_forward.y;
180 forward.z = listener_forward.z;
181 FMOD_VECTOR up;
182 up.x = listener_up.x;
183 up.y = listener_up.y;
184 up.z = listener_up.z;
185
186 //set attributes
187 soundsys->set3DListenerAttributes(0, &pos, &vel, &forward, &up);
188#endif
189}
190
191void SoundSystem::Cleanup(int index)
192{
193 //unloads sounds that are not associated with any channels
194
195 if (sbs->Verbose)
196 Report("Cleaning up unused sounds");
197
198 if (index >= 0 && index < GetSoundCount())
199 {
200 if (sounds[index]->handles.size() == 0)
201 {
202 delete sounds[index];
203 sounds.erase(sounds.begin() + index);
204 }
205 return;
206 }
207
208 for (int i = 0; i < GetSoundCount(); i++)
209 {
210 if (sounds[i]->handles.size() == 0)
211 {
212 delete sounds[i];
213 sounds.erase(sounds.begin() + i);
214 i--;
215 }
216 }
217}
218
220{
221 //get length of sound in milliseconds
222
223 if (!data)
224 return 0;
225
226 unsigned int length = 0;
227#ifndef DISABLE_SOUND
228 data->sound->getLength(&length, FMOD_TIMEUNIT_MS);
229#endif
230 return length;
231}
232
233SoundData* SoundSystem::Load(const std::string &filename)
234{
235 //load a sound file from specified filename
236
237 //exit if none specified
238 if (filename == "")
239 return 0;
240
241#ifndef DISABLE_SOUND
242 //return existing data element if file is already loaded
243 SoundData *existing = GetSoundData(filename);
244 if (existing)
245 return existing;
246
247 //create new SoundData element
248 SoundData *data = new SoundData();
249 data->filename = SetCaseCopy(filename, false);
250
251 //load new sound
252 std::string full_filename1 = "data/";
253 full_filename1.append(filename);
254 std::string processed = sbs->VerifyFile(full_filename1);
255 std::string full_filename = sbs->GetFilesystemPath(processed);
256
257#if (FMOD_VERSION >> 16 == 4)
258 FMOD_RESULT result = soundsys->createSound(full_filename.c_str(), (FMOD_MODE)(FMOD_3D | FMOD_ACCURATETIME | FMOD_SOFTWARE | FMOD_LOOP_NORMAL), 0, &data->sound);
259 //FMOD_RESULT result = soundsys->createStream(full_filename.c_str(), (FMOD_MODE)(FMOD_SOFTWARE | FMOD_3D), 0, &data.sound); //streamed version
260#else
261 FMOD_RESULT result = soundsys->createSound(full_filename.c_str(), (FMOD_MODE)(FMOD_3D | FMOD_ACCURATETIME | FMOD_LOOP_NORMAL), 0, &data->sound);
262 //FMOD_RESULT result = soundsys->createStream(full_filename.c_str(), (FMOD_MODE)(FMOD_3D), 0, &data.sound); //streamed version
263#endif
264
265 if (result != FMOD_OK)
266 {
267 std::string fmod_result = FMOD_ErrorString(result);
268 ReportError("Can't load file '" + filename + "':\n" + fmod_result);
269 return 0;
270 }
271
272 //add sound element to array
273 sounds.emplace_back(data);
274
275 return data;
276#else
277 return 0;
278#endif
279}
280
281bool SoundSystem::IsLoaded(std::string filename)
282{
283 //return true if a specific file is already loaded
284
285 SetCase(filename, false);
286 for (int i = 0; i < GetSoundCount(); i++)
287 {
288 std::string check = sounds[i]->filename;
289
290 if (check == filename)
291 return true;
292 }
293 return false;
294}
295
296#ifndef DISABLE_SOUND
297FMOD::Channel* SoundSystem::Prepare(SoundData *data)
298{
299 //prepare a sound for play - this allocates a channel
300
301 if (!data)
302 return 0;
303
304 FMOD::Channel *channel = 0;
305#if (FMOD_VERSION >> 16 == 4)
306 FMOD_RESULT result = soundsys->playSound(FMOD_CHANNEL_FREE, data->sound, true, &channel);
307#else
308 FMOD_RESULT result = soundsys->playSound(data->sound, 0, true, &channel);
309#endif
310
311 if (result != FMOD_OK || !channel)
312 return 0;
313
314 data->AddChannel(channel);
315
316 return channel;
317}
318#endif
319
321{
322 //get sound data element for related filename
323
324 SetCase(filename, false);
325 for (int i = 0; i < GetSoundCount(); i++)
326 {
327 if (sounds[i]->filename == filename)
328 return sounds[i];
329 }
330 return 0;
331}
332
334{
335 //get sound data element
336
337 if (number <= GetSoundCount())
338 return sounds[number];
339
340 return 0;
341}
342
343void SoundSystem::Report(const std::string &message)
344{
345 Object::Report("Sound System: " + message);
346}
347
348bool SoundSystem::ReportError(const std::string &message)
349{
350 return Object::ReportError("Sound System: " + message);
351}
352
354{
355 //get number of playing channels
356
357 int num = 0;
358#ifndef DISABLE_SOUND
359 soundsys->getChannelsPlaying(&num);
360#endif
361 return num;
362}
363
365{
366 return (int)sounds.size();
367}
368
370{
371#ifndef DISABLE_SOUND
372 Object::Report("");
373 Object::Report("--- Loaded Sounds ---");
374 Object::Report("");
375 Object::Report("Filename\t----\tSound Objects\t----\tChannels");
376 for (int i = 0; i < GetSoundCount(); i++)
377 {
378 Object::Report(sounds[i]->filename + "\t----\t" + ToString(sounds[i]->GetHandleCount()) + "\t----\t" + ToString(sounds[i]->GetChannelCount()));
379 }
380 Object::Report("");
381 Object::Report("Total loaded sounds: " + ToString(GetSoundCount()));
382#endif
383}
384
386{
387 if (verbose == true)
388 {
389 Object::Report("");
390 Object::Report("--- Playing Sounds ---");
391 Object::Report("");
392 }
393 for (int i = 0; i < GetSoundCount(); i++)
394 {
395 bool first = true;
396 for (int j = 0; j < sounds[i]->GetHandleCount(); j++)
397 {
398 if (sounds[i]->handles[j]->IsPlaying() == true)
399 {
400 if (first == true)
401 Object::Report(sounds[i]->filename + ":");
402 first = false;
403 Sound *sound = sounds[i]->handles[j];
404 Object::Report("\t" + sound->GetName() + "\t----\tParent: " + sound->GetParent()->GetName());
405 }
406 }
407 }
408 if (verbose == true)
409 {
410 Object::Report("");
412 }
413}
414
416{
417 Object::Report("Total playing sounds: " + ToString(GetPlayingCount()));
418}
419
420#ifndef DISABLE_SOUND
422{
423 return soundsys;
424}
425#endif
426
428{
429 sound = 0;
430}
431
433{
434#ifndef DISABLE_SOUND
435 if (sound)
436 sound->release();
437 sound = 0;
438#endif
439}
440
442{
443 //add a sound object handle
444
445 if (handle == 0)
446 return;
447
448 for (int i = 0; i < GetHandleCount(); i++)
449 {
450 if (handles[i] == handle)
451 return;
452 }
453 handles.emplace_back(handle);
454}
455
457{
458 //remove a sound object handle
459
460 if (handle == 0)
461 return;
462
463 for (int i = 0; i < GetHandleCount(); i++)
464 {
465 if (handles[i] == handle)
466 {
467 handles.erase(handles.begin() + i);
468#ifndef DISABLE_SOUND
469 RemoveChannel(handle->GetChannel());
470#endif
471 return;
472 }
473 }
474}
475
476#ifndef DISABLE_SOUND
477void SoundData::AddChannel(FMOD::Channel *channel)
478{
479 //add a sound channel
480
481 if (channel == 0)
482 return;
483
484 for (int i = 0; i < GetChannelCount(); i++)
485 {
486 if (channels[i] == channel)
487 return;
488 }
489 channels.emplace_back(channel);
490}
491
492void SoundData::RemoveChannel(FMOD::Channel *channel)
493{
494 //remove a sound channel
495
496 if (channel == 0)
497 return;
498
499 for (int i = 0; i < GetChannelCount(); i++)
500 {
501 if (channels[i] == channel)
502 {
503 channels.erase(channels.begin() + i);
504 return;
505 }
506 }
507}
508#endif
509
510}
bool IsActive()
Definition camera.h:171
void GetDirection(Vector3 &front, Vector3 &top, bool global=false)
Definition camera.cpp:263
Vector3 GetPosition(bool relative=false)
Definition camera.cpp:250
const std::string & GetName()
Definition object.cpp:53
virtual bool ReportError(const std::string &message)
Definition object.cpp:84
Object * GetParent()
Definition object.cpp:42
virtual void Report(const std::string &message)
Definition object.cpp:78
void SetValues(const std::string &type, const std::string &name, bool is_permanent, bool is_movable=true)
Definition object.cpp:144
static void Stop_Profile(void)
Definition profiler.cpp:245
static void Start_Profile(const char *name)
Definition profiler.cpp:229
unsigned int SmoothFrames
Definition sbs.h:193
Vector3 ToGlobal(const Vector3 &position)
Definition sbs.cpp:4409
unsigned long GetAverageTime()
Definition sbs.cpp:3302
std::string GetFilesystemPath(std::string filename)
Definition sbs.cpp:3015
unsigned long GetElapsedTime()
Definition sbs.cpp:3296
Camera * camera
Definition sbs.h:160
std::string VerifyFile(const std::string &filename)
Definition sbs.cpp:2916
bool Verbose
Definition sbs.h:186
void Cleanup(int index=-1)
bool ReportError(const std::string &message)
void SetListenerDirection(const Vector3 &front, const Vector3 &top)
void ShowPlayingSounds(bool verbose=true)
Vector3 listener_velocity
Definition soundsystem.h:74
Vector3 listener_up
Definition soundsystem.h:76
SoundData * GetSoundData(std::string filename)
void Report(const std::string &message)
void SetListenerPosition(const Vector3 &position)
Vector3 listener_position
Definition soundsystem.h:73
std::vector< SoundData * > sounds
Definition soundsystem.h:79
FMOD::System * GetFmodSystem()
bool IsLoaded(std::string filename)
FMOD::System * soundsys
Definition soundsystem.h:69
unsigned int GetLength(SoundData *data)
SoundData * Load(const std::string &filename)
Vector3 listener_forward
Definition soundsystem.h:75
FMOD::Channel * Prepare(SoundData *data)
SoundSystem(Object *parent, FMOD::System *fmodsystem)
FMOD::Channel * GetChannel()
Definition sound.cpp:558
Ogre::Vector3 Vector3
Definition globals.h:58
bool SBSIMPEXP enable_advanced_profiling
Definition profiler.cpp:16
void SetCase(std::string &string, bool uppercase)
Definition globals.cpp:172
std::string ToString(int number)
Definition globals.cpp:279
std::string SetCaseCopy(std::string string, bool uppercase)
Definition globals.cpp:165
std::vector< FMOD::Channel * > channels
FMOD::Sound * sound
std::string filename
void RemoveChannel(FMOD::Channel *channel)
void AddHandle(Sound *handle)
void AddChannel(FMOD::Channel *channel)
int GetChannelCount()
std::vector< Sound * > handles
void RemoveHandle(Sound *handle)