diff --git a/src/audio/AL/ALAudio.cpp b/src/audio/AL/ALAudio.cpp index 41ce83c08..3255195f1 100644 --- a/src/audio/AL/ALAudio.cpp +++ b/src/audio/AL/ALAudio.cpp @@ -40,6 +40,20 @@ static bool check_alc_errors(ALCdevice* device, const char* context) { return true; } +static LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti = nullptr; +static LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots = nullptr; +static LPALGENEFFECTS alGenEffects = nullptr; +static LPALDELETEEFFECTS alDeleteEffects = nullptr; +static LPALISEFFECT alIsEffect = nullptr; +static LPALEFFECTI alEffecti = nullptr; +static LPALEFFECTF alEffectf = nullptr; +static LPALGENFILTERS alGenFilters = nullptr; +static LPALDELETEFILTERS alDeleteFilters = nullptr; +static LPALISFILTER alIsFilter = nullptr; +static LPALFILTERI alFilteri = nullptr; +static LPALFILTERF alFilterf = nullptr; + + ALSound::ALSound( ALAudio* al, uint buffer, const std::shared_ptr& pcm, bool keepPCM ) @@ -382,6 +396,10 @@ void ALSpeaker::play() { AL_GAIN, volume * p_channel->getVolume() )); + if (al->useEffects) { + AL_CHECK(alSource3i(source, AL_AUXILIARY_SEND_FILTER, al->effectSlots[0], 0, al->filters[0])); + //AL_CHECK(alSourcei(source, AL_DIRECT_FILTER, al->filters[0])); + } AL_CHECK(alSourcePlay(source)); } @@ -455,15 +473,14 @@ int ALSpeaker::getPriority() const { return priority; } - bool ALSpeaker::isManuallyStopped() const { return manuallyStopped; } static bool alc_enumeration_ext = false; -ALAudio::ALAudio(ALCdevice* device, ALCcontext* context) - : device(device), context(context) { +ALAudio::ALAudio(ALCdevice* device, ALCcontext* context, bool useEffects) + : device(device), context(context), useEffects(useEffects) { ALCint size; alcGetIntegerv(device, ALC_ATTRIBUTES_SIZE, 1, &size); std::vector attrs(size); @@ -487,6 +504,11 @@ ALAudio::ALAudio(ALCdevice* device, ALCcontext* context) } alDopplerFactor(1.0 / 3.0); + alGetError(); + + if (useEffects) { + initEffects(); + } } ALAudio::~ALAudio() { @@ -513,6 +535,58 @@ ALAudio::~ALAudio() { context = nullptr; } +void ALAudio::initEffects() { + for (uint i = 0; i < effectSlots.size(); i++) { + alGenAuxiliaryEffectSlots(1, &effectSlots[i]); + if (alGetError() != AL_NO_ERROR) { + logger.error() << "could not to create aux effect slot #" << i; + useEffects = false; + return; + } + } + for (uint i = 0; i < effects.size(); i++) { + alGenEffects(1, &effects[i]); + if (alGetError() != AL_NO_ERROR || !alIsEffect(effects[i])) { + logger.error() << "could not to create effect #" << i; + useEffects = false; + return; + } + } + for (uint i = 0; i < filters.size(); i++) { + alGenFilters(1, &filters[i]); + if (alGetError() != AL_NO_ERROR || !alIsFilter(filters[i])) { + logger.error() << "could not to create filter #" << i; + useEffects = false; + return; + } + } + + // Create reverb effect + alEffecti(effects[0], AL_EFFECT_TYPE, AL_EFFECT_REVERB); + if (alGetError() != AL_NO_ERROR) { + logger.error() << "reverb effect is not supported"; + useEffects = false; + return; + } + alEffectf(effects[0], AL_REVERB_DECAY_TIME, 1.0f); + + // Create lowpass filter + alFilteri(filters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + if (alGetError() != AL_NO_ERROR) { + logger.error() << "lowpass filter is not supported"; + useEffects = false; + return; + } + alFilterf(filters[0], AL_LOWPASS_GAIN, 1.0f); + alFilterf(filters[0], AL_LOWPASS_GAINHF, 0.1f); + + // Attach effect to aux effect slot + alAuxiliaryEffectSloti(effectSlots[0], AL_EFFECTSLOT_EFFECT, effects[0]); + if (alGetError() == AL_NO_ERROR) { + logger.info() << "successfully loaded effect into effect slot"; + } +} + std::unique_ptr ALAudio::createSound( std::shared_ptr pcm, bool keepPCM ) { @@ -592,19 +666,62 @@ std::unique_ptr ALAudio::openInputDevice( ); } +template +static bool get_proc_address(const char* name, T& ptr) { + ptr = (T) alGetProcAddress(name); + return ptr != nullptr; +} + std::unique_ptr ALAudio::create() { alc_enumeration_ext = alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"); ALCdevice* device = alcOpenDevice(nullptr); - if (device == nullptr) return nullptr; + if (device == nullptr) { + return nullptr; + } + bool effects = true; + ALint attribs[4] {}; + if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE) { + logger.info() << "AL effects extension present"; + attribs[0] = ALC_MAX_AUXILIARY_SENDS; + attribs[1] = 4; + } else { + logger.warning() << "AL effects extension is not supported"; + effects = false; + } ALCcontext* context = alcCreateContext(device, nullptr); if (!alcMakeContextCurrent(context)) { alcCloseDevice(device); return nullptr; } AL_CHECK(); + + ALCint sends = 0; + alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &sends); + logger.info() << "device supports " << sends << " aux sends per source"; + + if (effects) { + bool ok = get_proc_address("alAuxiliaryEffectSloti", alAuxiliaryEffectSloti) + && get_proc_address("alGenAuxiliaryEffectSlots", alGenAuxiliaryEffectSlots) + && get_proc_address("alGenEffects", alGenEffects) + && get_proc_address("alDeleteEffects", alDeleteEffects) + && get_proc_address("alIsEffect", alIsEffect) + && get_proc_address("alEffecti", alEffecti) + && get_proc_address("alEffectf", alEffectf) + && get_proc_address("alGenFilters", alGenFilters) + && get_proc_address("alDeleteFilters", alDeleteFilters) + && get_proc_address("alIsFilter", alIsFilter) + && get_proc_address("alFilteri", alFilteri) + && get_proc_address("alFilterf", alFilterf) + ; + if (!ok) { + logger.error() << "could not get effects extension function pointers"; + effects = false; + } + } + logger.info() << "initialized"; - return std::make_unique(device, context); + return std::make_unique(device, context, effects); } uint ALAudio::getFreeSource() { diff --git a/src/audio/AL/ALAudio.hpp b/src/audio/AL/ALAudio.hpp index 5642f222b..8551e6697 100644 --- a/src/audio/AL/ALAudio.hpp +++ b/src/audio/AL/ALAudio.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -12,9 +13,11 @@ #ifdef __APPLE__ #include #include +#include #else #include #include +#include #endif namespace audio { @@ -176,10 +179,17 @@ namespace audio { std::vector allbuffers; std::vector freebuffers; - uint maxSources = 256; + + void initEffects(); public: - ALAudio(ALCdevice* device, ALCcontext* context); + std::array effectSlots; + std::array effects; + std::array filters; + + bool useEffects; + + ALAudio(ALCdevice* device, ALCcontext* context, bool effects); ~ALAudio(); uint getFreeSource();