{-# LANGUAGE TypeFamilies, DeriveFunctor, DeriveFoldable, GeneralizedNewtypeDeriving #-} ------------------------------------------------------------------------------------- -- | -- Copyright : (c) Hans Hoglund 2012 -- -- License : BSD-style -- -- Maintainer : hans@hanshoglund.se -- Stability : experimental -- Portability : non-portable (TF,GNTD) -- -- Provides a musical score represenation. -- ------------------------------------------------------------------------------------- module Music.Score.Time where import Prelude hiding (foldr, concat, foldl, mapM, concatMap, maximum, sum, minimum) import Data.Semigroup import Control.Applicative import Data.Traversable import Data.Maybe import Data.Either import Data.Function (on) import Data.Ord (comparing) import Data.Ratio import Data.VectorSpace import Data.AffineSpace import Music.Score.Duration ------------------------------------------------------------------------------------- -- Time type ------------------------------------------------------------------------------------- -- | -- This type represents absolute time in seconds a known reference time. -- The reference time can be any time, but is usually the the beginning of the -- musical performance. -- -- Times forms an affine space with durations as the underlying vector space, -- that is, we can add a time to a duration to get a new time using '.+^', -- take the difference of two times to get a duration using '.-.'. -- newtype Time = Time { getTime::Rational } deriving (Eq, Ord, Num, Enum, Real, Fractional, RealFrac) -- Note: no Floating as we want to be able to switch to rational instance Show Time where show = show . getTime instance AdditiveGroup Time where zeroV = 0 (^+^) = (+) negateV = negate instance VectorSpace Time where type Scalar Time = Time (*^) = (*) instance InnerSpace Time where (<.>) = (*) instance AffineSpace Time where type Diff Time = Duration a .-. b = t2d $ a - b where t2d = Duration . getTime a .+^ b = a + d2t b where d2t = Time . getDuration -- | -- Class of types with a position in time. -- -- Onset and offset are logical start and stop time, rather than actual sounding time, -- or to put it differently, the time of the attack and damp actions on an instrument, -- rather than the actual beginning or end of the sound. -- -- If a type has an instance for both 'HasOnset' and 'HasDuration', the following laws -- should hold: -- -- > duration a = offset a - onset a -- > offset a >= onset a -- -- implying -- -- > duration a >= 0 -- -- class HasOnset a where -- |  -- Get the onset of the given value. -- onset :: a -> Time -- |  -- Get the offset of the given value. -- offset :: a -> Time instance HasOnset a => HasOnset (WrappedMonoid a) where onset = onset . unwrapMonoid offset = offset . unwrapMonoid class HasPreOnset a where preOnset :: a -> Time class HasPostOnset a where postOnset :: a -> Time class HasPostOffset a where postOffset :: a -> Time