Audio.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. /**
  2. * Copyright (c) 2006-2020 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #include "Audio.h"
  21. #include "common/delay.h"
  22. #include "RecordingDevice.h"
  23. #include "sound/Decoder.h"
  24. #include <cstdlib>
  25. #include <iostream>
  26. #ifdef LOVE_IOS
  27. #include "common/ios.h"
  28. #endif
  29. namespace love
  30. {
  31. namespace audio
  32. {
  33. namespace openal
  34. {
  35. Audio::PoolThread::PoolThread(Pool *pool)
  36. : pool(pool)
  37. , finish(false)
  38. {
  39. threadName = "AudioPool";
  40. }
  41. Audio::PoolThread::~PoolThread()
  42. {
  43. }
  44. void Audio::PoolThread::threadFunction()
  45. {
  46. while (true)
  47. {
  48. {
  49. thread::Lock lock(mutex);
  50. if (finish)
  51. {
  52. return;
  53. }
  54. }
  55. pool->update();
  56. sleep(5);
  57. }
  58. }
  59. void Audio::PoolThread::setFinish()
  60. {
  61. thread::Lock lock(mutex);
  62. finish = true;
  63. }
  64. ALenum Audio::getFormat(int bitDepth, int channels)
  65. {
  66. if (bitDepth != 8 && bitDepth != 16)
  67. return AL_NONE;
  68. if (channels == 1)
  69. return bitDepth == 8 ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16;
  70. else if (channels == 2)
  71. return bitDepth == 8 ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16;
  72. #ifdef AL_EXT_MCFORMATS
  73. else if (alIsExtensionPresent("AL_EXT_MCFORMATS"))
  74. {
  75. if (channels == 6)
  76. return bitDepth == 8 ? AL_FORMAT_51CHN8 : AL_FORMAT_51CHN16;
  77. else if (channels == 8)
  78. return bitDepth == 8 ? AL_FORMAT_71CHN8 : AL_FORMAT_71CHN16;
  79. }
  80. #endif
  81. return AL_NONE;
  82. }
  83. Audio::Audio()
  84. : device(nullptr)
  85. , context(nullptr)
  86. , pool(nullptr)
  87. , poolThread(nullptr)
  88. , distanceModel(DISTANCE_INVERSE_CLAMPED)
  89. {
  90. #if defined(LOVE_LINUX)
  91. // Temporarly block signals, as the thread inherits this mask
  92. love::thread::disableSignals();
  93. #endif
  94. // Before opening new device, check if recording
  95. // is requested.
  96. if (getRequestRecordingPermission())
  97. {
  98. if (!hasRecordingPermission())
  99. // Request recording permission on some OSes.
  100. requestRecordingPermission();
  101. }
  102. // Passing null for default device.
  103. device = alcOpenDevice(nullptr);
  104. if (device == nullptr)
  105. throw love::Exception("Could not open device.");
  106. #ifdef ALC_EXT_EFX
  107. ALint attribs[4] = { ALC_MAX_AUXILIARY_SENDS, MAX_SOURCE_EFFECTS, 0, 0 };
  108. #else
  109. ALint *attribs = nullptr;
  110. #endif
  111. context = alcCreateContext(device, attribs);
  112. if (context == nullptr)
  113. throw love::Exception("Could not create context.");
  114. if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR)
  115. throw love::Exception("Could not make context current.");
  116. #if defined(LOVE_LINUX)
  117. love::thread::reenableSignals();
  118. #endif
  119. #ifdef ALC_EXT_EFX
  120. initializeEFX();
  121. alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &MAX_SOURCE_EFFECTS);
  122. alGetError();
  123. if (alGenAuxiliaryEffectSlots)
  124. {
  125. for (int i = 0; i < MAX_SCENE_EFFECTS; i++)
  126. {
  127. ALuint slot;
  128. alGenAuxiliaryEffectSlots(1, &slot);
  129. if (alGetError() == AL_NO_ERROR)
  130. slotlist.push(slot);
  131. else
  132. {
  133. MAX_SCENE_EFFECTS = i;
  134. break;
  135. }
  136. }
  137. }
  138. else
  139. MAX_SCENE_EFFECTS = MAX_SOURCE_EFFECTS = 0;
  140. #else
  141. MAX_SCENE_EFFECTS = MAX_SOURCE_EFFECTS = 0;
  142. #endif
  143. try
  144. {
  145. pool = new Pool();
  146. }
  147. catch (love::Exception &)
  148. {
  149. for (auto c : capture)
  150. delete c;
  151. #ifdef ALC_EXT_EFX
  152. if (alDeleteAuxiliaryEffectSlots)
  153. {
  154. while (!slotlist.empty())
  155. {
  156. alDeleteAuxiliaryEffectSlots(1, &slotlist.top());
  157. slotlist.pop();
  158. }
  159. }
  160. #endif
  161. alcMakeContextCurrent(nullptr);
  162. alcDestroyContext(context);
  163. alcCloseDevice(device);
  164. throw;
  165. }
  166. poolThread = new PoolThread(pool);
  167. poolThread->start();
  168. #ifdef LOVE_IOS
  169. love::ios::initAudioSessionInterruptionHandler();
  170. #endif
  171. }
  172. Audio::~Audio()
  173. {
  174. #ifdef LOVE_IOS
  175. love::ios::destroyAudioSessionInterruptionHandler();
  176. #endif
  177. poolThread->setFinish();
  178. poolThread->wait();
  179. delete poolThread;
  180. delete pool;
  181. for (auto c : capture)
  182. delete c;
  183. #ifdef ALC_EXT_EFX
  184. for (auto e : effectmap)
  185. {
  186. delete e.second.effect;
  187. slotlist.push(e.second.slot);
  188. }
  189. if (alDeleteAuxiliaryEffectSlots)
  190. {
  191. while (!slotlist.empty())
  192. {
  193. alDeleteAuxiliaryEffectSlots(1, &slotlist.top());
  194. slotlist.pop();
  195. }
  196. }
  197. #endif
  198. alcMakeContextCurrent(nullptr);
  199. alcDestroyContext(context);
  200. alcCloseDevice(device);
  201. }
  202. const char *Audio::getName() const
  203. {
  204. return "love.audio.openal";
  205. }
  206. love::audio::Source *Audio::newSource(love::sound::Decoder *decoder)
  207. {
  208. return new Source(pool, decoder);
  209. }
  210. love::audio::Source *Audio::newSource(love::sound::SoundData *soundData)
  211. {
  212. return new Source(pool, soundData);
  213. }
  214. love::audio::Source *Audio::newSource(int sampleRate, int bitDepth, int channels, int buffers)
  215. {
  216. return new Source(pool, sampleRate, bitDepth, channels, buffers);
  217. }
  218. int Audio::getActiveSourceCount() const
  219. {
  220. return pool->getActiveSourceCount();
  221. }
  222. int Audio::getMaxSources() const
  223. {
  224. return pool->getMaxSources();
  225. }
  226. bool Audio::play(love::audio::Source *source)
  227. {
  228. return source->play();
  229. }
  230. bool Audio::play(const std::vector<love::audio::Source*> &sources)
  231. {
  232. return Source::play(sources);
  233. }
  234. void Audio::stop(love::audio::Source *source)
  235. {
  236. source->stop();
  237. }
  238. void Audio::stop(const std::vector<love::audio::Source*> &sources)
  239. {
  240. return Source::stop(sources);
  241. }
  242. void Audio::stop()
  243. {
  244. return Source::stop(pool);
  245. }
  246. void Audio::pause(love::audio::Source *source)
  247. {
  248. source->pause();
  249. }
  250. void Audio::pause(const std::vector<love::audio::Source*> &sources)
  251. {
  252. return Source::pause(sources);
  253. }
  254. std::vector<love::audio::Source*> Audio::pause()
  255. {
  256. return Source::pause(pool);
  257. }
  258. void Audio::pauseContext()
  259. {
  260. alcMakeContextCurrent(nullptr);
  261. }
  262. void Audio::resumeContext()
  263. {
  264. if (context && alcGetCurrentContext() != context)
  265. alcMakeContextCurrent(context);
  266. }
  267. void Audio::setVolume(float volume)
  268. {
  269. alListenerf(AL_GAIN, volume);
  270. }
  271. float Audio::getVolume() const
  272. {
  273. ALfloat volume;
  274. alGetListenerf(AL_GAIN, &volume);
  275. return volume;
  276. }
  277. void Audio::getPosition(float *v) const
  278. {
  279. alGetListenerfv(AL_POSITION, v);
  280. }
  281. void Audio::setPosition(float *v)
  282. {
  283. alListenerfv(AL_POSITION, v);
  284. }
  285. void Audio::getOrientation(float *v) const
  286. {
  287. alGetListenerfv(AL_ORIENTATION, v);
  288. }
  289. void Audio::setOrientation(float *v)
  290. {
  291. alListenerfv(AL_ORIENTATION, v);
  292. }
  293. void Audio::getVelocity(float *v) const
  294. {
  295. alGetListenerfv(AL_VELOCITY, v);
  296. }
  297. void Audio::setVelocity(float *v)
  298. {
  299. alListenerfv(AL_VELOCITY, v);
  300. }
  301. void Audio::setDopplerScale(float scale)
  302. {
  303. if (scale >= 0.0f)
  304. alDopplerFactor(scale);
  305. }
  306. float Audio::getDopplerScale() const
  307. {
  308. return alGetFloat(AL_DOPPLER_FACTOR);
  309. }
  310. /*
  311. void Audio::setMeter(float scale)
  312. {
  313. if (scale >= 0.0f)
  314. {
  315. metersPerUnit = scale;
  316. #ifdef ALC_EXT_EFX
  317. alListenerf(AL_METERS_PER_UNIT, scale);
  318. #endif
  319. }
  320. }
  321. float Audio::getMeter() const
  322. {
  323. return metersPerUnit;
  324. }
  325. */
  326. Audio::DistanceModel Audio::getDistanceModel() const
  327. {
  328. return distanceModel;
  329. }
  330. void Audio::setDistanceModel(DistanceModel distanceModel)
  331. {
  332. this->distanceModel = distanceModel;
  333. switch (distanceModel)
  334. {
  335. case DISTANCE_NONE:
  336. alDistanceModel(AL_NONE);
  337. break;
  338. case DISTANCE_INVERSE:
  339. alDistanceModel(AL_INVERSE_DISTANCE);
  340. break;
  341. case DISTANCE_INVERSE_CLAMPED:
  342. alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
  343. break;
  344. case DISTANCE_LINEAR:
  345. alDistanceModel(AL_LINEAR_DISTANCE);
  346. break;
  347. case DISTANCE_LINEAR_CLAMPED:
  348. alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
  349. break;
  350. case DISTANCE_EXPONENT:
  351. alDistanceModel(AL_EXPONENT_DISTANCE);
  352. break;
  353. case DISTANCE_EXPONENT_CLAMPED:
  354. alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
  355. break;
  356. default:
  357. break;
  358. }
  359. }
  360. const std::vector<love::audio::RecordingDevice*> &Audio::getRecordingDevices()
  361. {
  362. std::vector<std::string> devnames;
  363. std::vector<love::audio::RecordingDevice*> devices;
  364. // If recording permission is not granted, inform user about it
  365. // and return empty list.
  366. if (!hasRecordingPermission() && getRequestRecordingPermission())
  367. {
  368. showRecordingPermissionMissingDialog();
  369. capture.clear();
  370. return capture;
  371. }
  372. std::string defaultname(alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
  373. //no device name obtained from AL, fallback to reading from device
  374. if (defaultname.length() == 0)
  375. {
  376. //use some safe basic parameters - 8 kHz, 8 bits, 1 channel
  377. ALCdevice *defaultdevice = alcCaptureOpenDevice(NULL, 8000, AL_FORMAT_MONO8, 1024);
  378. if (alGetError() == AL_NO_ERROR)
  379. {
  380. defaultname = alcGetString(defaultdevice, ALC_CAPTURE_DEVICE_SPECIFIER);
  381. alcCaptureCloseDevice(defaultdevice);
  382. }
  383. else
  384. {
  385. //failed to open default recording device - bail, return empty list
  386. capture.clear();
  387. return capture;
  388. }
  389. }
  390. devnames.reserve(capture.size());
  391. devnames.push_back(defaultname);
  392. //find devices name list
  393. const ALCchar *devstr = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
  394. size_t offset = 0;
  395. while (true)
  396. {
  397. if (devstr[offset] == '\0')
  398. break;
  399. std::string str((ALCchar*)&devstr[offset]);
  400. if (str != defaultname)
  401. devnames.push_back(str);
  402. offset += str.length() + 1;
  403. }
  404. devices.reserve(devnames.size());
  405. //build ordered list of devices
  406. for (int i = 0; i < (int) devnames.size(); i++)
  407. {
  408. devices.push_back(nullptr);
  409. auto d = devices.end() - 1;
  410. for (auto c : capture)
  411. if (devnames[i] == c->getName())
  412. *d = c;
  413. if (*d == nullptr)
  414. *d = new RecordingDevice(devnames[i].c_str());
  415. else
  416. (*d)->retain();
  417. }
  418. for (auto c : capture)
  419. c->release();
  420. capture.clear();
  421. capture.reserve(devices.size());
  422. //this needs to be executed in specific order
  423. for (unsigned int i = 0; i < devnames.size(); i++)
  424. capture.push_back(devices[i]);
  425. return capture;
  426. }
  427. bool Audio::setEffect(const char *name, std::map<Effect::Parameter, float> &params)
  428. {
  429. Effect *effect;
  430. ALuint slot;
  431. auto iter = effectmap.find(name);
  432. if (iter == effectmap.end())
  433. {
  434. //new effect needed but no more slots
  435. if (effectmap.size() >= (unsigned int)MAX_SCENE_EFFECTS)
  436. return false;
  437. effect = new Effect();
  438. slot = slotlist.top();
  439. slotlist.pop();
  440. effectmap[name] = {effect, slot};
  441. }
  442. else
  443. {
  444. effect = iter->second.effect;
  445. slot = iter->second.slot;
  446. }
  447. bool result = effect->setParams(params);
  448. #ifdef ALC_EXT_EFX
  449. if (alAuxiliaryEffectSloti)
  450. {
  451. if (result)
  452. {
  453. auto iter = params.find(Effect::EFFECT_VOLUME);
  454. if (iter != params.end())
  455. alAuxiliaryEffectSlotf(slot, AL_EFFECTSLOT_GAIN, iter->second);
  456. alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, effect->getEffect());
  457. }
  458. else
  459. alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
  460. alGetError();
  461. }
  462. #endif
  463. return result;
  464. }
  465. bool Audio::unsetEffect(const char *name)
  466. {
  467. auto iter = effectmap.find(name);
  468. if (iter == effectmap.end())
  469. return false;
  470. Effect *effect = iter->second.effect;
  471. ALuint slot = iter->second.slot;
  472. #ifdef ALC_EXT_EFX
  473. if (alAuxiliaryEffectSloti)
  474. alAuxiliaryEffectSloti(slot, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
  475. #endif
  476. delete effect;
  477. effectmap.erase(iter);
  478. slotlist.push(slot);
  479. return true;
  480. }
  481. bool Audio::getEffect(const char *name, std::map<Effect::Parameter, float> &params)
  482. {
  483. auto iter = effectmap.find(name);
  484. if (iter == effectmap.end())
  485. return false;
  486. params = iter->second.effect->getParams();
  487. return true;
  488. }
  489. bool Audio::getActiveEffects(std::vector<std::string> &list) const
  490. {
  491. if (effectmap.empty())
  492. return false;
  493. list.reserve(effectmap.size());
  494. for (auto i : effectmap)
  495. list.push_back(i.first);
  496. return true;
  497. }
  498. int Audio::getMaxSceneEffects() const
  499. {
  500. return MAX_SCENE_EFFECTS;
  501. }
  502. int Audio::getMaxSourceEffects() const
  503. {
  504. return MAX_SOURCE_EFFECTS;
  505. }
  506. bool Audio::isEFXsupported() const
  507. {
  508. #ifdef ALC_EXT_EFX
  509. return (alGenEffects != nullptr);
  510. #else
  511. return false;
  512. #endif
  513. }
  514. bool Audio::getEffectID(const char *name, ALuint &id)
  515. {
  516. auto iter = effectmap.find(name);
  517. if (iter == effectmap.end())
  518. return false;
  519. id = iter->second.slot;
  520. return true;
  521. }
  522. #ifdef ALC_EXT_EFX
  523. LPALGENEFFECTS alGenEffects = nullptr;
  524. LPALDELETEEFFECTS alDeleteEffects = nullptr;
  525. LPALISEFFECT alIsEffect = nullptr;
  526. LPALEFFECTI alEffecti = nullptr;
  527. LPALEFFECTIV alEffectiv = nullptr;
  528. LPALEFFECTF alEffectf = nullptr;
  529. LPALEFFECTFV alEffectfv = nullptr;
  530. LPALGETEFFECTI alGetEffecti = nullptr;
  531. LPALGETEFFECTIV alGetEffectiv = nullptr;
  532. LPALGETEFFECTF alGetEffectf = nullptr;
  533. LPALGETEFFECTFV alGetEffectfv = nullptr;
  534. LPALGENFILTERS alGenFilters = nullptr;
  535. LPALDELETEFILTERS alDeleteFilters = nullptr;
  536. LPALISFILTER alIsFilter = nullptr;
  537. LPALFILTERI alFilteri = nullptr;
  538. LPALFILTERIV alFilteriv = nullptr;
  539. LPALFILTERF alFilterf = nullptr;
  540. LPALFILTERFV alFilterfv = nullptr;
  541. LPALGETFILTERI alGetFilteri = nullptr;
  542. LPALGETFILTERIV alGetFilteriv = nullptr;
  543. LPALGETFILTERF alGetFilterf = nullptr;
  544. LPALGETFILTERFV alGetFilterfv = nullptr;
  545. LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots = nullptr;
  546. LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots = nullptr;
  547. LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot = nullptr;
  548. LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti = nullptr;
  549. LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv = nullptr;
  550. LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf = nullptr;
  551. LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv = nullptr;
  552. LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti = nullptr;
  553. LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv = nullptr;
  554. LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf = nullptr;
  555. LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv = nullptr;
  556. #endif
  557. void Audio::initializeEFX()
  558. {
  559. #ifdef ALC_EXT_EFX
  560. if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_FALSE)
  561. return;
  562. alGenEffects = (LPALGENEFFECTS)alGetProcAddress("alGenEffects");
  563. alDeleteEffects = (LPALDELETEEFFECTS)alGetProcAddress("alDeleteEffects");
  564. alIsEffect = (LPALISEFFECT)alGetProcAddress("alIsEffect");
  565. alEffecti = (LPALEFFECTI)alGetProcAddress("alEffecti");
  566. alEffectiv = (LPALEFFECTIV)alGetProcAddress("alEffectiv");
  567. alEffectf = (LPALEFFECTF)alGetProcAddress("alEffectf");
  568. alEffectfv = (LPALEFFECTFV)alGetProcAddress("alEffectfv");
  569. alGetEffecti = (LPALGETEFFECTI)alGetProcAddress("alGetEffecti");
  570. alGetEffectiv = (LPALGETEFFECTIV)alGetProcAddress("alGetEffectiv");
  571. alGetEffectf = (LPALGETEFFECTF)alGetProcAddress("alGetEffectf");
  572. alGetEffectfv = (LPALGETEFFECTFV)alGetProcAddress("alGetEffectfv");
  573. alGenFilters = (LPALGENFILTERS)alGetProcAddress("alGenFilters");
  574. alDeleteFilters = (LPALDELETEFILTERS)alGetProcAddress("alDeleteFilters");
  575. alIsFilter = (LPALISFILTER)alGetProcAddress("alIsFilter");
  576. alFilteri = (LPALFILTERI)alGetProcAddress("alFilteri");
  577. alFilteriv = (LPALFILTERIV)alGetProcAddress("alFilteriv");
  578. alFilterf = (LPALFILTERF)alGetProcAddress("alFilterf");
  579. alFilterfv = (LPALFILTERFV)alGetProcAddress("alFilterfv");
  580. alGetFilteri = (LPALGETFILTERI)alGetProcAddress("alGetFilteri");
  581. alGetFilteriv = (LPALGETFILTERIV)alGetProcAddress("alGetFilteriv");
  582. alGetFilterf = (LPALGETFILTERF)alGetProcAddress("alGetFilterf");
  583. alGetFilterfv = (LPALGETFILTERFV)alGetProcAddress("alGetFilterfv");
  584. alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)alGetProcAddress("alGenAuxiliaryEffectSlots");
  585. alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)alGetProcAddress("alDeleteAuxiliaryEffectSlots");
  586. alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT)alGetProcAddress("alIsAuxiliaryEffectSlot");
  587. alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)alGetProcAddress("alAuxiliaryEffectSloti");
  588. alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV)alGetProcAddress("alAuxiliaryEffectSlotiv");
  589. alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)alGetProcAddress("alAuxiliaryEffectSlotf");
  590. alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV)alGetProcAddress("alAuxiliaryEffectSlotfv");
  591. alGetAuxiliaryEffectSloti = (LPALGETAUXILIARYEFFECTSLOTI)alGetProcAddress("alGetAuxiliaryEffectSloti");
  592. alGetAuxiliaryEffectSlotiv = (LPALGETAUXILIARYEFFECTSLOTIV)alGetProcAddress("alGetAuxiliaryEffectSlotiv");
  593. alGetAuxiliaryEffectSlotf = (LPALGETAUXILIARYEFFECTSLOTF)alGetProcAddress("alGetAuxiliaryEffectSlotf");
  594. alGetAuxiliaryEffectSlotfv = (LPALGETAUXILIARYEFFECTSLOTFV)alGetProcAddress("alGetAuxiliaryEffectSlotfv");
  595. //failed to initialize functions, revert to nullptr
  596. if (!alGenEffects || !alDeleteEffects || !alIsEffect ||
  597. !alGenFilters || !alDeleteFilters || !alIsFilter ||
  598. !alGenAuxiliaryEffectSlots || !alDeleteAuxiliaryEffectSlots || !alIsAuxiliaryEffectSlot ||
  599. !alEffecti || !alEffectiv || !alEffectf || !alEffectfv ||
  600. !alGetEffecti || !alGetEffectiv || !alGetEffectf || !alGetEffectfv ||
  601. !alFilteri || !alFilteriv || !alFilterf || !alFilterfv ||
  602. !alGetFilteri || !alGetFilteriv || !alGetFilterf || !alGetFilterfv ||
  603. !alAuxiliaryEffectSloti || !alAuxiliaryEffectSlotiv || !alAuxiliaryEffectSlotf || !alAuxiliaryEffectSlotfv ||
  604. !alGetAuxiliaryEffectSloti || !alGetAuxiliaryEffectSlotiv || !alGetAuxiliaryEffectSlotf || !alGetAuxiliaryEffectSlotfv)
  605. {
  606. alGenEffects = nullptr; alDeleteEffects = nullptr; alIsEffect = nullptr;
  607. alEffecti = nullptr; alEffectiv = nullptr; alEffectf = nullptr; alEffectfv = nullptr;
  608. alGetEffecti = nullptr; alGetEffectiv = nullptr; alGetEffectf = nullptr; alGetEffectfv = nullptr;
  609. alGenFilters = nullptr; alDeleteFilters = nullptr; alIsFilter = nullptr;
  610. alFilteri = nullptr; alFilteriv = nullptr; alFilterf = nullptr; alFilterfv = nullptr;
  611. alGetFilteri = nullptr; alGetFilteriv = nullptr; alGetFilterf = nullptr; alGetFilterfv = nullptr;
  612. alGenAuxiliaryEffectSlots = nullptr; alDeleteAuxiliaryEffectSlots = nullptr; alIsAuxiliaryEffectSlot = nullptr;
  613. alAuxiliaryEffectSloti = nullptr; alAuxiliaryEffectSlotiv = nullptr;
  614. alAuxiliaryEffectSlotf = nullptr; alAuxiliaryEffectSlotfv = nullptr;
  615. alGetAuxiliaryEffectSloti = nullptr; alGetAuxiliaryEffectSlotiv = nullptr;
  616. alGetAuxiliaryEffectSlotf = nullptr; alGetAuxiliaryEffectSlotfv = nullptr;
  617. }
  618. #endif
  619. }
  620. } // openal
  621. } // audio
  622. } // love