Skyscraper 2.0
sound.cpp
Go to the documentation of this file.
1/*
2 Scalable Building Simulator - Sound Object
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#endif
27#include "globals.h"
28#include "sbs.h"
29#include "floor.h"
30#include "elevatorcar.h"
31#include "reverb.h"
32#include "soundsystem.h"
33#include "sound.h"
34
35namespace SBS {
36
37Sound::Sound(Object *parent, const std::string &name, bool permanent) : Object(parent)
38{
39 //set up SBS object
40 SetValues("Sound", name, permanent);
41
42 //first set default values
44 Position = Vector3::ZERO;
45 Volume = (float)sbs->GetConfigFloat("Skyscraper.SBS.Sound.Volume", 1.0);
46 MaxDistance = (float)sbs->GetConfigFloat("Skyscraper.SBS.Sound.MaxDistance", 10000.0);
47 MinDistance =(float) sbs->GetConfigFloat("Skyscraper.SBS.Sound.MinDistance", 1.0);
48 Direction = Vector3::ZERO;
49 SoundLoop = sbs->GetConfigBool("Skyscraper.SBS.Sound.Loop", false);
50 Speed = sbs->GetConfigInt("Skyscraper.SBS.Sound.Speed", 100);
51 Percent = 0;
53 sound = 0;
54#ifndef DISABLE_SOUND
55 channel = 0;
56#endif
57 default_speed = 0;
58 doppler_level = (float)sbs->GetConfigFloat("Skyscraper.SBS.Sound.Doppler", 0.0);
59 position_queued = false;
60 SetVelocity = false;
61 enabled = true;
62
63 if (sbs->Verbose)
64 Report("Created sound");
65}
66
68{
69 if (system)
70 {
71 if (sbs->FastDelete == false)
72 {
73 Unload();
75 }
76 else
77 Stop();
78 }
79
80 //unregister from parent
81 if (sbs->FastDelete == false)
82 {
83 if (parent_deleting == false)
84 {
85 std::string type = GetParent()->GetType();
86
87 if (type == "ElevatorCar")
88 static_cast<ElevatorCar*>(GetParent())->RemoveSound(this);
89 else if (type == "Floor")
90 static_cast<Floor*>(GetParent())->RemoveSound(this);
91 else if (type == "SBS")
92 sbs->RemoveSound(this);
93 }
94 }
95}
96
97void Sound::OnMove(bool parent)
98{
99#ifndef DISABLE_SOUND
100 Vector3 global_position = sbs->ToGlobal(GetPosition());
101
102 FMOD_VECTOR pos = {(float)global_position.x, (float)global_position.y, (float)global_position.z};
103 FMOD_VECTOR vel = { 0, 0, 0 };
104
105 //calculate sound velocity
106 if (sbs->GetElapsedTime() > 0 && SetVelocity == true)
107 {
108 vel.x = (float)(GetPosition().x - Position.x) * (1000 / sbs->GetElapsedTime());
109 vel.y = (float)(GetPosition().y - Position.y) * (1000 / sbs->GetElapsedTime());
110 vel.z = (float)(GetPosition().z - Position.z) * (1000 / sbs->GetElapsedTime());
111 }
112
114 Velocity.x = vel.x;
115 Velocity.y = vel.y;
116 Velocity.z = vel.z;
117 if (channel)
118 channel->set3DAttributes(&pos, &vel); //note - do not use ToRemote for positioning
119
120 //adjust reverb wet level based on distance to listener
121 /*Vector3 reverbPos;
122 bool result = GetNearestReverbPosition(reverbPos);
123 if (result == true)
124 {
125 Vector3 listener = system->GetListenerPosition();
126 float distanceSquaredToListener = pow(listener.x - reverbPos.x, 2) + pow(listener.y - reverbPos.y, 2) + pow(listener.z - reverbPos.z, 2);
127 channel->setReverbProperties(0, distanceSquaredToListener);
128 }*/
129#endif
130}
131
132void Sound::OnRotate(bool parent)
133{
134 if (parent == true)
135 OnMove(parent); //update position if parent object has been rotated
136}
137
139{
140 //set volume of sound
141
142#ifndef DISABLE_SOUND
143 if (sbs->Verbose)
144 Report("Setting volume to " + ToString(value));
145
146 Volume = (float)value;
147 if (channel)
148 channel->setVolume((float)value);
149#endif
150}
151
153{
154 //returns volume
155 return Volume;
156}
157
159{
160 //set minimum and maximum unattenuated distances
161 MinDistance = (float)min;
162 MaxDistance = (float)max;
163#ifndef DISABLE_SOUND
164 if (channel)
165 channel->set3DMinMaxDistance((float)min, (float)max);
166#endif
167}
168
173
178
179void Sound::SetDirection(const Vector3 &direction)
180{
181 Direction = direction;
182 Vector3 global_direction = sbs->GetOrientation() * direction;
183#ifndef DISABLE_SOUND
184 FMOD_VECTOR vec = { (float)global_direction.x, (float)global_direction.y, (float)global_direction.z };
185
186 if (channel)
187 channel->set3DConeOrientation(&vec);
188#endif
189}
190
192{
193 return Direction;
194}
195
196void Sound::SetConeSettings(Real inside_angle, Real outside_angle, Real outside_volume)
197{
198#ifndef DISABLE_SOUND
199 if (channel)
200 channel->set3DConeSettings((float)inside_angle, (float)outside_angle, (float)outside_volume);
201#endif
202}
203
204void Sound::SetLoopState(bool value)
205{
206 SoundLoop = value;
207#ifndef DISABLE_SOUND
208 if (channel)
209 {
210 if (value == true)
211 channel->setLoopCount(-1);
212 else
213 channel->setLoopCount(0);
214 }
215#endif
216}
217
219{
220 return SoundLoop;
221}
222
223void Sound::Pause(bool value)
224{
225 if (!IsValid())
226 return;
227
228 if (sbs->Verbose)
229 {
230 if (value == true)
231 Report("Pause");
232 else
233 Report("Unpause");
234 }
235
236#ifndef DISABLE_SOUND
237 if (channel)
238 channel->setPaused(value);
239#endif
240}
241
243{
244 bool paused = false;
245 if (!IsValid())
246 return true;
247#ifndef DISABLE_SOUND
248 if (channel)
249 channel->getPaused(&paused);
250#endif
251 return paused;
252}
253
255{
256 bool result = false;
257
258 if (!IsValid())
259 return false;
260
261#ifndef DISABLE_SOUND
262
263 if (!channel)
264 return false;
265
266 channel->isPlaying(&result);
267 if (result == true && IsPaused() == false)
268 return true;
269#endif
270 return false;
271}
272
273void Sound::SetSpeed(int percent)
274{
275 Speed = percent;
276#ifndef DISABLE_SOUND
277 if (!channel)
278 return;
279
280 if (sbs->Verbose)
281 Report("Setting speed to " + ToString(percent));
282
283 channel->setFrequency(default_speed * ((float)percent / 100));
284#endif
285}
286
288{
289 return Speed;
290}
291
293{
294#ifndef DISABLE_SOUND
295 if (sbs->Verbose == true)
296 Report("Stopping");
297
298 if (channel)
299 channel->stop();
300#endif
301}
302
304{
305#ifndef DISABLE_SOUND
306 if (!channel)
307 return false;
308 bool playing;
309 FMOD_RESULT result = channel->isPlaying(&playing);
310 if (result == FMOD_ERR_INVALID_HANDLE || result == FMOD_ERR_CHANNEL_STOLEN)
311 {
312 if (sound)
314 channel = 0;
315 return false;
316 }
317#endif
318 return true;
319}
320
321bool Sound::Play(bool reset)
322{
323 //exit if sound is disabled
324 if (!system || !enabled)
325 return false;
326
327#ifndef DISABLE_SOUND
328 if (!sound)
329 {
331
332 if (!sound)
333 {
334 if (sbs->Verbose)
335 ReportError("No sound loaded");
336 return false;
337 }
338 sound->AddHandle(this);
339 }
340
341 if (sbs->Verbose)
342 Report("Playing");
343
344 if (!IsValid())
345 {
346 //prepare sound (and keep paused)
348
349 if (!channel)
350 return false;
351
352 //get default speed value
353 channel->getFrequency(&default_speed);
354
355 //load previously stored values into new sound objects
363 if (position_queued == true)
365 position_queued = false;
366 }
367
368 if (reset == true)
369 Reset();
370
371 if (channel)
372 channel->setPaused(false);
373
374#endif
375 return true;
376}
377
379{
380 if (sbs->Verbose)
381 Report("Reset");
382
384}
385
386bool Sound::Load(const std::string &filename, bool force)
387{
388 //exit if sound is disabled
389 if (!system || !enabled)
390 return false;
391
392 //exit if filename is the same
393 if (filename == Filename && force == false)
394 return false;
395
396 //clear current references
397 Unload();
398
399 if (sbs->Verbose)
400 Report("Loading sound " + filename);
401
402 //have sound system load sound file
403 sound = system->Load(filename);
404 Filename = filename;
405
406 if (sound)
407 {
408 sound->AddHandle(this);
409 return true;
410 }
411 return false;
412}
413
415{
416 //returns the current sound playback position, in percent (1 = 100%)
417
418 if (!IsValid())
419 return Percent;
420
421#ifndef DISABLE_SOUND
422
423 if (!channel)
424 return -1;
425
426 //get length of sound in milliseconds
427 unsigned int length = system->GetLength(sound);
428
429 //get sound position in milliseconds
430 unsigned int position;
431 channel->getPosition(&position, FMOD_TIMEUNIT_MS);
432
433 if (length > 0)
434 Percent = (float)position / (float)length;
435#endif
436 return Percent;
437}
438
440{
441 //sets the current sound playback position, in percent (1 = 100%)
442
443 Percent = (float)percent;
444
445#ifndef DISABLE_SOUND
446 if (channel)
447 {
448 if (sbs->Verbose)
449 Report("Setting play position to " + ToString(percent));
450
451 //get length of sound in milliseconds
452 unsigned int length = system->GetLength(sound);
453
454 unsigned int position = (unsigned int)(percent * length);
455 channel->setPosition(position, FMOD_TIMEUNIT_MS);
456
457 position_queued = true;
458 }
459#endif
460}
461
463{
464 if (level < 0 || level > 5)
465 return;
466
467 doppler_level = (float)level;
468
469#ifndef DISABLE_SOUND
470 if (channel)
471 channel->set3DDopplerLevel((float)level);
472#endif
473}
474
476{
477 return (sound != 0);
478}
479
480void Sound::Report(const std::string &message)
481{
482 Object::Report("Sound '" + GetName() + "', parent '" + GetParent()->GetName() + "': " + message);
483}
484
485bool Sound::ReportError(const std::string &message)
486{
487 return Object::ReportError("Sound '" + GetName() + "', parent '" + GetParent()->GetName() + "': " + message);
488}
489
490void Sound::PlayQueued(const std::string &filename, bool stop, bool loop)
491{
492 //loads and plays a sound, with queuing support
493 //if "stop" is true, stops currently playing sound
494 //use the ProcessQueue function to process queued sounds
495
496 if (sbs->Verbose)
497 Report("Playing queued sound");
498
499 //queue sound object
500 SoundEntry snd;
501 snd.filename = filename;
502 snd.loop = loop;
503 snd.played = false;
504 queue.emplace_back(snd);
505
506 if (stop == true)
507 Stop();
508
509 ProcessQueue();
510}
511
513{
514 //if using the PlayQueued function, use this function to process queued sounds
515
516 if (queue.empty())
517 return;
518
519 SoundEntry *snd = &queue.front();
520
521 if (IsPlaying() == true)
522 return;
523 else if (snd->played == true)
524 {
525 //dequeue sound that already played
526 queue.erase(queue.begin());
527 return;
528 }
529
530 if (sbs->Verbose)
531 Report("Processing queued sound");
532
533 //play new sound
534 Load(snd->filename);
535 SetLoopState(snd->loop);
536 Play();
537 snd->played = true;
538}
539
541{
542 //stop and unload the sound channel
543
544 Stop();
545
546 if (sbs->Verbose)
547 Report("Unloading");
548
549 if (sound)
550 sound->RemoveHandle(this);
551 sound = 0;
552#ifndef DISABLE_SOUND
553 channel = 0;
554#endif
555}
556
557#ifndef DISABLE_SOUND
558FMOD::Channel* Sound::GetChannel()
559{
560 return channel;
561}
562#endif
563
565{
566 std::string type = GetParent()->GetType();
567 position = Vector3::ZERO;
568 bool result = false;
569
570 if (type == "ElevatorCar")
571 {
572 ElevatorCar *car = static_cast<ElevatorCar*>(GetParent());
573 if (car->GetReverb())
574 {
575 position = car->GetReverb()->GetPosition();
576 result = true;
577 }
578 }
579 else if (type == "Floor")
580 {
581 Floor *floor = static_cast<Floor*>(GetParent());
582 Real nearest = 99999999;
583 for (int i = 0; i < floor->GetReverbCount(); i++)
584 {
585 Reverb *reverb = floor->GetReverb(i);
586 if (!reverb)
587 continue;
588
589 Real distance = reverb->GetPosition().distance(position);
590 if (distance < nearest)
591 {
592 nearest = distance;
593 position = reverb->GetPosition();
594 result = true;
595 }
596 }
597 }
598 else if (type == "SBS")
599 {
600 Real nearest = 99999999;
601 for (int i = 0; i < sbs->GetReverbCount(); i++)
602 {
603 Reverb *reverb = sbs->GetReverb(i);
604 if (!reverb)
605 continue;
606
607 Real distance = reverb->GetPosition().distance(position);
608 if (distance < nearest)
609 {
610 nearest = distance;
611 position = reverb->GetPosition();
612 result = true;
613 }
614 }
615 }
616
617 return result;
618}
619
620void Sound::Enabled(bool value)
621{
622 //enable or disable this sound object
623
624 if (value == false)
625 Stop();
626
627 enabled = value;
628}
629
631{
632 return enabled;
633}
634
635}
Reverb * GetReverb(const std::string &name)
Definition floor.cpp:1973
int GetReverbCount()
Definition floor.cpp:2007
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
bool parent_deleting
Definition object.h:64
virtual Vector3 GetPosition(bool relative=false)
Definition object.cpp:321
void SetValues(const std::string &type, const std::string &name, bool is_permanent, bool is_movable=true)
Definition object.cpp:144
Quaternion GetOrientation(bool relative=false)
Definition object.cpp:377
const std::string & GetType()
Definition object.cpp:177
virtual void SetPosition(const Vector3 &position)
Definition object.cpp:274
Vector3 ToGlobal(const Vector3 &position)
Definition sbs.cpp:4409
void RemoveSound(Sound *sound)
Definition sbs.cpp:2801
Real GetConfigFloat(const std::string &key, Real default_value)
Definition sbs.cpp:3249
void IncrementSoundCount()
Definition sbs.cpp:2314
int GetReverbCount()
Definition sbs.cpp:4708
unsigned long GetElapsedTime()
Definition sbs.cpp:3296
bool FastDelete
Definition sbs.h:188
bool GetConfigBool(const std::string &key, bool default_value)
Definition sbs.cpp:3243
int GetConfigInt(const std::string &key, int default_value)
Definition sbs.cpp:3232
Reverb * GetReverb(const std::string &name)
Definition sbs.cpp:2332
SoundSystem * GetSoundSystem()
Definition sbs.cpp:4518
void DecrementSoundCount()
Definition sbs.cpp:2319
bool Verbose
Definition sbs.h:186
SoundData * GetSoundData(std::string filename)
unsigned int GetLength(SoundData *data)
SoundData * Load(const std::string &filename)
FMOD::Channel * Prepare(SoundData *data)
void Pause(bool value=true)
Definition sound.cpp:223
void Reset()
Definition sound.cpp:378
Vector3 Direction
Definition sound.h:94
int Speed
Definition sound.h:96
void OnRotate(bool parent)
Definition sound.cpp:132
SoundData * sound
Definition sound.h:84
Vector3 GetDirection()
Definition sound.cpp:191
bool Load(const std::string &filename, bool force=false)
Definition sound.cpp:386
bool ReportError(const std::string &message)
Definition sound.cpp:485
void OnMove(bool parent)
Definition sound.cpp:97
std::vector< SoundEntry > queue
Definition sound.h:111
void Unload()
Definition sound.cpp:540
bool SetVelocity
Definition sound.h:33
bool GetNearestReverbPosition(Vector3 &position)
Definition sound.cpp:564
Sound(Object *parent, const std::string &name, bool permanent)
Definition sound.cpp:37
Vector3 Velocity
Definition sound.h:90
void Stop()
Definition sound.cpp:292
bool Play(bool reset=true)
Definition sound.cpp:321
void PlayQueued(const std::string &filename, bool stop=true, bool loop=false)
Definition sound.cpp:490
bool position_queued
Definition sound.h:101
bool IsLoaded()
Definition sound.cpp:475
float MinDistance
Definition sound.h:93
Real GetMinimumDistance()
Definition sound.cpp:169
void ProcessQueue()
Definition sound.cpp:512
float Volume
Definition sound.h:91
void SetSpeed(int percent)
Definition sound.cpp:273
FMOD::Channel * channel
Definition sound.h:80
Real GetMaximumDistance()
Definition sound.cpp:174
void SetDopplerLevel(Real level)
Definition sound.cpp:462
void SetLoopState(bool value)
Definition sound.cpp:204
float doppler_level
Definition sound.h:100
int GetSpeed()
Definition sound.cpp:287
void SetPlayPosition(Real percent)
Definition sound.cpp:439
FMOD::Channel * GetChannel()
Definition sound.cpp:558
bool IsPaused()
Definition sound.cpp:242
float Percent
Definition sound.h:97
void Report(const std::string &message)
Definition sound.cpp:480
Vector3 Position
Definition sound.h:89
float default_speed
Definition sound.h:99
void Enabled(bool value)
Definition sound.cpp:620
void SetConeSettings(Real inside_angle=360.0, Real outside_angle=360.0, Real outside_volume=1.0)
Definition sound.cpp:196
void SetVolume(Real value)
Definition sound.cpp:138
bool GetLoopState()
Definition sound.cpp:218
bool IsEnabled()
Definition sound.cpp:630
bool enabled
Definition sound.h:102
SoundSystem * system
Definition sound.h:86
std::string Filename
Definition sound.h:98
Real GetPlayPosition()
Definition sound.cpp:414
bool IsPlaying()
Definition sound.cpp:254
void SetDirection(const Vector3 &direction)
Definition sound.cpp:179
float MaxDistance
Definition sound.h:92
void SetDistances(Real min, Real max)
Definition sound.cpp:158
bool SoundLoop
Definition sound.h:95
Real GetVolume()
Definition sound.cpp:152
bool IsValid()
Definition sound.cpp:303
Ogre::Vector3 Vector3
Definition globals.h:58
Ogre::Real Real
Definition globals.h:57
std::string ToString(int number)
Definition globals.cpp:279
void RemoveChannel(FMOD::Channel *channel)
void AddHandle(Sound *handle)
void RemoveHandle(Sound *handle)
std::string filename
Definition sound.h:106