Fix reverse iterators for spans
[openal-soft.git] / al / effect.cpp
blobf7d17f50a839c353c38922ce2830726f2aea734b
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 "effect.h"
25 #include <algorithm>
26 #include <cstdint>
27 #include <cstring>
28 #include <iterator>
29 #include <memory>
30 #include <mutex>
31 #include <new>
32 #include <numeric>
33 #include <utility>
35 #include "AL/al.h"
36 #include "AL/alc.h"
37 #include "AL/alext.h"
38 #include "AL/efx-presets.h"
39 #include "AL/efx.h"
41 #include "alcmain.h"
42 #include "alcontext.h"
43 #include "alexcpt.h"
44 #include "almalloc.h"
45 #include "alnumeric.h"
46 #include "alstring.h"
47 #include "effects/base.h"
48 #include "logging.h"
49 #include "opthelpers.h"
50 #include "vector.h"
53 const EffectList gEffectList[15]{
54 { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB },
55 { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB },
56 { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
57 { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS },
58 { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR },
59 { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION },
60 { "echo", ECHO_EFFECT, AL_EFFECT_ECHO },
61 { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER },
62 { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER },
63 { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER },
64 { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR },
65 { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER },
66 { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER },
67 { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
68 { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE },
71 ALboolean DisabledEffects[MAX_EFFECTS];
73 namespace {
75 constexpr struct FactoryItem {
76 ALenum Type;
77 EffectStateFactory* (&GetFactory)(void);
78 } FactoryList[] = {
79 { AL_EFFECT_NULL, NullStateFactory_getFactory },
80 { AL_EFFECT_EAXREVERB, ReverbStateFactory_getFactory },
81 { AL_EFFECT_REVERB, StdReverbStateFactory_getFactory },
82 { AL_EFFECT_AUTOWAH, AutowahStateFactory_getFactory },
83 { AL_EFFECT_CHORUS, ChorusStateFactory_getFactory },
84 { AL_EFFECT_COMPRESSOR, CompressorStateFactory_getFactory },
85 { AL_EFFECT_DISTORTION, DistortionStateFactory_getFactory },
86 { AL_EFFECT_ECHO, EchoStateFactory_getFactory },
87 { AL_EFFECT_EQUALIZER, EqualizerStateFactory_getFactory },
88 { AL_EFFECT_FLANGER, FlangerStateFactory_getFactory },
89 { AL_EFFECT_FREQUENCY_SHIFTER, FshifterStateFactory_getFactory },
90 { AL_EFFECT_RING_MODULATOR, ModulatorStateFactory_getFactory },
91 { AL_EFFECT_PITCH_SHIFTER, PshifterStateFactory_getFactory},
92 { AL_EFFECT_VOCAL_MORPHER, VmorpherStateFactory_getFactory},
93 { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedStateFactory_getFactory },
94 { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedStateFactory_getFactory }
98 template<typename... T>
99 void ALeffect_setParami(ALeffect *effect, T&& ...args)
100 { effect->vtab->setParami(&effect->Props, std::forward<T>(args)...); }
101 template<typename... T>
102 void ALeffect_setParamiv(ALeffect *effect, T&& ...args)
103 { effect->vtab->setParamiv(&effect->Props, std::forward<T>(args)...); }
104 template<typename... T>
105 void ALeffect_setParamf(ALeffect *effect, T&& ...args)
106 { effect->vtab->setParamf(&effect->Props, std::forward<T>(args)...); }
107 template<typename... T>
108 void ALeffect_setParamfv(ALeffect *effect, T&& ...args)
109 { effect->vtab->setParamfv(&effect->Props, std::forward<T>(args)...); }
111 template<typename... T>
112 void ALeffect_getParami(const ALeffect *effect, T&& ...args)
113 { effect->vtab->getParami(&effect->Props, std::forward<T>(args)...); }
114 template<typename... T>
115 void ALeffect_getParamiv(const ALeffect *effect, T&& ...args)
116 { effect->vtab->getParamiv(&effect->Props, std::forward<T>(args)...); }
117 template<typename... T>
118 void ALeffect_getParamf(const ALeffect *effect, T&& ...args)
119 { effect->vtab->getParamf(&effect->Props, std::forward<T>(args)...); }
120 template<typename... T>
121 void ALeffect_getParamfv(const ALeffect *effect, T&& ...args)
122 { effect->vtab->getParamfv(&effect->Props, std::forward<T>(args)...); }
125 void InitEffectParams(ALeffect *effect, ALenum type)
127 EffectStateFactory *factory = getFactoryByType(type);
128 if(factory)
130 effect->Props = factory->getDefaultProps();
131 effect->vtab = factory->getEffectVtable();
133 else
135 effect->Props = EffectProps{};
136 effect->vtab = nullptr;
138 effect->type = type;
141 bool EnsureEffects(ALCdevice *device, size_t needed)
143 size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0},
144 [](size_t cur, const EffectSubList &sublist) noexcept -> size_t
145 { return cur + static_cast<ALuint>(POPCNT64(sublist.FreeMask)); }
148 while(needed > count)
150 if UNLIKELY(device->EffectList.size() >= 1<<25)
151 return false;
153 device->EffectList.emplace_back();
154 auto sublist = device->EffectList.end() - 1;
155 sublist->FreeMask = ~0_u64;
156 sublist->Effects = static_cast<ALeffect*>(al_calloc(alignof(ALeffect), sizeof(ALeffect)*64));
157 if UNLIKELY(!sublist->Effects)
159 device->EffectList.pop_back();
160 return false;
162 count += 64;
164 return true;
167 ALeffect *AllocEffect(ALCdevice *device)
169 auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(),
170 [](const EffectSubList &entry) noexcept -> bool
171 { return entry.FreeMask != 0; }
173 auto lidx = static_cast<ALuint>(std::distance(device->EffectList.begin(), sublist));
174 auto slidx = static_cast<ALuint>(CTZ64(sublist->FreeMask));
176 ALeffect *effect{::new (sublist->Effects + slidx) ALeffect{}};
177 InitEffectParams(effect, AL_EFFECT_NULL);
179 /* Add 1 to avoid effect ID 0. */
180 effect->id = ((lidx<<6) | slidx) + 1;
182 sublist->FreeMask &= ~(1_u64 << slidx);
184 return effect;
187 void FreeEffect(ALCdevice *device, ALeffect *effect)
189 const ALuint id{effect->id - 1};
190 const size_t lidx{id >> 6};
191 const ALuint slidx{id & 0x3f};
193 al::destroy_at(effect);
195 device->EffectList[lidx].FreeMask |= 1_u64 << slidx;
198 inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
200 const size_t lidx{(id-1) >> 6};
201 const ALuint slidx{(id-1) & 0x3f};
203 if UNLIKELY(lidx >= device->EffectList.size())
204 return nullptr;
205 EffectSubList &sublist = device->EffectList[lidx];
206 if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
207 return nullptr;
208 return sublist.Effects + slidx;
211 } // namespace
213 AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
214 START_API_FUNC
216 ContextRef context{GetContextRef()};
217 if UNLIKELY(!context) return;
219 if UNLIKELY(n < 0)
220 context->setError(AL_INVALID_VALUE, "Generating %d effects", n);
221 if UNLIKELY(n <= 0) return;
223 ALCdevice *device{context->mDevice.get()};
224 std::lock_guard<std::mutex> _{device->EffectLock};
225 if(!EnsureEffects(device, static_cast<ALuint>(n)))
227 context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effect%s", n, (n==1)?"":"s");
228 return;
231 if LIKELY(n == 1)
233 /* Special handling for the easy and normal case. */
234 ALeffect *effect{AllocEffect(device)};
235 effects[0] = effect->id;
237 else
239 /* Store the allocated buffer IDs in a separate local list, to avoid
240 * modifying the user storage in case of failure.
242 al::vector<ALuint> ids;
243 ids.reserve(static_cast<ALuint>(n));
244 do {
245 ALeffect *effect{AllocEffect(device)};
246 ids.emplace_back(effect->id);
247 } while(--n);
248 std::copy(ids.cbegin(), ids.cend(), effects);
251 END_API_FUNC
253 AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
254 START_API_FUNC
256 ContextRef context{GetContextRef()};
257 if UNLIKELY(!context) return;
259 if UNLIKELY(n < 0)
260 context->setError(AL_INVALID_VALUE, "Deleting %d effects", n);
261 if UNLIKELY(n <= 0) return;
263 ALCdevice *device{context->mDevice.get()};
264 std::lock_guard<std::mutex> _{device->EffectLock};
266 /* First try to find any effects that are invalid. */
267 auto validate_effect = [device](const ALuint eid) -> bool
268 { return !eid || LookupEffect(device, eid) != nullptr; };
270 const ALuint *effects_end = effects + n;
271 auto inveffect = std::find_if_not(effects, effects_end, validate_effect);
272 if UNLIKELY(inveffect != effects_end)
274 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", *inveffect);
275 return;
278 /* All good. Delete non-0 effect IDs. */
279 auto delete_effect = [device](ALuint eid) -> void
281 ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr};
282 if(effect) FreeEffect(device, effect);
284 std::for_each(effects, effects_end, delete_effect);
286 END_API_FUNC
288 AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
289 START_API_FUNC
291 ContextRef context{GetContextRef()};
292 if LIKELY(context)
294 ALCdevice *device{context->mDevice.get()};
295 std::lock_guard<std::mutex> _{device->EffectLock};
296 if(!effect || LookupEffect(device, effect))
297 return AL_TRUE;
299 return AL_FALSE;
301 END_API_FUNC
303 AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
304 START_API_FUNC
306 ContextRef context{GetContextRef()};
307 if UNLIKELY(!context) return;
309 ALCdevice *device{context->mDevice.get()};
310 std::lock_guard<std::mutex> _{device->EffectLock};
312 ALeffect *aleffect{LookupEffect(device, effect)};
313 if UNLIKELY(!aleffect)
314 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
315 else
317 if(param == AL_EFFECT_TYPE)
319 ALboolean isOk{value == AL_EFFECT_NULL};
320 if(!isOk)
322 for(const EffectList &effectitem : gEffectList)
324 if(value == effectitem.val && !DisabledEffects[effectitem.type])
326 isOk = AL_TRUE;
327 break;
332 if(isOk)
333 InitEffectParams(aleffect, value);
334 else
335 context->setError(AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
337 else
339 /* Call the appropriate handler */
340 ALeffect_setParami(aleffect, context.get(), param, value);
344 END_API_FUNC
346 AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values)
347 START_API_FUNC
349 switch(param)
351 case AL_EFFECT_TYPE:
352 alEffecti(effect, param, values[0]);
353 return;
356 ContextRef context{GetContextRef()};
357 if UNLIKELY(!context) return;
359 ALCdevice *device{context->mDevice.get()};
360 std::lock_guard<std::mutex> _{device->EffectLock};
362 ALeffect *aleffect{LookupEffect(device, effect)};
363 if UNLIKELY(!aleffect)
364 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
365 else
367 /* Call the appropriate handler */
368 ALeffect_setParamiv(aleffect, context.get(), param, values);
371 END_API_FUNC
373 AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
374 START_API_FUNC
376 ContextRef context{GetContextRef()};
377 if UNLIKELY(!context) return;
379 ALCdevice *device{context->mDevice.get()};
380 std::lock_guard<std::mutex> _{device->EffectLock};
382 ALeffect *aleffect{LookupEffect(device, effect)};
383 if UNLIKELY(!aleffect)
384 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
385 else
387 /* Call the appropriate handler */
388 ALeffect_setParamf(aleffect, context.get(), param, value);
391 END_API_FUNC
393 AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values)
394 START_API_FUNC
396 ContextRef context{GetContextRef()};
397 if UNLIKELY(!context) return;
399 ALCdevice *device{context->mDevice.get()};
400 std::lock_guard<std::mutex> _{device->EffectLock};
402 ALeffect *aleffect{LookupEffect(device, effect)};
403 if UNLIKELY(!aleffect)
404 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
405 else
407 /* Call the appropriate handler */
408 ALeffect_setParamfv(aleffect, context.get(), param, values);
411 END_API_FUNC
413 AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value)
414 START_API_FUNC
416 ContextRef context{GetContextRef()};
417 if UNLIKELY(!context) return;
419 ALCdevice *device{context->mDevice.get()};
420 std::lock_guard<std::mutex> _{device->EffectLock};
422 const ALeffect *aleffect{LookupEffect(device, effect)};
423 if UNLIKELY(!aleffect)
424 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
425 else
427 if(param == AL_EFFECT_TYPE)
428 *value = aleffect->type;
429 else
431 /* Call the appropriate handler */
432 ALeffect_getParami(aleffect, context.get(), param, value);
436 END_API_FUNC
438 AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values)
439 START_API_FUNC
441 switch(param)
443 case AL_EFFECT_TYPE:
444 alGetEffecti(effect, param, values);
445 return;
448 ContextRef context{GetContextRef()};
449 if UNLIKELY(!context) return;
451 ALCdevice *device{context->mDevice.get()};
452 std::lock_guard<std::mutex> _{device->EffectLock};
454 const ALeffect *aleffect{LookupEffect(device, effect)};
455 if UNLIKELY(!aleffect)
456 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
457 else
459 /* Call the appropriate handler */
460 ALeffect_getParamiv(aleffect, context.get(), param, values);
463 END_API_FUNC
465 AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value)
466 START_API_FUNC
468 ContextRef context{GetContextRef()};
469 if UNLIKELY(!context) return;
471 ALCdevice *device{context->mDevice.get()};
472 std::lock_guard<std::mutex> _{device->EffectLock};
474 const ALeffect *aleffect{LookupEffect(device, effect)};
475 if UNLIKELY(!aleffect)
476 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
477 else
479 /* Call the appropriate handler */
480 ALeffect_getParamf(aleffect, context.get(), param, value);
483 END_API_FUNC
485 AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values)
486 START_API_FUNC
488 ContextRef context{GetContextRef()};
489 if UNLIKELY(!context) return;
491 ALCdevice *device{context->mDevice.get()};
492 std::lock_guard<std::mutex> _{device->EffectLock};
494 const ALeffect *aleffect{LookupEffect(device, effect)};
495 if UNLIKELY(!aleffect)
496 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
497 else
499 /* Call the appropriate handler */
500 ALeffect_getParamfv(aleffect, context.get(), param, values);
503 END_API_FUNC
506 void InitEffect(ALeffect *effect)
508 InitEffectParams(effect, AL_EFFECT_NULL);
511 EffectSubList::~EffectSubList()
513 uint64_t usemask{~FreeMask};
514 while(usemask)
516 ALsizei idx = CTZ64(usemask);
517 al::destroy_at(Effects+idx);
518 usemask &= ~(1_u64 << idx);
520 FreeMask = ~usemask;
521 al_free(Effects);
522 Effects = nullptr;
526 EffectStateFactory *getFactoryByType(ALenum type)
528 auto iter = std::find_if(std::begin(FactoryList), std::end(FactoryList),
529 [type](const FactoryItem &item) noexcept -> bool
530 { return item.Type == type; }
532 return (iter != std::end(FactoryList)) ? iter->GetFactory() : nullptr;
536 #define DECL(x) { #x, EFX_REVERB_PRESET_##x }
537 static const struct {
538 const char name[32];
539 EFXEAXREVERBPROPERTIES props;
540 } reverblist[] = {
541 DECL(GENERIC),
542 DECL(PADDEDCELL),
543 DECL(ROOM),
544 DECL(BATHROOM),
545 DECL(LIVINGROOM),
546 DECL(STONEROOM),
547 DECL(AUDITORIUM),
548 DECL(CONCERTHALL),
549 DECL(CAVE),
550 DECL(ARENA),
551 DECL(HANGAR),
552 DECL(CARPETEDHALLWAY),
553 DECL(HALLWAY),
554 DECL(STONECORRIDOR),
555 DECL(ALLEY),
556 DECL(FOREST),
557 DECL(CITY),
558 DECL(MOUNTAINS),
559 DECL(QUARRY),
560 DECL(PLAIN),
561 DECL(PARKINGLOT),
562 DECL(SEWERPIPE),
563 DECL(UNDERWATER),
564 DECL(DRUGGED),
565 DECL(DIZZY),
566 DECL(PSYCHOTIC),
568 DECL(CASTLE_SMALLROOM),
569 DECL(CASTLE_SHORTPASSAGE),
570 DECL(CASTLE_MEDIUMROOM),
571 DECL(CASTLE_LARGEROOM),
572 DECL(CASTLE_LONGPASSAGE),
573 DECL(CASTLE_HALL),
574 DECL(CASTLE_CUPBOARD),
575 DECL(CASTLE_COURTYARD),
576 DECL(CASTLE_ALCOVE),
578 DECL(FACTORY_SMALLROOM),
579 DECL(FACTORY_SHORTPASSAGE),
580 DECL(FACTORY_MEDIUMROOM),
581 DECL(FACTORY_LARGEROOM),
582 DECL(FACTORY_LONGPASSAGE),
583 DECL(FACTORY_HALL),
584 DECL(FACTORY_CUPBOARD),
585 DECL(FACTORY_COURTYARD),
586 DECL(FACTORY_ALCOVE),
588 DECL(ICEPALACE_SMALLROOM),
589 DECL(ICEPALACE_SHORTPASSAGE),
590 DECL(ICEPALACE_MEDIUMROOM),
591 DECL(ICEPALACE_LARGEROOM),
592 DECL(ICEPALACE_LONGPASSAGE),
593 DECL(ICEPALACE_HALL),
594 DECL(ICEPALACE_CUPBOARD),
595 DECL(ICEPALACE_COURTYARD),
596 DECL(ICEPALACE_ALCOVE),
598 DECL(SPACESTATION_SMALLROOM),
599 DECL(SPACESTATION_SHORTPASSAGE),
600 DECL(SPACESTATION_MEDIUMROOM),
601 DECL(SPACESTATION_LARGEROOM),
602 DECL(SPACESTATION_LONGPASSAGE),
603 DECL(SPACESTATION_HALL),
604 DECL(SPACESTATION_CUPBOARD),
605 DECL(SPACESTATION_ALCOVE),
607 DECL(WOODEN_SMALLROOM),
608 DECL(WOODEN_SHORTPASSAGE),
609 DECL(WOODEN_MEDIUMROOM),
610 DECL(WOODEN_LARGEROOM),
611 DECL(WOODEN_LONGPASSAGE),
612 DECL(WOODEN_HALL),
613 DECL(WOODEN_CUPBOARD),
614 DECL(WOODEN_COURTYARD),
615 DECL(WOODEN_ALCOVE),
617 DECL(SPORT_EMPTYSTADIUM),
618 DECL(SPORT_SQUASHCOURT),
619 DECL(SPORT_SMALLSWIMMINGPOOL),
620 DECL(SPORT_LARGESWIMMINGPOOL),
621 DECL(SPORT_GYMNASIUM),
622 DECL(SPORT_FULLSTADIUM),
623 DECL(SPORT_STADIUMTANNOY),
625 DECL(PREFAB_WORKSHOP),
626 DECL(PREFAB_SCHOOLROOM),
627 DECL(PREFAB_PRACTISEROOM),
628 DECL(PREFAB_OUTHOUSE),
629 DECL(PREFAB_CARAVAN),
631 DECL(DOME_TOMB),
632 DECL(PIPE_SMALL),
633 DECL(DOME_SAINTPAULS),
634 DECL(PIPE_LONGTHIN),
635 DECL(PIPE_LARGE),
636 DECL(PIPE_RESONANT),
638 DECL(OUTDOORS_BACKYARD),
639 DECL(OUTDOORS_ROLLINGPLAINS),
640 DECL(OUTDOORS_DEEPCANYON),
641 DECL(OUTDOORS_CREEK),
642 DECL(OUTDOORS_VALLEY),
644 DECL(MOOD_HEAVEN),
645 DECL(MOOD_HELL),
646 DECL(MOOD_MEMORY),
648 DECL(DRIVING_COMMENTATOR),
649 DECL(DRIVING_PITGARAGE),
650 DECL(DRIVING_INCAR_RACER),
651 DECL(DRIVING_INCAR_SPORTS),
652 DECL(DRIVING_INCAR_LUXURY),
653 DECL(DRIVING_FULLGRANDSTAND),
654 DECL(DRIVING_EMPTYGRANDSTAND),
655 DECL(DRIVING_TUNNEL),
657 DECL(CITY_STREETS),
658 DECL(CITY_SUBWAY),
659 DECL(CITY_MUSEUM),
660 DECL(CITY_LIBRARY),
661 DECL(CITY_UNDERPASS),
662 DECL(CITY_ABANDONED),
664 DECL(DUSTYROOM),
665 DECL(CHAPEL),
666 DECL(SMALLWATERROOM),
668 #undef DECL
670 void LoadReverbPreset(const char *name, ALeffect *effect)
672 if(al::strcasecmp(name, "NONE") == 0)
674 InitEffectParams(effect, AL_EFFECT_NULL);
675 TRACE("Loading reverb '%s'\n", "NONE");
676 return;
679 if(!DisabledEffects[EAXREVERB_EFFECT])
680 InitEffectParams(effect, AL_EFFECT_EAXREVERB);
681 else if(!DisabledEffects[REVERB_EFFECT])
682 InitEffectParams(effect, AL_EFFECT_REVERB);
683 else
684 InitEffectParams(effect, AL_EFFECT_NULL);
685 for(const auto &reverbitem : reverblist)
687 const EFXEAXREVERBPROPERTIES *props;
689 if(al::strcasecmp(name, reverbitem.name) != 0)
690 continue;
692 TRACE("Loading reverb '%s'\n", reverbitem.name);
693 props = &reverbitem.props;
694 effect->Props.Reverb.Density = props->flDensity;
695 effect->Props.Reverb.Diffusion = props->flDiffusion;
696 effect->Props.Reverb.Gain = props->flGain;
697 effect->Props.Reverb.GainHF = props->flGainHF;
698 effect->Props.Reverb.GainLF = props->flGainLF;
699 effect->Props.Reverb.DecayTime = props->flDecayTime;
700 effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio;
701 effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio;
702 effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain;
703 effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay;
704 effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
705 effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
706 effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
707 effect->Props.Reverb.LateReverbGain = props->flLateReverbGain;
708 effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay;
709 effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
710 effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
711 effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
712 effect->Props.Reverb.EchoTime = props->flEchoTime;
713 effect->Props.Reverb.EchoDepth = props->flEchoDepth;
714 effect->Props.Reverb.ModulationTime = props->flModulationTime;
715 effect->Props.Reverb.ModulationDepth = props->flModulationDepth;
716 effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
717 effect->Props.Reverb.HFReference = props->flHFReference;
718 effect->Props.Reverb.LFReference = props->flLFReference;
719 effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
720 effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit ? AL_TRUE : AL_FALSE;
721 return;
724 WARN("Reverb preset '%s' not found\n", name);