module Engine.Sound.Source where

import RIO

import Sound.OpenAL qualified as OpenAL
import UnliftIO.Resource qualified as Resource

class HasSource a where
  getSource :: a -> OpenAL.Source

instance HasSource OpenAL.Source where
  getSource :: Source -> Source
getSource = Source -> Source
forall a. a -> a
id

instance HasSource (a, OpenAL.Source) where
  getSource :: (a, Source) -> Source
getSource = (a, Source) -> Source
forall a b. (a, b) -> b
snd

allocateCollectionWith
  :: ( Resource.MonadResource m
     , Traversable t
     , HasSource o
     )
  => (i -> m o)
  -> t i
  -> m (Resource.ReleaseKey, t o)
allocateCollectionWith :: (i -> m o) -> t i -> m (ReleaseKey, t o)
allocateCollectionWith i -> m o
action t i
collection = do
  t o
loaded <- (i -> m o) -> t i -> m (t o)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse i -> m o
action t i
collection

  ReleaseKey
key <- IO () -> m ReleaseKey
forall (m :: * -> *). MonadResource m => IO () -> m ReleaseKey
Resource.register do
    let sources :: [Source]
sources = (o -> Source) -> [o] -> [Source]
forall a b. (a -> b) -> [a] -> [b]
map o -> Source
forall a. HasSource a => a -> Source
getSource ([o] -> [Source]) -> [o] -> [Source]
forall a b. (a -> b) -> a -> b
$ t o -> [o]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList t o
loaded
    [Source] -> IO ()
forall (m :: * -> *). MonadIO m => [Source] -> m ()
OpenAL.stop [Source]
sources
    [Source] -> (Source -> IO ()) -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [Source]
sources \Source
source ->
      Source -> StateVar (Maybe Buffer)
OpenAL.buffer Source
source StateVar (Maybe Buffer) -> Maybe Buffer -> IO ()
forall t a (m :: * -> *).
(HasSetter t a, MonadIO m) =>
t -> a -> m ()
OpenAL.$= Maybe Buffer
forall a. Maybe a
Nothing
    [Source] -> IO ()
forall a (m :: * -> *). (ObjectName a, MonadIO m) => [a] -> m ()
OpenAL.deleteObjectNames [Source]
sources

  pure (ReleaseKey
key, t o
loaded)

{-# INLINE play1 #-}
play1 :: (HasSource a, MonadIO m) => a -> m ()
play1 :: a -> m ()
play1 a
src = [a] -> m ()
forall (t :: * -> *) a (m :: * -> *).
(Foldable t, HasSource a, MonadIO m) =>
t a -> m ()
play [a
src]

{-# INLINE play #-}
play :: (Foldable t, HasSource a, MonadIO m) => t a -> m ()
play :: t a -> m ()
play = [Source] -> m ()
forall (m :: * -> *). MonadIO m => [Source] -> m ()
OpenAL.play ([Source] -> m ()) -> (t a -> [Source]) -> t a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Source) -> [a] -> [Source]
forall a b. (a -> b) -> [a] -> [b]
map a -> Source
forall a. HasSource a => a -> Source
getSource ([a] -> [Source]) -> (t a -> [a]) -> t a -> [Source]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList

{-# INLINE stop1 #-}
stop1 :: (HasSource a, MonadIO m) => a -> m ()
stop1 :: a -> m ()
stop1 a
src = [a] -> m ()
forall (t :: * -> *) a (m :: * -> *).
(Foldable t, HasSource a, MonadIO m) =>
t a -> m ()
stop [a
src]

{-# INLINE stop #-}
stop :: (Foldable t, HasSource a, MonadIO m) => t a -> m ()
stop :: t a -> m ()
stop = [Source] -> m ()
forall (m :: * -> *). MonadIO m => [Source] -> m ()
OpenAL.stop ([Source] -> m ()) -> (t a -> [Source]) -> t a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Source) -> [a] -> [Source]
forall a b. (a -> b) -> [a] -> [b]
map a -> Source
forall a. HasSource a => a -> Source
getSource ([a] -> [Source]) -> (t a -> [a]) -> t a -> [Source]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList

{-# INLINE toggle #-}
toggle :: (HasSource a, MonadIO m) => Bool -> a -> m ()
toggle :: Bool -> a -> m ()
toggle Bool
active a
src =
  if Bool
active then
    [Source] -> m ()
forall (m :: * -> *). MonadIO m => [Source] -> m ()
OpenAL.play [Source]
srcs
  else
    [Source] -> m ()
forall (m :: * -> *). MonadIO m => [Source] -> m ()
OpenAL.stop [Source]
srcs
  where
    srcs :: [Source]
srcs = [a -> Source
forall a. HasSource a => a -> Source
getSource a
src]