{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TypeFamilies #-} ------------------------------------------------------------------------------------- -- | -- Copyright : (c) Hans Hoglund 2012 -- -- License : BSD-style -- -- Maintainer : hans@hanshoglund.se -- Stability : experimental -- Portability : non-portable (TF,GNTD) -- -- Provides delayable values. -- ------------------------------------------------------------------------------------- module Music.Time.Delayable ( -- * Delayable class Delayable(..), undelay, delaying, move, moveBack, -- ** Utility delayTime, NoDelay(..), ) where import Data.AffineSpace import Data.AffineSpace.Point import Data.Map (Map) import qualified Data.Map as Map import Data.Semigroup import Data.Set (Set) import qualified Data.Set as Set import Data.VectorSpace hiding (Sum) import Music.Time.Time -- | -- Delayable values. -- class Delayable a where -- | -- Delay a value. -- delay :: Duration -> a -> a delay _ = id instance Delayable Time where delay n = (.+^ n) instance Delayable (Time -> a) where delay n = (. delay (negateV n)) instance Delayable a => Delayable [a] where delay n = fmap (delay n) instance (Ord a, Delayable a) => Delayable (Set a) where delay n = Set.map (delay n) instance Delayable a => Delayable (Map k a) where delay n = fmap (delay n) instance Delayable (Time, a) where delay n (t, a) = (n `delay` t, a) instance Delayable (Time, Duration, a) where delay n (t, d, a) = (n `delay` t, d, a) instance Delayable a => Delayable (Sum a) where delay n (Sum x) = Sum (delay n x) instance Delayable a => Delayable (Product a) where delay n (Product x) = Product (delay n x) -- | -- Move a score forward in time. Equivalent to 'delay'. -- move :: Delayable a => Duration -> a -> a -- | -- Move a score backward in time. Negated verison of 'delay'. -- moveBack :: Delayable a => Duration -> a -> a -- | -- Delay relative to 'origin'. Provided for situations when you have a value that -- should forward based on the distance between some time @t@ and the origin, but -- it does not necessarily have a start time. -- delayTime :: Delayable a => Time -> a -> a undelay t = delay (negateV t) move = delay moveBack t = delay (negateV t) delayTime t = delay (t .-. origin) -- | Apply a function under delay. -- See also 'sunder'. delaying :: (Delayable a, Delayable b) => Duration -> (a -> b) -> a -> b delaying t f = undelay t . f . delay t newtype NoDelay a = NoDelay { getNoDelay :: a } deriving (Eq, Ord, Enum, Show, Semigroup, Monoid {-Delayable, HasOnset, HasOffset, HasDuration-}) instance Delayable (NoDelay a) where delay _ = id