{-# LINE 1 "Sound/MikMod/Internal.hsc" #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LINE 2 "Sound/MikMod/Internal.hsc" #-}
module Sound.MikMod.Internal where

import Foreign
import Foreign.C.Types
import Foreign.C.String
import Data.Functor
import Control.Applicative
import System.IO.Unsafe
import Control.Exception

import Sound.MikMod.Synonyms
import Sound.MikMod.Types
import Sound.MikMod.Flags
import Sound.MikMod.Errors
import Sound.MikMod.MReader


{-# LINE 19 "Sound/MikMod/Internal.hsc" #-}

foreign import ccall "&MikMod_errno" c_MikMod_errno :: Ptr CInt
foreign import ccall "&MikMod_critical" c_MikMod_critical :: Ptr CInt

foreign import ccall "&md_musicvolume" c_md_musicvolume :: Ptr UBYTE
foreign import ccall "&md_pansep" c_md_pansep :: Ptr UBYTE
foreign import ccall "&md_reverb" c_md_reverb :: Ptr UBYTE
foreign import ccall "&md_sndfxvolume" c_md_sndfxvolume :: Ptr UBYTE
foreign import ccall "&md_volume" c_md_volume :: Ptr UBYTE

foreign import ccall "&md_device"  c_md_device  :: Ptr UWORD
foreign import ccall "&md_driver"  c_md_driver  :: Ptr (Ptr MDriver)
foreign import ccall "&md_mixfreq" c_md_mixfreq :: Ptr UWORD
foreign import ccall "&md_mode"    c_md_mode    :: Ptr UWORD

foreign import ccall safe "mikmod.h MikMod_Active" c_MikMod_Active :: IO BOOL
foreign import ccall safe "mikmod.h MikMod_DisableOutput" c_MikMod_DisableOutput :: IO ()
foreign import ccall safe "mikmod.h MikMod_EnableOutput" c_MikMod_EnableOutput :: IO ()
foreign import ccall safe "mikmod.h MikMod_Exit" c_MikMod_Exit :: IO ()
foreign import ccall safe "mikmod.h MikMod_GetVersion" c_MikMod_GetVersion :: IO CInt
foreign import ccall safe "mikmod.h MikMod_InfoDriver" c_MikMod_InfoDriver :: IO CString
foreign import ccall safe "mikmod.h MikMod_InfoLoader" c_MikMod_InfoLoader :: IO CString
foreign import ccall safe "mikmod.h MikMod_Init" c_MikMod_Init :: CString -> IO CInt
foreign import ccall safe "mikmod.h MikMod_InitThreads" c_MikMod_InitThreads :: IO CInt
foreign import ccall safe "mikmod.h MikMod_Lock" c_MikMod_Lock :: IO ()
foreign import ccall safe "mikmod.h MikMod_Unlock" c_MikMod_Unlock :: IO ()
foreign import ccall safe "mikmod.h MikMod_RegisterAllDrivers" c_MikMod_RegisterAllDrivers :: IO ()
foreign import ccall safe "mikmod.h MikMod_RegisterAllLoaders" c_MikMod_RegisterAllLoaders :: IO ()
foreign import ccall safe "mikmod.h MikMod_Reset" c_MikMod_Reset :: CString -> IO CInt
foreign import ccall safe "mikmod.h MikMod_SetNumVoices" c_MikMod_SetNumVoices :: CInt -> CInt -> IO CInt
foreign import ccall safe "mikmod.h MikMod_Update" c_MikMod_Update :: IO ()
foreign import ccall safe "mikmod.h MikMod_strerror" c_MikMod_strerror :: CInt -> IO CString

foreign import ccall safe "mikmod.h Player_Active" c_Player_Active :: IO CInt
foreign import ccall safe "mikmod.h Player_Free" c_Player_Free :: Ptr Module -> IO ()
foreign import ccall safe "mikmod.h Player_GetChannelVoice" c_Player_GetChannelVoice :: UBYTE -> IO SBYTE
foreign import ccall safe "mikmod.h Player_GetModule" c_Player_GetModule :: IO (Ptr Module)
foreign import ccall safe "mikmod.h Player_Load" c_Player_Load :: CString -> CInt -> CInt -> IO (Ptr Module)
foreign import ccall safe "mikmod.h Player_LoadGeneric" c_Player_LoadGeneric :: Ptr MREADER -> CInt -> CInt -> IO (Ptr Module)
foreign import ccall safe "mikmod.h Player_LoadTitle" c_Player_LoadTitle :: CString -> IO CString
foreign import ccall safe "mikmod.h Player_LoadTitleGeneric" c_Player_LoadTitleGeneric :: Ptr MREADER -> IO CString
foreign import ccall safe "mikmod.h Player_Mute" c_Player_MuteChannel :: CInt -> IO ()
foreign import ccall safe "mikmod.h Player_Mute" c_Player_MuteChannels :: CInt -> CInt -> CInt -> IO ()
foreign import ccall safe "mikmod.h Player_Muted" c_Player_Muted :: UBYTE -> IO CInt
foreign import ccall safe "mikmod.h Player_NextPosition" c_Player_NextPosition :: IO ()
foreign import ccall safe "mikmod.h Player_PrevPosition" c_Player_PrevPosition :: IO ()
foreign import ccall safe "mikmod.h Player_Paused" c_Player_Paused :: IO CInt
foreign import ccall safe "mikmod.h Player_SetPosition" c_Player_SetPosition :: UWORD -> IO ()
foreign import ccall safe "mikmod.h Player_SetSpeed" c_Player_SetSpeed :: UWORD -> IO ()
foreign import ccall safe "mikmod.h Player_SetTempo" c_Player_SetTempo :: UWORD -> IO ()
foreign import ccall safe "mikmod.h Player_SetVolume" c_Player_SetVolume :: SWORD -> IO ()
foreign import ccall safe "mikmod.h Player_Start" c_Player_Start :: Ptr Module -> IO ()
foreign import ccall safe "mikmod.h Player_Stop" c_Player_Stop :: IO ()
foreign import ccall safe "mikmod.h Player_ToggleMute" c_Player_ToggleMuteChannel :: CInt -> IO ()
foreign import ccall safe "mikmod.h Player_ToggleMute" c_Player_ToggleMuteChannels :: CInt -> CInt -> CInt -> IO ()
foreign import ccall safe "mikmod.h Player_TogglePause" c_Player_TogglePause :: IO ()
foreign import ccall safe "mikmod.h Player_Unmute" c_Player_UnmuteChannel :: CInt -> IO ()
foreign import ccall safe "mikmod.h Player_Unmute" c_Player_UnmuteChannels :: CInt -> CInt -> CInt -> IO ()

foreign import ccall safe "mikmod.h Sample_Free" c_Sample_Free :: Ptr Sample -> IO ()
foreign import ccall safe "mikmod.h Sample_Load" c_Sample_Load :: CString -> IO (Ptr Sample)
foreign import ccall safe "mikmod.h Sample_LoadGeneric" c_Sample_LoadGeneric :: Ptr MREADER -> IO (Ptr Sample)
foreign import ccall safe "mikmod.h Sample_Play" c_Sample_Play :: Ptr Sample -> ULONG -> UBYTE -> IO SBYTE

foreign import ccall safe "mikmod.h Voice_SetVolume" c_Voice_SetVolume :: SBYTE -> UWORD -> IO ()
foreign import ccall safe "mikmod.h Voice_GetVolume" c_Voice_GetVolume :: SBYTE -> IO UWORD
foreign import ccall safe "mikmod.h Voice_SetFrequency" c_Voice_SetFrequency :: SBYTE -> ULONG -> IO ()
foreign import ccall safe "mikmod.h Voice_GetFrequency" c_Voice_GetFrequency :: SBYTE -> IO ULONG
foreign import ccall safe "mikmod.h Voice_SetPanning" c_Voice_SetPanning :: SBYTE -> ULONG -> IO ()
foreign import ccall safe "mikmod.h Voice_GetPanning" c_Voice_GetPanning :: SBYTE -> IO ULONG
foreign import ccall safe "mikmod.h Voice_Play" c_Voice_Play :: SBYTE -> Ptr Sample -> ULONG -> IO ()
foreign import ccall safe "mikmod.h Voice_Stop" c_Voice_Stop :: SBYTE -> IO ()
foreign import ccall safe "mikmod.h Voice_Stopped" c_Voice_Stopped :: SBYTE -> IO BOOL
foreign import ccall safe "mikmod.h Voice_GetPosition" c_Voice_GetPosition :: SBYTE -> IO SLONG
foreign import ccall safe "mikmod.h Voice_RealVolume" c_Voice_RealVolume :: SBYTE -> IO ULONG

foreign import ccall safe "mikmod.h MikMod_free" c_MikMod_free :: Ptr a -> IO ()

marshalMuteOperation :: MuteOperation -> CInt
marshalMuteOperation MuteInclusive = (32001)
{-# LINE 99 "Sound/MikMod/Internal.hsc" #-}
marshalMuteOperation MuteExclusive = (32000)
{-# LINE 100 "Sound/MikMod/Internal.hsc" #-}

peekMDriver :: Ptr MDriver -> IO MDriverInfo
peekMDriver ptr = do
  name  <- peekCString =<< (peek (((\hsc_ptr -> hsc_ptr `plusPtr` 8)) ptr) :: IO CString)
{-# LINE 104 "Sound/MikMod/Internal.hsc" #-}
  alias <- peekCString =<< (peek (((\hsc_ptr -> hsc_ptr `plusPtr` 32)) ptr) :: IO CString)
{-# LINE 105 "Sound/MikMod/Internal.hsc" #-}
  hard  <- fromIntegral <$> (peek (((\hsc_ptr -> hsc_ptr `plusPtr` 24)) ptr) :: IO CUChar)
{-# LINE 106 "Sound/MikMod/Internal.hsc" #-}
  soft  <- fromIntegral <$> (peek (((\hsc_ptr -> hsc_ptr `plusPtr` 25)) ptr) :: IO CUChar)
{-# LINE 107 "Sound/MikMod/Internal.hsc" #-}
  return $ MDriverInfo name hard soft alias


-- | Query the current MikMod global errno and get the MikModError expressed
-- there, if any. This value is only valid if checked immediately after an
-- error occurs. If you are interested in MikModErrors use the ""Safe"" versions
-- of the API methods which return an Either MikModError.
mikmodGetError :: IO MikModError
mikmodGetError = do
  errno <- unmarshalMikModErrno <$> peek c_MikMod_errno
  crit  <- decodeBool <$> peek c_MikMod_critical
  if crit
    then return (Critical errno)
    else return (NonCritical errno)

sfxCritical :: UBYTE
sfxCritical = (1)
{-# LINE 124 "Sound/MikMod/Internal.hsc" #-}

marshalCurious :: Num a => CuriousFlag -> a
marshalCurious Curious = 1
marshalCurious NotCurious = 0

mikmodGetString :: IO CString -> IO (Maybe String)
mikmodGetString query = do
  ptr <- query
  if (ptr == nullPtr)
    then return Nothing
    else
      Just <$> peekCString ptr
      `finally`
      c_MikMod_free ptr