-
Notifications
You must be signed in to change notification settings - Fork 8
Description
Hello PyOpenAL team,
First, thank you for your work on this library. I am developing an application that uses EFX for sound occlusion and have run into a persistent issue that I cannot solve. I am hoping you can provide some guidance.
System Environment
• OS: Windows 11
• Python: 3.13.3
• PyOpenAL: Freshly installed from pip on May 25, 2025.
• OpenAL Backend: OpenAL Soft 1.24.3.0 (official binaries installed correctly in System32/SysWOW64)
The Problem
I am trying to use the EFX extension to apply a simple low-pass filter to a source. When I call efx.alFilterf to set the AL_LOWPASS_GAIN or AL_LOWPASS_GAINHF parameters, the function call succeeds and alGetError() returns AL_NO_ERROR. However, there is no audible change in the sound. The sound is not muffled or quieted.
Key Symptom
After performing a completely clean installation of both OpenAL Soft and PyOpenAL (from pip), my application logs the following warning on startup:
WARNING - PyOpenAL 'efx' submodule not found. EFX calls will attempt 'al.' prefix if EFX is device-supported.
This suggests to me that the EFX extension is not being built or included correctly during the pip installation, even though a fully capable OpenAL Soft backend is present. The functions appear to exist on the base al object, but they do not seem to be connected to the driver correctly, as they fail silently.
Minimal, Reproducible Test Case
I have created the following minimal script that completely reproduces the problem in isolation. When this script is run, the second sound that is played should be very quiet and heavily muffled, but on my system, it sounds identical to the first.
Python
Copy code
import time
import ctypes
import os
import sys
This script requires PyOpenAL and soundfile (pip install soundfile
)
try:
from openal import al, alc
# Attempt to import efx, but handle the case where it might not exist
try:
from openal import efx
print("--- EFX submodule found. ---")
except ImportError:
print("--- EFX submodule not found, using 'al' as fallback. ---")
efx = al
import soundfile
except ImportError:
print("ERROR: PyOpenAL or soundfile is not installed.")
print("Please run: pip install PyOpenAL soundfile")
sys.exit()
Helper function to check for OpenAL errors
def check_al_error(tag=""):
error = al.alGetError()
if error != al.AL_NO_ERROR:
# Assuming alGetString is available on the base 'al' object
print(f"!!! OpenAL Error ({tag}):", al.alGetString(error).decode())
return True
return False
Main Test
def run_efx_test():
print("--- Starting EFX Low-Pass Filter Test ---")
device = alc.alcOpenDevice(None)
if not device:
print("!!! Could not open audio device.")
return
context = alc.alcCreateContext(device, None)
if not context or not alc.alcMakeContextCurrent(context):
print("!!! Could not create or set audio context.")
alc.alcCloseDevice(device)
return
print("--- OpenAL Initialized ---")
if not alc.alcIsExtensionPresent(device, b"ALC_EXT_EFX"):
print("!!! EFX Extension not supported on this device. Test cannot continue.")
alc.alcMakeContextCurrent(None)
alc.alcDestroyContext(context)
alc.alcCloseDevice(device)
return
print("--- EFX Extension Supported ---")
sound_file = 'test_sound.wav'
if not os.path.exists(sound_file):
print(f"!!! ERROR: Cannot find '{sound_file}'.")
return
data, samplerate, channels, format_type = None, None, None, None
try:
with soundfile.SoundFile(sound_file, 'r') as sf:
data = sf.read(dtype='int16')
samplerate = sf.samplerate
channels = sf.channels
format_type = {
(1, 'PCM_16'): al.AL_FORMAT_MONO16,
(2, 'PCM_16'): al.AL_FORMAT_STEREO16
}.get((channels, sf.subtype), None)
if format_type is None: return
buffer_data = (ctypes.c_short * len(data))(*data)
buffer_size = ctypes.sizeof(buffer_data)
print(f"--- Loaded '{sound_file}' ---")
except Exception as e:
print(f"!!! Failed to load sound file: {e}")
return
source = al.alGenSources(1)
buffer = al.alGenBuffers(1)
al.alBufferData(buffer, format_type, buffer_data, buffer_size, samplerate)
al.alSourcei(source, al.AL_BUFFER, buffer)
if check_al_error("Creating source/buffer"): return
effect_slot = efx.alGenAuxiliaryEffectSlots(1)
null_effect = efx.alGenEffects(1)
efx.alEffecti(null_effect, efx.AL_EFFECT_TYPE, efx.AL_EFFECT_NULL)
lowpass_filter = efx.alGenFilters(1)
efx.alFilteri(lowpass_filter, efx.AL_FILTER_TYPE, efx.AL_FILTER_LOWPASS)
efx.alAuxiliaryEffectSloti(effect_slot, efx.AL_EFFECTSLOT_EFFECT, null_effect)
if check_al_error("Creating EFX objects"): return
print("--- EFX Objects Created Successfully ---")
# --- TEST 1: Play sound normally ---
print("\n>>> Playing sound normally...")
al.alSourcePlay(source)
while al.alGetSourcei(source, al.AL_SOURCE_STATE) == al.AL_PLAYING:
time.sleep(0.1)
print("...Finished.")
time.sleep(1)
# --- TEST 2: Play sound muffled ---
print("\n>>> Applying muffle and playing again...")
muffle_gain = 0.1 # Should be very quiet
muffle_gain_hf = 0.1 # Should be very muffled
efx.alFilterf(lowpass_filter, efx.AL_LOWPASS_GAIN, muffle_gain)
efx.alFilterf(lowpass_filter, efx.AL_LOWPASS_GAINHF, muffle_gain_hf)
print(f"--- Set filter GAIN to {muffle_gain} and GAINHF to {muffle_gain_hf} ---")
if check_al_error("Setting filter parameters"): return
al.alSource3i(source, efx.AL_AUXILIARY_SEND_FILTER, effect_slot, 0, lowpass_filter)
if check_al_error("Connecting source to filter"): return
print("--- Connected source to filter. Playing... ---")
al.alSourcePlay(source)
while al.alGetSourcei(source, al.AL_SOURCE_STATE) == al.AL_PLAYING:
time.sleep(0.1)
print("...Finished.")
# Cleanup
print("\n--- Cleaning up ---")
al.alSourcei(source, al.AL_BUFFER, 0)
al.alDeleteSources(1, ctypes.byref(ctypes.c_uint(source)))
al.alDeleteBuffers(1, ctypes.byref(ctypes.c_uint(buffer)))
efx.alDeleteFilters(1, ctypes.byref(ctypes.c_uint(lowpass_filter)))
efx.alDeleteEffects(1, ctypes.byref(ctypes.c_uint(null_effect)))
efx.alDeleteAuxiliaryEffectSlots(1, ctypes.byref(ctypes.c_uint(effect_slot)))
alc.alcMakeContextCurrent(None)
alc.alcDestroyContext(context)
alc.alcCloseDevice(device)
print("--- Test Complete ---")
if name == 'main':
run_efx_test()
Thank you for any guidance you can offer on how to achieve a fully functional EFX installation on Windows.