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.
8  *
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.
13  *
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
19  */
20 
21 #include "config.h"
22 
23 #include "effect.h"
24 
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>
34 
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"
40 
41 #include "albit.h"
42 #include "alcmain.h"
43 #include "alcontext.h"
44 #include "almalloc.h"
45 #include "alnumeric.h"
46 #include "alstring.h"
47 #include "core/except.h"
48 #include "core/logging.h"
49 #include "effects/base.h"
50 #include "opthelpers.h"
51 #include "vector.h"
52 
53 
54 const EffectList gEffectList[16]{
55     { "eaxreverb",   EAXREVERB_EFFECT,   AL_EFFECT_EAXREVERB },
56     { "reverb",      REVERB_EFFECT,      AL_EFFECT_REVERB },
57     { "autowah",     AUTOWAH_EFFECT,     AL_EFFECT_AUTOWAH },
58     { "chorus",      CHORUS_EFFECT,      AL_EFFECT_CHORUS },
59     { "compressor",  COMPRESSOR_EFFECT,  AL_EFFECT_COMPRESSOR },
60     { "distortion",  DISTORTION_EFFECT,  AL_EFFECT_DISTORTION },
61     { "echo",        ECHO_EFFECT,        AL_EFFECT_ECHO },
62     { "equalizer",   EQUALIZER_EFFECT,   AL_EFFECT_EQUALIZER },
63     { "flanger",     FLANGER_EFFECT,     AL_EFFECT_FLANGER },
64     { "fshifter",    FSHIFTER_EFFECT,    AL_EFFECT_FREQUENCY_SHIFTER },
65     { "modulator",   MODULATOR_EFFECT,   AL_EFFECT_RING_MODULATOR },
66     { "pshifter",    PSHIFTER_EFFECT,    AL_EFFECT_PITCH_SHIFTER },
67     { "vmorpher",    VMORPHER_EFFECT,    AL_EFFECT_VOCAL_MORPHER },
68     { "dedicated",   DEDICATED_EFFECT,   AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT },
69     { "dedicated",   DEDICATED_EFFECT,   AL_EFFECT_DEDICATED_DIALOGUE },
70     { "convolution", CONVOLUTION_EFFECT, AL_EFFECT_CONVOLUTION_REVERB_SOFT },
71 };
72 
73 bool DisabledEffects[MAX_EFFECTS];
74 
75 
76 effect_exception::effect_exception(ALenum code, const char *msg, ...) : mErrorCode{code}
77 {
78     std::va_list args;
79     va_start(args, msg);
80     setMessage(msg, args);
81     va_end(args);
82 }
83 
84 namespace {
85 
86 struct EffectPropsItem {
87     ALenum Type;
88     const EffectProps &DefaultProps;
89     const EffectVtable &Vtable;
90 };
91 constexpr EffectPropsItem EffectPropsList[] = {
92     { AL_EFFECT_NULL, NullEffectProps, NullEffectVtable },
93     { AL_EFFECT_EAXREVERB, ReverbEffectProps, ReverbEffectVtable },
94     { AL_EFFECT_REVERB, StdReverbEffectProps, StdReverbEffectVtable },
95     { AL_EFFECT_AUTOWAH, AutowahEffectProps, AutowahEffectVtable },
96     { AL_EFFECT_CHORUS, ChorusEffectProps, ChorusEffectVtable },
97     { AL_EFFECT_COMPRESSOR, CompressorEffectProps, CompressorEffectVtable },
98     { AL_EFFECT_DISTORTION, DistortionEffectProps, DistortionEffectVtable },
99     { AL_EFFECT_ECHO, EchoEffectProps, EchoEffectVtable },
100     { AL_EFFECT_EQUALIZER, EqualizerEffectProps, EqualizerEffectVtable },
101     { AL_EFFECT_FLANGER, FlangerEffectProps, FlangerEffectVtable },
102     { AL_EFFECT_FREQUENCY_SHIFTER, FshifterEffectProps, FshifterEffectVtable },
103     { AL_EFFECT_RING_MODULATOR, ModulatorEffectProps, ModulatorEffectVtable },
104     { AL_EFFECT_PITCH_SHIFTER, PshifterEffectProps, PshifterEffectVtable },
DecodeIMA4Block(int16_t * dst,const al::byte * src,size_t numchans,size_t align)105     { AL_EFFECT_VOCAL_MORPHER, VmorpherEffectProps, VmorpherEffectVtable },
106     { AL_EFFECT_DEDICATED_DIALOGUE, DedicatedEffectProps, DedicatedEffectVtable },
107     { AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT, DedicatedEffectProps, DedicatedEffectVtable },
108     { AL_EFFECT_CONVOLUTION_REVERB_SOFT, ConvolutionEffectProps, ConvolutionEffectVtable },
109 };
110 
111 
112 void ALeffect_setParami(ALeffect *effect, ALenum param, int value)
113 { effect->vtab->setParami(&effect->Props, param, value); }
114 void ALeffect_setParamiv(ALeffect *effect, ALenum param, const int *values)
115 { effect->vtab->setParamiv(&effect->Props, param, values); }
116 void ALeffect_setParamf(ALeffect *effect, ALenum param, float value)
117 { effect->vtab->setParamf(&effect->Props, param, value); }
118 void ALeffect_setParamfv(ALeffect *effect, ALenum param, const float *values)
119 { effect->vtab->setParamfv(&effect->Props, param, values); }
120 
121 void ALeffect_getParami(const ALeffect *effect, ALenum param, int *value)
122 { effect->vtab->getParami(&effect->Props, param, value); }
123 void ALeffect_getParamiv(const ALeffect *effect, ALenum param, int *values)
124 { effect->vtab->getParamiv(&effect->Props, param, values); }
125 void ALeffect_getParamf(const ALeffect *effect, ALenum param, float *value)
126 { effect->vtab->getParamf(&effect->Props, param, value); }
127 void ALeffect_getParamfv(const ALeffect *effect, ALenum param, float *values)
128 { effect->vtab->getParamfv(&effect->Props, param, values); }
129 
130 
131 const EffectPropsItem *getEffectPropsItemByType(ALenum type)
132 {
133     auto iter = std::find_if(std::begin(EffectPropsList), std::end(EffectPropsList),
134         [type](const EffectPropsItem &item) noexcept -> bool
135         { return item.Type == type; });
136     return (iter != std::end(EffectPropsList)) ? std::addressof(*iter) : nullptr;
137 }
138 
139 void InitEffectParams(ALeffect *effect, ALenum type)
140 {
141     const EffectPropsItem *item{getEffectPropsItemByType(type)};
142     if(item)
143     {
144         effect->Props = item->DefaultProps;
145         effect->vtab = &item->Vtable;
146     }
147     else
148     {
149         effect->Props = EffectProps{};
150         effect->vtab = &NullEffectVtable;
DecodeMSADPCMBlock(int16_t * dst,const al::byte * src,size_t numchans,size_t align)151     }
152     effect->type = type;
153 }
154 
155 bool EnsureEffects(ALCdevice *device, size_t needed)
156 {
157     size_t count{std::accumulate(device->EffectList.cbegin(), device->EffectList.cend(), size_t{0},
158         [](size_t cur, const EffectSubList &sublist) noexcept -> size_t
159         { return cur + static_cast<ALuint>(al::popcount(sublist.FreeMask)); })};
160 
161     while(needed > count)
162     {
163         if UNLIKELY(device->EffectList.size() >= 1<<25)
164             return false;
165 
166         device->EffectList.emplace_back();
167         auto sublist = device->EffectList.end() - 1;
168         sublist->FreeMask = ~0_u64;
169         sublist->Effects = static_cast<ALeffect*>(al_calloc(alignof(ALeffect), sizeof(ALeffect)*64));
170         if UNLIKELY(!sublist->Effects)
171         {
172             device->EffectList.pop_back();
173             return false;
174         }
175         count += 64;
176     }
177     return true;
178 }
179 
180 ALeffect *AllocEffect(ALCdevice *device)
181 {
182     auto sublist = std::find_if(device->EffectList.begin(), device->EffectList.end(),
183         [](const EffectSubList &entry) noexcept -> bool
184         { return entry.FreeMask != 0; }
185     );
186     auto lidx = static_cast<ALuint>(std::distance(device->EffectList.begin(), sublist));
187     auto slidx = static_cast<ALuint>(al::countr_zero(sublist->FreeMask));
188 
189     ALeffect *effect{::new (sublist->Effects + slidx) ALeffect{}};
190     InitEffectParams(effect, AL_EFFECT_NULL);
191 
192     /* Add 1 to avoid effect ID 0. */
193     effect->id = ((lidx<<6) | slidx) + 1;
194 
195     sublist->FreeMask &= ~(1_u64 << slidx);
196 
197     return effect;
198 }
199 
200 void FreeEffect(ALCdevice *device, ALeffect *effect)
201 {
202     const ALuint id{effect->id - 1};
203     const size_t lidx{id >> 6};
204     const ALuint slidx{id & 0x3f};
205 
206     al::destroy_at(effect);
207 
208     device->EffectList[lidx].FreeMask |= 1_u64 << slidx;
209 }
210 
211 inline ALeffect *LookupEffect(ALCdevice *device, ALuint id)
212 {
213     const size_t lidx{(id-1) >> 6};
214     const ALuint slidx{(id-1) & 0x3f};
Convert_int16_ima4(int16_t * dst,const al::byte * src,size_t numchans,size_t len,size_t align)215 
216     if UNLIKELY(lidx >= device->EffectList.size())
217         return nullptr;
218     EffectSubList &sublist = device->EffectList[lidx];
219     if UNLIKELY(sublist.FreeMask & (1_u64 << slidx))
220         return nullptr;
221     return sublist.Effects + slidx;
222 }
223 
224 } // namespace
225 
226 AL_API void AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
227 START_API_FUNC
228 {
229     ContextRef context{GetContextRef()};
Convert_int16_msadpcm(int16_t * dst,const al::byte * src,size_t numchans,size_t len,size_t align)230     if UNLIKELY(!context) return;
231 
232     if UNLIKELY(n < 0)
233         context->setError(AL_INVALID_VALUE, "Generating %d effects", n);
234     if UNLIKELY(n <= 0) return;
235 
236     ALCdevice *device{context->mDevice.get()};
237     std::lock_guard<std::mutex> _{device->EffectLock};
238     if(!EnsureEffects(device, static_cast<ALuint>(n)))
239     {
240         context->setError(AL_OUT_OF_MEMORY, "Failed to allocate %d effect%s", n, (n==1)?"":"s");
241         return;
242     }
243 
244     if LIKELY(n == 1)
245     {
BytesFromUserFmt(UserFmtType type)246         /* Special handling for the easy and normal case. */
247         ALeffect *effect{AllocEffect(device)};
248         effects[0] = effect->id;
249     }
250     else
251     {
252         /* Store the allocated buffer IDs in a separate local list, to avoid
253          * modifying the user storage in case of failure.
254          */
255         al::vector<ALuint> ids;
256         ids.reserve(static_cast<ALuint>(n));
257         do {
258             ALeffect *effect{AllocEffect(device)};
259             ids.emplace_back(effect->id);
260         } while(--n);
ChannelsFromUserFmt(UserFmtChannels chans,ALuint ambiorder)261         std::copy(ids.cbegin(), ids.cend(), effects);
262     }
263 }
264 END_API_FUNC
265 
266 AL_API void AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects)
267 START_API_FUNC
268 {
269     ContextRef context{GetContextRef()};
270     if UNLIKELY(!context) return;
271 
272     if UNLIKELY(n < 0)
273         context->setError(AL_INVALID_VALUE, "Deleting %d effects", n);
274     if UNLIKELY(n <= 0) return;
275 
276     ALCdevice *device{context->mDevice.get()};
277     std::lock_guard<std::mutex> _{device->EffectLock};
AmbiLayoutFromEnum(ALenum layout)278 
279     /* First try to find any effects that are invalid. */
280     auto validate_effect = [device](const ALuint eid) -> bool
281     { return !eid || LookupEffect(device, eid) != nullptr; };
282 
283     const ALuint *effects_end = effects + n;
284     auto inveffect = std::find_if_not(effects, effects_end, validate_effect);
285     if UNLIKELY(inveffect != effects_end)
286     {
EnumFromAmbiLayout(AmbiLayout layout)287         context->setError(AL_INVALID_NAME, "Invalid effect ID %u", *inveffect);
288         return;
289     }
290 
291     /* All good. Delete non-0 effect IDs. */
292     auto delete_effect = [device](ALuint eid) -> void
293     {
294         ALeffect *effect{eid ? LookupEffect(device, eid) : nullptr};
295         if(effect) FreeEffect(device, effect);
296     };
AmbiScalingFromEnum(ALenum scale)297     std::for_each(effects, effects_end, delete_effect);
298 }
299 END_API_FUNC
300 
301 AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
302 START_API_FUNC
303 {
304     ContextRef context{GetContextRef()};
305     if LIKELY(context)
306     {
EnumFromAmbiScaling(AmbiScaling scale)307         ALCdevice *device{context->mDevice.get()};
308         std::lock_guard<std::mutex> _{device->EffectLock};
309         if(!effect || LookupEffect(device, effect))
310             return AL_TRUE;
311     }
312     return AL_FALSE;
313 }
314 END_API_FUNC
315 
316 AL_API void AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint value)
317 START_API_FUNC
318 {
319     ContextRef context{GetContextRef()};
320     if UNLIKELY(!context) return;
321 
322     ALCdevice *device{context->mDevice.get()};
323     std::lock_guard<std::mutex> _{device->EffectLock};
324 
325     ALeffect *aleffect{LookupEffect(device, effect)};
EnsureBuffers(ALCdevice * device,size_t needed)326     if UNLIKELY(!aleffect)
327         context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
328     else if(param == AL_EFFECT_TYPE)
329     {
__anondb0abece0202() 330         bool isOk{value == AL_EFFECT_NULL};
331         if(!isOk)
332         {
333             for(const EffectList &effectitem : gEffectList)
334             {
335                 if(value == effectitem.val && !DisabledEffects[effectitem.type])
336                 {
337                     isOk = true;
338                     break;
339                 }
340             }
341         }
342 
343         if(isOk)
344             InitEffectParams(aleffect, value);
345         else
346             context->setError(AL_INVALID_VALUE, "Effect type 0x%04x not supported", value);
347     }
348     else try
349     {
350         /* Call the appropriate handler */
AllocBuffer(ALCdevice * device)351         ALeffect_setParami(aleffect, param, value);
352     }
353     catch(effect_exception &e) {
354         context->setError(e.errorCode(), "%s", e.what());
__anondb0abece0302(const BufferSubList &entry) 355     }
356 }
357 END_API_FUNC
358 
359 AL_API void AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *values)
360 START_API_FUNC
361 {
362     switch(param)
363     {
364     case AL_EFFECT_TYPE:
365         alEffecti(effect, param, values[0]);
366         return;
367     }
368 
369     ContextRef context{GetContextRef()};
370     if UNLIKELY(!context) return;
371 
372     ALCdevice *device{context->mDevice.get()};
373     std::lock_guard<std::mutex> _{device->EffectLock};
374 
375     ALeffect *aleffect{LookupEffect(device, effect)};
376     if UNLIKELY(!aleffect)
377         context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
378     else try
379     {
380         /* Call the appropriate handler */
381         ALeffect_setParamiv(aleffect, param, values);
382     }
383     catch(effect_exception &e) {
384         context->setError(e.errorCode(), "%s", e.what());
385     }
386 }
387 END_API_FUNC
388 
389 AL_API void AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat value)
390 START_API_FUNC
391 {
392     ContextRef context{GetContextRef()};
393     if UNLIKELY(!context) return;
394 
395     ALCdevice *device{context->mDevice.get()};
SanitizeAlignment(UserFmtType type,ALuint align)396     std::lock_guard<std::mutex> _{device->EffectLock};
397 
398     ALeffect *aleffect{LookupEffect(device, effect)};
399     if UNLIKELY(!aleffect)
400         context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
401     else try
402     {
403         /* Call the appropriate handler */
404         ALeffect_setParamf(aleffect, param, value);
405     }
406     catch(effect_exception &e) {
407         context->setError(e.errorCode(), "%s", e.what());
408     }
409 }
410 END_API_FUNC
411 
412 AL_API void AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *values)
413 START_API_FUNC
414 {
415     ContextRef context{GetContextRef()};
416     if UNLIKELY(!context) return;
417 
418     ALCdevice *device{context->mDevice.get()};
419     std::lock_guard<std::mutex> _{device->EffectLock};
420 
421     ALeffect *aleffect{LookupEffect(device, effect)};
422     if UNLIKELY(!aleffect)
423         context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
424     else try
425     {
426         /* Call the appropriate handler */
427         ALeffect_setParamfv(aleffect, param, values);
428     }
429     catch(effect_exception &e) {
NameFromUserFmtType(UserFmtType type)430         context->setError(e.errorCode(), "%s", e.what());
431     }
432 }
433 END_API_FUNC
434 
435 AL_API void AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *value)
436 START_API_FUNC
437 {
438     ContextRef context{GetContextRef()};
439     if UNLIKELY(!context) return;
440 
441     ALCdevice *device{context->mDevice.get()};
442     std::lock_guard<std::mutex> _{device->EffectLock};
443 
444     const ALeffect *aleffect{LookupEffect(device, effect)};
445     if UNLIKELY(!aleffect)
446         context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
LoadData(ALCcontext * context,ALbuffer * ALBuf,ALsizei freq,ALuint size,UserFmtChannels SrcChannels,UserFmtType SrcType,const al::byte * SrcData,ALbitfieldSOFT access)447     else if(param == AL_EFFECT_TYPE)
448         *value = aleffect->type;
449     else try
450     {
451         /* Call the appropriate handler */
452         ALeffect_getParami(aleffect, param, value);
453     }
454     catch(effect_exception &e) {
455         context->setError(e.errorCode(), "%s", e.what());
456     }
457 }
458 END_API_FUNC
459 
460 AL_API void AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *values)
461 START_API_FUNC
462 {
463     switch(param)
464     {
465     case AL_EFFECT_TYPE:
466         alGetEffecti(effect, param, values);
467         return;
468     }
469 
470     ContextRef context{GetContextRef()};
471     if UNLIKELY(!context) return;
472 
473     ALCdevice *device{context->mDevice.get()};
474     std::lock_guard<std::mutex> _{device->EffectLock};
475 
476     const ALeffect *aleffect{LookupEffect(device, effect)};
477     if UNLIKELY(!aleffect)
478         context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
479     else try
480     {
481         /* Call the appropriate handler */
482         ALeffect_getParamiv(aleffect, param, values);
483     }
484     catch(effect_exception &e) {
485         context->setError(e.errorCode(), "%s", e.what());
486     }
487 }
488 END_API_FUNC
489 
490 AL_API void AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *value)
491 START_API_FUNC
492 {
493     ContextRef context{GetContextRef()};
494     if UNLIKELY(!context) return;
495 
496     ALCdevice *device{context->mDevice.get()};
497     std::lock_guard<std::mutex> _{device->EffectLock};
498 
499     const ALeffect *aleffect{LookupEffect(device, effect)};
500     if UNLIKELY(!aleffect)
501         context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
502     else try
503     {
504         /* Call the appropriate handler */
505         ALeffect_getParamf(aleffect, param, value);
506     }
507     catch(effect_exception &e) {
508         context->setError(e.errorCode(), "%s", e.what());
509     }
510 }
511 END_API_FUNC
512 
513 AL_API void AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *values)
514 START_API_FUNC
515 {
516     ContextRef context{GetContextRef()};
517     if UNLIKELY(!context) return;
518 
519     ALCdevice *device{context->mDevice.get()};
520     std::lock_guard<std::mutex> _{device->EffectLock};
521 
522     const ALeffect *aleffect{LookupEffect(device, effect)};
523     if UNLIKELY(!aleffect)
524         context->setError(AL_INVALID_NAME, "Invalid effect ID %u", effect);
525     else try
526     {
527         /* Call the appropriate handler */
528         ALeffect_getParamfv(aleffect, param, values);
529     }
530     catch(effect_exception &e) {
531         context->setError(e.errorCode(), "%s", e.what());
532     }
533 }
534 END_API_FUNC
535 
536 
537 void InitEffect(ALeffect *effect)
538 {
539     InitEffectParams(effect, AL_EFFECT_NULL);
540 }
541 
542 EffectSubList::~EffectSubList()
543 {
544     uint64_t usemask{~FreeMask};
545     while(usemask)
546     {
547         const int idx{al::countr_zero(usemask)};
548         al::destroy_at(Effects+idx);
549         usemask &= ~(1_u64 << idx);
550     }
551     FreeMask = ~usemask;
552     al_free(Effects);
553     Effects = nullptr;
554 }
555 
556 
557 #define DECL(x) { #x, EFX_REVERB_PRESET_##x }
558 static const struct {
559     const char name[32];
560     EFXEAXREVERBPROPERTIES props;
561 } reverblist[] = {
562     DECL(GENERIC),
563     DECL(PADDEDCELL),
564     DECL(ROOM),
565     DECL(BATHROOM),
566     DECL(LIVINGROOM),
567     DECL(STONEROOM),
568     DECL(AUDITORIUM),
569     DECL(CONCERTHALL),
570     DECL(CAVE),
571     DECL(ARENA),
572     DECL(HANGAR),
573     DECL(CARPETEDHALLWAY),
574     DECL(HALLWAY),
575     DECL(STONECORRIDOR),
576     DECL(ALLEY),
577     DECL(FOREST),
578     DECL(CITY),
579     DECL(MOUNTAINS),
580     DECL(QUARRY),
581     DECL(PLAIN),
582     DECL(PARKINGLOT),
583     DECL(SEWERPIPE),
584     DECL(UNDERWATER),
585     DECL(DRUGGED),
586     DECL(DIZZY),
587     DECL(PSYCHOTIC),
588 
589     DECL(CASTLE_SMALLROOM),
590     DECL(CASTLE_SHORTPASSAGE),
591     DECL(CASTLE_MEDIUMROOM),
592     DECL(CASTLE_LARGEROOM),
593     DECL(CASTLE_LONGPASSAGE),
594     DECL(CASTLE_HALL),
595     DECL(CASTLE_CUPBOARD),
596     DECL(CASTLE_COURTYARD),
597     DECL(CASTLE_ALCOVE),
598 
599     DECL(FACTORY_SMALLROOM),
600     DECL(FACTORY_SHORTPASSAGE),
601     DECL(FACTORY_MEDIUMROOM),
602     DECL(FACTORY_LARGEROOM),
603     DECL(FACTORY_LONGPASSAGE),
PrepareCallback(ALCcontext * context,ALbuffer * ALBuf,ALsizei freq,UserFmtChannels SrcChannels,UserFmtType SrcType,LPALBUFFERCALLBACKTYPESOFT callback,void * userptr)604     DECL(FACTORY_HALL),
605     DECL(FACTORY_CUPBOARD),
606     DECL(FACTORY_COURTYARD),
607     DECL(FACTORY_ALCOVE),
608 
609     DECL(ICEPALACE_SMALLROOM),
610     DECL(ICEPALACE_SHORTPASSAGE),
611     DECL(ICEPALACE_MEDIUMROOM),
612     DECL(ICEPALACE_LARGEROOM),
613     DECL(ICEPALACE_LONGPASSAGE),
614     DECL(ICEPALACE_HALL),
615     DECL(ICEPALACE_CUPBOARD),
616     DECL(ICEPALACE_COURTYARD),
617     DECL(ICEPALACE_ALCOVE),
618 
619     DECL(SPACESTATION_SMALLROOM),
620     DECL(SPACESTATION_SHORTPASSAGE),
621     DECL(SPACESTATION_MEDIUMROOM),
622     DECL(SPACESTATION_LARGEROOM),
623     DECL(SPACESTATION_LONGPASSAGE),
624     DECL(SPACESTATION_HALL),
625     DECL(SPACESTATION_CUPBOARD),
626     DECL(SPACESTATION_ALCOVE),
627 
628     DECL(WOODEN_SMALLROOM),
629     DECL(WOODEN_SHORTPASSAGE),
630     DECL(WOODEN_MEDIUMROOM),
631     DECL(WOODEN_LARGEROOM),
632     DECL(WOODEN_LONGPASSAGE),
633     DECL(WOODEN_HALL),
634     DECL(WOODEN_CUPBOARD),
635     DECL(WOODEN_COURTYARD),
636     DECL(WOODEN_ALCOVE),
637 
638     DECL(SPORT_EMPTYSTADIUM),
639     DECL(SPORT_SQUASHCOURT),
640     DECL(SPORT_SMALLSWIMMINGPOOL),
641     DECL(SPORT_LARGESWIMMINGPOOL),
642     DECL(SPORT_GYMNASIUM),
643     DECL(SPORT_FULLSTADIUM),
644     DECL(SPORT_STADIUMTANNOY),
645 
646     DECL(PREFAB_WORKSHOP),
647     DECL(PREFAB_SCHOOLROOM),
648     DECL(PREFAB_PRACTISEROOM),
649     DECL(PREFAB_OUTHOUSE),
650     DECL(PREFAB_CARAVAN),
651 
652     DECL(DOME_TOMB),
653     DECL(PIPE_SMALL),
654     DECL(DOME_SAINTPAULS),
655     DECL(PIPE_LONGTHIN),
656     DECL(PIPE_LARGE),
657     DECL(PIPE_RESONANT),
658 
659     DECL(OUTDOORS_BACKYARD),
660     DECL(OUTDOORS_ROLLINGPLAINS),
661     DECL(OUTDOORS_DEEPCANYON),
662     DECL(OUTDOORS_CREEK),
663     DECL(OUTDOORS_VALLEY),
664 
665     DECL(MOOD_HEAVEN),
666     DECL(MOOD_HELL),
667     DECL(MOOD_MEMORY),
668 
669     DECL(DRIVING_COMMENTATOR),
670     DECL(DRIVING_PITGARAGE),
671     DECL(DRIVING_INCAR_RACER),
672     DECL(DRIVING_INCAR_SPORTS),
673     DECL(DRIVING_INCAR_LUXURY),
674     DECL(DRIVING_FULLGRANDSTAND),
675     DECL(DRIVING_EMPTYGRANDSTAND),
676     DECL(DRIVING_TUNNEL),
677 
678     DECL(CITY_STREETS),
679     DECL(CITY_SUBWAY),
680     DECL(CITY_MUSEUM),
681     DECL(CITY_LIBRARY),
682     DECL(CITY_UNDERPASS),
683     DECL(CITY_ABANDONED),
684 
685     DECL(DUSTYROOM),
686     DECL(CHAPEL),
687     DECL(SMALLWATERROOM),
688 };
689 #undef DECL
690 
691 void LoadReverbPreset(const char *name, ALeffect *effect)
692 {
693     if(al::strcasecmp(name, "NONE") == 0)
694     {
695         InitEffectParams(effect, AL_EFFECT_NULL);
696         TRACE("Loading reverb '%s'\n", "NONE");
697         return;
698     }
699 
700     if(!DisabledEffects[EAXREVERB_EFFECT])
701         InitEffectParams(effect, AL_EFFECT_EAXREVERB);
702     else if(!DisabledEffects[REVERB_EFFECT])
703         InitEffectParams(effect, AL_EFFECT_REVERB);
704     else
705         InitEffectParams(effect, AL_EFFECT_NULL);
706     for(const auto &reverbitem : reverblist)
707     {
708         const EFXEAXREVERBPROPERTIES *props;
709 
710         if(al::strcasecmp(name, reverbitem.name) != 0)
711             continue;
712 
713         TRACE("Loading reverb '%s'\n", reverbitem.name);
714         props = &reverbitem.props;
715         effect->Props.Reverb.Density   = props->flDensity;
716         effect->Props.Reverb.Diffusion = props->flDiffusion;
717         effect->Props.Reverb.Gain   = props->flGain;
718         effect->Props.Reverb.GainHF = props->flGainHF;
719         effect->Props.Reverb.GainLF = props->flGainLF;
720         effect->Props.Reverb.DecayTime    = props->flDecayTime;
721         effect->Props.Reverb.DecayHFRatio = props->flDecayHFRatio;
722         effect->Props.Reverb.DecayLFRatio = props->flDecayLFRatio;
723         effect->Props.Reverb.ReflectionsGain   = props->flReflectionsGain;
724         effect->Props.Reverb.ReflectionsDelay  = props->flReflectionsDelay;
725         effect->Props.Reverb.ReflectionsPan[0] = props->flReflectionsPan[0];
726         effect->Props.Reverb.ReflectionsPan[1] = props->flReflectionsPan[1];
727         effect->Props.Reverb.ReflectionsPan[2] = props->flReflectionsPan[2];
728         effect->Props.Reverb.LateReverbGain   = props->flLateReverbGain;
729         effect->Props.Reverb.LateReverbDelay  = props->flLateReverbDelay;
730         effect->Props.Reverb.LateReverbPan[0] = props->flLateReverbPan[0];
731         effect->Props.Reverb.LateReverbPan[1] = props->flLateReverbPan[1];
732         effect->Props.Reverb.LateReverbPan[2] = props->flLateReverbPan[2];
733         effect->Props.Reverb.EchoTime  = props->flEchoTime;
734         effect->Props.Reverb.EchoDepth = props->flEchoDepth;
735         effect->Props.Reverb.ModulationTime  = props->flModulationTime;
736         effect->Props.Reverb.ModulationDepth = props->flModulationDepth;
737         effect->Props.Reverb.AirAbsorptionGainHF = props->flAirAbsorptionGainHF;
738         effect->Props.Reverb.HFReference = props->flHFReference;
739         effect->Props.Reverb.LFReference = props->flLFReference;
740         effect->Props.Reverb.RoomRolloffFactor = props->flRoomRolloffFactor;
741         effect->Props.Reverb.DecayHFLimit = props->iDecayHFLimit ? AL_TRUE : AL_FALSE;
742         return;
743     }
744 
745     WARN("Reverb preset '%s' not found\n", name);
746 }
alGenBuffers(ALsizei n,ALuint * buffers)747