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