music-score-1.3: src/Music/Time/Onset.hs
{-# LANGUAGE
TypeFamilies,
DeriveFunctor,
DeriveFoldable,
FlexibleContexts,
GeneralizedNewtypeDeriving #-}
-------------------------------------------------------------------------------------
-- |
-- Copyright : (c) Hans Hoglund 2012
--
-- License : BSD-style
--
-- Maintainer : hans@hanshoglund.se
-- Stability : experimental
-- Portability : non-portable (TF,GNTD)
--
-------------------------------------------------------------------------------------
module Music.Time.Onset (
HasDuration(..),
HasOnset(..),
HasOffset(..),
HasPreOnset(..),
HasPostOnset(..),
HasPostOffset(..),
-- ** Defaults
durationDefault,
onsetDefault,
offsetDefault,
-- ** Wrappers
AddOffset(..),
) where
import Data.Semigroup
import Data.VectorSpace
import Data.AffineSpace
import Music.Time.Pos
import Music.Time.Time
import Music.Time.Duration
import Music.Time.Delayable
import Music.Time.Stretchable
class HasDuration s where
duration :: s a -> Duration s
-- |
-- Class of types with a position in time.
--
-- Onset and offset are logical start and stop time, i.e. the preferred beginning and end
-- of the sound, not o the the time of the attack and damp actions on an instrument,
--
-- 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 s where
-- |
-- Get the onset of the given value.
--
onset :: s a -> Time s
class HasOffset s where
-- |
-- Get the offset of the given value.
--
offset :: s a -> Time s
class HasPreOnset s where
preOnset :: s a -> Time s
class HasPostOnset s where
postOnset :: s a -> Time s
class HasPostOffset s where
postOffset :: s a -> Time s
-- | Given 'HasOnset' and 'HasOffset' instances, this function implements 'duration'.
durationDefault :: (AffineSpace (Time s), HasOffset s, HasOnset s) => s a -> Duration s
durationDefault x = offset x .-. onset x
-- | Given 'HasDuration' and 'HasOffset' instances, this function implements 'onset'.
onsetDefault :: (AffineSpace (Time s), HasOffset s, HasDuration s) => s a -> Time s
onsetDefault x = offset x .-^ duration x
-- | Given 'HasOnset' and 'HasOnset' instances, this function implements 'offset'.
offsetDefault :: (AffineSpace (Time s), HasOnset s, HasDuration s) => s a -> Time s
offsetDefault x = onset x .+^ duration x
newtype AddOffset t s a = AddOffset (t, s a)
type instance Time (AddOffset t s) = t
instance (Delayable a, t ~ Time a) => Delayable (AddOffset t a) where
delay d (AddOffset (t,a)) = AddOffset (t, delay d a)
instance (Stretchable a, t ~ Time a) => Stretchable (AddOffset t a) where
stretch d (AddOffset (t,a)) = AddOffset (t, stretch d a)
instance (HasOnset a, t ~ Time a) => HasOnset (AddOffset t a) where
onset (AddOffset (t,a)) = onset a
instance HasOffset (AddOffset t s) where
offset (AddOffset (t,_)) = t