Delphi

OpenAL

Tutorials

Lesson #17 (Using the EFX Extension)

This lesson is an follow up from lesson #13 . We are going to extend it to play an sound with an efx reverb effect.

For using an effect defined as an eax effect we also need to use the efxutil unit. So add it to the uses.

Next we need some additional variables controlling and storing the effect.
  uiEffectSlot: TALuint;
  uiEffect: TALuint;
  efxReverb: EFXEAXREVERBPROPERTIES;
  eaxBathroom: EAXREVERBPROPERTIES;

For setting the effect we also need some additional functions:

This function creates an slot in openal to hold an effect.
function CreateAuxEffectSlot(var uiAuxEffectSlot: TALuint): TALboolean;
var
  bReturn: TALboolean;
begin
 bReturn := false;

 // Clear AL Error state
 alGetError();

 // Generate an Auxiliary Effect Slot
 alGenAuxiliaryEffectSlots(1, @uiAuxEffectSlot);
 if (alGetError() = AL_NO_ERROR) then
  bReturn := true;

 result := bReturn;
end;

This function creates/enables an effect and set the type for it so it can be used in OpenAL.
function CreateEffect(var uiEffect: TALuint; eEffectType: TALenum): TALboolean;
var
  bReturn: TALboolean;
begin
 bReturn := false;

  // Clear AL Error State
  alGetError();

  // Generate an Effect
  alGenEffects(1, @uiEffect);
  if (alGetError() = AL_NO_ERROR) then
  begin
   // Set the Effect Type
   alEffecti(uiEffect, AL_EFFECT_TYPE, eEffectType );
   if (alGetError() = AL_NO_ERROR) then
    bReturn := true
   else
    alDeleteEffects(1, @uiEffect);
  end;

 result := bReturn;
end;

This function sends the effect properties the from eax to efx converted effect to OpenAL.
function SetEFXEAXReverbProperties( pEFXEAXReverb: PEFXEAXREVERBPROPERTIES;  uiEffect: TALuint): TALboolean;
var
  bReturn: TALboolean;
begin
 bReturn := false;

  // Clear AL Error code
  alGetError();

  alEffectf(uiEffect, AL_EAXREVERB_DENSITY, pEFXEAXReverb.flDensity);
  alEffectf(uiEffect, AL_EAXREVERB_DIFFUSION, pEFXEAXReverb.flDiffusion);
  alEffectf(uiEffect, AL_EAXREVERB_GAIN, pEFXEAXReverb.flGain);
  alEffectf(uiEffect, AL_EAXREVERB_GAINHF, pEFXEAXReverb.flGainHF);
  alEffectf(uiEffect, AL_EAXREVERB_GAINLF, pEFXEAXReverb.flGainLF);
  alEffectf(uiEffect, AL_EAXREVERB_DECAY_TIME, pEFXEAXReverb.flDecayTime);
  alEffectf(uiEffect, AL_EAXREVERB_DECAY_HFRATIO, pEFXEAXReverb.flDecayHFRatio);
  alEffectf(uiEffect, AL_EAXREVERB_DECAY_LFRATIO, pEFXEAXReverb.flDecayLFRatio);
  alEffectf(uiEffect, AL_EAXREVERB_REFLECTIONS_GAIN, pEFXEAXReverb.flReflectionsGain);
  alEffectf(uiEffect, AL_EAXREVERB_REFLECTIONS_DELAY, pEFXEAXReverb.flReflectionsDelay);
  alEffectfv(uiEffect, AL_EAXREVERB_REFLECTIONS_PAN, @pEFXEAXReverb.flReflectionsPan);
  alEffectf(uiEffect, AL_EAXREVERB_LATE_REVERB_GAIN, pEFXEAXReverb.flLateReverbGain);
  alEffectf(uiEffect, AL_EAXREVERB_LATE_REVERB_DELAY, pEFXEAXReverb.flLateReverbDelay);
  alEffectfv(uiEffect, AL_EAXREVERB_LATE_REVERB_PAN, @pEFXEAXReverb.flLateReverbPan);
  alEffectf(uiEffect, AL_EAXREVERB_ECHO_TIME, pEFXEAXReverb.flEchoTime);
  alEffectf(uiEffect, AL_EAXREVERB_ECHO_DEPTH, pEFXEAXReverb.flEchoDepth);
  alEffectf(uiEffect, AL_EAXREVERB_MODULATION_TIME, pEFXEAXReverb.flModulationTime);
  alEffectf(uiEffect, AL_EAXREVERB_MODULATION_DEPTH, pEFXEAXReverb.flModulationDepth);
  alEffectf(uiEffect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, pEFXEAXReverb.flAirAbsorptionGainHF);
  alEffectf(uiEffect, AL_EAXREVERB_HFREFERENCE, pEFXEAXReverb.flHFReference);
  alEffectf(uiEffect, AL_EAXREVERB_LFREFERENCE, pEFXEAXReverb.flLFReference);
  alEffectf(uiEffect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, pEFXEAXReverb.flRoomRolloffFactor);
  alEffecti(uiEffect, AL_EAXREVERB_DECAY_HFLIMIT, pEFXEAXReverb.iDecayHFLimit);

  if (alGetError() = AL_NO_ERROR) then
   bReturn := true;

 result := bReturn;
end;

Now in FormCreate we need to initialize the EFX-Util library so we can use an effect defined as EAX. To do this we need to place:
ReadOpenALEFXUtil;
as an last line there.

After choosing an device we can try to read in extensions. Do not do this before as the number of available extensions may differ between different devices.
So after the last line of the SetDeviceClick function we need to add the following line:
ReadOpenALExtensions;

Now we are ready to create the effect.

In this case we recreate the eax bathroom effect.  
  eaxbathroom.ulEnvironment:=3;
  eaxbathroom.flEnvironmentSize:=1.4;
  eaxbathroom.flEnvironmentDiffusion:=1.000;
  eaxbathroom.lRoom:=-1000;
  eaxbathroom.lRoomHF:=-1200;
  eaxbathroom.lRoomLF:=0;
  eaxbathroom.flDecayTime:=1.49;
  eaxbathroom.flDecayHFRatio:=0.54;
  eaxbathroom.flDecayLFRatio:=1.00;
  eaxbathroom.lReflections:=-370;
  eaxbathroom.flReflectionsDelay:=0.007;
  eaxbathroom.vReflectionsPan.x:=0.0;
  eaxbathroom.vReflectionsPan.y:=0.0;
  eaxbathroom.vReflectionsPan.z:=0.0;
  eaxbathroom.lReverb:=1030;
  eaxbathroom.flReverbDelay:=0.011;
  eaxbathroom.vReverbPan.x:=0.00;
  eaxbathroom.vReverbPan.y:=0.00;
  eaxbathroom.vReverbPan.z:=0.00;
  eaxbathroom.flEchoTime:=0.250;
  eaxbathroom.flEchoDepth:=0.000;
  eaxbathroom.flModulationTime:=0.250;
  eaxbathroom.flModulationDepth:=0.000;
  eaxbathroom.flAirAbsorptionHF:=-5.0;
  eaxbathroom.flHFReference:=5000.0;
  eaxbathroom.flLFReference:=250.0;
  eaxbathroom.flRoomRolloffFactor:=0.00;
  eaxbathroom.ulFlags:=$3f;

Now we can create an effect slot:
CreateAuxEffectSlot(uiEffectSlot);
If that succeeds we can create the effect:
CreateEffect(uiEffect, AL_EFFECT_EAXREVERB));
If that also succeeds we can convert the effect from EAX to EFX with:
ConvertReverbParameters(@eaxBathroom, @efxReverb);
Now we can set the efx properties to the created effect:
SetEFXEAXReverbProperties(@efxReverb, uiEffect);
We are almost there but for the effect to workt we need to link the effect to the slot:
alAuxiliaryEffectSloti(uiEffectSlot, AL_EFFECTSLOT_EFFECT, uiEffect);

Now if we play the sound there is still no heareable effect. That is because we have not yet assigned the effect to an source.

So after whe place the following lines just before the openal play command we should be able to hear the effect:
if EffectEnabled.Checked then
    alSource3i(source, AL_AUXILIARY_SEND_FILTER, uiEffectSlot, 0, AL_FILTER_NULL)
  else
    alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);

The line after the else removes the effect from an source. So we can enable and disable the effect.

Before closing our application we need to clean up the effects. So in Formclose we need to add the following lines in the beginning:
  alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
  alAuxiliaryEffectSloti(uiEffectSlot, AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
  alDeleteEffects(1, @uiEffect);
  alDeleteAuxiliaryEffectSlots(1, @uiEffectSlot);

For our next OpenAL EFX tutorial we are going a step deeper as there is much more possible with this then just applying a bathroom reverb effect.omming soon.

Only for some reason when i choose the hardware device the effect is always enabled on my pc even when it is not set to an source. Only in software it seems to function properly.