Add options to reverse local X and Y coordinates
[openal-soft.git] / al / effect.cpp
blob5a74ca534301e4d2abcc7907a70c35e6239e8630
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 "albit.h"
42 #include "alc/context.h"
43 #include "alc/device.h"
44 #include "alc/effects/base.h"
45 #include "alc/inprogext.h"
46 #include "almalloc.h"
47 #include "alnumeric.h"
48 #include "alstring.h"
49 #include "core/except.h"
50 #include "core/logging.h"
51 #include "opthelpers.h"
52 #include "vector.h"
54 #ifdef ALSOFT_EAX
55 #include <cassert>
57 #include "eax_exception.h"
58 #endif // ALSOFT_EAX
60 const EffectList gEffectList[16]{
61 { "eaxreverb", EAXREVERB_EFFECT, AL_EFFECT_EAXREVERB },
62 { "reverb", REVERB_EFFECT, AL_EFFECT_REVERB },
63 { "autowah", AUTOWAH_EFFECT, AL_EFFECT_AUTOWAH },
64 { "chorus", CHORUS_EFFECT, AL_EFFECT_CHORUS },
65 { "compressor", COMPRESSOR_EFFECT, AL_EFFECT_COMPRESSOR },
66 { "distortion", DISTORTION_EFFECT, AL_EFFECT_DISTORTION },
67 { "echo", ECHO_EFFECT, AL_EFFECT_ECHO },
68 { "equalizer", EQUALIZER_EFFECT, AL_EFFECT_EQUALIZER },
69 { "flanger", FLANGER_EFFECT, AL_EFFECT_FLANGER },
70 { "fshifter", FSHIFTER_EFFECT, AL_EFFECT_FREQUENCY_SHIFTER },
71 { "modulator", MODULATOR_EFFECT, AL_EFFECT_RING_MODULATOR },
72 { "pshifter", PSHIFTER_EFFECT, AL_EFFECT_PITCH_SHIFTER },
73 { "vmorpher", VMORPHER_EFFECT, AL_EFFECT_VOCAL_MORPHER },
74 { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
75 { "dedicated", DEDICATED_EFFECT, AL_EFFECT_DEDICATED_DIALOGUE },
76 { "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_REVERB_SOFT },
79 bool DisabledEffects[MAX_EFFECTS];
82 effect_exception::effect_exception(ALenum code, const char *msg, ...) : mErrorCode{code}
84 std::va_list args;
85 va_start(args, msg);
86 setMessage(msg, args);
87 va_end(args);
90 namespace {
92 struct EffectPropsItem {
93 ALenum Type;
94 const EffectProps &DefaultProps;
95 const EffectVtable &Vtable;
97 constexpr EffectPropsItem EffectPropsList[] = {
98 { AL_EFFECT_NULL, NullEffectProps, NullEffectVtable },
99 { AL_EFFECT_EAXREVERB, ReverbEffectProps, ReverbEffectVtable },
100 { AL_EFFECT_REVERB, StdReverbEffectProps, StdReverbEffectVtable },
101 { AL_EFFECT_AUTOWAH, AutowahEffectProps, AutowahEffectVtable },
102 { AL_EFFECT_CHORUS, ChorusEffectProps, ChorusEffectVtable },
103 { AL_EFFECT_COMPRESSOR, CompressorEffectProps, CompressorEffectVtable },
104 { AL_EFFECT_DISTORTION, DistortionEffectProps, DistortionEffectVtable },
105 { AL_EFFECT_ECHO, EchoEffectProps, EchoEffectVtable },
106 { AL_EFFECT_EQUALIZER, EqualizerEffectProps, EqualizerEffectVtable },
107 { AL_EFFECT_FLANGER, FlangerEffectProps, FlangerEffectVtable },
108 { AL_EFFECT_FREQUENCY_SHIFTER, FshifterEffectProps, FshifterEffectVtable },
109 { AL_EFFECT_RING_MODULATOR, ModulatorEffectProps, ModulatorEffectVtable },
110 { AL_EFFECT_PITCH_SHIFTER, PshifterEffectProps, PshifterEffectVtable },
111 { AL_EFFECT_VOCAL_MORPHER, VmorpherEffectProps, VmorpherEffectVtable },
112 { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedEffectProps, DedicatedEffectVtable },
113 { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedEffectProps, DedicatedEffectVtable },
114 { AL_EFFECT_CONVOLUTION_REVERB_SOFT, ConvolutionEffectProps, ConvolutionEffectVtable },
118 void ALeffect_setParami(ALeffect *effect, ALenum param, int value)
119 { effect->vtab->setParami(&effect->Props, param, value); }
120 void ALeffect_setParamiv(ALeffect *effect, ALenum param, const int *values)
121 { effect->vtab->setParamiv(&effect->Props, param, values); }
122 void ALeffect_setParamf(ALeffect *effect, ALenum param, float value)
123 { effect->vtab->setParamf(&effect->Props, param, value); }
124 void ALeffect_setParamfv(ALeffect *effect, ALenum param, const float *values)
125 { effect->vtab->setParamfv(&effect->Props, param, values); }
127 void ALeffect_getParami(const ALeffect *effect, ALenum param, int *value)
128 { effect->vtab->getParami(&effect->Props, param, value); }
129 void ALeffect_getParamiv(const ALeffect *effect, ALenum param, int *values)
130 { effect->vtab->getParamiv(&effect->Props, param, values); }
131 void ALeffect_getParamf(const ALeffect *effect, ALenum param, float *value)
132 { effect->vtab->getParamf(&effect->Props, param, value); }
133 void ALeffect_getParamfv(const ALeffect *effect, ALenum param, float *values)
134 { effect->vtab->getParamfv(&effect->Props, param, values); }
137 const EffectPropsItem *getEffectPropsItemByType(ALenum type)
139 auto iter = std::find_if(std::begin(EffectPropsList), std::end(EffectPropsList),
140 [type](const EffectPropsItem &item) noexcept -> bool
141 { return item.Type == type; });
142 return (iter != std::end(EffectPropsList)) ? std::addressof(*iter) : nullptr;
145 void InitEffectParams(ALeffect *effect, ALenum type)
147 const EffectPropsItem *item{getEffectPropsItemByType(type)};
148 if(item)
150 effect->Props = item->DefaultProps;
151 effect->vtab = &item->Vtable;
153 else
155 effect->Props = EffectProps{};
156 effect->vtab = &NullEffectVtable;
158 effect->type = type;
161 bool EnsureEffects(ALCdevice *device, size_t needed)
163 size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0},
164 [](size_t cur, const EffectSubList &sublist) noexcept -> size_t
165 { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
167 while(needed > count)
169 if UNLIKELY(device->EffectList.size() >= 1<<25)
170 return false;
172 device->EffectList.emplace_back();
173 auto sublist = device->EffectList.end() - 1;
174 sublist->FreeMask = ~0_u64;
175 sublist->Effects = static_cast<ALeffect*>(al_calloc(alignof(ALeffect), sizeof(ALeffect)*64));
176 if UNLIKELY(!sublist->Effects)
178 device->EffectList.pop_back();
179 return false;
181 count += 64;
183 return true;
186 ALeffect *AllocEffect(ALCdevice *device)
188 auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(),
189 [](const EffectSubList &entry) noexcept -> bool
190 { return entry.FreeMask != 0; });
191 auto lidx = static_cast<ALuint>(std::distance(device->EffectList.begin(), sublist));
192 auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
193 ASSUME(slidx < 64);
195 ALeffect *effect{al::construct_at(sublist->Effects + slidx)};
196 InitEffectParams(effect, AL_EFFECT_NULL);
198 /* Add 1 to avoid effect ID 0. */
199 effect->id = ((lidx<<6) | slidx) + 1;
201 sublist->FreeMask &= ~(1_u64 << slidx);
203 return effect;
206 void FreeEffect(ALCdevice *device, ALeffect *effect)
208 const ALuint id{effect->id - 1};
209 const size_t lidx{id >> 6};
210 const ALuint slidx{id & 0x3f};
212 al::destroy_at(effect);
214 device->EffectList[lidx].FreeMask |= 1_u64 << slidx;
217 inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
219 const size_t lidx{(id-1) >> 6};
220 const ALuint slidx{(id-1) & 0x3f};
222 if UNLIKELY(lidx >= device->EffectList.size())
223 return nullptr;
224 EffectSubList &sublist = device->EffectList[lidx];
225 if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
226 return nullptr;
227 return sublist.Effects + slidx;
230 } // namespace
232 AL_API void AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
233 START_API_FUNC
235 ContextRef context{GetContextRef()};
236 if UNLIKELY(!context) return;
238 if UNLIKELY(n < 0)
239 context->setError(AL_INVALID_VALUE, "Generating %d effects", n);
240 if UNLIKELY(n <= 0) return;
242 ALCdevice *device{context->mALDevice.get()};
243 std::lock_guard<std::mutex> _{device->EffectLock};
244 if(!EnsureEffects(device, static_cast<ALuint>(n)))
246 context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effect%s", n, (n==1)?"":"s");
247 return;
250 if LIKELY(n == 1)
252 /* Special handling for the easy and normal case. */
253 ALeffect *effect{AllocEffect(device)};
254 effects[0] = effect->id;
256 else
258 /* Store the allocated buffer IDs in a separate local list, to avoid
259 * modifying the user storage in case of failure.
261 al::vector<ALuint> ids;
262 ids.reserve(static_cast<ALuint>(n));
263 do {
264 ALeffect *effect{AllocEffect(device)};
265 ids.emplace_back(effect->id);
266 } while(--n);
267 std::copy(ids.cbegin(), ids.cend(), effects);
270 END_API_FUNC
272 AL_API void AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
273 START_API_FUNC
275 ContextRef context{GetContextRef()};
276 if UNLIKELY(!context) return;
278 if UNLIKELY(n < 0)
279 context->setError(AL_INVALID_VALUE, "Deleting %d effects", n);
280 if UNLIKELY(n <= 0) return;
282 ALCdevice *device{context->mALDevice.get()};
283 std::lock_guard<std::mutex> _{device->EffectLock};
285 /* First try to find any effects that are invalid. */
286 auto validate_effect = [device](const ALuint eid) -> bool
287 { return !eid || LookupEffect(device, eid) != nullptr; };
289 const ALuint *effects_end = effects + n;
290 auto inveffect = std::find_if_not(effects, effects_end, validate_effect);
291 if UNLIKELY(inveffect != effects_end)
293 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", *inveffect);
294 return;
297 /* All good. Delete non-0 effect IDs. */
298 auto delete_effect = [device](ALuint eid) -> void
300 ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr};
301 if(effect) FreeEffect(device, effect);
303 std::for_each(effects, effects_end, delete_effect);
305 END_API_FUNC
307 AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
308 START_API_FUNC
310 ContextRef context{GetContextRef()};
311 if LIKELY(context)
313 ALCdevice *device{context->mALDevice.get()};
314 std::lock_guard<std::mutex> _{device->EffectLock};
315 if(!effect || LookupEffect(device, effect))
316 return AL_TRUE;
318 return AL_FALSE;
320 END_API_FUNC
322 AL_API void AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
323 START_API_FUNC
325 ContextRef context{GetContextRef()};
326 if UNLIKELY(!context) return;
328 ALCdevice *device{context->mALDevice.get()};
329 std::lock_guard<std::mutex> _{device->EffectLock};
331 ALeffect *aleffect{LookupEffect(device, effect)};
332 if UNLIKELY(!aleffect)
333 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
334 else if(param == AL_EFFECT_TYPE)
336 bool isOk{value == AL_EFFECT_NULL};
337 if(!isOk)
339 for(const EffectList &effectitem : gEffectList)
341 if(value == effectitem.val && !DisabledEffects[effectitem.type])
343 isOk = true;
344 break;
349 if(isOk)
350 InitEffectParams(aleffect, value);
351 else
352 context->setError(AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
354 else try
356 /* Call the appropriate handler */
357 ALeffect_setParami(aleffect, param, value);
359 catch(effect_exception &e) {
360 context->setError(e.errorCode(), "%s", e.what());
363 END_API_FUNC
365 AL_API void AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values)
366 START_API_FUNC
368 switch(param)
370 case AL_EFFECT_TYPE:
371 alEffecti(effect, param, values[0]);
372 return;
375 ContextRef context{GetContextRef()};
376 if UNLIKELY(!context) return;
378 ALCdevice *device{context->mALDevice.get()};
379 std::lock_guard<std::mutex> _{device->EffectLock};
381 ALeffect *aleffect{LookupEffect(device, effect)};
382 if UNLIKELY(!aleffect)
383 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
384 else try
386 /* Call the appropriate handler */
387 ALeffect_setParamiv(aleffect, param, values);
389 catch(effect_exception &e) {
390 context->setError(e.errorCode(), "%s", e.what());
393 END_API_FUNC
395 AL_API void AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
396 START_API_FUNC
398 ContextRef context{GetContextRef()};
399 if UNLIKELY(!context) return;
401 ALCdevice *device{context->mALDevice.get()};
402 std::lock_guard<std::mutex> _{device->EffectLock};
404 ALeffect *aleffect{LookupEffect(device, effect)};
405 if UNLIKELY(!aleffect)
406 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
407 else try
409 /* Call the appropriate handler */
410 ALeffect_setParamf(aleffect, param, value);
412 catch(effect_exception &e) {
413 context->setError(e.errorCode(), "%s", e.what());
416 END_API_FUNC
418 AL_API void AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values)
419 START_API_FUNC
421 ContextRef context{GetContextRef()};
422 if UNLIKELY(!context) return;
424 ALCdevice *device{context->mALDevice.get()};
425 std::lock_guard<std::mutex> _{device->EffectLock};
427 ALeffect *aleffect{LookupEffect(device, effect)};
428 if UNLIKELY(!aleffect)
429 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
430 else try
432 /* Call the appropriate handler */
433 ALeffect_setParamfv(aleffect, param, values);
435 catch(effect_exception &e) {
436 context->setError(e.errorCode(), "%s", e.what());
439 END_API_FUNC
441 AL_API void AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value)
442 START_API_FUNC
444 ContextRef context{GetContextRef()};
445 if UNLIKELY(!context) return;
447 ALCdevice *device{context->mALDevice.get()};
448 std::lock_guard<std::mutex> _{device->EffectLock};
450 const ALeffect *aleffect{LookupEffect(device, effect)};
451 if UNLIKELY(!aleffect)
452 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
453 else if(param == AL_EFFECT_TYPE)
454 *value = aleffect->type;
455 else try
457 /* Call the appropriate handler */
458 ALeffect_getParami(aleffect, param, value);
460 catch(effect_exception &e) {
461 context->setError(e.errorCode(), "%s", e.what());
464 END_API_FUNC
466 AL_API void AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values)
467 START_API_FUNC
469 switch(param)
471 case AL_EFFECT_TYPE:
472 alGetEffecti(effect, param, values);
473 return;
476 ContextRef context{GetContextRef()};
477 if UNLIKELY(!context) return;
479 ALCdevice *device{context->mALDevice.get()};
480 std::lock_guard<std::mutex> _{device->EffectLock};
482 const ALeffect *aleffect{LookupEffect(device, effect)};
483 if UNLIKELY(!aleffect)
484 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
485 else try
487 /* Call the appropriate handler */
488 ALeffect_getParamiv(aleffect, param, values);
490 catch(effect_exception &e) {
491 context->setError(e.errorCode(), "%s", e.what());
494 END_API_FUNC
496 AL_API void AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value)
497 START_API_FUNC
499 ContextRef context{GetContextRef()};
500 if UNLIKELY(!context) return;
502 ALCdevice *device{context->mALDevice.get()};
503 std::lock_guard<std::mutex> _{device->EffectLock};
505 const ALeffect *aleffect{LookupEffect(device, effect)};
506 if UNLIKELY(!aleffect)
507 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
508 else try
510 /* Call the appropriate handler */
511 ALeffect_getParamf(aleffect, param, value);
513 catch(effect_exception &e) {
514 context->setError(e.errorCode(), "%s", e.what());
517 END_API_FUNC
519 AL_API void AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values)
520 START_API_FUNC
522 ContextRef context{GetContextRef()};
523 if UNLIKELY(!context) return;
525 ALCdevice *device{context->mALDevice.get()};
526 std::lock_guard<std::mutex> _{device->EffectLock};
528 const ALeffect *aleffect{LookupEffect(device, effect)};
529 if UNLIKELY(!aleffect)
530 context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
531 else try
533 /* Call the appropriate handler */
534 ALeffect_getParamfv(aleffect, param, values);
536 catch(effect_exception &e) {
537 context->setError(e.errorCode(), "%s", e.what());
540 END_API_FUNC
543 void InitEffect(ALeffect *effect)
545 InitEffectParams(effect, AL_EFFECT_NULL);
548 EffectSubList::~EffectSubList()
550 uint64_t usemask{~FreeMask};
551 while(usemask)
553 const int idx{al::countr_zero(usemask)};
554 al::destroy_at(Effects+idx);
555 usemask &= ~(1_u64 << idx);
557 FreeMask = ~usemask;
558 al_free(Effects);
559 Effects = nullptr;
563 #define DECL(x) { #x, EFX_REVERB_PRESET_##x }
564 static const struct {
565 const char name[32];
566 EFXEAXREVERBPROPERTIES props;
567 } reverblist[] = {
568 DECL(GENERIC),
569 DECL(PADDEDCELL),
570 DECL(ROOM),
571 DECL(BATHROOM),
572 DECL(LIVINGROOM),
573 DECL(STONEROOM),
574 DECL(AUDITORIUM),
575 DECL(CONCERTHALL),
576 DECL(CAVE),
577 DECL(ARENA),
578 DECL(HANGAR),
579 DECL(CARPETEDHALLWAY),
580 DECL(HALLWAY),
581 DECL(STONECORRIDOR),
582 DECL(ALLEY),
583 DECL(FOREST),
584 DECL(CITY),
585 DECL(MOUNTAINS),
586 DECL(QUARRY),
587 DECL(PLAIN),
588 DECL(PARKINGLOT),
589 DECL(SEWERPIPE),
590 DECL(UNDERWATER),
591 DECL(DRUGGED),
592 DECL(DIZZY),
593 DECL(PSYCHOTIC),
595 DECL(CASTLE_SMALLROOM),
596 DECL(CASTLE_SHORTPASSAGE),
597 DECL(CASTLE_MEDIUMROOM),
598 DECL(CASTLE_LARGEROOM),
599 DECL(CASTLE_LONGPASSAGE),
600 DECL(CASTLE_HALL),
601 DECL(CASTLE_CUPBOARD),
602 DECL(CASTLE_COURTYARD),
603 DECL(CASTLE_ALCOVE),
605 DECL(FACTORY_SMALLROOM),
606 DECL(FACTORY_SHORTPASSAGE),
607 DECL(FACTORY_MEDIUMROOM),
608 DECL(FACTORY_LARGEROOM),
609 DECL(FACTORY_LONGPASSAGE),
610 DECL(FACTORY_HALL),
611 DECL(FACTORY_CUPBOARD),
612 DECL(FACTORY_COURTYARD),
613 DECL(FACTORY_ALCOVE),
615 DECL(ICEPALACE_SMALLROOM),
616 DECL(ICEPALACE_SHORTPASSAGE),
617 DECL(ICEPALACE_MEDIUMROOM),
618 DECL(ICEPALACE_LARGEROOM),
619 DECL(ICEPALACE_LONGPASSAGE),
620 DECL(ICEPALACE_HALL),
621 DECL(ICEPALACE_CUPBOARD),
622 DECL(ICEPALACE_COURTYARD),
623 DECL(ICEPALACE_ALCOVE),
625 DECL(SPACESTATION_SMALLROOM),
626 DECL(SPACESTATION_SHORTPASSAGE),
627 DECL(SPACESTATION_MEDIUMROOM),
628 DECL(SPACESTATION_LARGEROOM),
629 DECL(SPACESTATION_LONGPASSAGE),
630 DECL(SPACESTATION_HALL),
631 DECL(SPACESTATION_CUPBOARD),
632 DECL(SPACESTATION_ALCOVE),
634 DECL(WOODEN_SMALLROOM),
635 DECL(WOODEN_SHORTPASSAGE),
636 DECL(WOODEN_MEDIUMROOM),
637 DECL(WOODEN_LARGEROOM),
638 DECL(WOODEN_LONGPASSAGE),
639 DECL(WOODEN_HALL),
640 DECL(WOODEN_CUPBOARD),
641 DECL(WOODEN_COURTYARD),
642 DECL(WOODEN_ALCOVE),
644 DECL(SPORT_EMPTYSTADIUM),
645 DECL(SPORT_SQUASHCOURT),
646 DECL(SPORT_SMALLSWIMMINGPOOL),
647 DECL(SPORT_LARGESWIMMINGPOOL),
648 DECL(SPORT_GYMNASIUM),
649 DECL(SPORT_FULLSTADIUM),
650 DECL(SPORT_STADIUMTANNOY),
652 DECL(PREFAB_WORKSHOP),
653 DECL(PREFAB_SCHOOLROOM),
654 DECL(PREFAB_PRACTISEROOM),
655 DECL(PREFAB_OUTHOUSE),
656 DECL(PREFAB_CARAVAN),
658 DECL(DOME_TOMB),
659 DECL(PIPE_SMALL),
660 DECL(DOME_SAINTPAULS),
661 DECL(PIPE_LONGTHIN),
662 DECL(PIPE_LARGE),
663 DECL(PIPE_RESONANT),
665 DECL(OUTDOORS_BACKYARD),
666 DECL(OUTDOORS_ROLLINGPLAINS),
667 DECL(OUTDOORS_DEEPCANYON),
668 DECL(OUTDOORS_CREEK),
669 DECL(OUTDOORS_VALLEY),
671 DECL(MOOD_HEAVEN),
672 DECL(MOOD_HELL),
673 DECL(MOOD_MEMORY),
675 DECL(DRIVING_COMMENTATOR),
676 DECL(DRIVING_PITGARAGE),
677 DECL(DRIVING_INCAR_RACER),
678 DECL(DRIVING_INCAR_SPORTS),
679 DECL(DRIVING_INCAR_LUXURY),
680 DECL(DRIVING_FULLGRANDSTAND),
681 DECL(DRIVING_EMPTYGRANDSTAND),
682 DECL(DRIVING_TUNNEL),
684 DECL(CITY_STREETS),
685 DECL(CITY_SUBWAY),
686 DECL(CITY_MUSEUM),
687 DECL(CITY_LIBRARY),
688 DECL(CITY_UNDERPASS),
689 DECL(CITY_ABANDONED),
691 DECL(DUSTYROOM),
692 DECL(CHAPEL),
693 DECL(SMALLWATERROOM),
695 #undef DECL
697 void LoadReverbPreset(const char *name, ALeffect *effect)
699 if(al::strcasecmp(name, "NONE") == 0)
701 InitEffectParams(effect, AL_EFFECT_NULL);
702 TRACE("Loading reverb '%s'\n", "NONE");
703 return;
706 if(!DisabledEffects[EAXREVERB_EFFECT])
707 InitEffectParams(effect, AL_EFFECT_EAXREVERB);
708 else if(!DisabledEffects[REVERB_EFFECT])
709 InitEffectParams(effect, AL_EFFECT_REVERB);
710 else
711 InitEffectParams(effect, AL_EFFECT_NULL);
712 for(const auto &reverbitem : reverblist)
714 const EFXEAXREVERBPROPERTIES *props;
716 if(al::strcasecmp(name, reverbitem.name) != 0)
717 continue;
719 TRACE("Loading reverb '%s'\n", reverbitem.name);
720 props = &reverbitem.props;
721 effect->Props.Reverb.Density = props->flDensity;
722 effect->Props.Reverb.Diffusion = props->flDiffusion;
723 effect->Props.Reverb.Gain = props->flGain;
724 effect->Props.Reverb.GainHF = props->flGainHF;
725 effect->Props.Reverb.GainLF = props->flGainLF;
726 effect->Props.Reverb.DecayTime = props->flDecayTime;
727 effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio;
728 effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio;
729 effect->Props.Reverb.ReflectionsGain = props->flReflectionsGain;
730 effect->Props.Reverb.ReflectionsDelay = props->flReflectionsDelay;
731 effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
732 effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
733 effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
734 effect->Props.Reverb.LateReverbGain = props->flLateReverbGain;
735 effect->Props.Reverb.LateReverbDelay = props->flLateReverbDelay;
736 effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
737 effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
738 effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
739 effect->Props.Reverb.EchoTime = props->flEchoTime;
740 effect->Props.Reverb.EchoDepth = props->flEchoDepth;
741 effect->Props.Reverb.ModulationTime = props->flModulationTime;
742 effect->Props.Reverb.ModulationDepth = props->flModulationDepth;
743 effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
744 effect->Props.Reverb.HFReference = props->flHFReference;
745 effect->Props.Reverb.LFReference = props->flLFReference;
746 effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
747 effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit ? AL_TRUE : AL_FALSE;
748 return;
751 WARN("Reverb preset '%s' not found\n", name);
754 bool IsValidEffectType(ALenum type) noexcept
756 if(type == AL_EFFECT_NULL)
757 return true;
759 for(const auto &effect_item : gEffectList)
761 if(type == effect_item.val && !DisabledEffects[effect_item.type])
762 return true;
764 return false;