Cytopia  0.3
A city building simulation game
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AudioMixer.cxx
Go to the documentation of this file.
1 #include "AudioMixer.hxx"
2 #include "../engine/MessageQueue.hxx"
3 #include "basics/Settings.hxx"
4 #include "LOG.hxx"
5 #include "Exception.hxx"
6 #include "../services/ResourceManager.hxx"
7 #include "../services/GameClock.hxx"
8 #include "../services/Randomizer.hxx"
10 #include "Filesystem.hxx"
11 
12 #include <fstream>
13 
15 using nlohmann::json;
16 
17 template <typename Type, size_t N> using Array = std::array<Type, N>;
18 
19 std::function<void(int)> AudioMixer::onTrackFinishedFunc;
20 
22 {
23  std::string jsonFileContent = fs::readFileAsString(Settings::instance().audioConfigJSONFile.get());
24  json config_json = json::parse(jsonFileContent, nullptr, false);
25 
26  // check if json file can be parsed
27  if (config_json.is_discarded())
28  throw ConfigurationError(TRACE_INFO "Error parsing JSON File " + Settings::instance().audioConfigJSONFile.get());
29 
30  AudioConfig audioConfig = config_json;
31  for (auto &item : audioConfig.Music)
32  for (auto &trigger : item.second.triggers)
33  m_Triggers[trigger].emplace_back(item.first);
34  for (auto &item : audioConfig.Sound)
35  for (auto &trigger : item.second.triggers)
36  m_Triggers[trigger].emplace_back(item.first);
37 
38  /* use default audio device */
39  gAudioDevice = alcOpenDevice(nullptr);
40  if (!gAudioDevice)
41  {
42  const char *error_msg = get_al_error_msg(alGetError());
43  LOG(LOG_WARNING) << "Unable to initialize default audio device! " << error_msg;
44  return;
45  }
46 
47  /* create context */
48  alContext = alcCreateContext(gAudioDevice, nullptr);
49  if (!alContext)
50  {
51  const char *error_msg = get_al_error_msg(alGetError());
52  throw AudioError(TRACE_INFO "Unable to initialize OpenAL context! " + error_msg);
53  }
54  alcMakeContextCurrent(alContext);
55 
56  /* Check if an error occurred, and clean up if so. */
57  ALenum err;
58  err = alGetError();
59  if (err != AL_NO_ERROR)
60  throw AudioError(TRACE_INFO "OpenAL error occurred: " + get_al_error_msg(err));
61 
62  /* set listener position one space behind origin */
63  Array<float, 3> listener_position_vector{0.0f, 0.0f, 1.0f};
64 
65  /* Initialize Listener speed */
66  alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f); // is not moving in 3d space
67 
68  /* initialize listener position 1 space behind origin in openal
69  * forward direction(-z direction in regular cartesian) */
70  alListener3f(AL_POSITION, listener_position_vector[static_cast<int>(AudioMixer::POSITION_INDEX::X)],
71  listener_position_vector[static_cast<int>(AudioMixer::POSITION_INDEX::Y)],
72  listener_position_vector[static_cast<int>(AudioMixer::POSITION_INDEX::Z)]);
73 
74  /* Set Listener orientation
75  * forward x, forward y, forward z, up x, up y, up z */
76  Array<float, 6> listener_orientation_vector{0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f};
77  alListenerfv(AL_ORIENTATION, listener_orientation_vector.data());
78 
79  /* Set a pruning repeated task to get rid of soundtracks that have finished playing */
81  [&mixer = *this]
82  {
83  mixer.prune();
84  return false;
85  },
86  0s, 5min);
87 
88  LOG(LOG_DEBUG) << "Created AudioMixer";
89 }
90 
92 {
93  if (!gAudioDevice)
94  {
95  return;
96  }
97 
98  alcDestroyContext(alContext); //delete context
99  alcCloseDevice(gAudioDevice); //close device
100 
101  LOG(LOG_DEBUG) << "Destroyed AudioMixer";
102 }
103 
104 static SoundtrackUPtr noResoruce = nullptr;
105 
106 SoundtrackUPtr &AudioMixer::getTrack(const AudioTrigger &trigger)
107 {
108  if (!gAudioDevice)
109  {
110  return noResoruce;
111  }
112 
113  auto &possibilities = m_Triggers[trigger];
114  if (possibilities.empty())
115  {
116  LOG(LOG_WARNING) << "No Soundtracks are triggered by " << trigger._to_string();
117  return noResoruce;
118  }
119  const SoundtrackID &trackID = *Randomizer::instance().choose(possibilities.begin(), possibilities.end());
120  return ResourceManager::instance().get(trackID);
121 }
122 
124 {
125  if (!gAudioDevice)
126  {
127  return noResoruce;
128  }
129 
130  return ResourceManager::instance().get(id);
131 }
132 
133 /*
134  +---------------------+
135  | Service Interface |
136  +---------------------+
137  */
138 
139 void AudioMixer::setMusicVolume(float volume)
140 {
141  for (auto it : m_Playing)
142  {
143  alSourcef((**it).source[1], AL_GAIN, volume);
144  }
145  // update the settings accordingly
146  Settings::instance().musicVolume = volume;
147 }
148 
150 {
151  for (auto it : m_Playing)
152  {
153  alSourcef((**it).source[0], AL_GAIN, volume);
154  }
156 }
157 
158 void AudioMixer::play(const SoundtrackID &id, int effect)
159 {
160  auto &track = getTrack(id);
161  if (track)
162  {
163  if (effect == AL_EFFECT_NULL)
164  playSoundtrack(track);
165  else
166  playSoundtrackWithEffect(track, effect);
167  }
168 }
169 
170 void AudioMixer::play(const AudioTrigger &trigger, int effect)
171 {
172  auto &track = getTrack(trigger);
173  if (track)
174  {
175  if (effect == AL_EFFECT_NULL)
176  playSoundtrack(track);
177  else
178  playSoundtrackWithEffect(track, effect);
179  }
180 }
181 
182 void AudioMixer::play(const SoundtrackID &id, const Coordinate3D &position, int effect)
183 {
184  if (getTrack(id))
185  {
186  auto &track = getTrack(id);
187  /* set position of sources in track */
188  alSource3f(track->source[0], AL_POSITION, static_cast<ALfloat>(position.x), static_cast<ALfloat>(position.y),
189  static_cast<ALfloat>(position.z));
190  alSource3f(track->source[1], AL_POSITION, static_cast<ALfloat>(position.x), static_cast<ALfloat>(position.y),
191  static_cast<ALfloat>(position.z));
192  play(id, effect);
193  }
194 }
195 
196 void AudioMixer::play(const AudioTrigger &trigger, const Coordinate3D &position, int effect)
197 {
198  if (getTrack(trigger))
199  {
200  auto &track = getTrack(trigger);
201  /* set position of sources in track
202  * converted to regular Cartesian coordinate system */
203  alSource3f(track->source[0], AL_POSITION, static_cast<ALfloat>(position.x), static_cast<ALfloat>(position.y),
204  static_cast<ALfloat>(position.z));
205  alSource3f(track->source[1], AL_POSITION, static_cast<ALfloat>(position.x), static_cast<ALfloat>(position.y),
206  static_cast<ALfloat>(position.z));
207  play(trigger, effect);
208  }
209 }
210 
211 void AudioMixer::setMuted(bool isMuted) { throw UnimplementedError(TRACE_INFO "Unimplemented Error"); }
212 
214 {
215  if (!gAudioDevice)
216  {
217  return;
218  }
219 
220  while (!m_Playing.empty())
221  {
222  auto it = m_Playing.begin();
223  alSourceStop((**it)->source[0]);
224  alSourceStop((**it)->source[1]);
225  (**it)->isPlaying = false;
226  m_Playing.erase(it);
227  }
228 }
229 
231 {
232  if (!gAudioDevice)
233  {
234  return;
235  }
236 
237  for (auto it = m_Playing.begin(); it != m_Playing.end();)
238  {
239  int state = 0;
240  alGetSourcei((**it)->source[(**it)->isMusic], AL_SOURCE_STATE, &state);
241  if (state != AL_PLAYING)
242  {
243  (**it)->isPlaying = false;
244  it = m_Playing.erase(it);
245  }
246  else
247  {
248  ++it;
249  }
250  }
251 }
252 
253 /*
254  +-----------+
255  | Helpers |
256  +-----------+
257  */
258 
260 {
261  if (!track)
262  throw AudioError(TRACE_INFO "Received an invalid soundtrack");
263 
264  if (!track->source)
265  throw AudioError{TRACE_INFO "Unable to play track because its source is uninitialized"};
266 
267  alSourcePlay(track->source[track->isMusic]);
268 
269  m_Playing.push_front(&track);
270  track->isPlaying = true;
271 }
272 
273 /* Effect object functions */
274 static LPALGENEFFECTS alGenEffects;
275 static LPALDELETEEFFECTS alDeleteEffects;
276 static LPALISEFFECT alIsEffect;
277 static LPALEFFECTI alEffecti;
278 static LPALEFFECTIV alEffectiv;
279 static LPALEFFECTF alEffectf;
280 static LPALEFFECTFV alEffectfv;
281 static LPALGETEFFECTI alGetEffecti;
282 static LPALGETEFFECTIV alGetEffectiv;
283 static LPALGETEFFECTF alGetEffectf;
284 static LPALGETEFFECTFV alGetEffectfv;
285 
286 /* Auxiliary Effect Slot object functions */
287 static LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
288 static LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
289 static LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
290 static LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
291 static LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
292 static LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
293 static LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
294 static LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
295 static LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
296 static LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
297 static LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
298 
300 {
301  if (!track)
302  throw AudioError(TRACE_INFO "Received an invalid soundtrack");
303 
304  if (!track->source)
305  throw AudioError{TRACE_INFO "Unable to play track because its source is uninitialized"};
306 
307  //set up effect
308 #define LOAD_PROC(T, x) ((x) = (T)alGetProcAddress(#x))
309  LOAD_PROC(LPALGENEFFECTS, alGenEffects);
310  LOAD_PROC(LPALDELETEEFFECTS, alDeleteEffects);
311  LOAD_PROC(LPALISEFFECT, alIsEffect);
312  LOAD_PROC(LPALEFFECTI, alEffecti);
313  LOAD_PROC(LPALEFFECTIV, alEffectiv);
314  LOAD_PROC(LPALEFFECTF, alEffectf);
315  LOAD_PROC(LPALEFFECTFV, alEffectfv);
316  LOAD_PROC(LPALGETEFFECTI, alGetEffecti);
317  LOAD_PROC(LPALGETEFFECTIV, alGetEffectiv);
318  LOAD_PROC(LPALGETEFFECTF, alGetEffectf);
319  LOAD_PROC(LPALGETEFFECTFV, alGetEffectfv);
320 
321  LOAD_PROC(LPALGENAUXILIARYEFFECTSLOTS, alGenAuxiliaryEffectSlots);
322  LOAD_PROC(LPALDELETEAUXILIARYEFFECTSLOTS, alDeleteAuxiliaryEffectSlots);
323  LOAD_PROC(LPALISAUXILIARYEFFECTSLOT, alIsAuxiliaryEffectSlot);
324  LOAD_PROC(LPALAUXILIARYEFFECTSLOTI, alAuxiliaryEffectSloti);
325  LOAD_PROC(LPALAUXILIARYEFFECTSLOTIV, alAuxiliaryEffectSlotiv);
326  LOAD_PROC(LPALAUXILIARYEFFECTSLOTF, alAuxiliaryEffectSlotf);
327  LOAD_PROC(LPALAUXILIARYEFFECTSLOTFV, alAuxiliaryEffectSlotfv);
328  LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTI, alGetAuxiliaryEffectSloti);
329  LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTIV, alGetAuxiliaryEffectSlotiv);
330  LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTF, alGetAuxiliaryEffectSlotf);
331  LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv);
332 #undef LOAD_PROC
333 
334  //load effect
335  ALuint effect = 0;
336 
337  // Create the effect object
338  alGenEffects(1, &effect);
339 
340  alEffecti(effect, AL_EFFECT_TYPE, ALEffect);
341 
342  // this is where we would put code to customize the properties of the effect
343 
344  // Check if an error occured, and clean up if so.
345  ALenum err = alGetError();
346  if (err != AL_NO_ERROR)
347  {
348  if (alIsEffect(effect))
349  alDeleteEffects(1, &effect);
350 
351  throw AudioError{TRACE_INFO "Unable to add effect to track."};
352  fprintf(stderr, "OpenAL error: %s\n", alGetString(err));
353  }
354 
355  /* Create the effect slot object. This is what "plays" an effect on sources
356  * that connect to it. */
357  alGenAuxiliaryEffectSlots(1, &track->effect_slot);
358 
359  /* Tell the effect slot to use the loaded effect object. Note that this
360  * effectively copies the effect properties. You can modify or delete the
361  * effect object afterward without affecting the effect slot.
362  */
363  alAuxiliaryEffectSloti(track->effect_slot, AL_EFFECTSLOT_EFFECT, (ALint)effect);
364  assert(alGetError() == AL_NO_ERROR && "Failed to set effect slot");
365 
366  alDeleteEffects(1, &effect);
367 
368  //apply effect to source
369  alSource3i(track->source[track->isMusic], AL_AUXILIARY_SEND_FILTER, (ALint)(track->effect_slot), 0, AL_FILTER_NULL);
370  assert(alGetError() == AL_NO_ERROR && "Failed to setup reverb for sound source send 0.");
371 
372  //play sound
373  alSourcePlay(track->source[track->isMusic]);
374  m_Playing.push_front(&track);
375  track->isPlaying = true;
376 }
377 
378 void AudioMixer::onTrackFinished(int channelID)
379 {
380  auto it = std::find_if(m_Playing.begin(), m_Playing.end(),
381  [channelID](const auto trackptr)
382  {
383  const auto &track = *trackptr;
384  return track && track->Channel.get() == channelID;
385  });
386  auto &track = **it;
387  if (track)
388  {
389  track->isPlaying = false;
390  if (!track->isMusic)
391  track->Channel = -1;
392  }
393  m_Playing.erase(it);
394 }
395 
396 const char *AudioMixer::get_al_error_msg(ALenum error)
397 {
398  switch (error)
399  {
400  case AL_INVALID_NAME:
401  return "a bad name (ID) was passed to an OpenAL function";
402  case AL_INVALID_ENUM:
403  return "an invalid enum value was passed to an OpenAL function";
404  case AL_INVALID_VALUE:
405  return "an invalid value was passed to an OpenAL function";
406  case AL_INVALID_OPERATION:
407  return "the requested operation is not valid";
408  case AL_OUT_OF_MEMORY:
409  return "the requested operation resulted in OpenAL running out of memory";
410  case AL_NO_ERROR:
411  return "there is not currently an error";
412  default:
413  return "Unknown error";
414  }
415 }
TRACE_INFO
#define TRACE_INFO
Definition: Exception.hxx:12
alGetEffectf
static LPALGETEFFECTF alGetEffectf
Definition: AudioMixer.cxx:283
ConfigurationError
A configuration error.
Definition: Exception.hxx:36
alEffecti
static LPALEFFECTI alEffecti
Definition: AudioMixer.cxx:277
AudioMixer::getTrack
SoundtrackUPtr & getTrack(const AudioTrigger &trigger)
Definition: AudioMixer.cxx:106
SettingsData::soundEffectsVolume
float soundEffectsVolume
the volume of sound effects as float between [0, 1]
Definition: Settings.hxx:88
LOAD_PROC
#define LOAD_PROC(T, x)
StrongType< string, struct SoundtrackIDTag >
AudioMixer::POSITION_INDEX::X
@ X
AudioMixer::stopAll
void stopAll()
Stops all soundtracks.
Definition: AudioMixer.cxx:213
Randomizer::choose
Iterator choose(Iterator begin, Iterator end)
Pick random item from container.
Definition: Randomizer.hxx:29
AudioMixer::POSITION_INDEX::Y
@ Y
AudioMixer::onTrackFinishedFunc
static std::function< void(int)> onTrackFinishedFunc
Definition: AudioMixer.hxx:194
AudioConfig
Definition: AudioConfig.hxx:22
LOG
Definition: LOG.hxx:32
alAuxiliaryEffectSlotfv
static LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv
Definition: AudioMixer.cxx:293
AudioMixer::setMusicVolume
void setMusicVolume(float volume)
sets the music volume
Definition: AudioMixer.cxx:139
LOG.hxx
AudioMixer::playSoundtrack
void playSoundtrack(SoundtrackUPtr &soundtrack)
Plays the Soundtrack.
Definition: AudioMixer.cxx:259
alGetAuxiliaryEffectSloti
static LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti
Definition: AudioMixer.cxx:294
Coordinate3D
a 3-dimensional coordinate
Definition: AudioMixer.hxx:35
SoundtrackUPtr
std::unique_ptr< Soundtrack > SoundtrackUPtr
Definition: Soundtrack.hxx:98
AudioMixer::onTrackFinished
void onTrackFinished(int channelID)
Called whenever a Channel has finished playing.
Definition: AudioMixer.cxx:378
alIsEffect
static LPALISEFFECT alIsEffect
Definition: AudioMixer.cxx:276
alGetAuxiliaryEffectSlotiv
static LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv
Definition: AudioMixer.cxx:295
alEffectiv
static LPALEFFECTIV alEffectiv
Definition: AudioMixer.cxx:278
alGenEffects
static LPALGENEFFECTS alGenEffects
Definition: AudioMixer.cxx:274
Coordinate3D::y
double y
Definition: AudioMixer.hxx:37
LOG_DEBUG
@ LOG_DEBUG
Definition: LOG.hxx:26
alAuxiliaryEffectSloti
static LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti
Definition: AudioMixer.cxx:290
alDeleteEffects
static LPALDELETEEFFECTS alDeleteEffects
Definition: AudioMixer.cxx:275
Coordinate3D::x
double x
Definition: AudioMixer.hxx:37
AudioMixer::setMuted
void setMuted(bool isMuted)
toggles the mute option for sounds
Definition: AudioMixer.cxx:211
alGetAuxiliaryEffectSlotfv
static LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv
Definition: AudioMixer.cxx:297
readFileAsString
std::string readFileAsString(const std::string &fileName, bool binaryMode)
Read contents from a file as string.
Definition: Filesystem.cxx:12
ifstream
std::ifstream ifstream
Definition: AudioMixer.cxx:14
AudioMixer::setSoundEffectVolume
void setSoundEffectVolume(float volume)
sets the sound effects volume
Definition: AudioMixer.cxx:149
AudioMixer::playSoundtrackWithEffect
void playSoundtrackWithEffect(SoundtrackUPtr &soundtrack, int ALEffect)
Plays the Soundtrack with a certain effect applied.
Definition: AudioMixer.cxx:299
noResoruce
static SoundtrackUPtr noResoruce
Definition: AudioMixer.cxx:104
alAuxiliaryEffectSlotiv
static LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv
Definition: AudioMixer.cxx:291
Filesystem.hxx
Settings.hxx
AudioMixer::prune
void prune()
Updates soundtracks that are no longer playing.
Definition: AudioMixer.cxx:230
AudioMixer::m_Playing
List< SoundtrackUPtr * > m_Playing
All the currently playing Soundtracks.
Definition: AudioMixer.hxx:161
alAuxiliaryEffectSlotf
static LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf
Definition: AudioMixer.cxx:292
alEffectf
static LPALEFFECTF alEffectf
Definition: AudioMixer.cxx:279
UnimplementedError
An unimplemented function was called.
Definition: Exception.hxx:44
alGetEffecti
static LPALGETEFFECTI alGetEffecti
Definition: AudioMixer.cxx:281
JsonSerialization.hxx
SettingsData::musicVolume
float musicVolume
the volume of music as float between [0, 1]
Definition: Settings.hxx:85
alGetEffectfv
static LPALGETEFFECTFV alGetEffectfv
Definition: AudioMixer.cxx:284
alGenAuxiliaryEffectSlots
static LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots
Definition: AudioMixer.cxx:287
AudioConfig::Sound
Mapping< string, SoundtrackConfiguration > Sound
Definition: AudioConfig.hxx:31
AudioMixer::POSITION_INDEX::Z
@ Z
AudioMixer::alContext
ALCcontext * alContext
OpenAL Soft setup, context of where audio is played.
Definition: AudioMixer.hxx:217
AudioMixer::play
void play(const SoundtrackID &id, int effect=AL_EFFECT_NULL)
Plays a Soundtrack given its ID and optionally applies an effect.
Definition: AudioMixer.cxx:158
alGetAuxiliaryEffectSlotf
static LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf
Definition: AudioMixer.cxx:296
alEffectfv
static LPALEFFECTFV alEffectfv
Definition: AudioMixer.cxx:280
Singleton< Settings >::instance
static Settings & instance(void)
Get an instance of the singleton.
Definition: Singleton.hxx:15
Exception.hxx
AudioMixer::get_al_error_msg
const char * get_al_error_msg(ALenum error)
Get a descriptive error message from an error code.
Definition: AudioMixer.cxx:396
AudioMixer.hxx
AudioMixer::~AudioMixer
~AudioMixer()
Definition: AudioMixer.cxx:91
AudioMixer::AudioMixer
AudioMixer()
Definition: AudioMixer.cxx:21
Coordinate3D::z
double z
Definition: AudioMixer.hxx:37
AudioMixer::m_Triggers
Array< Vector< SoundtrackID >, AudioTrigger::_size()> m_Triggers
A Mapping between triggers and SoundtrackID.
Definition: AudioMixer.hxx:151
Array
std::array< Type, N > Array
Definition: AudioMixer.cxx:17
GameClock::addRealTimeClockTask
GameClock::ClockTaskHndl addRealTimeClockTask(ClockCbk cbk, DelayType delay, PeriodType period=TimePointZero)
Add new real time clock task.
Definition: GameClock.inl.hxx:5
alDeleteAuxiliaryEffectSlots
static LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots
Definition: AudioMixer.cxx:288
json
nlohmann::json json
Definition: Settings.hxx:12
ResourceManager::get
resource_type< ResourceID >::type get(const ResourceID &)
Fetches and return a Soundtrack.
Definition: ResourceManager.inl.hxx:14
string
std::string string
Definition: AudioConfig.hxx:14
AudioMixer::gAudioDevice
ALCdevice * gAudioDevice
OpenAL Soft setup, audio device to be used.
Definition: AudioMixer.hxx:212
AudioConfig::Music
Mapping< string, SoundtrackConfiguration > Music
Definition: AudioConfig.hxx:30
alGetEffectiv
static LPALGETEFFECTIV alGetEffectiv
Definition: AudioMixer.cxx:282
AudioError
An audio-related error occured.
Definition: Exception.hxx:52
alIsAuxiliaryEffectSlot
static LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot
Definition: AudioMixer.cxx:289
LOG_WARNING
@ LOG_WARNING
Definition: LOG.hxx:27