Use c++ headers
[openal-soft.git] / OpenAL32 / alEffect.cpp
blobca05bad995154ec94a2d9d882117b0a21c2fd1c7
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <cstdlib>
24 #include <cmath>
25 #include <cfloat>
27 #include <algorithm>
29 #include "AL/al.h"
30 #include "AL/alc.h"
32 #include "alMain.h"
33 #include "alcontext.h"
34 #include "alEffect.h"
35 #include "alError.h"
38 const EffectList gEffectList[14]{
39 { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB },
40 { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB },
41 { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
42 { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS },
43 { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR },
44 { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION },
45 { "echo", ECHO_EFFECT, AL_EFFECT_ECHO },
46 { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER },
47 { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER },
48 { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER },
49 { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR },
50 { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER },
51 { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
52 { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE },
55 ALboolean DisabledEffects[MAX_EFFECTS];
57 namespace {
59 void InitEffectParams(ALeffect *effect, ALenum type)
61 switch(type)
63 case AL_EFFECT_EAXREVERB:
64 effect->Props.Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY;
65 effect->Props.Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
66 effect->Props.Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN;
67 effect->Props.Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF;
68 effect->Props.Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF;
69 effect->Props.Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
70 effect->Props.Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
71 effect->Props.Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
72 effect->Props.Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN;
73 effect->Props.Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY;
74 effect->Props.Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
75 effect->Props.Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
76 effect->Props.Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
77 effect->Props.Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN;
78 effect->Props.Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY;
79 effect->Props.Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
80 effect->Props.Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
81 effect->Props.Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
82 effect->Props.Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME;
83 effect->Props.Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH;
84 effect->Props.Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME;
85 effect->Props.Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH;
86 effect->Props.Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
87 effect->Props.Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
88 effect->Props.Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
89 effect->Props.Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
90 effect->Props.Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
91 effect->vtab = &ALeaxreverb_vtable;
92 break;
93 case AL_EFFECT_REVERB:
94 effect->Props.Reverb.Density = AL_REVERB_DEFAULT_DENSITY;
95 effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
96 effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN;
97 effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF;
98 effect->Props.Reverb.GainLF = 1.0f;
99 effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME;
100 effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
101 effect->Props.Reverb.DecayLFRatio = 1.0f;
102 effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
103 effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
104 effect->Props.Reverb.ReflectionsPan[0] = 0.0f;
105 effect->Props.Reverb.ReflectionsPan[1] = 0.0f;
106 effect->Props.Reverb.ReflectionsPan[2] = 0.0f;
107 effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
108 effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
109 effect->Props.Reverb.LateReverbPan[0] = 0.0f;
110 effect->Props.Reverb.LateReverbPan[1] = 0.0f;
111 effect->Props.Reverb.LateReverbPan[2] = 0.0f;
112 effect->Props.Reverb.EchoTime = 0.25f;
113 effect->Props.Reverb.EchoDepth = 0.0f;
114 effect->Props.Reverb.ModulationTime = 0.25f;
115 effect->Props.Reverb.ModulationDepth = 0.0f;
116 effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
117 effect->Props.Reverb.HFReference = 5000.0f;
118 effect->Props.Reverb.LFReference = 250.0f;
119 effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
120 effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
121 effect->vtab = &ALreverb_vtable;
122 break;
123 case AL_EFFECT_AUTOWAH:
124 effect->Props.Autowah.AttackTime = AL_AUTOWAH_DEFAULT_ATTACK_TIME;
125 effect->Props.Autowah.ReleaseTime = AL_AUTOWAH_DEFAULT_RELEASE_TIME;
126 effect->Props.Autowah.Resonance = AL_AUTOWAH_DEFAULT_RESONANCE;
127 effect->Props.Autowah.PeakGain = AL_AUTOWAH_DEFAULT_PEAK_GAIN;
128 effect->vtab = &ALautowah_vtable;
129 break;
130 case AL_EFFECT_CHORUS:
131 effect->Props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM;
132 effect->Props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE;
133 effect->Props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE;
134 effect->Props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH;
135 effect->Props.Chorus.Feedback = AL_CHORUS_DEFAULT_FEEDBACK;
136 effect->Props.Chorus.Delay = AL_CHORUS_DEFAULT_DELAY;
137 effect->vtab = &ALchorus_vtable;
138 break;
139 case AL_EFFECT_COMPRESSOR:
140 effect->Props.Compressor.OnOff = AL_COMPRESSOR_DEFAULT_ONOFF;
141 effect->vtab = &ALcompressor_vtable;
142 break;
143 case AL_EFFECT_DISTORTION:
144 effect->Props.Distortion.Edge = AL_DISTORTION_DEFAULT_EDGE;
145 effect->Props.Distortion.Gain = AL_DISTORTION_DEFAULT_GAIN;
146 effect->Props.Distortion.LowpassCutoff = AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF;
147 effect->Props.Distortion.EQCenter = AL_DISTORTION_DEFAULT_EQCENTER;
148 effect->Props.Distortion.EQBandwidth = AL_DISTORTION_DEFAULT_EQBANDWIDTH;
149 effect->vtab = &ALdistortion_vtable;
150 break;
151 case AL_EFFECT_ECHO:
152 effect->Props.Echo.Delay = AL_ECHO_DEFAULT_DELAY;
153 effect->Props.Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
154 effect->Props.Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
155 effect->Props.Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
156 effect->Props.Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
157 effect->vtab = &ALecho_vtable;
158 break;
159 case AL_EFFECT_EQUALIZER:
160 effect->Props.Equalizer.LowCutoff = AL_EQUALIZER_DEFAULT_LOW_CUTOFF;
161 effect->Props.Equalizer.LowGain = AL_EQUALIZER_DEFAULT_LOW_GAIN;
162 effect->Props.Equalizer.Mid1Center = AL_EQUALIZER_DEFAULT_MID1_CENTER;
163 effect->Props.Equalizer.Mid1Gain = AL_EQUALIZER_DEFAULT_MID1_GAIN;
164 effect->Props.Equalizer.Mid1Width = AL_EQUALIZER_DEFAULT_MID1_WIDTH;
165 effect->Props.Equalizer.Mid2Center = AL_EQUALIZER_DEFAULT_MID2_CENTER;
166 effect->Props.Equalizer.Mid2Gain = AL_EQUALIZER_DEFAULT_MID2_GAIN;
167 effect->Props.Equalizer.Mid2Width = AL_EQUALIZER_DEFAULT_MID2_WIDTH;
168 effect->Props.Equalizer.HighCutoff = AL_EQUALIZER_DEFAULT_HIGH_CUTOFF;
169 effect->Props.Equalizer.HighGain = AL_EQUALIZER_DEFAULT_HIGH_GAIN;
170 effect->vtab = &ALequalizer_vtable;
171 break;
172 case AL_EFFECT_FLANGER:
173 effect->Props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM;
174 effect->Props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE;
175 effect->Props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE;
176 effect->Props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH;
177 effect->Props.Chorus.Feedback = AL_FLANGER_DEFAULT_FEEDBACK;
178 effect->Props.Chorus.Delay = AL_FLANGER_DEFAULT_DELAY;
179 effect->vtab = &ALflanger_vtable;
180 break;
181 case AL_EFFECT_FREQUENCY_SHIFTER:
182 effect->Props.Fshifter.Frequency = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
183 effect->Props.Fshifter.LeftDirection = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION;
184 effect->Props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION;
185 effect->vtab = &ALfshifter_vtable;
186 break;
187 case AL_EFFECT_RING_MODULATOR:
188 effect->Props.Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
189 effect->Props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
190 effect->Props.Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
191 effect->vtab = &ALmodulator_vtable;
192 break;
193 case AL_EFFECT_PITCH_SHIFTER:
194 effect->Props.Pshifter.CoarseTune = AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE;
195 effect->Props.Pshifter.FineTune = AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE;
196 effect->vtab = &ALpshifter_vtable;
197 break;
198 case AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT:
199 case AL_EFFECT_DEDICATED_DIALOGUE:
200 effect->Props.Dedicated.Gain = 1.0f;
201 effect->vtab = &ALdedicated_vtable;
202 break;
203 default:
204 effect->vtab = &ALnull_vtable;
205 break;
207 effect->type = type;
210 ALeffect *AllocEffect(ALCcontext *context)
212 ALCdevice *device{context->Device};
213 std::lock_guard<std::mutex> _{device->EffectLock};
214 auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(),
215 [](const EffectSubList &entry) noexcept -> bool
216 { return entry.FreeMask != 0; }
219 auto lidx = static_cast<ALsizei>(std::distance(device->EffectList.begin(), sublist));
220 ALeffect *effect{nullptr};
221 ALsizei slidx{0};
222 if(LIKELY(sublist != device->EffectList.end()))
224 slidx = CTZ64(sublist->FreeMask);
225 effect = sublist->Effects + slidx;
227 else
229 /* Don't allocate so many list entries that the 32-bit ID could
230 * overflow...
232 if(UNLIKELY(device->EffectList.size() >= 1<<25))
234 alSetError(context, AL_OUT_OF_MEMORY, "Too many effects allocated");
235 return nullptr;
237 device->EffectList.emplace_back();
238 sublist = device->EffectList.end() - 1;
239 sublist->FreeMask = ~0_u64;
240 sublist->Effects = static_cast<ALeffect*>(al_calloc(16, sizeof(ALeffect)*64));
241 if(UNLIKELY(!sublist->Effects))
243 device->EffectList.pop_back();
244 alSetError(context, AL_OUT_OF_MEMORY, "Failed to allocate effect batch");
245 return nullptr;
248 slidx = 0;
249 effect = sublist->Effects + slidx;
252 effect = new (effect) ALeffect{};
253 InitEffectParams(effect, AL_EFFECT_NULL);
255 /* Add 1 to avoid effect ID 0. */
256 effect->id = ((lidx<<6) | slidx) + 1;
258 sublist->FreeMask &= ~(1_u64 << slidx);
260 return effect;
263 void FreeEffect(ALCdevice *device, ALeffect *effect)
265 ALuint id = effect->id - 1;
266 ALsizei lidx = id >> 6;
267 ALsizei slidx = id & 0x3f;
269 effect->~ALeffect();
271 device->EffectList[lidx].FreeMask |= 1_u64 << slidx;
274 inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
276 ALuint lidx = (id-1) >> 6;
277 ALsizei slidx = (id-1) & 0x3f;
279 if(UNLIKELY(lidx >= device->EffectList.size()))
280 return nullptr;
281 EffectSubList &sublist = device->EffectList[lidx];
282 if(UNLIKELY(sublist.FreeMask & (1_u64 << slidx)))
283 return nullptr;
284 return sublist.Effects + slidx;
287 } // namespace
289 AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
291 ContextRef context{GetContextRef()};
292 if(UNLIKELY(!context)) return;
294 if(UNLIKELY(n < 0))
296 alSetError(context.get(), AL_INVALID_VALUE, "Generating %d effects", n);
297 return;
300 if(LIKELY(n == 1))
302 /* Special handling for the easy and normal case. */
303 ALeffect *effect = AllocEffect(context.get());
304 if(effect) effects[0] = effect->id;
306 else if(n > 1)
308 /* Store the allocated buffer IDs in a separate local list, to avoid
309 * modifying the user storage in case of failure.
311 al::vector<ALuint> ids;
312 ids.reserve(n);
313 do {
314 ALeffect *effect = AllocEffect(context.get());
315 if(!effect)
317 alDeleteEffects(static_cast<ALsizei>(ids.size()), ids.data());
318 return;
321 ids.emplace_back(effect->id);
322 } while(--n);
323 std::copy(ids.begin(), ids.end(), effects);
327 AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
329 ContextRef context{GetContextRef()};
330 if(UNLIKELY(!context)) return;
332 if(UNLIKELY(n < 0))
334 alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d effects", n);
335 return;
337 if(UNLIKELY(n == 0))
338 return;
340 ALCdevice *device{context->Device};
341 std::lock_guard<std::mutex> _{device->EffectLock};
343 /* First try to find any effects that are invalid. */
344 const ALuint *effects_end = effects + n;
345 auto inveffect = std::find_if(effects, effects_end,
346 [device, &context](ALuint eid) -> bool
348 if(!eid) return false;
349 ALeffect *effect{LookupEffect(device, eid)};
350 if(UNLIKELY(!effect))
352 alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", eid);
353 return true;
355 return false;
358 if(LIKELY(inveffect == effects_end))
360 /* All good. Delete non-0 effect IDs. */
361 std::for_each(effects, effects_end,
362 [device](ALuint eid) -> void
364 ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr};
365 if(effect) FreeEffect(device, effect);
371 AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
373 ContextRef context{GetContextRef()};
374 if(LIKELY(context))
376 ALCdevice *device{context->Device};
377 std::lock_guard<std::mutex> _{device->EffectLock};
378 if(!effect || LookupEffect(device, effect))
379 return AL_TRUE;
381 return AL_FALSE;
384 AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
386 ContextRef context{GetContextRef()};
387 if(UNLIKELY(!context)) return;
389 ALCdevice *device{context->Device};
390 std::lock_guard<std::mutex> _{device->EffectLock};
392 ALeffect *aleffect{LookupEffect(device, effect)};
393 if(UNLIKELY(!aleffect))
394 alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect);
395 else
397 if(param == AL_EFFECT_TYPE)
399 ALboolean isOk = (value == AL_EFFECT_NULL);
400 for(size_t i{0u};!isOk && i < countof(gEffectList);i++)
402 if(value == gEffectList[i].val && !DisabledEffects[gEffectList[i].type])
403 isOk = AL_TRUE;
406 if(isOk)
407 InitEffectParams(aleffect, value);
408 else
409 alSetError(context.get(), AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
411 else
413 /* Call the appropriate handler */
414 ALeffect_setParami(aleffect, context.get(), param, value);
419 AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values)
421 switch(param)
423 case AL_EFFECT_TYPE:
424 alEffecti(effect, param, values[0]);
425 return;
428 ContextRef context{GetContextRef()};
429 if(UNLIKELY(!context)) return;
431 ALCdevice *device{context->Device};
432 std::lock_guard<std::mutex> _{device->EffectLock};
434 ALeffect *aleffect{LookupEffect(device, effect)};
435 if(UNLIKELY(!aleffect))
436 alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect);
437 else
439 /* Call the appropriate handler */
440 ALeffect_setParamiv(aleffect, context.get(), param, values);
444 AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
446 ContextRef context{GetContextRef()};
447 if(UNLIKELY(!context)) return;
449 ALCdevice *device{context->Device};
450 std::lock_guard<std::mutex> _{device->EffectLock};
452 ALeffect *aleffect{LookupEffect(device, effect)};
453 if(UNLIKELY(!aleffect))
454 alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect);
455 else
457 /* Call the appropriate handler */
458 ALeffect_setParamf(aleffect, context.get(), param, value);
462 AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values)
464 ContextRef context{GetContextRef()};
465 if(UNLIKELY(!context)) return;
467 ALCdevice *device{context->Device};
468 std::lock_guard<std::mutex> _{device->EffectLock};
470 ALeffect *aleffect{LookupEffect(device, effect)};
471 if(UNLIKELY(!aleffect))
472 alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect);
473 else
475 /* Call the appropriate handler */
476 ALeffect_setParamfv(aleffect, context.get(), param, values);
480 AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value)
482 ContextRef context{GetContextRef()};
483 if(UNLIKELY(!context)) return;
485 ALCdevice *device{context->Device};
486 std::lock_guard<std::mutex> _{device->EffectLock};
488 const ALeffect *aleffect{LookupEffect(device, effect)};
489 if(UNLIKELY(!aleffect))
490 alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect);
491 else
493 if(param == AL_EFFECT_TYPE)
494 *value = aleffect->type;
495 else
497 /* Call the appropriate handler */
498 ALeffect_getParami(aleffect, context.get(), param, value);
503 AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values)
505 switch(param)
507 case AL_EFFECT_TYPE:
508 alGetEffecti(effect, param, values);
509 return;
512 ContextRef context{GetContextRef()};
513 if(UNLIKELY(!context)) return;
515 ALCdevice *device{context->Device};
516 std::lock_guard<std::mutex> _{device->EffectLock};
518 const ALeffect *aleffect{LookupEffect(device, effect)};
519 if(UNLIKELY(!aleffect))
520 alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect);
521 else
523 /* Call the appropriate handler */
524 ALeffect_getParamiv(aleffect, context.get(), param, values);
528 AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value)
530 ContextRef context{GetContextRef()};
531 if(UNLIKELY(!context)) return;
533 ALCdevice *device{context->Device};
534 std::lock_guard<std::mutex> _{device->EffectLock};
536 const ALeffect *aleffect{LookupEffect(device, effect)};
537 if(UNLIKELY(!aleffect))
538 alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect);
539 else
541 /* Call the appropriate handler */
542 ALeffect_getParamf(aleffect, context.get(), param, value);
546 AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values)
548 ContextRef context{GetContextRef()};
549 if(UNLIKELY(!context)) return;
551 ALCdevice *device{context->Device};
552 std::lock_guard<std::mutex> _{device->EffectLock};
554 const ALeffect *aleffect{LookupEffect(device, effect)};
555 if(UNLIKELY(!aleffect))
556 alSetError(context.get(), AL_INVALID_NAME, "Invalid effect ID %u", effect);
557 else
559 /* Call the appropriate handler */
560 ALeffect_getParamfv(aleffect, context.get(), param, values);
565 void InitEffect(ALeffect *effect)
567 InitEffectParams(effect, AL_EFFECT_NULL);
570 EffectSubList::~EffectSubList()
572 ALuint64 usemask = ~FreeMask;
573 while(usemask)
575 ALsizei idx = CTZ64(usemask);
576 Effects[idx].~ALeffect();
577 usemask &= ~(1_u64 << idx);
579 FreeMask = ~usemask;
580 al_free(Effects);
581 Effects = nullptr;
585 #include "AL/efx-presets.h"
587 #define DECL(x) { #x, EFX_REVERB_PRESET_##x }
588 static const struct {
589 const char name[32];
590 EFXEAXREVERBPROPERTIES props;
591 } reverblist[] = {
592 DECL(GENERIC),
593 DECL(PADDEDCELL),
594 DECL(ROOM),
595 DECL(BATHROOM),
596 DECL(LIVINGROOM),
597 DECL(STONEROOM),
598 DECL(AUDITORIUM),
599 DECL(CONCERTHALL),
600 DECL(CAVE),
601 DECL(ARENA),
602 DECL(HANGAR),
603 DECL(CARPETEDHALLWAY),
604 DECL(HALLWAY),
605 DECL(STONECORRIDOR),
606 DECL(ALLEY),
607 DECL(FOREST),
608 DECL(CITY),
609 DECL(MOUNTAINS),
610 DECL(QUARRY),
611 DECL(PLAIN),
612 DECL(PARKINGLOT),
613 DECL(SEWERPIPE),
614 DECL(UNDERWATER),
615 DECL(DRUGGED),
616 DECL(DIZZY),
617 DECL(PSYCHOTIC),
619 DECL(CASTLE_SMALLROOM),
620 DECL(CASTLE_SHORTPASSAGE),
621 DECL(CASTLE_MEDIUMROOM),
622 DECL(CASTLE_LARGEROOM),
623 DECL(CASTLE_LONGPASSAGE),
624 DECL(CASTLE_HALL),
625 DECL(CASTLE_CUPBOARD),
626 DECL(CASTLE_COURTYARD),
627 DECL(CASTLE_ALCOVE),
629 DECL(FACTORY_SMALLROOM),
630 DECL(FACTORY_SHORTPASSAGE),
631 DECL(FACTORY_MEDIUMROOM),
632 DECL(FACTORY_LARGEROOM),
633 DECL(FACTORY_LONGPASSAGE),
634 DECL(FACTORY_HALL),
635 DECL(FACTORY_CUPBOARD),
636 DECL(FACTORY_COURTYARD),
637 DECL(FACTORY_ALCOVE),
639 DECL(ICEPALACE_SMALLROOM),
640 DECL(ICEPALACE_SHORTPASSAGE),
641 DECL(ICEPALACE_MEDIUMROOM),
642 DECL(ICEPALACE_LARGEROOM),
643 DECL(ICEPALACE_LONGPASSAGE),
644 DECL(ICEPALACE_HALL),
645 DECL(ICEPALACE_CUPBOARD),
646 DECL(ICEPALACE_COURTYARD),
647 DECL(ICEPALACE_ALCOVE),
649 DECL(SPACESTATION_SMALLROOM),
650 DECL(SPACESTATION_SHORTPASSAGE),
651 DECL(SPACESTATION_MEDIUMROOM),
652 DECL(SPACESTATION_LARGEROOM),
653 DECL(SPACESTATION_LONGPASSAGE),
654 DECL(SPACESTATION_HALL),
655 DECL(SPACESTATION_CUPBOARD),
656 DECL(SPACESTATION_ALCOVE),
658 DECL(WOODEN_SMALLROOM),
659 DECL(WOODEN_SHORTPASSAGE),
660 DECL(WOODEN_MEDIUMROOM),
661 DECL(WOODEN_LARGEROOM),
662 DECL(WOODEN_LONGPASSAGE),
663 DECL(WOODEN_HALL),
664 DECL(WOODEN_CUPBOARD),
665 DECL(WOODEN_COURTYARD),
666 DECL(WOODEN_ALCOVE),
668 DECL(SPORT_EMPTYSTADIUM),
669 DECL(SPORT_SQUASHCOURT),
670 DECL(SPORT_SMALLSWIMMINGPOOL),
671 DECL(SPORT_LARGESWIMMINGPOOL),
672 DECL(SPORT_GYMNASIUM),
673 DECL(SPORT_FULLSTADIUM),
674 DECL(SPORT_STADIUMTANNOY),
676 DECL(PREFAB_WORKSHOP),
677 DECL(PREFAB_SCHOOLROOM),
678 DECL(PREFAB_PRACTISEROOM),
679 DECL(PREFAB_OUTHOUSE),
680 DECL(PREFAB_CARAVAN),
682 DECL(DOME_TOMB),
683 DECL(PIPE_SMALL),
684 DECL(DOME_SAINTPAULS),
685 DECL(PIPE_LONGTHIN),
686 DECL(PIPE_LARGE),
687 DECL(PIPE_RESONANT),
689 DECL(OUTDOORS_BACKYARD),
690 DECL(OUTDOORS_ROLLINGPLAINS),
691 DECL(OUTDOORS_DEEPCANYON),
692 DECL(OUTDOORS_CREEK),
693 DECL(OUTDOORS_VALLEY),
695 DECL(MOOD_HEAVEN),
696 DECL(MOOD_HELL),
697 DECL(MOOD_MEMORY),
699 DECL(DRIVING_COMMENTATOR),
700 DECL(DRIVING_PITGARAGE),
701 DECL(DRIVING_INCAR_RACER),
702 DECL(DRIVING_INCAR_SPORTS),
703 DECL(DRIVING_INCAR_LUXURY),
704 DECL(DRIVING_FULLGRANDSTAND),
705 DECL(DRIVING_EMPTYGRANDSTAND),
706 DECL(DRIVING_TUNNEL),
708 DECL(CITY_STREETS),
709 DECL(CITY_SUBWAY),
710 DECL(CITY_MUSEUM),
711 DECL(CITY_LIBRARY),
712 DECL(CITY_UNDERPASS),
713 DECL(CITY_ABANDONED),
715 DECL(DUSTYROOM),
716 DECL(CHAPEL),
717 DECL(SMALLWATERROOM),
719 #undef DECL
721 void LoadReverbPreset(const char *name, ALeffect *effect)
723 size_t i;
725 if(strcasecmp(name, "NONE") == 0)
727 InitEffectParams(effect, AL_EFFECT_NULL);
728 TRACE("Loading reverb '%s'\n", "NONE");
729 return;
732 if(!DisabledEffects[EAXREVERB_EFFECT])
733 InitEffectParams(effect, AL_EFFECT_EAXREVERB);
734 else if(!DisabledEffects[REVERB_EFFECT])
735 InitEffectParams(effect, AL_EFFECT_REVERB);
736 else
737 InitEffectParams(effect, AL_EFFECT_NULL);
738 for(i = 0;i < COUNTOF(reverblist);i++)
740 const EFXEAXREVERBPROPERTIES *props;
742 if(strcasecmp(name, reverblist[i].name) != 0)
743 continue;
745 TRACE("Loading reverb '%s'\n", reverblist[i].name);
746 props = &reverblist[i].props;
747 effect->Props.Reverb.Density = props->flDensity;
748 effect->Props.Reverb.Diffusion = props->flDiffusion;
749 effect->Props.Reverb.Gain = props->flGain;
750 effect->Props.Reverb.GainHF = props->flGainHF;
751 effect->Props.Reverb.GainLF = props->flGainLF;
752 effect->Props.Reverb.DecayTime = props->flDecayTime;
753 effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio;
754 effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio;
755 effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain;
756 effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay;
757 effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
758 effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
759 effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
760 effect->Props.Reverb.LateReverbGain = props->flLateReverbGain;
761 effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay;
762 effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
763 effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
764 effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
765 effect->Props.Reverb.EchoTime = props->flEchoTime;
766 effect->Props.Reverb.EchoDepth = props->flEchoDepth;
767 effect->Props.Reverb.ModulationTime = props->flModulationTime;
768 effect->Props.Reverb.ModulationDepth = props->flModulationDepth;
769 effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
770 effect->Props.Reverb.HFReference = props->flHFReference;
771 effect->Props.Reverb.LFReference = props->flLFReference;
772 effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
773 effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit;
774 return;
777 WARN("Reverb preset '%s' not found\n", name);