{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} ------------------------------------------------------------------------------------- -- | -- Copyright : (c) Hans Hoglund 2012 -- -- License : BSD-style -- -- Maintainer : hans@hanshoglund.se -- Stability : experimental -- Portability : non-portable (TF,GNTD) -- -- Provides stretchable values. -- ------------------------------------------------------------------------------------- module Music.Time.Stretchable ( -- * Stretchable class Stretchable(..), compress, stretching, -- ** Utility NoStretch(..), ) where import Control.Arrow 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 -- | -- Stretchable values. -- class Stretchable a where -- | -- Stretch (augment) a value by the given factor. -- stretch :: Duration -> a -> a stretch _ = id instance Stretchable Time where stretch n = (n*.) instance Stretchable Duration where stretch n = (n*^) instance Stretchable (Time, a) where stretch n (t, a) = (n `stretch` t, a) instance Stretchable (Duration, a) where stretch n (d, a) = (n `stretch` d, a) instance Stretchable (Time, Duration, a) where stretch n (t, d, a) = (n `stretch` t, n `stretch` d, a) instance Stretchable (Time -> a) where stretch n = (. relative origin (^/ n)) instance Stretchable (Duration -> a) where stretch n = (. (^/ n)) instance Stretchable a => Stretchable [a] where stretch n = fmap (stretch n) instance Stretchable a => Stretchable (Map k a) where stretch n = fmap (stretch n) instance Stretchable a => Stretchable (Product a) where stretch n (Product x) = Product (stretch n x) instance Stretchable a => Stretchable (Sum a) where stretch n (Sum x) = Sum (stretch n x) -- | -- Compress (diminish) a score. Flipped version of 'stretch'. -- compress :: Stretchable a => Duration -> a -> a compress x = stretch (recip x) -- | Apply a function under stretch. -- See also 'sunder'. stretching :: (Stretchable a, Stretchable b) => Duration -> (a -> b) -> a -> b stretching t f = compress t . f . stretch t newtype NoStretch a = NoStretch { getNoStretch :: a } deriving (Eq, Ord, Enum, Show, Semigroup, Monoid {-Delayable, HasOnset, HasOffset, HasDuration-}) instance Stretchable (NoStretch a) where stretch _ = id