{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} ------------------------------------------------------------------------------------- -- | -- Copyright : (c) Hans Hoglund 2012-2014 -- -- License : BSD-style -- -- Maintainer : hans@hanshoglund.se -- Stability : experimental -- Portability : non-portable (TF,GNTD) -- ------------------------------------------------------------------------------------- module Music.Time.Split ( module Music.Time.Position, -- * The Splittable class Splittable(..), -- * Miscellaneous chunks, ) where import Control.Lens hiding (Indexable, Level, above, below, index, inside, parts, reversed, transform, (<|), (|>)) import Data.AffineSpace import Data.AffineSpace.Point import Data.Functor.Adjunction (unzipR) import Data.Functor.Rep import Data.Map (Map) import qualified Data.Map as Map import Data.Semigroup hiding () import Data.Sequence (Seq) import qualified Data.Sequence as Seq import Data.VectorSpace hiding (Sum (..)) import Music.Time.Internal.Util import Music.Time.Position -- | -- Class of values that can be split. -- -- Instances should satisfy: -- -- @ -- ('beginning' t x)^.'duration' + ('ending' t x)^.'duration' = x^.'duration' -- ('beginning' t x)^.'duration' = t `min` x^.'duration' iff t >= 0 -- ('ending' t x)^.'duration' = x^.'duration' - (t `min` x^.'duration') iff t >= 0 -- @ -- -- (Note that any of these three laws can be derived from the other two, so it is -- sufficient to prove two!). -- class HasDuration a => Splittable a where -- | Split a value at the given duration and return both parts. split :: Duration -> a -> (a, a) split d x = (beginning d x, ending d x) -- | Split a value at the given duration and return only the first part. beginning :: Duration -> a -> a -- | Split a value at the given duration and return only the second part. ending :: Duration -> a -> a beginning d = fst . split d ending d = snd . split d {-# MINIMAL (split) | (beginning, ending) #-} instance Splittable () where split _ x = (x, x) instance Splittable Char where split _ x = (x,x) instance Splittable Int where split _ x = (x,x) instance Splittable Double where split _ x = (x,x) instance Splittable Duration where -- Directly from the laws -- Guard against t < 0 split t x = (t' `min` x, x ^-^ (t' `min` x)) where t' = t `max` 0 chunks :: (Transformable a, Splittable a) => Duration -> a -> [a] chunks d xs = if xs^.duration <= 0 then [] else chunks' d xs where chunks' d (split d -> (x, xs)) = [x] ++ chunks d xs