{-# Language TypeFamilies #-}
module Temporal.Class(
   DurOf, Duration(..), Melody(..), Harmony(..), Compose(..),
   loopBy, melMap, harMap,
   Delay(..), (+|),
   Rest(..), Stretch(..), (*|), Limit(..),
   Loop(..)
) where

-- | Calculates duration.
class Duration a where
   dur :: a -> DurOf a

-- | Duration for the given type.
type family DurOf a :: *

class Melody a where
   -- | Sequent composition for a list of values (melody).
   mel :: [a] -> a
   -- | Sequent composition. Play first track then second.
   (+:+) :: a -> a -> a

   a +:+ b = mel [a, b]
   mel = foldl1 (+:+)
   {-# MINIMAL mel | (+:+) #-}

class Harmony a where
   -- | Parallel composition for a list of values (harmony).
   har :: [a] -> a

   -- | Parallel composition. Play two tracks simultaneously.
   (=:=) :: a -> a -> a

   a =:= b = har [a, b]
   har = foldl1 (=:=)
   {-# MINIMAL har | (=:=) #-}


class (Melody a, Harmony a) => Compose a where

-- | Repeats the given audio segment several times.
loopBy :: Melody a => Int -> a -> a
loopBy n = mel . replicate n

class Delay a where
   -- | Delays the sound source by the given duration.
   del :: DurOf a -> a -> a

class Stretch a where
   -- | Delays the sound source by the given duration factor.
   str :: DurOf a -> a -> a

-- | Infix 'del' function.
(+|) :: Delay a => DurOf a -> a -> a
(+|) = del

-- | Infix 'str' function.
(*|) :: Stretch a => DurOf a -> a -> a
(*|) = str

class Rest a where
   rest :: DurOf a -> a

class Limit a where
   -- | Limits the duration of the sound source.
   lim :: DurOf a -> a -> a

class Loop a where
   -- | Loops over the sound
   loop :: a -> a

-- | Transforms a sequence and then applies a mel.
melMap :: (Melody b) => (a -> b) -> [a] -> b
melMap f xs = mel $ fmap f xs

-- | Transforms a sequence and then applies a har.
harMap :: (Harmony b) => (a -> b) -> [a] -> b
harMap f xs = har $ fmap f xs