    --------------------------------------------------------------------------------
    -- |
    -- Module      :  Sound.OpenAL.AL.Doppler
    -- Copyright   :  (c) Sven Panne 2005
    -- License     :  BSD-style (see the file libraries/OpenAL/LICENSE)
    --
    -- Maintainer  :  sven.panne@aedion.de
    -- Stability   :  provisional
    -- Portability :  portable
    --
    -- This module corresponds to section 3.5.2. (Velocity Dependent Doppler Effect)
    -- of the OpenAL Specification and Reference (version 1.1).
    --
    --------------------------------------------------------------------------------

    module Sound.OpenAL.AL.Doppler (
       -- * Introduction
       -- $Introduction
       dopplerFactor, speedOfSound
    ) where

    import Foreign.Ptr ( FunPtr )
    import Graphics.Rendering.OpenGL.GL.StateVar (
       HasGetter(get), StateVar, makeStateVar )
    import Sound.OpenAL.AL.BasicTypes ( ALenum, ALfloat )
    import Sound.OpenAL.AL.Extensions ( alProcAddress )
    import Sound.OpenAL.AL.QueryUtils (
       GetPName(GetDopplerFactor,GetSpeedOfSound), marshalGetPName )

    #ifdef __HADDOCK__
    import Sound.OpenAL.AL.Errors ( ALError(ALInvalidValue) )
    #endif

    --------------------------------------------------------------------------------

    -- | 'dopplerFactor' is a simple scaling of source and listener velocities to
    -- exaggerate or deemphasize the Doppler (pitch) shift resulting from the
    -- calculation. Setting 'dopplerFactor' to a negative value will result in an
    -- 'ALInvalidValue' error, the command is then ignored. The default value is 1.
    -- The implementation is free to optimize the case of 'dopplerFactor' containing
    -- zero, as this effectively disables the effect.

    dopplerFactor :: StateVar ALfloat
    dopplerFactor = makeDopplerVar GetDopplerFactor "alDopplerFactor"

    --------------------------------------------------------------------------------

    -- | 'speedOfSound' allows the application to change the reference (propagation)
    -- speed used in the Doppler calculation. The source and listener velocities
    -- should be expressed in the same units as the speed of sound. Setting
    -- 'speedOfSound' to a negative or zero value will result in an 'ALInvalidValue'
    -- error, the command is ignored then. The default value is 343.3 (appropriate
    -- for velocity units of meters and air as the propagation medium).

    speedOfSound :: StateVar ALfloat
    speedOfSound = makeDopplerVar GetSpeedOfSound "alSpeedOfSound"

    --------------------------------------------------------------------------------

    makeDopplerVar :: GetPName -> String -> StateVar ALfloat
    makeDopplerVar p apiEntryName =
       makeStateVar
          (alGetFloat (marshalGetPName p))
          (\value -> do
             -- ToDo: Should we check alcVersion or alIsExtensionPresent here?
             funPtr <- get (alProcAddress apiEntryName)
             invokeWithFloat funPtr value)

    foreign import CALLCONV unsafe "alGetFloat"
       alGetFloat :: ALenum -> IO ALfloat

    type Invoker a = FunPtr a -> a

    foreign import CALLCONV unsafe "dynamic"
       invokeWithFloat :: Invoker (ALfloat -> IO ())

    --------------------------------------------------------------------------------
    -- $Introduction
    -- The Doppler Effect depends on the velocities of source and listener relative
    -- to the medium, and the propagation speed of sound in that medium.  The
    -- application might want to emphasize or de-emphasize the Doppler Effect as
    -- physically accurate calculation might not give the desired results.
    -- The amount of frequency shift (pitch change) is proportional to the speed of
    -- listener and source along their line of sight.
    --
    -- The Doppler Effect as implemented by OpenAL is described in detail in section
    -- 3.5.2 of the OpenAL 1.1 specification. Note that effects of the medium (air,
    -- water) moving with respect to listener and source are ignored. There are two
    -- API calls global to the current context that provide control of the Doppler
    -- factor and the speed of sound. Distance and velocity units are completely
    -- independent of one another (so you could use different units for each if
    -- desired).