//########################################################################### // // L4AUDEFX.cpp -- OpenAL EFX bridge (task #50, AUDIO_FIDELITY F9/F11). // See L4AUDEFX.h for the fidelity rationale. // //########################################################################### #include #include "mungal4.h" #pragma hdrstop #include "l4audefx.h" #include "openal/alc.h" #include "openal/efx.h" #ifndef AL_EFFECT_EAXREVERB #define AL_EFFECT_EAXREVERB 0x8000 // newer efx.h constant; OpenAL Soft supports it #endif namespace { bool s_available = false; ALuint s_reverbSlot = 0; ALuint s_reverbEffect = 0; ALuint s_scratchFilter = 0; LPALGENEFFECTS p_alGenEffects = 0; LPALEFFECTI p_alEffecti = 0; LPALEFFECTF p_alEffectf = 0; LPALGENAUXILIARYEFFECTSLOTS p_alGenAuxiliaryEffectSlots = 0; LPALAUXILIARYEFFECTSLOTI p_alAuxiliaryEffectSloti = 0; LPALAUXILIARYEFFECTSLOTF p_alAuxiliaryEffectSlotf = 0; LPALGENFILTERS p_alGenFilters = 0; LPALFILTERI p_alFilteri = 0; LPALFILTERF p_alFilterf = 0; } bool EFX_Available() { return s_available; } bool EFX_Initialize(float global_reverb_scale) { ALCcontext *context = alcGetCurrentContext(); if (context == 0) { return false; } ALCdevice *device = alcGetContextsDevice(context); if (device == 0 || !alcIsExtensionPresent(device, "ALC_EXT_EFX")) { if (getenv("BT_AUDIO_LOG")) DEBUG_STREAM << "[audio] EFX: ALC_EXT_EFX NOT present -- filters/reverb inert\n" << std::flush; return false; } p_alGenEffects = (LPALGENEFFECTS)alGetProcAddress("alGenEffects"); p_alEffecti = (LPALEFFECTI)alGetProcAddress("alEffecti"); p_alEffectf = (LPALEFFECTF)alGetProcAddress("alEffectf"); p_alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)alGetProcAddress("alGenAuxiliaryEffectSlots"); p_alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)alGetProcAddress("alAuxiliaryEffectSloti"); p_alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)alGetProcAddress("alAuxiliaryEffectSlotf"); p_alGenFilters = (LPALGENFILTERS)alGetProcAddress("alGenFilters"); p_alFilteri = (LPALFILTERI)alGetProcAddress("alFilteri"); p_alFilterf = (LPALFILTERF)alGetProcAddress("alFilterf"); if (!p_alGenEffects || !p_alEffecti || !p_alEffectf || !p_alGenAuxiliaryEffectSlots || !p_alAuxiliaryEffectSloti || !p_alAuxiliaryEffectSlotf || !p_alGenFilters || !p_alFilteri || !p_alFilterf) { if (getenv("BT_AUDIO_LOG")) DEBUG_STREAM << "[audio] EFX: entry points missing -- filters/reverb inert\n" << std::flush; return false; } alGetError(); p_alGenAuxiliaryEffectSlots(1, &s_reverbSlot); p_alGenEffects(1, &s_reverbEffect); if (alGetError() != AL_NO_ERROR) { return false; } // EAXReverb where available (OpenAL Soft: yes), plain reverb otherwise. p_alEffecti(s_reverbEffect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); if (alGetError() != AL_NO_ERROR) { p_alEffecti(s_reverbEffect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); } p_alAuxiliaryEffectSloti(s_reverbSlot, AL_EFFECTSLOT_EFFECT, (ALint)s_reverbEffect); // The authentic wet level: the original sent CC91 = global_reverb_scale // (0.3 -> value 38) on every 3D channel; one global slot gain reproduces // the same uniform send. p_alAuxiliaryEffectSlotf(s_reverbSlot, AL_EFFECTSLOT_GAIN, (global_reverb_scale < 0.0f) ? 0.0f : (global_reverb_scale > 1.0f) ? 1.0f : global_reverb_scale); p_alGenFilters(1, &s_scratchFilter); p_alFilteri(s_scratchFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS); s_available = (alGetError() == AL_NO_ERROR); if (getenv("BT_AUDIO_LOG")) DEBUG_STREAM << "[audio] EFX: " << (s_available ? "READY" : "FAILED") << " (reverb slot gain=" << global_reverb_scale << ")\n" << std::flush; return s_available; } void EFX_SetSourceLowpassGainHF(ALuint source, float gainhf) { if (!s_available) { return; } if (gainhf < 0.001f) gainhf = 0.001f; if (gainhf > 1.0f) gainhf = 1.0f; // filter params are COPIED at attach, so one scratch filter serves all p_alFilterf(s_scratchFilter, AL_LOWPASS_GAIN, 1.0f); p_alFilterf(s_scratchFilter, AL_LOWPASS_GAINHF, gainhf); alSourcei(source, AL_DIRECT_FILTER, (ALint)s_scratchFilter); } void EFX_AttachReverbSend(ALuint source) { if (!s_available) { return; } alSource3i(source, AL_AUXILIARY_SEND_FILTER, (ALint)s_reverbSlot, 0, AL_FILTER_NULL); }