music-score-1.7: src/Music/Time/Note.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# 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.Note (
-- * Note type
Note,
-- * Construction
note,
event,
noteValue,
) where
import Data.AffineSpace
import Data.AffineSpace.Point
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Ratio
import Data.Semigroup
import Data.Set (Set)
import qualified Data.Set as Set
import Data.VectorSpace
import Music.Time.Reverse
import Music.Time.Split
import Control.Applicative
import Control.Arrow (first, second, (&&&), (***))
import Control.Comonad
import Control.Comonad.Env
import Control.Lens hiding (Indexable, Level, above, below,
index, inside, parts, reversed,
transform, (<|), (|>))
import Data.Foldable (Foldable)
import qualified Data.Foldable as Foldable
import Data.PairMonad
import Data.Typeable
import Music.Time.Internal.Util (through, tripped)
-- |
-- A 'Note' is a value with an 'onset' and and 'offset' in time. It is an instance
-- of 'Transformable'.
--
-- You can use 'value' to apply a function in the context of the transformation,
-- i.e.
--
-- @
-- over value (* line) (delay 2 $ return line)
-- @
--
-- @
-- ('view' 'value') . 'transform' s = 'transform' s . ('view' 'value')
-- @
--
-- The semantics are given by
--
-- @
-- type Note a = (Span, a)
-- @
--
newtype Note a = Note { _noteValue :: (Span, a) }
deriving (Typeable)
deriving instance Eq a => Eq (Note a)
deriving instance Functor Note
deriving instance Foldable Note
deriving instance Traversable Note
deriving instance Comonad Note
instance (Show a, Transformable a) => Show (Note a) where
show x = show (x^.from note) ++ "^.note"
-- |
-- Note is a 'Monad' and 'Applicative' in the style of pair, with 'return' placing a value
-- at the default span 'mempty' and 'join' composing time transformations.
deriving instance Monad Note
deriving instance Applicative Note
-- instance ComonadEnv Span Note where
-- ask = noteValueSpan
-- | Unsafe: Do not use 'Wrapped' instances
instance Wrapped (Note a) where
type Unwrapped (Note a) = (Span, a)
_Wrapped' = iso _noteValue Note
instance Rewrapped (Note a) (Note b)
instance Transformable (Note a) where
transform t = over _Wrapped $ first (transform t)
instance HasDuration (Note a) where
_duration = _duration . ask . view _Wrapped
instance HasPosition (Note a) where
x `_position` p = ask (view _Wrapped x) `_position` p
instance Splittable a => Splittable (Note a) where
-- beginning d = over _Wrapped $ \(s, v) -> (beginning d s, beginning (transform (negateV s) d) v)
beginning d = over _Wrapped $ \(s, v) -> (beginning d s, beginning (d / _duration s) v)
ending d = over _Wrapped $ \(s, v) -> (ending d s, ending (1 - (d / _duration s)) v)
instance Reversible (Note a) where
rev = revDefault
-- |
-- View a note as a pair of the original value and the transformation (and vice versa).
--
note :: ({-Transformable a, Transformable b-}) => Iso (Span, a) (Span, b) (Note a) (Note b)
note = _Unwrapped
-- |
-- View the value in the note.
--
noteValue :: (Transformable a, Transformable b) => Lens (Note a) (Note b) a b
noteValue = lens runNote (flip $ mapNote . const)
where
runNote = uncurry transform . view _Wrapped
-- setNote f (view (from note) -> (s,x)) = view note (s, itransform s x)
mapNote f (view (from note) -> (s,x)) = view note (s, f `whilst` negateV s $ x)
{-# INLINE noteValue #-}
-- |
-- View a note as an events, i.e. a time-duration-value triplet.
--
event :: Iso (Note a) (Note b) (Time, Duration, a) (Time, Duration, b)
event = from note . bimapping delta id . tripped