    {-# LANGUAGE DerivingStrategies #-}
    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    {-# LANGUAGE LambdaCase #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE PatternSynonyms #-}
    {-# LANGUAGE RecordWildCards #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE TypeFamilies #-}

    -- |
    --
    -- Module      : SDL.Mixer
    -- License     : BSD3
    -- Stability   : experimental
    --
    -- Bindings to the @SDL2_mixer@ library.
    module SDL.Mixer
      ( -- * Audio setup

        --

        -- | In order to use the rest of the library, you need to
        -- supply 'withAudio' or 'openAudio' with an 'Audio' configuration.
        withAudio,
        Audio (..),
        Format (..),
        Output (..),
        defaultAudio,
        ChunkSize,
        queryAudio,

        -- ** Alternative
        openAudio,
        closeAudio,

        -- * Loading audio data

        --

        -- | Use 'load' or 'decode' to get both 'Chunk' and 'Music' values.
        Loadable (..),
        Chunk (..),
        chunkDecoders,
        Music (..),
        musicDecoders,

        -- * Chunks

        --

        -- | 'Chunk's are played on 'Channel's, which can be combined into 'Group's.

        -- ** Playing chunks
        Channel,
        pattern AllChannels,
        setChannels,
        getChannels,
        play,
        playForever,
        Times,
        pattern Once,
        pattern Forever,
        playOn,
        Milliseconds,
        Limit,
        pattern NoLimit,
        playLimit,
        fadeIn,
        fadeInOn,
        fadeInLimit,

        -- ** Grouping channels
        reserveChannels,
        Group,
        pattern DefaultGroup,
        group,
        groupSpan,
        groupCount,
        getAvailable,
        getOldest,
        getNewest,

        -- ** Controlling playback
        pause,
        resume,
        halt,
        haltAfter,
        haltGroup,

        -- ** Setting the volume
        Volume,
        HasVolume (..),

        -- ** Querying for status
        playing,
        playingCount,
        paused,
        pausedCount,
        playedLast,
        Fading,
        fading,

        -- ** Fading out
        fadeOut,
        fadeOutGroup,

        -- ** Reacting to finish
        whenChannelFinished,

        -- * Music

        --

        -- | 'Chunk's and 'Music' differ by the way they are played. While multiple
        -- 'Chunk's can be played on different desired 'Channel's at the same time,
        -- there can only be one 'Music' playing at the same time.
        --
        -- Therefore, the functions used for 'Music' are separate.

        -- ** Playing music
        playMusic,
        Position,
        fadeInMusic,
        fadeInMusicAt,
        fadeInMusicAtMOD,

        -- ** Controlling playback
        pauseMusic,
        haltMusic,
        resumeMusic,
        rewindMusic,
        setMusicPosition,
        setMusicPositionMOD,

        -- ** Setting the volume
        setMusicVolume,
        getMusicVolume,

        -- ** Querying for status
        playingMusic,
        pausedMusic,
        fadingMusic,
        MusicType (..),
        musicType,
        playingMusicType,

        -- ** Fading out
        fadeOutMusic,

        -- ** Reacting to finish
        whenMusicFinished,

        -- * Effects
        Effect,
        EffectFinished,
        pattern PostProcessing,
        effect,

        -- ** In-built effects
        effectPan,
        effectDistance,
        effectPosition,
        effectReverseStereo,

        -- * Other
        initialize,
        InitFlag (..),
        quit,
        version,
      )
    where

    import Control.Exception (throwIO)
    import Control.Exception.Lifted (finally)
    import Control.Monad (forM, void, when, (<=<), (>=>))
    import Control.Monad.IO.Class (MonadIO, liftIO)
    import Control.Monad.Trans.Control (MonadBaseControl)
    import Data.Bits ((.&.), (.|.))
    import Data.ByteString as BS (ByteString, readFile)
    import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
    import Data.Default.Class (Default (def))
    import Data.IORef (IORef, newIORef, readIORef, writeIORef)
    import Data.Int (Int16)
    import Data.Vector.Storable.Mutable (IOVector, unsafeFromForeignPtr0)
    import Data.Word (Word8)
    import Foreign.C.String (peekCString)
    import Foreign.C.Types (CInt)
    import Foreign.ForeignPtr (castForeignPtr, newForeignPtr_)
    import Foreign.Marshal.Alloc (alloca)
    import Foreign.Ptr (FunPtr, Ptr, castPtr, freeHaskellFunPtr, nullFunPtr, nullPtr)
    import Foreign.Storable (Storable (peek))
    import SDL (SDLException (SDLCallFailed))
    import SDL.Internal.Exception
      ( getError,
        throwIf0,
        throwIfNeg,
        throwIfNeg_,
        throwIfNull,
        throwIf_,
      )
    import qualified SDL.Raw
    import SDL.Raw.Filesystem (rwFromConstMem)
    import qualified SDL.Raw.Mixer
    import System.IO.Unsafe (unsafePerformIO)

    -- | Initialize the library by loading support for a certain set of
    -- sample/music formats.
    --
    -- Note that calling this is not strictly necessary: support for a certain
    -- format will be loaded automatically when attempting to load data in that
    -- format. Using 'initialize' allows you to decide /when/ to load support.
    --
    -- You may call this function multiple times.
    initialize :: (Foldable f, MonadIO m) => f InitFlag -> m ()
    initialize :: forall (f :: * -> *) (m :: * -> *).
    (Foldable f, MonadIO m) =>
    f InitFlag -> m ()
    initialize f InitFlag
    flags = do
      let raw :: CInt
    raw = (CInt -> InitFlag -> CInt) -> CInt -> f InitFlag -> CInt
    forall b a. (b -> a -> b) -> b -> f a -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl (\CInt
    a InitFlag
    b -> CInt
    a CInt -> CInt -> CInt
    forall a. Bits a => a -> a -> a
    .|. InitFlag -> CInt
    initToCInt InitFlag
    b) CInt
    0 f InitFlag
    flags
      (CInt -> Bool) -> Text -> Text -> m CInt -> m ()
    forall (m :: * -> *) a.
    MonadIO m =>
    (a -> Bool) -> Text -> Text -> m a -> m ()
    throwIf_ ((CInt -> CInt -> Bool
    forall a. Eq a => a -> a -> Bool
    /= CInt
    raw) (CInt -> Bool) -> (CInt -> CInt) -> CInt -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (CInt -> CInt -> CInt
    forall a. Bits a => a -> a -> a
    .&. CInt
    raw)) Text
    "SDL.Mixer.initialize" Text
    "Mix_Init" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.init CInt
    raw

    -- | Used with 'initialize' to designate loading support for a particular
    -- sample/music format.
    data InitFlag
      = InitFLAC
      | InitMOD
      | InitMP3
      | InitOGG
      deriving stock (InitFlag -> InitFlag -> Bool
    (InitFlag -> InitFlag -> Bool)
    -> (InitFlag -> InitFlag -> Bool) -> Eq InitFlag
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: InitFlag -> InitFlag -> Bool
    == :: InitFlag -> InitFlag -> Bool
    $c/= :: InitFlag -> InitFlag -> Bool
    /= :: InitFlag -> InitFlag -> Bool
    Eq, Eq InitFlag
    Eq InitFlag =>
    (InitFlag -> InitFlag -> Ordering)
    -> (InitFlag -> InitFlag -> Bool)
    -> (InitFlag -> InitFlag -> Bool)
    -> (InitFlag -> InitFlag -> Bool)
    -> (InitFlag -> InitFlag -> Bool)
    -> (InitFlag -> InitFlag -> InitFlag)
    -> (InitFlag -> InitFlag -> InitFlag)
    -> Ord InitFlag
    InitFlag -> InitFlag -> Bool
    InitFlag -> InitFlag -> Ordering
    InitFlag -> InitFlag -> InitFlag
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: InitFlag -> InitFlag -> Ordering
    compare :: InitFlag -> InitFlag -> Ordering
    $c< :: InitFlag -> InitFlag -> Bool
    < :: InitFlag -> InitFlag -> Bool
    $c<= :: InitFlag -> InitFlag -> Bool
    <= :: InitFlag -> InitFlag -> Bool
    $c> :: InitFlag -> InitFlag -> Bool
    > :: InitFlag -> InitFlag -> Bool
    $c>= :: InitFlag -> InitFlag -> Bool
    >= :: InitFlag -> InitFlag -> Bool
    $cmax :: InitFlag -> InitFlag -> InitFlag
    max :: InitFlag -> InitFlag -> InitFlag
    $cmin :: InitFlag -> InitFlag -> InitFlag
    min :: InitFlag -> InitFlag -> InitFlag
    Ord, InitFlag
    InitFlag -> InitFlag -> Bounded InitFlag
    forall a. a -> a -> Bounded a
    $cminBound :: InitFlag
    minBound :: InitFlag
    $cmaxBound :: InitFlag
    maxBound :: InitFlag
    Bounded, ReadPrec [InitFlag]
    ReadPrec InitFlag
    Volume -> ReadS InitFlag
    ReadS [InitFlag]
    (Volume -> ReadS InitFlag)
    -> ReadS [InitFlag]
    -> ReadPrec InitFlag
    -> ReadPrec [InitFlag]
    -> Read InitFlag
    forall a.
    (Volume -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Volume -> ReadS InitFlag
    readsPrec :: Volume -> ReadS InitFlag
    $creadList :: ReadS [InitFlag]
    readList :: ReadS [InitFlag]
    $creadPrec :: ReadPrec InitFlag
    readPrec :: ReadPrec InitFlag
    $creadListPrec :: ReadPrec [InitFlag]
    readListPrec :: ReadPrec [InitFlag]
    Read, Volume -> InitFlag -> ShowS
    [InitFlag] -> ShowS
    InitFlag -> String
    (Volume -> InitFlag -> ShowS)
    -> (InitFlag -> String) -> ([InitFlag] -> ShowS) -> Show InitFlag
    forall a.
    (Volume -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Volume -> InitFlag -> ShowS
    showsPrec :: Volume -> InitFlag -> ShowS
    $cshow :: InitFlag -> String
    show :: InitFlag -> String
    $cshowList :: [InitFlag] -> ShowS
    showList :: [InitFlag] -> ShowS
    Show)

    initToCInt :: InitFlag -> CInt
    initToCInt :: InitFlag -> CInt
    initToCInt = \case
      InitFlag
    InitFLAC -> CInt
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.INIT_FLAC
      InitFlag
    InitMOD -> CInt
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.INIT_MOD
      InitFlag
    InitMP3 -> CInt
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.INIT_MP3
      InitFlag
    InitOGG -> CInt
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.INIT_OGG

    -- | Cleans up any loaded libraries, freeing memory.
    quit :: MonadIO m => m ()
    quit :: forall (m :: * -> *). MonadIO m => m ()
    quit = m ()
    forall (m :: * -> *). MonadIO m => m ()
    SDL.Raw.Mixer.quit -- FIXME: May not free all init'd libs! Check docs.

    -- | Gets the major, minor, patch versions of the linked @SDL2_mixer@ library.
    version :: (Integral a, MonadIO m) => m (a, a, a)
    version :: forall a (m :: * -> *). (Integral a, MonadIO m) => m (a, a, a)
    version = IO (a, a, a) -> m (a, a, a)
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO (a, a, a) -> m (a, a, a)) -> IO (a, a, a) -> m (a, a, a)
    forall a b. (a -> b) -> a -> b
    $ do
      SDL.Raw.Version major minor patch <- Ptr Version -> IO Version
    forall a. Storable a => Ptr a -> IO a
    peek (Ptr Version -> IO Version) -> IO (Ptr Version) -> IO Version
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< IO (Ptr Version)
    forall (m :: * -> *). MonadIO m => m (Ptr Version)
    SDL.Raw.Mixer.getVersion
      return (fromIntegral major, fromIntegral minor, fromIntegral patch)

    -- | Initializes the @SDL2_mixer@ API.
    --
    -- This should be the first function you call after initializing @SDL@ itself
    -- with 'SDL.Init.InitAudio'.
    --
    -- Automatically cleans up the API when the inner computation finishes.
    withAudio ::
      (MonadBaseControl IO m, MonadIO m) => Audio -> ChunkSize -> m a -> m a
    withAudio :: forall (m :: * -> *) a.
    (MonadBaseControl IO m, MonadIO m) =>
    Audio -> Volume -> m a -> m a
    withAudio Audio
    conf Volume
    csize m a
    act = do
      Audio -> Volume -> m ()
    forall (m :: * -> *). MonadIO m => Audio -> Volume -> m ()
    openAudio Audio
    conf Volume
    csize
      m a -> m () -> m a
    forall (m :: * -> *) a b.
    MonadBaseControl IO m =>
    m a -> m b -> m a
    finally m a
    act m ()
    forall (m :: * -> *). MonadIO m => m ()
    closeAudio

    -- | An alternative to 'withAudio', also initializes the @SDL2_mixer@ API.
    --
    -- However, 'openAudio' does not take care of automatically calling
    -- 'closeAudio' after a computation ends, so you have to take care to do so
    -- manually.
    openAudio :: MonadIO m => Audio -> ChunkSize -> m ()
    openAudio :: forall (m :: * -> *). MonadIO m => Audio -> Volume -> m ()
    openAudio Audio {Volume
    Output
    Format
    audioFrequency :: Volume
    audioFormat :: Format
    audioOutput :: Output
    audioOutput :: Audio -> Output
    audioFormat :: Audio -> Format
    audioFrequency :: Audio -> Volume
    ..} Volume
    chunkSize =
      Text -> Text -> m CInt -> m ()
    forall (m :: * -> *) a.
    (MonadIO m, Num a, Ord a) =>
    Text -> Text -> m a -> m ()
    throwIfNeg_ Text
    "SDL.Mixer.openAudio" Text
    "Mix_OpenAudio" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        CInt -> Format -> CInt -> CInt -> m CInt
    forall {m :: * -> *}.
    MonadIO m =>
    CInt -> Format -> CInt -> CInt -> m CInt
    SDL.Raw.Mixer.openAudio
          (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    audioFrequency)
          (Format -> Format
    formatToWord Format
    audioFormat)
          (Output -> CInt
    outputToCInt Output
    audioOutput)
          (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    chunkSize)

    -- | An audio configuration. Use this with 'withAudio'.
    data Audio = Audio
      { -- | A sampling frequency.
        Audio -> Volume
    audioFrequency :: Int,
        -- | An output sample format.
        Audio -> Format
    audioFormat :: Format,
        -- | 'Mono' or 'Stereo' output.
        Audio -> Output
    audioOutput :: Output
      }
      deriving stock (Audio -> Audio -> Bool
    (Audio -> Audio -> Bool) -> (Audio -> Audio -> Bool) -> Eq Audio
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Audio -> Audio -> Bool
    == :: Audio -> Audio -> Bool
    $c/= :: Audio -> Audio -> Bool
    /= :: Audio -> Audio -> Bool
    Eq, ReadPrec [Audio]
    ReadPrec Audio
    Volume -> ReadS Audio
    ReadS [Audio]
    (Volume -> ReadS Audio)
    -> ReadS [Audio]
    -> ReadPrec Audio
    -> ReadPrec [Audio]
    -> Read Audio
    forall a.
    (Volume -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Volume -> ReadS Audio
    readsPrec :: Volume -> ReadS Audio
    $creadList :: ReadS [Audio]
    readList :: ReadS [Audio]
    $creadPrec :: ReadPrec Audio
    readPrec :: ReadPrec Audio
    $creadListPrec :: ReadPrec [Audio]
    readListPrec :: ReadPrec [Audio]
    Read, Volume -> Audio -> ShowS
    [Audio] -> ShowS
    Audio -> String
    (Volume -> Audio -> ShowS)
    -> (Audio -> String) -> ([Audio] -> ShowS) -> Show Audio
    forall a.
    (Volume -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Volume -> Audio -> ShowS
    showsPrec :: Volume -> Audio -> ShowS
    $cshow :: Audio -> String
    show :: Audio -> String
    $cshowList :: [Audio] -> ShowS
    showList :: [Audio] -> ShowS
    Show)

    instance Default Audio where
      def :: Audio
    def =
        Audio
          { audioFrequency :: Volume
    audioFrequency = Volume
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.DEFAULT_FREQUENCY,
            audioFormat :: Format
    audioFormat = Format -> Format
    wordToFormat Format
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.DEFAULT_FORMAT,
            audioOutput :: Output
    audioOutput = CInt -> Output
    cIntToOutput CInt
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.DEFAULT_CHANNELS
          }

    -- | A default 'Audio' configuration.
    --
    -- Same as 'Data.Default.Class.def'.
    --
    -- Uses 22050 as the 'audioFrequency', 'FormatS16_Sys' as the 'audioFormat' and
    -- 'Stereo' as the 'audioOutput'.
    defaultAudio :: Audio
    defaultAudio :: Audio
    defaultAudio = Audio
    forall a. Default a => a
    def

    -- | The size of each mixed sample.
    --
    -- The smaller this is, the more often callbacks will be invoked. If this is
    -- made too small on a slow system, the sounds may skip. If made too large,
    -- sound effects could lag.
    type ChunkSize = Int

    -- | A sample format.
    data Format
      = -- | Unsigned 8-bit samples.
        FormatU8
      | -- | Signed 8-bit samples.
        FormatS8
      | -- | Unsigned 16-bit samples, in little-endian byte order.
        FormatU16_LSB
      | -- | Signed 16-bit samples, in little-endian byte order.
        FormatS16_LSB
      | -- | Unsigned 16-bit samples, in big-endian byte order.
        FormatU16_MSB
      | -- | signed 16-bit samples, in big-endian byte order.
        FormatS16_MSB
      | -- | Unsigned 16-bit samples, in system byte order.
        FormatU16_Sys
      | -- | Signed 16-bit samples, in system byte order.
        FormatS16_Sys
      deriving stock (Format -> Format -> Bool
    (Format -> Format -> Bool)
    -> (Format -> Format -> Bool) -> Eq Format
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Format -> Format -> Bool
    == :: Format -> Format -> Bool
    $c/= :: Format -> Format -> Bool
    /= :: Format -> Format -> Bool
    Eq, Eq Format
    Eq Format =>
    (Format -> Format -> Ordering)
    -> (Format -> Format -> Bool)
    -> (Format -> Format -> Bool)
    -> (Format -> Format -> Bool)
    -> (Format -> Format -> Bool)
    -> (Format -> Format -> Format)
    -> (Format -> Format -> Format)
    -> Ord Format
    Format -> Format -> Bool
    Format -> Format -> Ordering
    Format -> Format -> Format
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Format -> Format -> Ordering
    compare :: Format -> Format -> Ordering
    $c< :: Format -> Format -> Bool
    < :: Format -> Format -> Bool
    $c<= :: Format -> Format -> Bool
    <= :: Format -> Format -> Bool
    $c> :: Format -> Format -> Bool
    > :: Format -> Format -> Bool
    $c>= :: Format -> Format -> Bool
    >= :: Format -> Format -> Bool
    $cmax :: Format -> Format -> Format
    max :: Format -> Format -> Format
    $cmin :: Format -> Format -> Format
    min :: Format -> Format -> Format
    Ord, Format
    Format -> Format -> Bounded Format
    forall a. a -> a -> Bounded a
    $cminBound :: Format
    minBound :: Format
    $cmaxBound :: Format
    maxBound :: Format
    Bounded, ReadPrec [Format]
    ReadPrec Format
    Volume -> ReadS Format
    ReadS [Format]
    (Volume -> ReadS Format)
    -> ReadS [Format]
    -> ReadPrec Format
    -> ReadPrec [Format]
    -> Read Format
    forall a.
    (Volume -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Volume -> ReadS Format
    readsPrec :: Volume -> ReadS Format
    $creadList :: ReadS [Format]
    readList :: ReadS [Format]
    $creadPrec :: ReadPrec Format
    readPrec :: ReadPrec Format
    $creadListPrec :: ReadPrec [Format]
    readListPrec :: ReadPrec [Format]
    Read, Volume -> Format -> ShowS
    [Format] -> ShowS
    Format -> String
    (Volume -> Format -> ShowS)
    -> (Format -> String) -> ([Format] -> ShowS) -> Show Format
    forall a.
    (Volume -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Volume -> Format -> ShowS
    showsPrec :: Volume -> Format -> ShowS
    $cshow :: Format -> String
    show :: Format -> String
    $cshowList :: [Format] -> ShowS
    showList :: [Format] -> ShowS
    Show)

    formatToWord :: Format -> SDL.Raw.Mixer.Format
    formatToWord :: Format -> Format
    formatToWord = \case
      Format
    FormatU8 -> Format
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.AUDIO_U8
      Format
    FormatS8 -> Format
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.AUDIO_S8
      Format
    FormatU16_LSB -> Format
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.AUDIO_U16LSB
      Format
    FormatS16_LSB -> Format
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.AUDIO_S16LSB
      Format
    FormatU16_MSB -> Format
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.AUDIO_U16MSB
      Format
    FormatS16_MSB -> Format
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.AUDIO_S16MSB
      Format
    FormatU16_Sys -> Format
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.AUDIO_U16SYS
      Format
    FormatS16_Sys -> Format
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.AUDIO_S16SYS

    wordToFormat :: SDL.Raw.Mixer.Format -> Format
    wordToFormat :: Format -> Format
    wordToFormat = \case
      Format
    SDL.Raw.Mixer.AUDIO_U8 -> Format
    FormatU8
      Format
    SDL.Raw.Mixer.AUDIO_S8 -> Format
    FormatS8
      Format
    SDL.Raw.Mixer.AUDIO_U16LSB -> Format
    FormatU16_LSB
      Format
    SDL.Raw.Mixer.AUDIO_S16LSB -> Format
    FormatS16_LSB
      Format
    SDL.Raw.Mixer.AUDIO_U16MSB -> Format
    FormatU16_MSB
      Format
    SDL.Raw.Mixer.AUDIO_S16MSB -> Format
    FormatS16_MSB
      Format
    SDL.Raw.Mixer.AUDIO_U16SYS -> Format
    FormatU16_Sys
      Format
    SDL.Raw.Mixer.AUDIO_S16SYS -> Format
    FormatS16_Sys
      Format
    _ -> String -> Format
    forall a. HasCallStack => String -> a
    error String
    "SDL.Mixer.wordToFormat: unknown Format."

    -- | The number of sound channels in output.
    data Output = Mono | Stereo
      deriving stock (Output -> Output -> Bool
    (Output -> Output -> Bool)
    -> (Output -> Output -> Bool) -> Eq Output
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Output -> Output -> Bool
    == :: Output -> Output -> Bool
    $c/= :: Output -> Output -> Bool
    /= :: Output -> Output -> Bool
    Eq, Eq Output
    Eq Output =>
    (Output -> Output -> Ordering)
    -> (Output -> Output -> Bool)
    -> (Output -> Output -> Bool)
    -> (Output -> Output -> Bool)
    -> (Output -> Output -> Bool)
    -> (Output -> Output -> Output)
    -> (Output -> Output -> Output)
    -> Ord Output
    Output -> Output -> Bool
    Output -> Output -> Ordering
    Output -> Output -> Output
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Output -> Output -> Ordering
    compare :: Output -> Output -> Ordering
    $c< :: Output -> Output -> Bool
    < :: Output -> Output -> Bool
    $c<= :: Output -> Output -> Bool
    <= :: Output -> Output -> Bool
    $c> :: Output -> Output -> Bool
    > :: Output -> Output -> Bool
    $c>= :: Output -> Output -> Bool
    >= :: Output -> Output -> Bool
    $cmax :: Output -> Output -> Output
    max :: Output -> Output -> Output
    $cmin :: Output -> Output -> Output
    min :: Output -> Output -> Output
    Ord, Output
    Output -> Output -> Bounded Output
    forall a. a -> a -> Bounded a
    $cminBound :: Output
    minBound :: Output
    $cmaxBound :: Output
    maxBound :: Output
    Bounded, ReadPrec [Output]
    ReadPrec Output
    Volume -> ReadS Output
    ReadS [Output]
    (Volume -> ReadS Output)
    -> ReadS [Output]
    -> ReadPrec Output
    -> ReadPrec [Output]
    -> Read Output
    forall a.
    (Volume -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Volume -> ReadS Output
    readsPrec :: Volume -> ReadS Output
    $creadList :: ReadS [Output]
    readList :: ReadS [Output]
    $creadPrec :: ReadPrec Output
    readPrec :: ReadPrec Output
    $creadListPrec :: ReadPrec [Output]
    readListPrec :: ReadPrec [Output]
    Read, Volume -> Output -> ShowS
    [Output] -> ShowS
    Output -> String
    (Volume -> Output -> ShowS)
    -> (Output -> String) -> ([Output] -> ShowS) -> Show Output
    forall a.
    (Volume -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Volume -> Output -> ShowS
    showsPrec :: Volume -> Output -> ShowS
    $cshow :: Output -> String
    show :: Output -> String
    $cshowList :: [Output] -> ShowS
    showList :: [Output] -> ShowS
    Show)

    outputToCInt :: Output -> CInt
    outputToCInt :: Output -> CInt
    outputToCInt = \case
      Output
    Mono -> CInt
    1
      Output
    Stereo -> CInt
    2

    cIntToOutput :: CInt -> Output
    cIntToOutput :: CInt -> Output
    cIntToOutput = \case
      CInt
    1 -> Output
    Mono
      CInt
    2 -> Output
    Stereo
      CInt
    _ -> String -> Output
    forall a. HasCallStack => String -> a
    error String
    "SDL.Mixer.cIntToOutput: unknown number of channels."

    -- | Get the audio format in use by the opened audio device.
    --
    -- This may or may not match the 'Audio' you asked for when calling
    -- 'withAudio'.
    queryAudio :: MonadIO m => m Audio
    queryAudio :: forall (m :: * -> *). MonadIO m => m Audio
    queryAudio =
      IO Audio -> m Audio
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO
        (IO Audio -> m Audio)
    -> ((Ptr CInt -> IO Audio) -> IO Audio)
    -> (Ptr CInt -> IO Audio)
    -> m Audio
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Ptr CInt -> IO Audio) -> IO Audio
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
    alloca
        ((Ptr CInt -> IO Audio) -> m Audio)
    -> (Ptr CInt -> IO Audio) -> m Audio
    forall a b. (a -> b) -> a -> b
    $ \Ptr CInt
    freq ->
          (Ptr Format -> IO Audio) -> IO Audio
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
    alloca ((Ptr Format -> IO Audio) -> IO Audio)
    -> (Ptr Format -> IO Audio) -> IO Audio
    forall a b. (a -> b) -> a -> b
    $ \Ptr Format
    form ->
            (Ptr CInt -> IO Audio) -> IO Audio
    forall a b. Storable a => (Ptr a -> IO b) -> IO b
    alloca ((Ptr CInt -> IO Audio) -> IO Audio)
    -> (Ptr CInt -> IO Audio) -> IO Audio
    forall a b. (a -> b) -> a -> b
    $ \Ptr CInt
    chan -> do
              IO CInt -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO CInt -> IO ()) -> (IO CInt -> IO CInt) -> IO CInt -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text -> IO CInt -> IO CInt
    forall a (m :: * -> *).
    (Eq a, MonadIO m, Num a) =>
    Text -> Text -> m a -> m a
    throwIf0 Text
    "SDL.Mixer.queryAudio" Text
    "Mix_QuerySpec" (IO CInt -> IO ()) -> IO CInt -> IO ()
    forall a b. (a -> b) -> a -> b
    $
                Ptr CInt -> Ptr Format -> Ptr CInt -> IO CInt
    forall {m :: * -> *}.
    MonadIO m =>
    Ptr CInt -> Ptr Format -> Ptr CInt -> m CInt
    SDL.Raw.Mixer.querySpec Ptr CInt
    freq Ptr Format
    form Ptr CInt
    chan
              Volume -> Format -> Output -> Audio
    Audio
                (Volume -> Format -> Output -> Audio)
    -> IO Volume -> IO (Format -> Output -> Audio)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Volume) -> IO CInt -> IO Volume
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr CInt -> IO CInt
    forall a. Storable a => Ptr a -> IO a
    peek Ptr CInt
    freq)
                IO (Format -> Output -> Audio) -> IO Format -> IO (Output -> Audio)
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> (Format -> Format
    wordToFormat (Format -> Format) -> IO Format -> IO Format
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr Format -> IO Format
    forall a. Storable a => Ptr a -> IO a
    peek Ptr Format
    form)
                IO (Output -> Audio) -> IO Output -> IO Audio
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> (CInt -> Output
    cIntToOutput (CInt -> Output) -> IO CInt -> IO Output
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr CInt -> IO CInt
    forall a. Storable a => Ptr a -> IO a
    peek Ptr CInt
    chan)

    -- | Shut down and clean up the @SDL2_mixer@ API.
    --
    -- After calling this, all audio stops.
    --
    -- You don't have to call this if you're using 'withAudio'.
    closeAudio :: MonadIO m => m ()
    closeAudio :: forall (m :: * -> *). MonadIO m => m ()
    closeAudio = m ()
    forall (m :: * -> *). MonadIO m => m ()
    SDL.Raw.Mixer.closeAudio

    -- | A class of all values that can be loaded from some source. You can load
    -- both 'Chunk's and 'Music' this way.
    --
    -- Note that you must call 'withAudio' before using these, since they have to
    -- know the audio configuration to properly convert the data for playback.
    class Loadable a where
      -- | Load the value from a 'ByteString'.
      decode :: MonadIO m => ByteString -> m a

      -- | Same as 'decode', but loads from a file instead.
      load :: MonadIO m => FilePath -> m a
      load = ByteString -> m a
    forall a (m :: * -> *).
    (Loadable a, MonadIO m) =>
    ByteString -> m a
    forall (m :: * -> *). MonadIO m => ByteString -> m a
    decode (ByteString -> m a) -> (String -> m ByteString) -> String -> m a
    forall (m :: * -> *) b c a.
    Monad m =>
    (b -> m c) -> (a -> m b) -> a -> m c
    <=< (IO ByteString -> m ByteString
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO ByteString -> m ByteString)
    -> (String -> IO ByteString) -> String -> m ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> IO ByteString
    BS.readFile)

      -- | Frees the value's memory. It should no longer be used.
      --
      -- __Note that you shouldn't free those values that are currently playing.__
      free :: MonadIO m => a -> m ()

    -- | A volume, where 0 is silent and 128 loudest.
    --
    -- 'Volume's lesser than 0 or greater than 128 function as if they are 0 and
    -- 128, respectively.
    type Volume = Int

    volumeToCInt :: Volume -> CInt
    volumeToCInt :: Volume -> CInt
    volumeToCInt = Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Volume -> CInt) -> (Volume -> Volume) -> Volume -> CInt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Volume -> Volume -> Volume
    forall a. Ord a => a -> a -> a
    max Volume
    0 (Volume -> Volume) -> (Volume -> Volume) -> Volume -> Volume
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Volume -> Volume -> Volume
    forall a. Ord a => a -> a -> a
    min Volume
    128

    -- | A class of all values that have a 'Volume'.
    class HasVolume a where
      -- | Gets the value's currently set 'Volume'.
      --
      -- If the value is a 'Channel' and 'AllChannels' is used, gets the /average/
      -- 'Volume' of all 'Channel's.
      getVolume :: MonadIO m => a -> m Volume

      -- | Sets a value's 'Volume'.
      --
      -- If the value is a 'Chunk', the volume setting only takes effect when the
      -- 'Chunk' is used on a 'Channel', being mixed into the output.
      --
      -- In case of being used on a 'Channel', the volume setting takes effect
      -- during the final mix, along with the 'Chunk' volume. For instance, setting
      -- the 'Volume' of a certain 'Channel' to 64 will halve the volume of all
      -- 'Chunk's played on that 'Channel'. If 'AllChannels' is used, sets all
      -- 'Channel's to the given 'Volume' instead.
      setVolume :: MonadIO m => Volume -> a -> m ()

    -- | Returns the names of all chunk decoders currently available.
    --
    -- These depend on the availability of shared libraries for each of the
    -- formats. The list may contain any of the following, and possibly others:
    -- @WAVE@, @AIFF@, @VOC@, @OFF@, @FLAC@, @MP3@.
    chunkDecoders :: MonadIO m => m [String]
    chunkDecoders :: forall (m :: * -> *). MonadIO m => m [String]
    chunkDecoders =
      IO [String] -> m [String]
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO [String] -> m [String]) -> IO [String] -> m [String]
    forall a b. (a -> b) -> a -> b
    $ do
        num <- IO CInt
    forall (m :: * -> *). MonadIO m => m CInt
    SDL.Raw.Mixer.getNumChunkDecoders
        forM [0 .. num - 1] $ SDL.Raw.Mixer.getChunkDecoder >=> peekCString

    -- | A loaded audio chunk.
    newtype Chunk = Chunk (Ptr SDL.Raw.Mixer.Chunk)
      deriving stock (Chunk -> Chunk -> Bool
    (Chunk -> Chunk -> Bool) -> (Chunk -> Chunk -> Bool) -> Eq Chunk
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Chunk -> Chunk -> Bool
    == :: Chunk -> Chunk -> Bool
    $c/= :: Chunk -> Chunk -> Bool
    /= :: Chunk -> Chunk -> Bool
    Eq, Volume -> Chunk -> ShowS
    [Chunk] -> ShowS
    Chunk -> String
    (Volume -> Chunk -> ShowS)
    -> (Chunk -> String) -> ([Chunk] -> ShowS) -> Show Chunk
    forall a.
    (Volume -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Volume -> Chunk -> ShowS
    showsPrec :: Volume -> Chunk -> ShowS
    $cshow :: Chunk -> String
    show :: Chunk -> String
    $cshowList :: [Chunk] -> ShowS
    showList :: [Chunk] -> ShowS
    Show)

    instance Loadable Chunk where
      decode :: forall (m :: * -> *). MonadIO m => ByteString -> m Chunk
    decode ByteString
    bytes = IO Chunk -> m Chunk
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Chunk -> m Chunk) -> IO Chunk -> m Chunk
    forall a b. (a -> b) -> a -> b
    $ do
        ByteString -> (CStringLen -> IO Chunk) -> IO Chunk
    forall a. ByteString -> (CStringLen -> IO a) -> IO a
    unsafeUseAsCStringLen ByteString
    bytes ((CStringLen -> IO Chunk) -> IO Chunk)
    -> (CStringLen -> IO Chunk) -> IO Chunk
    forall a b. (a -> b) -> a -> b
    $ \(CString
    cstr, Volume
    len) -> do
          rw <- Ptr () -> CInt -> IO (Ptr RWops)
    forall (m :: * -> *). MonadIO m => Ptr () -> CInt -> m (Ptr RWops)
    rwFromConstMem (CString -> Ptr ()
    forall a b. Ptr a -> Ptr b
    castPtr CString
    cstr) (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    len)
          fmap Chunk
            . throwIfNull "SDL.Mixer.decode<Chunk>" "Mix_LoadWAV_RW"
            $ SDL.Raw.Mixer.loadWAV_RW rw 0

      free :: forall (m :: * -> *). MonadIO m => Chunk -> m ()
    free (Chunk Ptr Chunk
    p) = IO () -> m ()
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> m ()) -> IO () -> m ()
    forall a b. (a -> b) -> a -> b
    $ Ptr Chunk -> IO ()
    forall {m :: * -> *}. MonadIO m => Ptr Chunk -> m ()
    SDL.Raw.Mixer.freeChunk Ptr Chunk
    p

    instance HasVolume Chunk where
      getVolume :: forall (m :: * -> *). MonadIO m => Chunk -> m Volume
    getVolume (Chunk Ptr Chunk
    p) = CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Volume) -> m CInt -> m Volume
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr Chunk -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => Ptr Chunk -> CInt -> m CInt
    SDL.Raw.Mixer.volumeChunk Ptr Chunk
    p (-CInt
    1)
      setVolume :: forall (m :: * -> *). MonadIO m => Volume -> Chunk -> m ()
    setVolume Volume
    v (Chunk Ptr Chunk
    p) = m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> (CInt -> m CInt) -> CInt -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Ptr Chunk -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => Ptr Chunk -> CInt -> m CInt
    SDL.Raw.Mixer.volumeChunk Ptr Chunk
    p (CInt -> m ()) -> CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ Volume -> CInt
    volumeToCInt Volume
    v

    -- | A mixing channel.
    --
    -- Use the 'Integral' instance to define these: the first channel is 0, the
    -- second 1 and so on.
    --
    -- The default number of 'Channel's available at startup is 8, so note that you
    -- cannot usemore than these starting 8 if you haven't created more with
    -- 'setChannels'.
    --
    -- The starting 'Volume' of each 'Channel' is the maximum: 128.
    newtype Channel = Channel CInt
      deriving stock (Channel -> Channel -> Bool
    (Channel -> Channel -> Bool)
    -> (Channel -> Channel -> Bool) -> Eq Channel
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Channel -> Channel -> Bool
    == :: Channel -> Channel -> Bool
    $c/= :: Channel -> Channel -> Bool
    /= :: Channel -> Channel -> Bool
    Eq, Eq Channel
    Eq Channel =>
    (Channel -> Channel -> Ordering)
    -> (Channel -> Channel -> Bool)
    -> (Channel -> Channel -> Bool)
    -> (Channel -> Channel -> Bool)
    -> (Channel -> Channel -> Bool)
    -> (Channel -> Channel -> Channel)
    -> (Channel -> Channel -> Channel)
    -> Ord Channel
    Channel -> Channel -> Bool
    Channel -> Channel -> Ordering
    Channel -> Channel -> Channel
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Channel -> Channel -> Ordering
    compare :: Channel -> Channel -> Ordering
    $c< :: Channel -> Channel -> Bool
    < :: Channel -> Channel -> Bool
    $c<= :: Channel -> Channel -> Bool
    <= :: Channel -> Channel -> Bool
    $c> :: Channel -> Channel -> Bool
    > :: Channel -> Channel -> Bool
    $c>= :: Channel -> Channel -> Bool
    >= :: Channel -> Channel -> Bool
    $cmax :: Channel -> Channel -> Channel
    max :: Channel -> Channel -> Channel
    $cmin :: Channel -> Channel -> Channel
    min :: Channel -> Channel -> Channel
    Ord)
      deriving newtype (Volume -> Channel
    Channel -> Volume
    Channel -> [Channel]
    Channel -> Channel
    Channel -> Channel -> [Channel]
    Channel -> Channel -> Channel -> [Channel]
    (Channel -> Channel)
    -> (Channel -> Channel)
    -> (Volume -> Channel)
    -> (Channel -> Volume)
    -> (Channel -> [Channel])
    -> (Channel -> Channel -> [Channel])
    -> (Channel -> Channel -> [Channel])
    -> (Channel -> Channel -> Channel -> [Channel])
    -> Enum Channel
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Volume -> a)
    -> (a -> Volume)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: Channel -> Channel
    succ :: Channel -> Channel
    $cpred :: Channel -> Channel
    pred :: Channel -> Channel
    $ctoEnum :: Volume -> Channel
    toEnum :: Volume -> Channel
    $cfromEnum :: Channel -> Volume
    fromEnum :: Channel -> Volume
    $cenumFrom :: Channel -> [Channel]
    enumFrom :: Channel -> [Channel]
    $cenumFromThen :: Channel -> Channel -> [Channel]
    enumFromThen :: Channel -> Channel -> [Channel]
    $cenumFromTo :: Channel -> Channel -> [Channel]
    enumFromTo :: Channel -> Channel -> [Channel]
    $cenumFromThenTo :: Channel -> Channel -> Channel -> [Channel]
    enumFromThenTo :: Channel -> Channel -> Channel -> [Channel]
    Enum, Enum Channel
    Real Channel
    (Real Channel, Enum Channel) =>
    (Channel -> Channel -> Channel)
    -> (Channel -> Channel -> Channel)
    -> (Channel -> Channel -> Channel)
    -> (Channel -> Channel -> Channel)
    -> (Channel -> Channel -> (Channel, Channel))
    -> (Channel -> Channel -> (Channel, Channel))
    -> (Channel -> Integer)
    -> Integral Channel
    Channel -> Integer
    Channel -> Channel -> (Channel, Channel)
    Channel -> Channel -> Channel
    forall a.
    (Real a, Enum a) =>
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> (a, a))
    -> (a -> a -> (a, a))
    -> (a -> Integer)
    -> Integral a
    $cquot :: Channel -> Channel -> Channel
    quot :: Channel -> Channel -> Channel
    $crem :: Channel -> Channel -> Channel
    rem :: Channel -> Channel -> Channel
    $cdiv :: Channel -> Channel -> Channel
    div :: Channel -> Channel -> Channel
    $cmod :: Channel -> Channel -> Channel
    mod :: Channel -> Channel -> Channel
    $cquotRem :: Channel -> Channel -> (Channel, Channel)
    quotRem :: Channel -> Channel -> (Channel, Channel)
    $cdivMod :: Channel -> Channel -> (Channel, Channel)
    divMod :: Channel -> Channel -> (Channel, Channel)
    $ctoInteger :: Channel -> Integer
    toInteger :: Channel -> Integer
    Integral, Num Channel
    Ord Channel
    (Num Channel, Ord Channel) => (Channel -> Rational) -> Real Channel
    Channel -> Rational
    forall a. (Num a, Ord a) => (a -> Rational) -> Real a
    $ctoRational :: Channel -> Rational
    toRational :: Channel -> Rational
    Real, Integer -> Channel
    Channel -> Channel
    Channel -> Channel -> Channel
    (Channel -> Channel -> Channel)
    -> (Channel -> Channel -> Channel)
    -> (Channel -> Channel -> Channel)
    -> (Channel -> Channel)
    -> (Channel -> Channel)
    -> (Channel -> Channel)
    -> (Integer -> Channel)
    -> Num Channel
    forall a.
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (Integer -> a)
    -> Num a
    $c+ :: Channel -> Channel -> Channel
    + :: Channel -> Channel -> Channel
    $c- :: Channel -> Channel -> Channel
    - :: Channel -> Channel -> Channel
    $c* :: Channel -> Channel -> Channel
    * :: Channel -> Channel -> Channel
    $cnegate :: Channel -> Channel
    negate :: Channel -> Channel
    $cabs :: Channel -> Channel
    abs :: Channel -> Channel
    $csignum :: Channel -> Channel
    signum :: Channel -> Channel
    $cfromInteger :: Integer -> Channel
    fromInteger :: Integer -> Channel
    Num)

    instance Show Channel where
      show :: Channel -> String
    show = \case
        Channel
    AllChannels -> String
    "AllChannels"
        Channel CInt
    c -> String
    "Channel " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ CInt -> String
    forall a. Show a => a -> String
    show CInt
    c

    -- The lowest-numbered channel is CHANNEL_POST, or -2, for post processing
    -- effects. This function makes sure a channel is higher than CHANNEL_POST.
    clipChan :: CInt -> CInt
    clipChan :: CInt -> CInt
    clipChan = CInt -> CInt -> CInt
    forall a. Ord a => a -> a -> a
    max CInt
    forall {a}. (Eq a, Num a) => a
    SDL.Raw.Mixer.CHANNEL_POST

    -- | Prepares a given number of 'Channel's for use.
    --
    -- There are 8 such 'Channel's already prepared for use after 'withAudio' is
    -- called.
    --
    -- You may call this multiple times, even with sounds playing. If setting a
    -- lesser number of 'Channel's than are currently in use, the higher 'Channel's
    -- will be stopped, their finish callbacks invoked, and their memory freed.
    -- Passing in 0 or less will therefore stop and free all mixing channels.
    --
    -- Any 'Music' playing is not affected by this function.
    setChannels :: MonadIO m => Int -> m ()
    setChannels :: forall (m :: * -> *). MonadIO m => Volume -> m ()
    setChannels = m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> (Volume -> m CInt) -> Volume -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.allocateChannels (CInt -> m CInt) -> (Volume -> CInt) -> Volume -> m CInt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Volume -> CInt) -> (Volume -> Volume) -> Volume -> CInt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Volume -> Volume -> Volume
    forall a. Ord a => a -> a -> a
    max Volume
    0

    -- | Gets the number of 'Channel's currently in use.
    getChannels :: MonadIO m => m Int
    getChannels :: forall (m :: * -> *). MonadIO m => m Volume
    getChannels = CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Volume) -> m CInt -> m Volume
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.allocateChannels (-CInt
    1)

    -- | Reserve a given number of 'Channel's, starting from 'Channel' 0.
    --
    -- A reserved 'Channel' is considered not to be available for playing samples
    -- when using any 'play' or 'fadeIn' function variant with 'AllChannels'. In
    -- other words, whenever you let 'SDL.Mixer' pick the first available 'Channel'
    -- itself, these reserved 'Channel's will not be considered.
    reserveChannels :: MonadIO m => Int -> m Int
    reserveChannels :: forall (m :: * -> *). MonadIO m => Volume -> m Volume
    reserveChannels =
      (CInt -> Volume) -> m CInt -> m Volume
    forall a b. (a -> b) -> m a -> m b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (m CInt -> m Volume) -> (Volume -> m CInt) -> Volume -> m Volume
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.reserveChannels (CInt -> m CInt) -> (Volume -> CInt) -> Volume -> m CInt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral

    -- | Gets the most recent 'Chunk' played on a 'Channel', if any.
    --
    -- Using 'AllChannels' is not valid here, and will return 'Nothing'.
    --
    -- Note that the returned 'Chunk' might be invalid if it was already 'free'd.
    playedLast :: MonadIO m => Channel -> m (Maybe Chunk)
    playedLast :: forall (m :: * -> *). MonadIO m => Channel -> m (Maybe Chunk)
    playedLast (Channel CInt
    c) = do
      p <- CInt -> m (Ptr Chunk)
    forall {m :: * -> *}. MonadIO m => CInt -> m (Ptr Chunk)
    SDL.Raw.Mixer.getChunk (CInt -> m (Ptr Chunk)) -> CInt -> m (Ptr Chunk)
    forall a b. (a -> b) -> a -> b
    $ CInt -> CInt
    clipChan CInt
    c
      return $ if p == nullPtr then Nothing else Just (Chunk p)

    -- | Use this value when you wish to perform an operation on /all/ 'Channel's.
    --
    -- For more information, see each of the functions accepting a 'Channel'.
    pattern AllChannels :: Channel
    pattern $mAllChannels :: forall {r}. Channel -> ((# #) -> r) -> ((# #) -> r) -> r
    $bAllChannels :: Channel
    AllChannels = -1

    instance HasVolume Channel where
      setVolume :: forall (m :: * -> *). MonadIO m => Volume -> Channel -> m ()
    setVolume Volume
    v (Channel CInt
    c) =
        m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> (CInt -> m CInt) -> CInt -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> CInt -> m CInt
    SDL.Raw.Mixer.volume (CInt -> CInt
    clipChan CInt
    c) (CInt -> m ()) -> CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ Volume -> CInt
    volumeToCInt Volume
    v
      getVolume :: forall (m :: * -> *). MonadIO m => Channel -> m Volume
    getVolume (Channel CInt
    c) =
        CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Volume) -> m CInt -> m Volume
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> CInt -> m CInt
    SDL.Raw.Mixer.volume (CInt -> CInt
    clipChan CInt
    c) (-CInt
    1)

    -- | Play a 'Chunk' once, using the first available 'Channel'.
    play :: MonadIO m => Chunk -> m ()
    play :: forall (m :: * -> *). MonadIO m => Chunk -> m ()
    play = m Channel -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m Channel -> m ()) -> (Chunk -> m Channel) -> Chunk -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Channel -> Times -> Chunk -> m Channel
    forall (m :: * -> *).
    MonadIO m =>
    Channel -> Times -> Chunk -> m Channel
    playOn (-Channel
    1) Times
    Once

    -- | Same as 'play', but keeps playing the 'Chunk' forever.
    playForever :: MonadIO m => Chunk -> m ()
    playForever :: forall (m :: * -> *). MonadIO m => Chunk -> m ()
    playForever = m Channel -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m Channel -> m ()) -> (Chunk -> m Channel) -> Chunk -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Channel -> Times -> Chunk -> m Channel
    forall (m :: * -> *).
    MonadIO m =>
    Channel -> Times -> Chunk -> m Channel
    playOn (-Channel
    1) Times
    Forever

    -- | How many times should a certain 'Chunk' be played?
    newtype Times = Times CInt
      deriving stock (Times -> Times -> Bool
    (Times -> Times -> Bool) -> (Times -> Times -> Bool) -> Eq Times
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Times -> Times -> Bool
    == :: Times -> Times -> Bool
    $c/= :: Times -> Times -> Bool
    /= :: Times -> Times -> Bool
    Eq, Eq Times
    Eq Times =>
    (Times -> Times -> Ordering)
    -> (Times -> Times -> Bool)
    -> (Times -> Times -> Bool)
    -> (Times -> Times -> Bool)
    -> (Times -> Times -> Bool)
    -> (Times -> Times -> Times)
    -> (Times -> Times -> Times)
    -> Ord Times
    Times -> Times -> Bool
    Times -> Times -> Ordering
    Times -> Times -> Times
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Times -> Times -> Ordering
    compare :: Times -> Times -> Ordering
    $c< :: Times -> Times -> Bool
    < :: Times -> Times -> Bool
    $c<= :: Times -> Times -> Bool
    <= :: Times -> Times -> Bool
    $c> :: Times -> Times -> Bool
    > :: Times -> Times -> Bool
    $c>= :: Times -> Times -> Bool
    >= :: Times -> Times -> Bool
    $cmax :: Times -> Times -> Times
    max :: Times -> Times -> Times
    $cmin :: Times -> Times -> Times
    min :: Times -> Times -> Times
    Ord)
      deriving newtype (Volume -> Times
    Times -> Volume
    Times -> [Times]
    Times -> Times
    Times -> Times -> [Times]
    Times -> Times -> Times -> [Times]
    (Times -> Times)
    -> (Times -> Times)
    -> (Volume -> Times)
    -> (Times -> Volume)
    -> (Times -> [Times])
    -> (Times -> Times -> [Times])
    -> (Times -> Times -> [Times])
    -> (Times -> Times -> Times -> [Times])
    -> Enum Times
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Volume -> a)
    -> (a -> Volume)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: Times -> Times
    succ :: Times -> Times
    $cpred :: Times -> Times
    pred :: Times -> Times
    $ctoEnum :: Volume -> Times
    toEnum :: Volume -> Times
    $cfromEnum :: Times -> Volume
    fromEnum :: Times -> Volume
    $cenumFrom :: Times -> [Times]
    enumFrom :: Times -> [Times]
    $cenumFromThen :: Times -> Times -> [Times]
    enumFromThen :: Times -> Times -> [Times]
    $cenumFromTo :: Times -> Times -> [Times]
    enumFromTo :: Times -> Times -> [Times]
    $cenumFromThenTo :: Times -> Times -> Times -> [Times]
    enumFromThenTo :: Times -> Times -> Times -> [Times]
    Enum, Enum Times
    Real Times
    (Real Times, Enum Times) =>
    (Times -> Times -> Times)
    -> (Times -> Times -> Times)
    -> (Times -> Times -> Times)
    -> (Times -> Times -> Times)
    -> (Times -> Times -> (Times, Times))
    -> (Times -> Times -> (Times, Times))
    -> (Times -> Integer)
    -> Integral Times
    Times -> Integer
    Times -> Times -> (Times, Times)
    Times -> Times -> Times
    forall a.
    (Real a, Enum a) =>
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> (a, a))
    -> (a -> a -> (a, a))
    -> (a -> Integer)
    -> Integral a
    $cquot :: Times -> Times -> Times
    quot :: Times -> Times -> Times
    $crem :: Times -> Times -> Times
    rem :: Times -> Times -> Times
    $cdiv :: Times -> Times -> Times
    div :: Times -> Times -> Times
    $cmod :: Times -> Times -> Times
    mod :: Times -> Times -> Times
    $cquotRem :: Times -> Times -> (Times, Times)
    quotRem :: Times -> Times -> (Times, Times)
    $cdivMod :: Times -> Times -> (Times, Times)
    divMod :: Times -> Times -> (Times, Times)
    $ctoInteger :: Times -> Integer
    toInteger :: Times -> Integer
    Integral, Num Times
    Ord Times
    (Num Times, Ord Times) => (Times -> Rational) -> Real Times
    Times -> Rational
    forall a. (Num a, Ord a) => (a -> Rational) -> Real a
    $ctoRational :: Times -> Rational
    toRational :: Times -> Rational
    Real, Integer -> Times
    Times -> Times
    Times -> Times -> Times
    (Times -> Times -> Times)
    -> (Times -> Times -> Times)
    -> (Times -> Times -> Times)
    -> (Times -> Times)
    -> (Times -> Times)
    -> (Times -> Times)
    -> (Integer -> Times)
    -> Num Times
    forall a.
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (Integer -> a)
    -> Num a
    $c+ :: Times -> Times -> Times
    + :: Times -> Times -> Times
    $c- :: Times -> Times -> Times
    - :: Times -> Times -> Times
    $c* :: Times -> Times -> Times
    * :: Times -> Times -> Times
    $cnegate :: Times -> Times
    negate :: Times -> Times
    $cabs :: Times -> Times
    abs :: Times -> Times
    $csignum :: Times -> Times
    signum :: Times -> Times
    $cfromInteger :: Integer -> Times
    fromInteger :: Integer -> Times
    Num)

    -- | A shorthand for playing once.
    pattern Once :: Times
    pattern $mOnce :: forall {r}. Times -> ((# #) -> r) -> ((# #) -> r) -> r
    $bOnce :: Times
    Once = 1

    -- | A shorthand for looping a 'Chunk' forever.
    pattern Forever :: Times
    pattern $mForever :: forall {r}. Times -> ((# #) -> r) -> ((# #) -> r) -> r
    $bForever :: Times
    Forever = 0

    -- | Same as 'play', but plays the 'Chunk' using a given 'Channel' a certain
    -- number of 'Times'.
    --
    -- If 'AllChannels' is used, then plays the 'Chunk' using the first available
    -- 'Channel' instead.
    --
    -- Returns the 'Channel' that was used.
    playOn :: MonadIO m => Channel -> Times -> Chunk -> m Channel
    playOn :: forall (m :: * -> *).
    MonadIO m =>
    Channel -> Times -> Chunk -> m Channel
    playOn = Volume -> Channel -> Times -> Chunk -> m Channel
    forall (m :: * -> *).
    MonadIO m =>
    Volume -> Channel -> Times -> Chunk -> m Channel
    playLimit Volume
    NoLimit

    -- | A time in milliseconds.
    type Milliseconds = Int

    -- | An upper limit of time, in milliseconds.
    type Limit = Milliseconds

    -- | A lack of an upper limit.
    pattern NoLimit :: Limit
    pattern $mNoLimit :: forall {r}. Volume -> ((# #) -> r) -> ((# #) -> r) -> r
    $bNoLimit :: Volume
    NoLimit = -1

    -- | Same as 'playOn', but imposes an upper limit in 'Milliseconds' to how long
    -- the 'Chunk' can play.
    --
    -- The playing may still stop before the limit is reached.
    --
    -- This is the most generic play function variant.
    playLimit :: MonadIO m => Limit -> Channel -> Times -> Chunk -> m Channel
    playLimit :: forall (m :: * -> *).
    MonadIO m =>
    Volume -> Channel -> Times -> Chunk -> m Channel
    playLimit Volume
    l (Channel CInt
    c) (Times CInt
    t) (Chunk Ptr Chunk
    p) =
      Text -> Text -> m Channel -> m Channel
    forall (m :: * -> *) a.
    (MonadIO m, Num a, Ord a) =>
    Text -> Text -> m a -> m a
    throwIfNeg
        Text
    "SDL.Mixer.playLimit"
        Text
    "Mix_PlayChannelTimed"
        ( CInt -> Channel
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral
            (CInt -> Channel) -> m CInt -> m Channel
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> Ptr Chunk -> CInt -> CInt -> m CInt
    forall {m :: * -> *}.
    MonadIO m =>
    CInt -> Ptr Chunk -> CInt -> CInt -> m CInt
    SDL.Raw.Mixer.playChannelTimed
              (CInt -> CInt
    clipChan CInt
    c)
              Ptr Chunk
    p
              (CInt -> CInt -> CInt
    forall a. Ord a => a -> a -> a
    max (-CInt
    1) (CInt -> CInt) -> CInt -> CInt
    forall a b. (a -> b) -> a -> b
    $ CInt
    t CInt -> CInt -> CInt
    forall a. Num a => a -> a -> a
    - CInt
    1)
              (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    l)
        )

    -- | Same as 'play', but fades in the 'Chunk' by making the 'Channel' 'Volume'
    -- start at 0 and rise to a full 128 over the course of a given number of
    -- 'Milliseconds'.
    --
    -- The 'Chunk' may end playing before the fade-in is complete, if it doesn't
    -- last as long as the given fade-in time.
    fadeIn :: MonadIO m => Milliseconds -> Chunk -> m ()
    fadeIn :: forall (m :: * -> *). MonadIO m => Volume -> Chunk -> m ()
    fadeIn Volume
    ms = m Channel -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m Channel -> m ()) -> (Chunk -> m Channel) -> Chunk -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Channel -> Times -> Volume -> Chunk -> m Channel
    forall (m :: * -> *).
    MonadIO m =>
    Channel -> Times -> Volume -> Chunk -> m Channel
    fadeInOn Channel
    AllChannels Times
    Once Volume
    ms

    -- | Same as 'fadeIn', but allows you to specify the 'Channel' to play on and
    -- how many 'Times' to play it, similar to 'playOn'.
    --
    -- If 'AllChannels' is used, will play the 'Chunk' on the first available
    -- 'Channel'.
    --
    -- Returns the 'Channel' that was used.
    fadeInOn :: MonadIO m => Channel -> Times -> Milliseconds -> Chunk -> m Channel
    fadeInOn :: forall (m :: * -> *).
    MonadIO m =>
    Channel -> Times -> Volume -> Chunk -> m Channel
    fadeInOn = Volume -> Channel -> Times -> Volume -> Chunk -> m Channel
    forall (m :: * -> *).
    MonadIO m =>
    Volume -> Channel -> Times -> Volume -> Chunk -> m Channel
    fadeInLimit Volume
    NoLimit

    -- | Same as 'fadeInOn', but imposes an upper 'Limit' to how long the 'Chunk'
    -- can play, similar to 'playLimit'.
    --
    -- This is the most generic fade-in function variant.
    fadeInLimit ::
      MonadIO m =>
      Limit ->
      Channel ->
      Times ->
      Milliseconds ->
      Chunk ->
      m Channel
    fadeInLimit :: forall (m :: * -> *).
    MonadIO m =>
    Volume -> Channel -> Times -> Volume -> Chunk -> m Channel
    fadeInLimit Volume
    l (Channel CInt
    c) (Times CInt
    t) Volume
    ms (Chunk Ptr Chunk
    p) =
      Text -> Text -> m Channel -> m Channel
    forall (m :: * -> *) a.
    (MonadIO m, Num a, Ord a) =>
    Text -> Text -> m a -> m a
    throwIfNeg Text
    "SDL.Mixer.fadeInLimit" Text
    "Mix_FadeInChannelTimed" (m Channel -> m Channel) -> m Channel -> m Channel
    forall a b. (a -> b) -> a -> b
    $
        CInt -> Channel
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral
          (CInt -> Channel) -> m CInt -> m Channel
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> Ptr Chunk -> CInt -> CInt -> CInt -> m CInt
    forall {m :: * -> *}.
    MonadIO m =>
    CInt -> Ptr Chunk -> CInt -> CInt -> CInt -> m CInt
    SDL.Raw.Mixer.fadeInChannelTimed
            (CInt -> CInt
    clipChan CInt
    c)
            Ptr Chunk
    p
            (CInt -> CInt -> CInt
    forall a. Ord a => a -> a -> a
    max (-CInt
    1) (CInt -> CInt) -> CInt -> CInt
    forall a b. (a -> b) -> a -> b
    $ CInt
    t CInt -> CInt -> CInt
    forall a. Num a => a -> a -> a
    - CInt
    1)
            (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    ms)
            (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    l)

    -- | Gradually fade out a given playing 'Channel' during the next
    -- 'Milliseconds', even if it is 'pause'd.
    --
    -- If 'AllChannels' is used, fades out all the playing 'Channel's instead.
    fadeOut :: MonadIO m => Milliseconds -> Channel -> m ()
    fadeOut :: forall (m :: * -> *). MonadIO m => Volume -> Channel -> m ()
    fadeOut Volume
    ms (Channel CInt
    c) =
      m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ CInt -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> CInt -> m CInt
    SDL.Raw.Mixer.fadeOutChannel (CInt -> CInt
    clipChan CInt
    c) (CInt -> m CInt) -> CInt -> m CInt
    forall a b. (a -> b) -> a -> b
    $ Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    ms

    -- | Same as 'fadeOut', but fades out an entire 'Group' instead.
    --
    -- Using 'DefaultGroup' here is the same as calling 'fadeOut' with
    -- 'AllChannels'.
    fadeOutGroup :: MonadIO m => Milliseconds -> Group -> m ()
    fadeOutGroup :: forall (m :: * -> *). MonadIO m => Volume -> Group -> m ()
    fadeOutGroup Volume
    ms = \case
      Group
    DefaultGroup -> Volume -> Channel -> m ()
    forall (m :: * -> *). MonadIO m => Volume -> Channel -> m ()
    fadeOut Volume
    ms Channel
    AllChannels
      Group CInt
    g -> m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ CInt -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> CInt -> m CInt
    SDL.Raw.Mixer.fadeOutGroup CInt
    g (CInt -> m CInt) -> CInt -> m CInt
    forall a b. (a -> b) -> a -> b
    $ Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    ms

    -- | Pauses the given 'Channel', if it is actively playing.
    --
    -- If 'AllChannels' is used, will pause all actively playing 'Channel's
    -- instead.
    --
    -- Note that 'pause'd 'Channel's may still be 'halt'ed.
    pause :: MonadIO m => Channel -> m ()
    pause :: forall (m :: * -> *). MonadIO m => Channel -> m ()
    pause (Channel CInt
    c) = CInt -> m ()
    forall {m :: * -> *}. MonadIO m => CInt -> m ()
    SDL.Raw.Mixer.pause (CInt -> m ()) -> CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ CInt -> CInt
    clipChan CInt
    c

    -- | Resumes playing a 'Channel', or all 'Channel's if 'AllChannels' is used.
    resume :: MonadIO m => Channel -> m ()
    resume :: forall (m :: * -> *). MonadIO m => Channel -> m ()
    resume (Channel CInt
    c) = CInt -> m ()
    forall {m :: * -> *}. MonadIO m => CInt -> m ()
    SDL.Raw.Mixer.resume (CInt -> m ()) -> CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ CInt -> CInt
    clipChan CInt
    c

    -- | Halts playback on a 'Channel', or all 'Channel's if 'AllChannels' is used.
    halt :: MonadIO m => Channel -> m ()
    halt :: forall (m :: * -> *). MonadIO m => Channel -> m ()
    halt (Channel CInt
    c) = m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.haltChannel (CInt -> m CInt) -> CInt -> m CInt
    forall a b. (a -> b) -> a -> b
    $ CInt -> CInt
    clipChan CInt
    c

    -- | Same as 'halt', but only does so after a certain number of 'Milliseconds'.
    --
    -- If 'AllChannels' is used, it will halt all the 'Channel's after the given
    -- time instead.
    haltAfter :: MonadIO m => Milliseconds -> Channel -> m ()
    haltAfter :: forall (m :: * -> *). MonadIO m => Volume -> Channel -> m ()
    haltAfter Volume
    ms (Channel CInt
    c) =
      m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> (CInt -> m CInt) -> CInt -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> CInt -> m CInt
    SDL.Raw.Mixer.expireChannel (CInt -> CInt
    clipChan CInt
    c) (CInt -> m ()) -> CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    ms

    -- | Same as 'halt', but halts an entire 'Group' instead.
    --
    -- Note that using 'DefaultGroup' here is the same as calling 'halt'
    -- 'AllChannels'.
    haltGroup :: MonadIO m => Group -> m ()
    haltGroup :: forall (m :: * -> *). MonadIO m => Group -> m ()
    haltGroup = \case
      Group
    DefaultGroup -> Channel -> m ()
    forall (m :: * -> *). MonadIO m => Channel -> m ()
    halt Channel
    AllChannels
      Group CInt
    g -> m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.haltGroup (CInt -> m CInt) -> CInt -> m CInt
    forall a b. (a -> b) -> a -> b
    $ CInt -> CInt -> CInt
    forall a. Ord a => a -> a -> a
    max CInt
    0 CInt
    g

    -- Quackery of the highest order! We keep track of a pointer we gave SDL_mixer,
    -- so we can free it at a later time. May the gods have mercy...
    {-# NOINLINE channelFinishedFunPtr #-}
    channelFinishedFunPtr :: IORef (FunPtr (SDL.Raw.Mixer.Channel -> IO ()))
    channelFinishedFunPtr :: IORef (FunPtr (CInt -> IO ()))
    channelFinishedFunPtr = IO (IORef (FunPtr (CInt -> IO ())))
    -> IORef (FunPtr (CInt -> IO ()))
    forall a. IO a -> a
    unsafePerformIO (IO (IORef (FunPtr (CInt -> IO ())))
     -> IORef (FunPtr (CInt -> IO ())))
    -> IO (IORef (FunPtr (CInt -> IO ())))
    -> IORef (FunPtr (CInt -> IO ()))
    forall a b. (a -> b) -> a -> b
    $ FunPtr (CInt -> IO ()) -> IO (IORef (FunPtr (CInt -> IO ())))
    forall a. a -> IO (IORef a)
    newIORef FunPtr (CInt -> IO ())
    forall a. FunPtr a
    nullFunPtr

    -- | Sets a callback that gets invoked each time a 'Channel' finishes playing.
    --
    -- A 'Channel' finishes playing both when playback ends normally and when it is
    -- 'halt'ed (also possibly via 'setChannels').
    --
    -- __Note: don't call other 'SDL.Mixer' functions within this callback.__
    whenChannelFinished :: MonadIO m => (Channel -> IO ()) -> m ()
    whenChannelFinished :: forall (m :: * -> *). MonadIO m => (Channel -> IO ()) -> m ()
    whenChannelFinished Channel -> IO ()
    callback = IO () -> m ()
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> m ()) -> IO () -> m ()
    forall a b. (a -> b) -> a -> b
    $ do
      -- Sets the callback.
      let callback' :: CInt -> IO ()
    callback' = Channel -> IO ()
    callback (Channel -> IO ()) -> (CInt -> Channel) -> CInt -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> Channel
    Channel
      callbackRaw <- (CInt -> IO ()) -> IO (FunPtr (CInt -> IO ()))
    SDL.Raw.Mixer.wrapChannelCallback CInt -> IO ()
    callback'
      SDL.Raw.Mixer.channelFinished callbackRaw

      -- Free the function we set last time, if any.
      lastFunPtr <- readIORef channelFinishedFunPtr
      when (lastFunPtr /= nullFunPtr) $ freeHaskellFunPtr lastFunPtr

      -- Then remember the new one. And weep in shame.
      writeIORef channelFinishedFunPtr callbackRaw

    -- | Returns whether the given 'Channel' is playing or not.
    --
    -- If 'AllChannels' is used, this returns whether /any/ of the channels is
    -- currently playing.
    playing :: MonadIO m => Channel -> m Bool
    playing :: forall (m :: * -> *). MonadIO m => Channel -> m Bool
    playing (Channel CInt
    c) = (CInt -> CInt -> Bool
    forall a. Ord a => a -> a -> Bool
    > CInt
    0) (CInt -> Bool) -> m CInt -> m Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.playing (CInt -> CInt
    clipChan CInt
    c)

    -- | Returns how many 'Channel's are currently playing.
    playingCount :: MonadIO m => m Int
    playingCount :: forall (m :: * -> *). MonadIO m => m Volume
    playingCount = CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Volume) -> m CInt -> m Volume
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.playing (-CInt
    1)

    -- | Returns whether the given 'Channel' is paused or not.
    --
    -- If 'AllChannels' is used, this returns whether /any/ of the channels is
    -- currently paused.
    paused :: MonadIO m => Channel -> m Bool
    paused :: forall (m :: * -> *). MonadIO m => Channel -> m Bool
    paused (Channel CInt
    c) = (CInt -> CInt -> Bool
    forall a. Ord a => a -> a -> Bool
    > CInt
    0) (CInt -> Bool) -> m CInt -> m Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.paused (CInt -> CInt
    clipChan CInt
    c)

    -- | Returns how many 'Channel's are currently paused.
    pausedCount :: MonadIO m => m Int
    pausedCount :: forall (m :: * -> *). MonadIO m => m Volume
    pausedCount = CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Volume) -> m CInt -> m Volume
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.paused (-CInt
    1)

    -- | Describes whether a 'Channel' is fading in, out, or not at all.
    data Fading = NoFading | FadingIn | FadingOut
      deriving stock (Fading -> Fading -> Bool
    (Fading -> Fading -> Bool)
    -> (Fading -> Fading -> Bool) -> Eq Fading
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Fading -> Fading -> Bool
    == :: Fading -> Fading -> Bool
    $c/= :: Fading -> Fading -> Bool
    /= :: Fading -> Fading -> Bool
    Eq, Eq Fading
    Eq Fading =>
    (Fading -> Fading -> Ordering)
    -> (Fading -> Fading -> Bool)
    -> (Fading -> Fading -> Bool)
    -> (Fading -> Fading -> Bool)
    -> (Fading -> Fading -> Bool)
    -> (Fading -> Fading -> Fading)
    -> (Fading -> Fading -> Fading)
    -> Ord Fading
    Fading -> Fading -> Bool
    Fading -> Fading -> Ordering
    Fading -> Fading -> Fading
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Fading -> Fading -> Ordering
    compare :: Fading -> Fading -> Ordering
    $c< :: Fading -> Fading -> Bool
    < :: Fading -> Fading -> Bool
    $c<= :: Fading -> Fading -> Bool
    <= :: Fading -> Fading -> Bool
    $c> :: Fading -> Fading -> Bool
    > :: Fading -> Fading -> Bool
    $c>= :: Fading -> Fading -> Bool
    >= :: Fading -> Fading -> Bool
    $cmax :: Fading -> Fading -> Fading
    max :: Fading -> Fading -> Fading
    $cmin :: Fading -> Fading -> Fading
    min :: Fading -> Fading -> Fading
    Ord, Volume -> Fading -> ShowS
    [Fading] -> ShowS
    Fading -> String
    (Volume -> Fading -> ShowS)
    -> (Fading -> String) -> ([Fading] -> ShowS) -> Show Fading
    forall a.
    (Volume -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Volume -> Fading -> ShowS
    showsPrec :: Volume -> Fading -> ShowS
    $cshow :: Fading -> String
    show :: Fading -> String
    $cshowList :: [Fading] -> ShowS
    showList :: [Fading] -> ShowS
    Show, ReadPrec [Fading]
    ReadPrec Fading
    Volume -> ReadS Fading
    ReadS [Fading]
    (Volume -> ReadS Fading)
    -> ReadS [Fading]
    -> ReadPrec Fading
    -> ReadPrec [Fading]
    -> Read Fading
    forall a.
    (Volume -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Volume -> ReadS Fading
    readsPrec :: Volume -> ReadS Fading
    $creadList :: ReadS [Fading]
    readList :: ReadS [Fading]
    $creadPrec :: ReadPrec Fading
    readPrec :: ReadPrec Fading
    $creadListPrec :: ReadPrec [Fading]
    readListPrec :: ReadPrec [Fading]
    Read)

    wordToFading :: SDL.Raw.Mixer.Fading -> Fading
    wordToFading :: MusicType -> Fading
    wordToFading = \case
      MusicType
    SDL.Raw.Mixer.NO_FADING -> Fading
    NoFading
      MusicType
    SDL.Raw.Mixer.FADING_IN -> Fading
    FadingIn
      MusicType
    SDL.Raw.Mixer.FADING_OUT -> Fading
    FadingOut
      MusicType
    _ -> String -> Fading
    forall a. HasCallStack => String -> a
    error String
    "SDL.Mixer.wordToFading: unknown Fading value."

    -- | Returns a `Channel`'s 'Fading' status.
    --
    -- Note that using 'AllChannels' here is not valid, and will simply return the
    -- 'Fading' status of the first 'Channel' instead.
    fading :: MonadIO m => Channel -> m Fading
    fading :: forall (m :: * -> *). MonadIO m => Channel -> m Fading
    fading (Channel CInt
    c) =
      MusicType -> Fading
    wordToFading (MusicType -> Fading) -> m MusicType -> m Fading
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> m MusicType
    forall {m :: * -> *}. MonadIO m => CInt -> m MusicType
    SDL.Raw.Mixer.fadingChannel (CInt -> CInt
    clipChan CInt
    c)

    -- | A group of 'Channel's.
    --
    -- Grouping 'Channel's together allows you to perform some operations on all of
    -- them at once.
    --
    -- By default, all 'Channel's are members of the 'DefaultGroup'.
    newtype Group = Group CInt
      deriving stock (Group -> Group -> Bool
    (Group -> Group -> Bool) -> (Group -> Group -> Bool) -> Eq Group
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Group -> Group -> Bool
    == :: Group -> Group -> Bool
    $c/= :: Group -> Group -> Bool
    /= :: Group -> Group -> Bool
    Eq, Eq Group
    Eq Group =>
    (Group -> Group -> Ordering)
    -> (Group -> Group -> Bool)
    -> (Group -> Group -> Bool)
    -> (Group -> Group -> Bool)
    -> (Group -> Group -> Bool)
    -> (Group -> Group -> Group)
    -> (Group -> Group -> Group)
    -> Ord Group
    Group -> Group -> Bool
    Group -> Group -> Ordering
    Group -> Group -> Group
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Group -> Group -> Ordering
    compare :: Group -> Group -> Ordering
    $c< :: Group -> Group -> Bool
    < :: Group -> Group -> Bool
    $c<= :: Group -> Group -> Bool
    <= :: Group -> Group -> Bool
    $c> :: Group -> Group -> Bool
    > :: Group -> Group -> Bool
    $c>= :: Group -> Group -> Bool
    >= :: Group -> Group -> Bool
    $cmax :: Group -> Group -> Group
    max :: Group -> Group -> Group
    $cmin :: Group -> Group -> Group
    min :: Group -> Group -> Group
    Ord)
      deriving newtype (Volume -> Group
    Group -> Volume
    Group -> [Group]
    Group -> Group
    Group -> Group -> [Group]
    Group -> Group -> Group -> [Group]
    (Group -> Group)
    -> (Group -> Group)
    -> (Volume -> Group)
    -> (Group -> Volume)
    -> (Group -> [Group])
    -> (Group -> Group -> [Group])
    -> (Group -> Group -> [Group])
    -> (Group -> Group -> Group -> [Group])
    -> Enum Group
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Volume -> a)
    -> (a -> Volume)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: Group -> Group
    succ :: Group -> Group
    $cpred :: Group -> Group
    pred :: Group -> Group
    $ctoEnum :: Volume -> Group
    toEnum :: Volume -> Group
    $cfromEnum :: Group -> Volume
    fromEnum :: Group -> Volume
    $cenumFrom :: Group -> [Group]
    enumFrom :: Group -> [Group]
    $cenumFromThen :: Group -> Group -> [Group]
    enumFromThen :: Group -> Group -> [Group]
    $cenumFromTo :: Group -> Group -> [Group]
    enumFromTo :: Group -> Group -> [Group]
    $cenumFromThenTo :: Group -> Group -> Group -> [Group]
    enumFromThenTo :: Group -> Group -> Group -> [Group]
    Enum, Enum Group
    Real Group
    (Real Group, Enum Group) =>
    (Group -> Group -> Group)
    -> (Group -> Group -> Group)
    -> (Group -> Group -> Group)
    -> (Group -> Group -> Group)
    -> (Group -> Group -> (Group, Group))
    -> (Group -> Group -> (Group, Group))
    -> (Group -> Integer)
    -> Integral Group
    Group -> Integer
    Group -> Group -> (Group, Group)
    Group -> Group -> Group
    forall a.
    (Real a, Enum a) =>
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> (a, a))
    -> (a -> a -> (a, a))
    -> (a -> Integer)
    -> Integral a
    $cquot :: Group -> Group -> Group
    quot :: Group -> Group -> Group
    $crem :: Group -> Group -> Group
    rem :: Group -> Group -> Group
    $cdiv :: Group -> Group -> Group
    div :: Group -> Group -> Group
    $cmod :: Group -> Group -> Group
    mod :: Group -> Group -> Group
    $cquotRem :: Group -> Group -> (Group, Group)
    quotRem :: Group -> Group -> (Group, Group)
    $cdivMod :: Group -> Group -> (Group, Group)
    divMod :: Group -> Group -> (Group, Group)
    $ctoInteger :: Group -> Integer
    toInteger :: Group -> Integer
    Integral, Num Group
    Ord Group
    (Num Group, Ord Group) => (Group -> Rational) -> Real Group
    Group -> Rational
    forall a. (Num a, Ord a) => (a -> Rational) -> Real a
    $ctoRational :: Group -> Rational
    toRational :: Group -> Rational
    Real, Integer -> Group
    Group -> Group
    Group -> Group -> Group
    (Group -> Group -> Group)
    -> (Group -> Group -> Group)
    -> (Group -> Group -> Group)
    -> (Group -> Group)
    -> (Group -> Group)
    -> (Group -> Group)
    -> (Integer -> Group)
    -> Num Group
    forall a.
    (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (a -> a)
    -> (Integer -> a)
    -> Num a
    $c+ :: Group -> Group -> Group
    + :: Group -> Group -> Group
    $c- :: Group -> Group -> Group
    - :: Group -> Group -> Group
    $c* :: Group -> Group -> Group
    * :: Group -> Group -> Group
    $cnegate :: Group -> Group
    negate :: Group -> Group
    $cabs :: Group -> Group
    abs :: Group -> Group
    $csignum :: Group -> Group
    signum :: Group -> Group
    $cfromInteger :: Integer -> Group
    fromInteger :: Integer -> Group
    Num)

    -- | The default 'Group' all 'Channel's are in the moment they are created.
    pattern DefaultGroup :: Group
    pattern $mDefaultGroup :: forall {r}. Group -> ((# #) -> r) -> ((# #) -> r) -> r
    $bDefaultGroup :: Group
    DefaultGroup = -1

    -- | Assigns a given 'Channel' to a certain 'Group'.
    --
    -- If 'DefaultGroup' is used, assigns the 'Channel' the the default starting
    -- 'Group' (essentially /ungrouping/ them).
    --
    -- If 'AllChannels' is used, assigns all 'Channel's to the given 'Group'.
    --
    -- Returns whether the 'Channel' was successfully grouped or not. Failure is
    -- poosible if the 'Channel' does not exist, for instance.
    group :: MonadIO m => Group -> Channel -> m Bool
    group :: forall (m :: * -> *). MonadIO m => Group -> Channel -> m Bool
    group wrapped :: Group
    wrapped@(Group CInt
    g) Channel
    channel =
      case Channel
    channel of
        Channel
    AllChannels -> do
          total <- m Volume
    forall (m :: * -> *). MonadIO m => m Volume
    getChannels
          if total > 0
            then (> 0) <$> groupSpan wrapped 0 (Channel $ fromIntegral $ total - 1)
            else return True -- No channels available -- still a success probably.
        Channel CInt
    c ->
          if CInt
    c CInt -> CInt -> Bool
    forall a. Ord a => a -> a -> Bool
    >= CInt
    0
            then (CInt -> CInt -> Bool
    forall a. Eq a => a -> a -> Bool
    == CInt
    1) (CInt -> Bool) -> m CInt -> m Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> CInt -> m CInt
    SDL.Raw.Mixer.groupChannel CInt
    c CInt
    g
            else Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    False -- Can't group the post-processing channel or below.

    -- | Same as 'groupChannel', but groups all 'Channel's between the first and
    -- last given, inclusive.
    --
    -- If 'DefaultGroup' is used, assigns the entire 'Channel' span to the default
    -- starting 'Group' (essentially /ungrouping/ them).
    --
    -- Using 'AllChannels' is invalid.
    --
    -- Returns the number of 'Channel's successfully grouped. This number may be
    -- less than the number of 'Channel's given, for instance if some of them do
    -- not exist.
    groupSpan :: MonadIO m => Group -> Channel -> Channel -> m Int
    groupSpan :: forall (m :: * -> *).
    MonadIO m =>
    Group -> Channel -> Channel -> m Volume
    groupSpan wrap :: Group
    wrap@(Group CInt
    g) from :: Channel
    from@(Channel CInt
    c1) to :: Channel
    to@(Channel CInt
    c2)
      | CInt
    c1 CInt -> CInt -> Bool
    forall a. Ord a => a -> a -> Bool
    < CInt
    0 Bool -> Bool -> Bool
    || CInt
    c2 CInt -> CInt -> Bool
    forall a. Ord a => a -> a -> Bool
    < CInt
    0 = Volume -> m Volume
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Volume
    0
      | CInt
    c1 CInt -> CInt -> Bool
    forall a. Ord a => a -> a -> Bool
    > CInt
    c2 = Group -> Channel -> Channel -> m Volume
    forall (m :: * -> *).
    MonadIO m =>
    Group -> Channel -> Channel -> m Volume
    groupSpan Group
    wrap Channel
    to Channel
    from
      | Bool
    otherwise = CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Volume) -> m CInt -> m Volume
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> CInt -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> CInt -> CInt -> m CInt
    SDL.Raw.Mixer.groupChannels CInt
    c1 CInt
    c2 CInt
    g

    -- | Returns the number of 'Channels' within a 'Group'.
    --
    -- If 'DefaultGroup' is used, will return the number of all 'Channel's, since
    -- all of them are within the default 'Group'.
    groupCount :: MonadIO m => Group -> m Int
    groupCount :: forall (m :: * -> *). MonadIO m => Group -> m Volume
    groupCount (Group CInt
    g) = CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Volume) -> m CInt -> m Volume
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.groupCount CInt
    g

    -- | Gets the first inactive (not playing) 'Channel' within a given 'Group',
    -- if any.
    --
    -- Using 'DefaultGroup' will give you the first inactive 'Channel' out of all
    -- that exist.
    getAvailable :: MonadIO m => Group -> m (Maybe Channel)
    getAvailable :: forall (m :: * -> *). MonadIO m => Group -> m (Maybe Channel)
    getAvailable (Group CInt
    g) = do
      found <- CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.groupAvailable CInt
    g
      return $ if found >= 0 then Just $ fromIntegral found else Nothing

    -- | Gets the oldest actively playing 'Channel' within a given 'Group'.
    --
    -- Returns 'Nothing' when the 'Group' is empty or no 'Channel's within it are
    -- playing.
    getOldest :: MonadIO m => Group -> m (Maybe Channel)
    getOldest :: forall (m :: * -> *). MonadIO m => Group -> m (Maybe Channel)
    getOldest (Group CInt
    g) = do
      found <- CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.groupOldest CInt
    g
      return $ if found >= 0 then Just $ fromIntegral found else Nothing

    -- | Gets the newest actively playing 'Channel' within a given 'Group'.
    --
    -- Returns 'Nothing' when the 'Group' is empty or no 'Channel's within it are
    -- playing.
    getNewest :: MonadIO m => Group -> m (Maybe Channel)
    getNewest :: forall (m :: * -> *). MonadIO m => Group -> m (Maybe Channel)
    getNewest (Group CInt
    g) = do
      found <- CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.groupNewer CInt
    g
      return $ if found >= 0 then Just $ fromIntegral found else Nothing

    -- | Returns the names of all music decoders currently available.
    --
    -- These depend on the availability of shared libraries for each of the
    -- formats. The list may contain any of the following, and possibly others:
    -- @WAVE@, @MODPLUG@, @MIKMOD@, @TIMIDITY@, @FLUIDSYNTH@, @NATIVEMIDI@, @OGG@,
    -- @FLAC@, @MP3@.
    musicDecoders :: MonadIO m => m [String]
    musicDecoders :: forall (m :: * -> *). MonadIO m => m [String]
    musicDecoders =
      IO [String] -> m [String]
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO [String] -> m [String]) -> IO [String] -> m [String]
    forall a b. (a -> b) -> a -> b
    $ do
        num <- IO CInt
    forall (m :: * -> *). MonadIO m => m CInt
    SDL.Raw.Mixer.getNumMusicDecoders
        forM [0 .. num - 1] $ SDL.Raw.Mixer.getMusicDecoder >=> peekCString

    -- | A loaded music file.
    --
    -- 'Music' is played on a separate channel different from the normal mixing
    -- 'Channel's.
    --
    -- To manipulate 'Music' outside of post-processing callbacks, use the music
    -- variant functions listed below.
    newtype Music = Music (Ptr SDL.Raw.Mixer.Music)
      deriving stock (Music -> Music -> Bool
    (Music -> Music -> Bool) -> (Music -> Music -> Bool) -> Eq Music
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Music -> Music -> Bool
    == :: Music -> Music -> Bool
    $c/= :: Music -> Music -> Bool
    /= :: Music -> Music -> Bool
    Eq, Volume -> Music -> ShowS
    [Music] -> ShowS
    Music -> String
    (Volume -> Music -> ShowS)
    -> (Music -> String) -> ([Music] -> ShowS) -> Show Music
    forall a.
    (Volume -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Volume -> Music -> ShowS
    showsPrec :: Volume -> Music -> ShowS
    $cshow :: Music -> String
    show :: Music -> String
    $cshowList :: [Music] -> ShowS
    showList :: [Music] -> ShowS
    Show)

    instance Loadable Music where
      decode :: forall (m :: * -> *). MonadIO m => ByteString -> m Music
    decode ByteString
    bytes = IO Music -> m Music
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO Music -> m Music) -> IO Music -> m Music
    forall a b. (a -> b) -> a -> b
    $ do
        ByteString -> (CStringLen -> IO Music) -> IO Music
    forall a. ByteString -> (CStringLen -> IO a) -> IO a
    unsafeUseAsCStringLen ByteString
    bytes ((CStringLen -> IO Music) -> IO Music)
    -> (CStringLen -> IO Music) -> IO Music
    forall a b. (a -> b) -> a -> b
    $ \(CString
    cstr, Volume
    len) -> do
          rw <- Ptr () -> CInt -> IO (Ptr RWops)
    forall (m :: * -> *). MonadIO m => Ptr () -> CInt -> m (Ptr RWops)
    rwFromConstMem (CString -> Ptr ()
    forall a b. Ptr a -> Ptr b
    castPtr CString
    cstr) (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    len)
          fmap Music
            . throwIfNull "SDL.Mixer.decode<Music>" "Mix_LoadMUS_RW"
            $ SDL.Raw.Mixer.loadMUS_RW rw 0

      free :: forall (m :: * -> *). MonadIO m => Music -> m ()
    free (Music Ptr Music
    p) = IO () -> m ()
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> m ()) -> IO () -> m ()
    forall a b. (a -> b) -> a -> b
    $ Ptr Music -> IO ()
    forall {m :: * -> *}. MonadIO m => Ptr Music -> m ()
    SDL.Raw.Mixer.freeMusic Ptr Music
    p

    -- | Plays a given 'Music' a certain number of 'Times'.
    --
    -- The previously playing 'Music' will be halted, unless it is fading out in
    -- which case a blocking wait occurs until it fades out completely.
    playMusic :: MonadIO m => Times -> Music -> m ()
    playMusic :: forall (m :: * -> *). MonadIO m => Times -> Music -> m ()
    playMusic Times
    times (Music Ptr Music
    p) =
      Text -> Text -> m CInt -> m ()
    forall (m :: * -> *) a.
    (MonadIO m, Num a, Ord a) =>
    Text -> Text -> m a -> m ()
    throwIfNeg_ Text
    "SDL.Mixer.playMusic" Text
    "Mix_PlayMusic" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        Ptr Music -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => Ptr Music -> CInt -> m CInt
    SDL.Raw.Mixer.playMusic Ptr Music
    p (CInt -> m CInt) -> CInt -> m CInt
    forall a b. (a -> b) -> a -> b
    $
          case Times
    times of
            Times
    Forever -> (-CInt
    1)
            Times CInt
    t -> CInt -> CInt -> CInt
    forall a. Ord a => a -> a -> a
    max CInt
    1 CInt
    t -- Interpretation differs from normal play? :/

    -- | Pauses 'Music' playback, if it is actively playing.
    --
    -- You may still 'haltMusic' paused 'Music'.
    pauseMusic :: MonadIO m => m ()
    pauseMusic :: forall (m :: * -> *). MonadIO m => m ()
    pauseMusic = m ()
    forall (m :: * -> *). MonadIO m => m ()
    SDL.Raw.Mixer.pauseMusic

    -- | Halts 'Music' playback.
    haltMusic :: MonadIO m => m ()
    haltMusic :: forall (m :: * -> *). MonadIO m => m ()
    haltMusic = m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void m CInt
    forall (m :: * -> *). MonadIO m => m CInt
    SDL.Raw.Mixer.haltMusic

    -- | Resumes 'Music' playback.
    --
    -- This works on both paused and halted 'Music'.
    --
    -- If 'Music' is currently actively playing, this has no effect.
    resumeMusic :: MonadIO m => m ()
    resumeMusic :: forall (m :: * -> *). MonadIO m => m ()
    resumeMusic = m ()
    forall (m :: * -> *). MonadIO m => m ()
    SDL.Raw.Mixer.resumeMusic

    -- | Returns whether a 'Music' is currently playing or not.
    --
    -- Note that this returns 'True' even if the 'Music' is currently paused.
    playingMusic :: MonadIO m => m Bool
    playingMusic :: forall (m :: * -> *). MonadIO m => m Bool
    playingMusic = (CInt -> CInt -> Bool
    forall a. Ord a => a -> a -> Bool
    > CInt
    0) (CInt -> Bool) -> m CInt -> m Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> m CInt
    forall (m :: * -> *). MonadIO m => m CInt
    SDL.Raw.Mixer.playingMusic

    -- | Returns whether a 'Music' is currently paused or not.
    --
    -- Note that this returns 'False' if the 'Music' is currently halted.
    pausedMusic :: MonadIO m => m Bool
    pausedMusic :: forall (m :: * -> *). MonadIO m => m Bool
    pausedMusic = (CInt -> CInt -> Bool
    forall a. Ord a => a -> a -> Bool
    > CInt
    0) (CInt -> Bool) -> m CInt -> m Bool
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> m CInt
    forall (m :: * -> *). MonadIO m => m CInt
    SDL.Raw.Mixer.pausedMusic

    -- | Rewinds the 'Music' to the beginning.
    --
    -- When playing new 'Music', it starts at the beginning by default.
    --
    -- This function only works with @MOD@, @OGG@, @MP3@ and @NATIVEMIDI@ streams.
    rewindMusic :: MonadIO m => m ()
    rewindMusic :: forall (m :: * -> *). MonadIO m => m ()
    rewindMusic = m ()
    forall (m :: * -> *). MonadIO m => m ()
    SDL.Raw.Mixer.rewindMusic

    -- | Plays a given 'Music' a number of 'Times', but fading it in during a
    -- certain number of 'Milliseconds'.
    --
    -- The fading only occurs during the first time the 'Music' is played.
    fadeInMusic :: MonadIO m => Milliseconds -> Times -> Music -> m ()
    fadeInMusic :: forall (m :: * -> *). MonadIO m => Volume -> Times -> Music -> m ()
    fadeInMusic Volume
    ms Times
    times (Music Ptr Music
    p) =
      Text -> Text -> m CInt -> m ()
    forall (m :: * -> *) a.
    (MonadIO m, Num a, Ord a) =>
    Text -> Text -> m a -> m ()
    throwIfNeg_ Text
    "SDL.Mixer.fadeInMusic" Text
    "Mix_FadeInMusic" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        Ptr Music -> CInt -> CInt -> m CInt
    forall {m :: * -> *}.
    MonadIO m =>
    Ptr Music -> CInt -> CInt -> m CInt
    SDL.Raw.Mixer.fadeInMusic Ptr Music
    p CInt
    t' (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    ms)
      where
        t' :: CInt
    t' = case Times
    times of
          Times
    Forever -> (-CInt
    1)
          Times CInt
    t -> CInt -> CInt -> CInt
    forall a. Ord a => a -> a -> a
    max CInt
    1 CInt
    t

    -- | Gradually fade out the 'Music' over a given number of 'Milliseconds'.
    --
    -- The 'Music' is set to fade out only when it is playing and not fading
    -- already.
    --
    -- Returns whether the 'Music' was successfully set to fade out.
    fadeOutMusic :: MonadIO m => Milliseconds -> m Bool
    fadeOutMusic :: forall (m :: * -> *). MonadIO m => Volume -> m Bool
    fadeOutMusic = (CInt -> Bool) -> m CInt -> m Bool
    forall a b. (a -> b) -> m a -> m b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (CInt -> CInt -> Bool
    forall a. Eq a => a -> a -> Bool
    == CInt
    1) (m CInt -> m Bool) -> (Volume -> m CInt) -> Volume -> m Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.fadeOutMusic (CInt -> m CInt) -> (Volume -> CInt) -> Volume -> m CInt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral

    -- | A position in milliseconds within a piece of 'Music'.
    type Position = Milliseconds

    -- | Set the 'Position' for currently playing 'Music'.
    --
    -- Note: this only works for @OGG@ and @MP3@ 'Music'.
    setMusicPosition :: MonadIO m => Position -> m ()
    setMusicPosition :: forall (m :: * -> *). MonadIO m => Volume -> m ()
    setMusicPosition Volume
    at = do
      m ()
    forall (m :: * -> *). MonadIO m => m ()
    rewindMusic -- Due to weird behaviour for MP3s...
      Text -> Text -> m CInt -> m ()
    forall (m :: * -> *) a.
    (MonadIO m, Num a, Ord a) =>
    Text -> Text -> m a -> m ()
    throwIfNeg_ Text
    "SDL.Mixer.setMusicPosition" Text
    "Mix_SetMusicPosition" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        CDouble -> m CInt
    forall {m :: * -> *}. MonadIO m => CDouble -> m CInt
    SDL.Raw.Mixer.setMusicPosition (CDouble -> m CInt) -> CDouble -> m CInt
    forall a b. (a -> b) -> a -> b
    $ Volume -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    realToFrac Volume
    at CDouble -> CDouble -> CDouble
    forall a. Fractional a => a -> a -> a
    / CDouble
    1000.0

    -- | Similar to 'setMusicPosition', but works only with @MOD@ 'Music'.
    --
    -- Pass in the pattern number.
    setMusicPositionMOD :: MonadIO m => Int -> m ()
    setMusicPositionMOD :: forall (m :: * -> *). MonadIO m => Volume -> m ()
    setMusicPositionMOD Volume
    n = do
      Text -> Text -> m CInt -> m ()
    forall (m :: * -> *) a.
    (MonadIO m, Num a, Ord a) =>
    Text -> Text -> m a -> m ()
    throwIfNeg_ Text
    "SDL.Mixer.setMusicPositionMOD" Text
    "Mix_SetMusicPosition" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        CDouble -> m CInt
    forall {m :: * -> *}. MonadIO m => CDouble -> m CInt
    SDL.Raw.Mixer.setMusicPosition (CDouble -> m CInt) -> CDouble -> m CInt
    forall a b. (a -> b) -> a -> b
    $ Volume -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    realToFrac Volume
    n

    -- | Same as 'fadeInMusic', but with a custom starting `Music`'s 'Position'.
    --
    -- Note that this only works on 'Music' that 'setMusicPosition' works on.
    fadeInMusicAt :: MonadIO m => Position -> Milliseconds -> Times -> Music -> m ()
    fadeInMusicAt :: forall (m :: * -> *).
    MonadIO m =>
    Volume -> Volume -> Times -> Music -> m ()
    fadeInMusicAt Volume
    at Volume
    ms Times
    times (Music Ptr Music
    p) =
      Text -> Text -> m CInt -> m ()
    forall (m :: * -> *) a.
    (MonadIO m, Num a, Ord a) =>
    Text -> Text -> m a -> m ()
    throwIfNeg_ Text
    "SDL.Mixer.fadeInMusicAt" Text
    "Mix_FadeInMusicPos" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        Ptr Music -> CInt -> CInt -> CDouble -> m CInt
    forall {m :: * -> *}.
    MonadIO m =>
    Ptr Music -> CInt -> CInt -> CDouble -> m CInt
    SDL.Raw.Mixer.fadeInMusicPos
          Ptr Music
    p
          CInt
    t'
          (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    ms)
          (Volume -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    realToFrac Volume
    at CDouble -> CDouble -> CDouble
    forall a. Fractional a => a -> a -> a
    / CDouble
    1000.0)
      where
        t' :: CInt
    t' = case Times
    times of
          Times
    Forever -> (-CInt
    1)
          Times CInt
    t -> CInt -> CInt -> CInt
    forall a. Ord a => a -> a -> a
    max CInt
    1 CInt
    t

    -- | Same as 'fadeInMusicAt', but works with @MOD@ 'Music'.
    --
    -- Instead of milliseconds, specify the position with a pattern number.
    fadeInMusicAtMOD :: MonadIO m => Int -> Milliseconds -> Times -> Music -> m ()
    fadeInMusicAtMOD :: forall (m :: * -> *).
    MonadIO m =>
    Volume -> Volume -> Times -> Music -> m ()
    fadeInMusicAtMOD Volume
    at Volume
    ms Times
    times (Music Ptr Music
    p) =
      Text -> Text -> m CInt -> m ()
    forall (m :: * -> *) a.
    (MonadIO m, Num a, Ord a) =>
    Text -> Text -> m a -> m ()
    throwIfNeg_ Text
    "SDL.Mixer.fadeInMusicAtMOD" Text
    "Mix_FadeInMusicPos" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        Ptr Music -> CInt -> CInt -> CDouble -> m CInt
    forall {m :: * -> *}.
    MonadIO m =>
    Ptr Music -> CInt -> CInt -> CDouble -> m CInt
    SDL.Raw.Mixer.fadeInMusicPos
          Ptr Music
    p
          CInt
    t'
          (Volume -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Volume
    ms)
          (Volume -> CDouble
    forall a b. (Real a, Fractional b) => a -> b
    realToFrac Volume
    at)
      where
        t' :: CInt
    t' = case Times
    times of
          Times
    Forever -> (-CInt
    1)
          Times CInt
    t -> CInt -> CInt -> CInt
    forall a. Ord a => a -> a -> a
    max CInt
    1 CInt
    t

    -- | Returns the `Music`'s 'Fading' status.
    fadingMusic :: MonadIO m => m Fading
    fadingMusic :: forall (m :: * -> *). MonadIO m => m Fading
    fadingMusic = MusicType -> Fading
    wordToFading (MusicType -> Fading) -> m MusicType -> m Fading
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> m MusicType
    forall (m :: * -> *). MonadIO m => m MusicType
    SDL.Raw.Mixer.fadingMusic

    -- | Gets the current 'Volume' setting for 'Music'.
    getMusicVolume :: MonadIO m => m Volume
    getMusicVolume :: forall (m :: * -> *). MonadIO m => m Volume
    getMusicVolume = CInt -> Volume
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Volume) -> m CInt -> m Volume
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.volumeMusic (-CInt
    1)

    -- | Sets the 'Volume' for 'Music'.
    --
    -- Note that this won't work if any 'Music' is currently fading.
    setMusicVolume :: MonadIO m => Volume -> m ()
    setMusicVolume :: forall (m :: * -> *). MonadIO m => Volume -> m ()
    setMusicVolume Volume
    v = m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> (CInt -> m CInt) -> CInt -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> m CInt
    SDL.Raw.Mixer.volumeMusic (CInt -> m ()) -> CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $ Volume -> CInt
    volumeToCInt Volume
    v

    -- | A `Music`'s type.
    data MusicType
      = CMD
      | WAV
      | MOD
      | MID
      | OGG
      | MP3
      | FLAC
      deriving stock (MusicType -> MusicType -> Bool
    (MusicType -> MusicType -> Bool)
    -> (MusicType -> MusicType -> Bool) -> Eq MusicType
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: MusicType -> MusicType -> Bool
    == :: MusicType -> MusicType -> Bool
    $c/= :: MusicType -> MusicType -> Bool
    /= :: MusicType -> MusicType -> Bool
    Eq, Volume -> MusicType -> ShowS
    [MusicType] -> ShowS
    MusicType -> String
    (Volume -> MusicType -> ShowS)
    -> (MusicType -> String)
    -> ([MusicType] -> ShowS)
    -> Show MusicType
    forall a.
    (Volume -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Volume -> MusicType -> ShowS
    showsPrec :: Volume -> MusicType -> ShowS
    $cshow :: MusicType -> String
    show :: MusicType -> String
    $cshowList :: [MusicType] -> ShowS
    showList :: [MusicType] -> ShowS
    Show, ReadPrec [MusicType]
    ReadPrec MusicType
    Volume -> ReadS MusicType
    ReadS [MusicType]
    (Volume -> ReadS MusicType)
    -> ReadS [MusicType]
    -> ReadPrec MusicType
    -> ReadPrec [MusicType]
    -> Read MusicType
    forall a.
    (Volume -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Volume -> ReadS MusicType
    readsPrec :: Volume -> ReadS MusicType
    $creadList :: ReadS [MusicType]
    readList :: ReadS [MusicType]
    $creadPrec :: ReadPrec MusicType
    readPrec :: ReadPrec MusicType
    $creadListPrec :: ReadPrec [MusicType]
    readListPrec :: ReadPrec [MusicType]
    Read, Eq MusicType
    Eq MusicType =>
    (MusicType -> MusicType -> Ordering)
    -> (MusicType -> MusicType -> Bool)
    -> (MusicType -> MusicType -> Bool)
    -> (MusicType -> MusicType -> Bool)
    -> (MusicType -> MusicType -> Bool)
    -> (MusicType -> MusicType -> MusicType)
    -> (MusicType -> MusicType -> MusicType)
    -> Ord MusicType
    MusicType -> MusicType -> Bool
    MusicType -> MusicType -> Ordering
    MusicType -> MusicType -> MusicType
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: MusicType -> MusicType -> Ordering
    compare :: MusicType -> MusicType -> Ordering
    $c< :: MusicType -> MusicType -> Bool
    < :: MusicType -> MusicType -> Bool
    $c<= :: MusicType -> MusicType -> Bool
    <= :: MusicType -> MusicType -> Bool
    $c> :: MusicType -> MusicType -> Bool
    > :: MusicType -> MusicType -> Bool
    $c>= :: MusicType -> MusicType -> Bool
    >= :: MusicType -> MusicType -> Bool
    $cmax :: MusicType -> MusicType -> MusicType
    max :: MusicType -> MusicType -> MusicType
    $cmin :: MusicType -> MusicType -> MusicType
    min :: MusicType -> MusicType -> MusicType
    Ord, MusicType
    MusicType -> MusicType -> Bounded MusicType
    forall a. a -> a -> Bounded a
    $cminBound :: MusicType
    minBound :: MusicType
    $cmaxBound :: MusicType
    maxBound :: MusicType
    Bounded)

    wordToMusicType :: SDL.Raw.Mixer.MusicType -> Maybe MusicType
    wordToMusicType :: MusicType -> Maybe MusicType
    wordToMusicType = \case
      MusicType
    SDL.Raw.Mixer.MUS_NONE -> Maybe MusicType
    forall a. Maybe a
    Nothing
      MusicType
    SDL.Raw.Mixer.MUS_CMD -> MusicType -> Maybe MusicType
    forall a. a -> Maybe a
    Just MusicType
    CMD
      MusicType
    SDL.Raw.Mixer.MUS_WAV -> MusicType -> Maybe MusicType
    forall a. a -> Maybe a
    Just MusicType
    WAV
      MusicType
    SDL.Raw.Mixer.MUS_MOD -> MusicType -> Maybe MusicType
    forall a. a -> Maybe a
    Just MusicType
    MOD
      MusicType
    SDL.Raw.Mixer.MUS_MID -> MusicType -> Maybe MusicType
    forall a. a -> Maybe a
    Just MusicType
    MID
      MusicType
    SDL.Raw.Mixer.MUS_OGG -> MusicType -> Maybe MusicType
    forall a. a -> Maybe a
    Just MusicType
    OGG
      MusicType
    SDL.Raw.Mixer.MUS_MP3 -> MusicType -> Maybe MusicType
    forall a. a -> Maybe a
    Just MusicType
    MP3
      MusicType
    SDL.Raw.Mixer.MUS_FLAC -> MusicType -> Maybe MusicType
    forall a. a -> Maybe a
    Just MusicType
    FLAC
      MusicType
    _ -> Maybe MusicType
    forall a. Maybe a
    Nothing

    -- | Gets the 'MusicType' of a given 'Music'.
    musicType :: Music -> Maybe MusicType
    musicType :: Music -> Maybe MusicType
    musicType (Music Ptr Music
    p) =
      MusicType -> Maybe MusicType
    wordToMusicType (MusicType -> Maybe MusicType) -> MusicType -> Maybe MusicType
    forall a b. (a -> b) -> a -> b
    $ IO MusicType -> MusicType
    forall a. IO a -> a
    unsafePerformIO (Ptr Music -> IO MusicType
    forall {m :: * -> *}. MonadIO m => Ptr Music -> m MusicType
    SDL.Raw.Mixer.getMusicType Ptr Music
    p)

    -- | Gets the 'MusicType' of currently playing 'Music', if any.
    playingMusicType :: MonadIO m => m (Maybe MusicType)
    playingMusicType :: forall (m :: * -> *). MonadIO m => m (Maybe MusicType)
    playingMusicType = MusicType -> Maybe MusicType
    wordToMusicType (MusicType -> Maybe MusicType)
    -> m MusicType -> m (Maybe MusicType)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr Music -> m MusicType
    forall {m :: * -> *}. MonadIO m => Ptr Music -> m MusicType
    SDL.Raw.Mixer.getMusicType Ptr Music
    forall a. Ptr a
    nullPtr

    -- More quackery, but this time for the music finished callback.
    {-# NOINLINE musicFinishedFunPtr #-}
    musicFinishedFunPtr :: IORef (FunPtr (IO ()))
    musicFinishedFunPtr :: IORef (FunPtr (IO ()))
    musicFinishedFunPtr = IO (IORef (FunPtr (IO ()))) -> IORef (FunPtr (IO ()))
    forall a. IO a -> a
    unsafePerformIO (IO (IORef (FunPtr (IO ()))) -> IORef (FunPtr (IO ())))
    -> IO (IORef (FunPtr (IO ()))) -> IORef (FunPtr (IO ()))
    forall a b. (a -> b) -> a -> b
    $ FunPtr (IO ()) -> IO (IORef (FunPtr (IO ())))
    forall a. a -> IO (IORef a)
    newIORef FunPtr (IO ())
    forall a. FunPtr a
    nullFunPtr

    -- | Sets a callback that gets invoked each time a 'Music' finishes playing.
    --
    -- __Note: don't call other 'SDL.Mixer' functions within this callback.__
    whenMusicFinished :: MonadIO m => IO () -> m ()
    whenMusicFinished :: forall (m :: * -> *). MonadIO m => IO () -> m ()
    whenMusicFinished IO ()
    callback = IO () -> m ()
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> m ()) -> IO () -> m ()
    forall a b. (a -> b) -> a -> b
    $ do
      callbackRaw <- IO () -> IO (FunPtr (IO ()))
    SDL.Raw.Mixer.wrapMusicCallback IO ()
    callback
      SDL.Raw.Mixer.hookMusicFinished callbackRaw
      lastFunPtr <- readIORef musicFinishedFunPtr
      when (lastFunPtr /= nullFunPtr) $ freeHaskellFunPtr lastFunPtr
      writeIORef musicFinishedFunPtr callbackRaw

    -- | A post-processing effect as a function operating on a mutable stream.
    --
    -- __Note that, at the moment, this is a stream of bytes. Depending on the__
    -- __'Audio' 'Format' you're using, you're probably going to want to treat is__
    -- __as a stream of 16-bit values instead.__
    type Effect = Channel -> IOVector Word8 -> IO () -- TODO: Don't hardcode Word8.

    -- | A function called when a processor is finished being used.
    --
    -- This allows you to clean up any state you might have had.
    type EffectFinished = Channel -> IO ()

    -- | A way to refer to the special 'Channel' used for post-processing effects.
    --
    -- You can only use this value with 'effect' and the other in-built effect
    -- functions such as 'effectPan' and 'effectDistance'.
    pattern PostProcessing :: Channel
    pattern $mPostProcessing :: forall {r}. Channel -> ((# #) -> r) -> ((# #) -> r) -> r
    $bPostProcessing :: Channel
    PostProcessing = SDL.Raw.Mixer.CHANNEL_POST

    -- | Adds a post-processing 'Effect' to a certain 'Channel'.
    --
    -- A `Channel`'s 'Effect's are called in the order they were added.
    --
    -- Returns an action that, when executed, removes this 'Effect'. __Note: do__
    -- __execute this returned action more than once.__
    effect :: MonadIO m => Channel -> EffectFinished -> Effect -> m (m ())
    effect :: forall (m :: * -> *).
    MonadIO m =>
    Channel -> (Channel -> IO ()) -> Effect -> m (m ())
    effect (Channel CInt
    channel) Channel -> IO ()
    fin Effect
    ef = do
      ef' <- IO (FunPtr Effect) -> m (FunPtr Effect)
    forall a. IO a -> m a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO (FunPtr Effect) -> m (FunPtr Effect))
    -> IO (FunPtr Effect) -> m (FunPtr Effect)
    forall a b. (a -> b) -> a -> b
    $
        Effect -> IO (FunPtr Effect)
    SDL.Raw.Mixer.wrapEffect (Effect -> IO (FunPtr Effect)) -> Effect -> IO (FunPtr Effect)
    forall a b. (a -> b) -> a -> b
    $ \CInt
    c Ptr ()
    p CInt
    len Ptr ()
    _ -> do
          fp <- ForeignPtr () -> ForeignPtr Word8
    forall a b. ForeignPtr a -> ForeignPtr b
    castForeignPtr (ForeignPtr () -> ForeignPtr Word8)
    -> IO (ForeignPtr ()) -> IO (ForeignPtr Word8)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> Ptr () -> IO (ForeignPtr ())
    forall a. Ptr a -> IO (ForeignPtr a)
    newForeignPtr_ Ptr ()
    p
          ef (Channel c) . unsafeFromForeignPtr0 fp $ fromIntegral len

      fin' <- liftIO $
        SDL.Raw.Mixer.wrapEffectFinished $ \CInt
    c Ptr ()
    _ ->
          Channel -> IO ()
    fin (Channel -> IO ()) -> Channel -> IO ()
    forall a b. (a -> b) -> a -> b
    $ CInt -> Channel
    Channel CInt
    c

      result <- SDL.Raw.Mixer.registerEffect channel ef' fin' nullPtr

      if result == 0
        then do
          liftIO $ do
            freeHaskellFunPtr ef' >> freeHaskellFunPtr fin'
            err <- getError
            throwIO $ SDLCallFailed "SDL.Raw.Mixer.addEffect" "Mix_RegisterEffect" err
        else return . liftIO $ do
          -- The unregister action.
          removed <- SDL.Raw.Mixer.unregisterEffect channel ef'
          freeHaskellFunPtr ef' >> freeHaskellFunPtr fin'
          when (removed == 0) $ do
            err <- getError
            throwIO $
              SDLCallFailed "SDL.Raw.Mixer.removeEffect" "Mix_UnregisterEffect" err

    -- | Applies an in-built effect implementing panning.
    --
    -- Sets the left-channel and right-channel 'Volume' to the given values.
    --
    -- This only works when `Audio`'s 'Output' is 'Stereo', which is the default.
    --
    -- Returns an action that, when executed, removes this effect. That action
    -- simply calls 'effectPan' with 'Volumes' 128 and 128.
    effectPan :: MonadIO m => Channel -> Volume -> Volume -> m (m ())
    effectPan :: forall (m :: * -> *).
    MonadIO m =>
    Channel -> Volume -> Volume -> m (m ())
    effectPan channel :: Channel
    channel@(Channel CInt
    c) Volume
    lVol Volume
    rVol = do
      m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> (m CInt -> m CInt) -> m CInt -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text -> m CInt -> m CInt
    forall a (m :: * -> *).
    (Eq a, MonadIO m, Num a) =>
    Text -> Text -> m a -> m a
    throwIf0 Text
    "SDL.Raw.Mixer.effectPan" Text
    "Mix_SetPanning" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        CInt -> Word8 -> Word8 -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> Word8 -> Word8 -> m CInt
    SDL.Raw.Mixer.setPanning CInt
    c (Volume -> Word8
    wordVol Volume
    lVol) (Volume -> Word8
    wordVol Volume
    rVol)
      m () -> m (m ())
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (m () -> m (m ())) -> (m (m ()) -> m ()) -> m (m ()) -> m (m ())
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . m (m ()) -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m (m ()) -> m (m ())) -> m (m ()) -> m (m ())
    forall a b. (a -> b) -> a -> b
    $ Channel -> Volume -> Volume -> m (m ())
    forall (m :: * -> *).
    MonadIO m =>
    Channel -> Volume -> Volume -> m (m ())
    effectPan Channel
    channel Volume
    128 Volume
    128

    wordVol :: Volume -> Word8
    wordVol :: Volume -> Word8
    wordVol = CInt -> Word8
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (CInt -> Word8) -> (Volume -> CInt) -> Volume -> Word8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> CInt -> CInt
    forall a. Ord a => a -> a -> a
    min CInt
    255 (CInt -> CInt) -> (Volume -> CInt) -> Volume -> CInt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (CInt -> CInt -> CInt
    forall a. Num a => a -> a -> a
    * CInt
    2) (CInt -> CInt) -> (Volume -> CInt) -> Volume -> CInt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Volume -> CInt
    volumeToCInt

    -- | Applies a different volume based on the distance (as 'Word8') specified.
    --
    -- The volume is loudest at distance 0, quietest at distance 255.
    --
    -- Returns an action that, when executed, removes this effect. That action
    -- simply calls 'effectDistance' with a distance of 0.
    effectDistance :: MonadIO m => Channel -> Word8 -> m (m ())
    effectDistance :: forall (m :: * -> *). MonadIO m => Channel -> Word8 -> m (m ())
    effectDistance channel :: Channel
    channel@(Channel CInt
    c) Word8
    dist = do
      m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> (m CInt -> m CInt) -> m CInt -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text -> m CInt -> m CInt
    forall a (m :: * -> *).
    (Eq a, MonadIO m, Num a) =>
    Text -> Text -> m a -> m a
    throwIf0 Text
    "SDL.Raw.Mixer.effectDistance" Text
    "Mix_SetDistance" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        CInt -> Word8 -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> Word8 -> m CInt
    SDL.Raw.Mixer.setDistance CInt
    c Word8
    dist
      m () -> m (m ())
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (m () -> m (m ())) -> (m (m ()) -> m ()) -> m (m ()) -> m (m ())
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . m (m ()) -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m (m ()) -> m (m ())) -> m (m ()) -> m (m ())
    forall a b. (a -> b) -> a -> b
    $ Channel -> Word8 -> m (m ())
    forall (m :: * -> *). MonadIO m => Channel -> Word8 -> m (m ())
    effectDistance Channel
    channel Word8
    0

    -- | Simulates a simple 3D audio effect.
    --
    -- Accepts the angle in degrees (as 'Int16') in relation to the source of the
    -- sound (0 is directly in front, 90 directly to the right, and so on) and a
    -- distance (as 'Word8') from the source of the sound (where 255 is very far
    -- away, and 0 extremely close).
    --
    -- Returns an action that, when executed, removes this effect. That action
    -- simply calls 'effectPosition' with both angle and distance set to 0.
    effectPosition :: MonadIO m => Channel -> Int16 -> Word8 -> m (m ())
    effectPosition :: forall (m :: * -> *).
    MonadIO m =>
    Channel -> Int16 -> Word8 -> m (m ())
    effectPosition channel :: Channel
    channel@(Channel CInt
    c) Int16
    angle Word8
    dist = do
      m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> (m CInt -> m CInt) -> m CInt -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text -> m CInt -> m CInt
    forall a (m :: * -> *).
    (Eq a, MonadIO m, Num a) =>
    Text -> Text -> m a -> m a
    throwIf0 Text
    "SDL.Raw.Mixer.effectPosition" Text
    "Mix_SetPosition" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        CInt -> Int16 -> Word8 -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> Int16 -> Word8 -> m CInt
    SDL.Raw.Mixer.setPosition CInt
    c Int16
    angle Word8
    dist
      m () -> m (m ())
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (m () -> m (m ())) -> (m (m ()) -> m ()) -> m (m ()) -> m (m ())
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . m (m ()) -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m (m ()) -> m (m ())) -> m (m ()) -> m (m ())
    forall a b. (a -> b) -> a -> b
    $ Channel -> Int16 -> Word8 -> m (m ())
    forall (m :: * -> *).
    MonadIO m =>
    Channel -> Int16 -> Word8 -> m (m ())
    effectPosition Channel
    channel Int16
    0 Word8
    0

    -- | Swaps the left and right channel sound.
    --
    -- If given 'True', will swap the sound channels.
    --
    -- Returns an action that, when executed, removes this effect. That action
    -- simply calls 'effectReverseStereo' with 'False'.
    effectReverseStereo :: MonadIO m => Channel -> Bool -> m (m ())
    effectReverseStereo :: forall (m :: * -> *). MonadIO m => Channel -> Bool -> m (m ())
    effectReverseStereo channel :: Channel
    channel@(Channel CInt
    c) Bool
    rev = do
      m CInt -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m CInt -> m ()) -> (m CInt -> m CInt) -> m CInt -> m ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text -> m CInt -> m CInt
    forall a (m :: * -> *).
    (Eq a, MonadIO m, Num a) =>
    Text -> Text -> m a -> m a
    throwIf0 Text
    "SDL.Raw.Mixer.effectReverseStereo" Text
    "Mix_SetReverseStereo" (m CInt -> m ()) -> m CInt -> m ()
    forall a b. (a -> b) -> a -> b
    $
        CInt -> CInt -> m CInt
    forall {m :: * -> *}. MonadIO m => CInt -> CInt -> m CInt
    SDL.Raw.Mixer.setReverseStereo CInt
    c (if Bool
    rev then CInt
    1 else CInt
    0)
      m () -> m (m ())
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (m () -> m (m ())) -> (m (m ()) -> m ()) -> m (m ()) -> m (m ())
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . m (m ()) -> m ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (m (m ()) -> m (m ())) -> m (m ()) -> m (m ())
    forall a b. (a -> b) -> a -> b
    $ Channel -> Bool -> m (m ())
    forall (m :: * -> *). MonadIO m => Channel -> Bool -> m (m ())
    effectReverseStereo Channel
    channel Bool
    False

    -- Music
    -- TODO: hookMusic
    -- TODO: setMusicCMD
    -- TODO: getMusicHookData

    -- Effects
    -- TODO: setPostMix

    -- SoundFonts
    -- TODO: setSynchroValue
    -- TODO: getSynchroValue
    -- TODO: setSoundFonts
    -- TODO: getSoundFonts
    -- TODO: eachSoundFont