RigsofRods
Soft-body Physics Simulation
SoundManager.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5  Copyright 2013-2020 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #ifdef USE_OPENAL
23 
24 #include "SoundManager.h"
25 
26 #include "Application.h"
27 #include "Sound.h"
28 
29 #include <OgreResourceGroupManager.h>
30 
31 #define LOGSTREAM Ogre::LogManager::getSingleton().stream() << "[RoR|Audio] "
32 
33 bool _checkALErrors(const char* filename, int linenum)
34 {
35  int err = alGetError();
36  if (err != AL_NO_ERROR)
37  {
38  char buf[1000] = {};
39  snprintf(buf, 1000, "OpenAL Error: %s (0x%x), @ %s:%d", alGetString(err), err, filename, linenum);
40  LOGSTREAM << buf;
41  return true;
42  }
43  return false;
44 }
45 
46 #define hasALErrors() _checkALErrors(__FILE__, __LINE__)
47 
48 using namespace RoR;
49 using namespace Ogre;
50 
51 const float SoundManager::MAX_DISTANCE = 500.0f;
52 const float SoundManager::ROLLOFF_FACTOR = 1.0f;
53 const float SoundManager::REFERENCE_DISTANCE = 7.5f;
54 
56 {
57  if (App::audio_device_name->getStr() == "")
58  {
59  LOGSTREAM << "No audio device configured, opening default.";
60  audio_device = alcOpenDevice(nullptr);
61  }
62  else
63  {
64  audio_device = alcOpenDevice(App::audio_device_name->getStr().c_str());
65  if (!audio_device)
66  {
67  LOGSTREAM << "Failed to open configured audio device \"" << App::audio_device_name->getStr() << "\", opening default.";
69  audio_device = alcOpenDevice(nullptr);
70  }
71  }
72 
73  if (!audio_device)
74  {
75  LOGSTREAM << "Failed to open default audio device. Sound disabled.";
76  hasALErrors();
77  return;
78  }
79 
80  sound_context = alcCreateContext(audio_device, NULL);
81 
82  if (!sound_context)
83  {
84  alcCloseDevice(audio_device);
85  audio_device = NULL;
86  hasALErrors();
87  return;
88  }
89 
90  alcMakeContextCurrent(sound_context);
91 
92  if (alGetString(AL_VENDOR)) LOG("SoundManager: OpenAL vendor is: " + String(alGetString(AL_VENDOR)));
93  if (alGetString(AL_VERSION)) LOG("SoundManager: OpenAL version is: " + String(alGetString(AL_VERSION)));
94  if (alGetString(AL_RENDERER)) LOG("SoundManager: OpenAL renderer is: " + String(alGetString(AL_RENDERER)));
95  if (alGetString(AL_EXTENSIONS)) LOG("SoundManager: OpenAL extensions are: " + String(alGetString(AL_EXTENSIONS)));
96  if (alcGetString(audio_device, ALC_DEVICE_SPECIFIER)) LOG("SoundManager: OpenAL device is: " + String(alcGetString(audio_device, ALC_DEVICE_SPECIFIER)));
97  if (alcGetString(audio_device, ALC_EXTENSIONS)) LOG("SoundManager: OpenAL ALC extensions are: " + String(alcGetString(audio_device, ALC_EXTENSIONS)));
98 
99  // generate the AL sources
100  for (hardware_sources_num = 0; hardware_sources_num < MAX_HARDWARE_SOURCES; hardware_sources_num++)
101  {
102  alGetError();
103  alGenSources(1, &hardware_sources[hardware_sources_num]);
104  if (alGetError() != AL_NO_ERROR)
105  break;
106  alSourcef(hardware_sources[hardware_sources_num], AL_REFERENCE_DISTANCE, REFERENCE_DISTANCE);
107  alSourcef(hardware_sources[hardware_sources_num], AL_ROLLOFF_FACTOR, ROLLOFF_FACTOR);
108  alSourcef(hardware_sources[hardware_sources_num], AL_MAX_DISTANCE, MAX_DISTANCE);
109  }
110 
111  alDopplerFactor(1.0f);
112  alDopplerVelocity(343.0f);
113 
114  for (int i = 0; i < MAX_HARDWARE_SOURCES; i++)
115  {
116  hardware_sources_map[i] = -1;
117  }
118 }
119 
121 {
122  // delete the sources and buffers
123  alDeleteSources(MAX_HARDWARE_SOURCES, hardware_sources);
124  alDeleteBuffers(MAX_AUDIO_BUFFERS, audio_buffers);
125 
126  // destroy the sound context and device
127  sound_context = alcGetCurrentContext();
128  audio_device = alcGetContextsDevice(sound_context);
129  alcMakeContextCurrent(NULL);
130  alcDestroyContext(sound_context);
131  if (audio_device)
132  {
133  alcCloseDevice(audio_device);
134  }
135  LOG("SoundManager destroyed.");
136 }
137 
138 void SoundManager::setCamera(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity)
139 {
140  if (!audio_device)
141  return;
142  camera_position = position;
143  recomputeAllSources();
144 
145  float orientation[6];
146  // direction
147  orientation[0] = direction.x;
148  orientation[1] = direction.y;
149  orientation[2] = direction.z;
150  // up
151  orientation[3] = up.x;
152  orientation[4] = up.y;
153  orientation[5] = up.z;
154 
155  alListener3f(AL_POSITION, position.x, position.y, position.z);
156  alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
157  alListenerfv(AL_ORIENTATION, orientation);
158 }
159 
160 bool compareByAudibility(std::pair<int, float> a, std::pair<int, float> b)
161 {
162  return a.second > b.second;
163 }
164 
165 // called when the camera moves
167 {
168  // Creates this issue: https://github.com/RigsOfRods/rigs-of-rods/issues/1054
169 #if 0
170  if (!audio_device) return;
171 
172  for (int i=0; i < audio_buffers_in_use_count; i++)
173  {
174  audio_sources[i]->computeAudibility(camera_position);
175  audio_sources_most_audible[i].first = i;
176  audio_sources_most_audible[i].second = audio_sources[i]->audibility;
177  }
178  // sort first 'num_hardware_sources' sources by audibility
179  // see: https://en.wikipedia.org/wiki/Selection_algorithm
180  if ((audio_buffers_in_use_count - 1) > hardware_sources_num)
181  {
182  std::nth_element(audio_sources_most_audible, audio_sources_most_audible+hardware_sources_num, audio_sources_most_audible + audio_buffers_in_use_count - 1, compareByAudibility);
183  }
184  // retire out of range sources first
185  for (int i=0; i < audio_buffers_in_use_count; i++)
186  {
187  if (audio_sources[audio_sources_most_audible[i].first]->hardware_index != -1 && (i >= hardware_sources_num || audio_sources_most_audible[i].second == 0))
188  retire(audio_sources_most_audible[i].first);
189  }
190  // assign new sources
191  for (int i=0; i < std::min(audio_buffers_in_use_count, hardware_sources_num); i++)
192  {
193  if (audio_sources[audio_sources_most_audible[i].first]->hardware_index == -1 && audio_sources_most_audible[i].second > 0)
194  {
195  for (int j=0; j < hardware_sources_num; j++)
196  {
197  if (hardware_sources_map[j] == -1)
198  {
199  assign(audio_sources_most_audible[i].first, j);
200  break;
201  }
202  }
203  }
204  }
205 #endif
206 }
207 
208 void SoundManager::recomputeSource(int source_index, int reason, float vfl, Vector3* vvec)
209 {
210  if (!audio_device)
211  return;
212  audio_sources[source_index]->computeAudibility(camera_position);
213 
214  if (audio_sources[source_index]->audibility == 0.0f)
215  {
216  if (audio_sources[source_index]->hardware_index != -1)
217  {
218  // retire the source if it is currently assigned
219  retire(source_index);
220  }
221  }
222  else
223  {
224  // this is a potentially audible m_audio_sources[source_index]
225  if (audio_sources[source_index]->hardware_index != -1)
226  {
227  ALuint hw_source = hardware_sources[audio_sources[source_index]->hardware_index];
228  // m_audio_sources[source_index] already playing
229  // update the AL settings
230  switch (reason)
231  {
232  case Sound::REASON_PLAY: alSourcePlay(hw_source);
233  break;
234  case Sound::REASON_STOP: alSourceStop(hw_source);
235  break;
236  case Sound::REASON_GAIN: alSourcef(hw_source, AL_GAIN, vfl * App::audio_master_volume->getFloat());
237  break;
238  case Sound::REASON_LOOP: alSourcei(hw_source, AL_LOOPING, (vfl > 0.5) ? AL_TRUE : AL_FALSE);
239  break;
240  case Sound::REASON_PTCH: alSourcef(hw_source, AL_PITCH, vfl);
241  break;
242  case Sound::REASON_POSN: alSource3f(hw_source, AL_POSITION, vvec->x, vvec->y, vvec->z);
243  break;
244  case Sound::REASON_VLCT: alSource3f(hw_source, AL_VELOCITY, vvec->x, vvec->y, vvec->z);
245  break;
246  default: break;
247  }
248  }
249  else
250  {
251  // try to make it play by the hardware
252  // check if there is one free m_audio_sources[source_index] in the pool
253  if (hardware_sources_in_use_count < hardware_sources_num)
254  {
255  for (int i = 0; i < hardware_sources_num; i++)
256  {
257  if (hardware_sources_map[i] == -1)
258  {
259  assign(source_index, i);
260  break;
261  }
262  }
263  }
264  else
265  {
266  // now, compute who is the faintest
267  // note: we know the table m_hardware_sources_map is full!
268  float fv = 1.0f;
269  int al_faintest = 0;
270  for (int i = 0; i < hardware_sources_num; i++)
271  {
272  if (hardware_sources_map[i] >= 0 && audio_sources[hardware_sources_map[i]]->audibility < fv)
273  {
274  fv = audio_sources[hardware_sources_map[i]]->audibility;
275  al_faintest = i;
276  }
277  }
278  // check to ensure that the sound is louder than the faintest sound currently playing
279  if (fv < audio_sources[source_index]->audibility)
280  {
281  // this new m_audio_sources[source_index] is louder than the faintest!
282  retire(hardware_sources_map[al_faintest]);
283  assign(source_index, al_faintest);
284  }
285  // else this m_audio_sources[source_index] is too faint, we don't play it!
286  }
287  }
288  }
289 }
290 
291 void SoundManager::assign(int source_index, int hardware_index)
292 {
293  if (!audio_device)
294  return;
295  audio_sources[source_index]->hardware_index = hardware_index;
296  hardware_sources_map[hardware_index] = source_index;
297 
298  ALuint hw_source = hardware_sources[hardware_index];
299  SoundPtr& audio_source = audio_sources[source_index];
300 
301  // the hardware source is supposed to be stopped!
302  alSourcei(hw_source, AL_BUFFER, audio_source->buffer);
303  alSourcef(hw_source, AL_GAIN, audio_source->gain * App::audio_master_volume->getFloat());
304  alSourcei(hw_source, AL_LOOPING, (audio_source->loop) ? AL_TRUE : AL_FALSE);
305  alSourcef(hw_source, AL_PITCH, audio_source->pitch);
306  alSource3f(hw_source, AL_POSITION, audio_source->position.x, audio_source->position.y, audio_source->position.z);
307  alSource3f(hw_source, AL_VELOCITY, audio_source->velocity.x, audio_source->velocity.y, audio_source->velocity.z);
308 
309  if (audio_source->should_play)
310  {
311  alSourcePlay(hw_source);
312  }
313 
314  hardware_sources_in_use_count++;
315 }
316 
317 void SoundManager::retire(int source_index)
318 {
319  if (!audio_device)
320  return;
321  if (audio_sources[source_index]->hardware_index == -1)
322  return;
323  alSourceStop(hardware_sources[audio_sources[source_index]->hardware_index]);
324  hardware_sources_map[audio_sources[source_index]->hardware_index] = -1;
325  audio_sources[source_index]->hardware_index = -1;
326  hardware_sources_in_use_count--;
327 }
328 
330 {
331  if (!audio_device)
332  return;
333  // no mutex needed
334  alListenerf(AL_GAIN, 0.0f);
335 }
336 
338 {
339  if (!audio_device)
340  return;
341  // no mutex needed
342  alListenerf(AL_GAIN, App::audio_master_volume->getFloat());
343 }
344 
346 {
347  if (!audio_device)
348  return;
349  // no mutex needed
350  App::audio_master_volume->setVal(v); // TODO: Use 'pending' mechanism and set externally, only 'apply' here.
351  alListenerf(AL_GAIN, v);
352 }
353 
354 SoundPtr SoundManager::createSound(String filename, Ogre::String resource_group_name /* = "" */)
355 {
356  if (!audio_device)
357  return NULL;
358 
359  if (audio_buffers_in_use_count >= MAX_AUDIO_BUFFERS)
360  {
361  LOG("SoundManager: Reached MAX_AUDIO_BUFFERS limit (" + TOSTRING(MAX_AUDIO_BUFFERS) + ")");
362  return NULL;
363  }
364 
365  ALuint buffer = 0;
366 
367  // is the file already loaded?
368  for (int i = 0; i < audio_buffers_in_use_count; i++)
369  {
370  if (filename == audio_buffer_file_name[i])
371  {
372  buffer = audio_buffers[i];
373  break;
374  }
375  }
376 
377  if (!buffer)
378  {
379  // load the file
380  alGenBuffers(1, &audio_buffers[audio_buffers_in_use_count]);
381  if (loadWAVFile(filename, audio_buffers[audio_buffers_in_use_count], resource_group_name))
382  {
383  // there was an error!
384  alDeleteBuffers(1, &audio_buffers[audio_buffers_in_use_count]);
385  audio_buffer_file_name[audio_buffers_in_use_count] = "";
386  return NULL;
387  }
388  buffer = audio_buffers[audio_buffers_in_use_count];
389  audio_buffer_file_name[audio_buffers_in_use_count] = filename;
390  }
391 
392  audio_sources[audio_buffers_in_use_count] = new Sound(buffer, this, audio_buffers_in_use_count);
393 
394  return audio_sources[audio_buffers_in_use_count++];
395 }
396 
397 bool SoundManager::loadWAVFile(String filename, ALuint buffer, Ogre::String resource_group_name /*= ""*/)
398 {
399  if (!audio_device)
400  return true;
401  LOG("Loading WAV file "+filename);
402 
403  // create the Stream
404  ResourceGroupManager* rgm = ResourceGroupManager::getSingletonPtr();
405  if (resource_group_name == "")
406  {
407  resource_group_name = rgm->findGroupContainingResource(filename);
408  }
409  DataStreamPtr stream = rgm->openResource(filename, resource_group_name);
410 
411  // load RIFF/WAVE
412  char magic[5];
413  magic[4] = 0;
414  unsigned int lbuf; // uint32_t
415  unsigned short sbuf; // uint16_t
416 
417  // check magic
418  if (stream->read(magic, 4) != 4)
419  {
420  LOG("Could not read file "+filename);
421  return true;
422  }
423  if (String(magic) != String("RIFF"))
424  {
425  LOG("Invalid WAV file (no RIFF): "+filename);
426  return true;
427  }
428  // skip 4 bytes (magic)
429  stream->skip(4);
430  // check file format
431  if (stream->read(magic, 4) != 4)
432  {
433  LOG("Could not read file "+filename);
434  return true;
435  }
436  if (String(magic) != String("WAVE"))
437  {
438  LOG("Invalid WAV file (no WAVE): "+filename);
439  return true;
440  }
441  // check 'fmt ' sub chunk (1)
442  if (stream->read(magic, 4) != 4)
443  {
444  LOG("Could not read file "+filename);
445  return true;
446  }
447  if (String(magic) != String("fmt "))
448  {
449  LOG("Invalid WAV file (no fmt): "+filename);
450  return true;
451  }
452  // read (1)'s size
453  if (stream->read(&lbuf, 4) != 4)
454  {
455  LOG("Could not read file "+filename);
456  return true;
457  }
458  unsigned long subChunk1Size = lbuf;
459  if (subChunk1Size < 16)
460  {
461  LOG("Invalid WAV file (invalid subChunk1Size): "+filename);
462  return true;
463  }
464  // check PCM audio format
465  if (stream->read(&sbuf, 2) != 2)
466  {
467  LOG("Could not read file "+filename);
468  return true;
469  }
470  unsigned short audioFormat = sbuf;
471  if (audioFormat != 1)
472  {
473  LOG("Invalid WAV file (invalid audioformat "+TOSTRING(audioFormat)+"): "+filename);
474  return true;
475  }
476  // read number of channels
477  if (stream->read(&sbuf, 2) != 2)
478  {
479  LOG("Could not read file "+filename);
480  return true;
481  }
482  unsigned short channels = sbuf;
483  // read frequency (sample rate)
484  if (stream->read(&lbuf, 4) != 4)
485  {
486  LOG("Could not read file "+filename);
487  return true;
488  }
489  unsigned long freq = lbuf;
490  // skip 6 bytes (Byte rate (4), Block align (2))
491  stream->skip(6);
492  // read bits per sample
493  if (stream->read(&sbuf, 2) != 2)
494  {
495  LOG("Could not read file "+filename);
496  return true;
497  }
498  unsigned short bps = sbuf;
499  // check 'data' sub chunk (2)
500  if (stream->read(magic, 4) != 4)
501  {
502  LOG("Could not read file "+filename);
503  return true;
504  }
505  if (String(magic) != String("data") && String(magic) != String("fact"))
506  {
507  LOG("Invalid WAV file (no data/fact): "+filename);
508  return true;
509  }
510  // fact is an option section we don't need to worry about
511  if (String(magic) == String("fact"))
512  {
513  stream->skip(8);
514  // now we should hit the data chunk
515  if (stream->read(magic, 4) != 4)
516  {
517  LOG("Could not read file "+filename);
518  return true;
519  }
520  if (String(magic) != String("data"))
521  {
522  LOG("Invalid WAV file (no data): "+filename);
523  return true;
524  }
525  }
526  // the next four bytes are the remaining size of the file
527  if (stream->read(&lbuf, 4) != 4)
528  {
529  LOG("Could not read file "+filename);
530  return true;
531  }
532 
533  unsigned long dataSize = lbuf;
534  int format = 0;
535 
536  if (channels == 1 && bps == 8)
537  format = AL_FORMAT_MONO8;
538  else if (channels == 1 && bps == 16)
539  format = AL_FORMAT_MONO16;
540  else if (channels == 2 && bps == 8)
541  format = AL_FORMAT_STEREO16;
542  else if (channels == 2 && bps == 16)
543  format = AL_FORMAT_STEREO16;
544  else
545  {
546  LOG("Invalid WAV file (wrong channels/bps): "+filename);
547  return true;
548  }
549 
550  if (channels != 1) LOG("Invalid WAV file: the file needs to be mono, and nothing else. Will try to continue anyways ...");
551 
552  // ok, creating buffer
553  void* bdata = malloc(dataSize);
554  if (!bdata)
555  {
556  LOG("Memory error reading file "+filename);
557  return true;
558  }
559  if (stream->read(bdata, dataSize) != dataSize)
560  {
561  LOG("Could not read file "+filename);
562  free(bdata);
563  return true;
564  }
565 
566  //LOG("alBufferData: format "+TOSTRING(format)+" size "+TOSTRING(dataSize)+" freq "+TOSTRING(freq));
567  alGetError(); // Reset errors
568  ALint error;
569  alBufferData(buffer, format, bdata, dataSize, freq);
570  error = alGetError();
571 
572  free(bdata);
573  // stream will be closed by itself
574 
575  if (error != AL_NO_ERROR)
576  {
577  LOG("OpenAL error while loading buffer for "+filename+" : "+TOSTRING(error));
578  return true;
579  }
580 
581  return false;
582 }
583 
584 #endif // USE_OPENAL
RoR::SoundManager::pauseAllSounds
void pauseAllSounds()
Definition: SoundManager.cpp:329
Sound.h
RoR::Sound::REASON_PTCH
@ REASON_PTCH
Definition: Sound.h:74
LOGSTREAM
#define LOGSTREAM
Definition: SoundManager.cpp:31
RoR::SoundManager::loadWAVFile
bool loadWAVFile(Ogre::String filename, ALuint buffer, Ogre::String resource_group_name="")
Definition: SoundManager.cpp:397
RoR::SoundManager::assign
void assign(int source_index, int hardware_index)
Definition: SoundManager.cpp:291
RoR::SoundManager::setMasterVolume
void setMasterVolume(float v)
Definition: SoundManager.cpp:345
RoR::SoundManager::recomputeSource
void recomputeSource(int source_index, int reason, float vfl, Ogre::Vector3 *vvec)
Definition: SoundManager.cpp:208
RoR::Sound::pitch
float pitch
Definition: Sound.h:84
format
Truck file format(technical spec)
RoR::Sound::loop
bool loop
Definition: Sound.h:85
SoundManager.h
RoR::SoundManager::REFERENCE_DISTANCE
static const float REFERENCE_DISTANCE
Definition: SoundManager.h:69
RoR::Sound
Definition: Sound.h:39
RoR::Sound::position
Ogre::Vector3 position
Definition: Sound.h:93
RoR::Sound::should_play
bool should_play
Definition: Sound.h:87
_checkALErrors
bool _checkALErrors(const char *filename, int linenum)
Definition: SoundManager.cpp:33
RefCountingObjectPtr< Sound >
RoR::SoundManager::retire
void retire(int source_index)
Definition: SoundManager.cpp:317
hasALErrors
#define hasALErrors()
Definition: SoundManager.cpp:46
RoR::SoundManager::createSound
SoundPtr createSound(Ogre::String filename, Ogre::String resource_group_name="")
Definition: SoundManager.cpp:354
RoR::App::audio_master_volume
CVar * audio_master_volume
Definition: Application.cpp:209
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
RoR::CVar::getStr
std::string const & getStr() const
Definition: CVar.h:95
RoR::SoundManager::resumeAllSounds
void resumeAllSounds()
Definition: SoundManager.cpp:337
RoR::Sound::REASON_LOOP
@ REASON_LOOP
Definition: Sound.h:73
RoR::Sound::REASON_PLAY
@ REASON_PLAY
Definition: Sound.h:70
Application.h
Central state/object manager and communications hub.
RoR::SoundManager::recomputeAllSources
void recomputeAllSources()
Definition: SoundManager.cpp:166
RoR::Sound::REASON_STOP
@ REASON_STOP
Definition: Sound.h:71
RoR::SoundManager::SoundManager
SoundManager()
Definition: SoundManager.cpp:55
RoR::SoundManager::MAX_DISTANCE
static const float MAX_DISTANCE
Definition: SoundManager.h:67
compareByAudibility
bool compareByAudibility(std::pair< int, float > a, std::pair< int, float > b)
Definition: SoundManager.cpp:160
RoR::CVar::setVal
void setVal(T val)
Definition: CVar.h:72
RoR::SoundManager::setCamera
void setCamera(Ogre::Vector3 position, Ogre::Vector3 direction, Ogre::Vector3 up, Ogre::Vector3 velocity)
Definition: SoundManager.cpp:138
RoR::Sound::buffer
ALuint buffer
Definition: Sound.h:91
RoR::CVar::getFloat
float getFloat() const
Definition: CVar.h:96
Ogre
Definition: ExtinguishableFireAffector.cpp:35
RoR::Sound::REASON_POSN
@ REASON_POSN
Definition: Sound.h:75
RoR::Sound::REASON_GAIN
@ REASON_GAIN
Definition: Sound.h:72
RoR::App::audio_device_name
CVar * audio_device_name
Definition: Application.cpp:211
RoR::SoundManager::~SoundManager
~SoundManager()
Definition: SoundManager.cpp:120
RoR::Sound::REASON_VLCT
@ REASON_VLCT
Definition: Sound.h:76
RoR
Definition: AppContext.h:36
RoR::CVar::setStr
void setStr(std::string const &str)
Definition: CVar.h:83
RoR::Sound::velocity
Ogre::Vector3 velocity
Definition: Sound.h:94
RoR::Sound::gain
float gain
Definition: Sound.h:83
RoR::SoundManager::ROLLOFF_FACTOR
static const float ROLLOFF_FACTOR
Definition: SoundManager.h:68