{-# LANGUAGE ForeignFunctionInterface #-} {-# OPTIONS_HADDOCK hide #-} -------------------------------------------------------------------------------- -- | -- Module : Sound.OpenAL.ALC.QueryUtils -- Copyright : (c) Sven Panne 2003-2013 -- License : BSD3 -- -- Maintainer : Sven Panne -- Stability : stable -- Portability : portable -- -------------------------------------------------------------------------------- module Sound.OpenAL.ALC.QueryUtils ( StringQuery(..), getString, getStringRaw, IntQuery(..), marshalIntQuery, getInteger, getIntegerv, alcIsExtensionPresent ) where import Control.Monad ( when ) import Graphics.Rendering.OpenGL.GL.StateVar import Foreign.C.Types import Foreign.Marshal.Array ( withArray, peekArray ) import Foreign.Ptr ( Ptr ) import Sound.OpenAL.ALC.ALCboolean ( unmarshalALCboolean ) import Sound.OpenAL.ALC.BasicTypes ( ALCboolean, ALCchar, ALCint, ALCenum, ALCsizei ) import Sound.OpenAL.ALC.String ( withALCString, peekALCString ) import Sound.OpenAL.Config ( Device, ALCdevice(..), nullDevice, marshalDevice ) import Sound.OpenAL.Constants ( alc_DEFAULT_DEVICE_SPECIFIER, alc_DEVICE_SPECIFIER, alc_EXTENSIONS, alc_CAPTURE_DEFAULT_DEVICE_SPECIFIER, alc_CAPTURE_DEVICE_SPECIFIER, alc_ATTRIBUTES_SIZE, alc_ALL_ATTRIBUTES, alc_MAJOR_VERSION, alc_MINOR_VERSION, alc_CAPTURE_SAMPLES ) -------------------------------------------------------------------------------- data StringQuery = DefaultDeviceSpecifier | DeviceSpecifier | Extensions | CaptureDefaultDeviceSpecifier | CaptureDeviceSpecifier | ALCErrorCategory ALCenum marshalStringQuery :: StringQuery -> ALCenum marshalStringQuery x = case x of DefaultDeviceSpecifier -> alc_DEFAULT_DEVICE_SPECIFIER DeviceSpecifier -> alc_DEVICE_SPECIFIER Extensions -> alc_EXTENSIONS CaptureDefaultDeviceSpecifier -> alc_CAPTURE_DEFAULT_DEVICE_SPECIFIER CaptureDeviceSpecifier -> alc_CAPTURE_DEVICE_SPECIFIER ALCErrorCategory e -> e -------------------------------------------------------------------------------- getString :: Maybe Device -> StringQuery -> IO String getString device query = getStringRaw device query >>= peekALCString getStringRaw :: Maybe Device -> StringQuery -> IO (Ptr ALCchar) getStringRaw maybeDevice = alcGetString (marshalMaybeDevice maybeDevice) . marshalStringQuery marshalMaybeDevice :: Maybe Device -> ALCdevice marshalMaybeDevice = marshalDevice . maybe nullDevice id foreign import ccall unsafe "alcGetString" alcGetString :: ALCdevice -> ALCenum -> IO (Ptr ALCchar) -------------------------------------------------------------------------------- data IntQuery = AttributesSize | AllAttributes | MajorVersion | MinorVersion | CaptureSamples marshalIntQuery :: IntQuery -> ALCenum marshalIntQuery x = case x of AttributesSize -> alc_ATTRIBUTES_SIZE AllAttributes -> alc_ALL_ATTRIBUTES MajorVersion -> alc_MAJOR_VERSION MinorVersion -> alc_MINOR_VERSION CaptureSamples -> alc_CAPTURE_SAMPLES -------------------------------------------------------------------------------- getInteger :: Maybe Device -> IntQuery -> IO ALCint getInteger maybeDevice query = fmap head $ getIntegerv maybeDevice query 1 -- We are extremely careful below to avoid segfaults in case that there is no -- current context, an invalid device, etc. getIntegerv :: Maybe Device -> IntQuery -> ALCsizei -> IO [ALCint] getIntegerv maybeDevice query numALCints = let n = fromIntegral numALCints in withArray (replicate n 0) $ \buf -> do when (numALCints > 0) $ alcGetIntegerv (marshalMaybeDevice maybeDevice) (marshalIntQuery query) numALCints buf peekArray n buf foreign import ccall unsafe "alcGetIntegerv" alcGetIntegerv :: ALCdevice -> ALCenum -> ALCsizei -> Ptr ALCint -> IO () -------------------------------------------------------------------------------- -- | To verify that a given extension is available for the current context and -- the device it is associated with, use 'alcIsExtensionPresent'. For invalid -- and unsupported string tokens it contains 'False'. Using 'Nothing' as the -- device is acceptable. The extension name is not case sensitive: The -- implementation will convert the name to all upper-case internally (and will -- express extension names in upper-case). alcIsExtensionPresent :: Maybe Device -> String -> GettableStateVar Bool alcIsExtensionPresent maybeDevice extensionName = makeGettableStateVar $ fmap unmarshalALCboolean $ withALCString extensionName $ alcIsExtensionPresent_ (marshalMaybeDevice maybeDevice) foreign import ccall unsafe "alcIsExtensionPresent" alcIsExtensionPresent_ :: ALCdevice -> Ptr ALCchar -> IO ALCboolean