{-# LANGUAGE CPP #-} {-# 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 TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} ------------------------------------------------------------------------------------- -- | -- Copyright : (c) Hans Hoglund 2012-2014 -- -- License : BSD-style -- -- Maintainer : hans@hanshoglund.se -- Stability : experimental -- Portability : non-portable (TF,GNTD) -- -- Provides functions for manipulating dynamics. -- ------------------------------------------------------------------------------------- module Music.Score.Dynamics ( -- * Dynamic type functions Dynamic, SetDynamic, DynamicLensLaws', DynamicLensLaws, -- * Accessing dynamics HasDynamics(..), HasDynamic(..), HasDynamics', HasDynamic', dynamic', dynamics', -- * Manipulating dynamics Level, Attenuable, louder, softer, level, compressor, fadeIn, fadeOut, DynamicT(..), -- * Context vdynamic, addDynCon, ) where import Control.Applicative import Control.Comonad import Control.Lens hiding (Level, transform) import Control.Monad import Data.AffineSpace import Data.Foldable import Data.Functor.Couple import Data.Functor.Context import qualified Data.List as List import Data.Maybe import Data.Ratio import Data.Semigroup import Data.Typeable import Data.VectorSpace hiding (Sum) import Music.Dynamics.Literal import Music.Pitch.Literal import Music.Score.Harmonics import Music.Score.Part import Music.Score.Phrases import Music.Score.Slide import Music.Score.Text import Music.Score.Ties import Music.Score.Internal.Util (through) import Music.Time import Music.Time.Internal.Transform -- | -- Dynamics type. -- type family Dynamic (s :: *) :: * -- | -- Dynamic type. -- type family SetDynamic (b :: *) (s :: *) :: * -- | -- Class of types that provide a single dynamic. -- class (HasDynamics s t) => HasDynamic s t where -- | Access a single dynamic. dynamic :: Lens s t (Dynamic s) (Dynamic t) type DynamicLensLaws' s t a b = ( Dynamic (SetDynamic a s) ~ a, SetDynamic (Dynamic t) s ~ t, SetDynamic a (SetDynamic b s) ~ SetDynamic a s ) type DynamicLensLaws s t = DynamicLensLaws' s t (Dynamic s) (Dynamic t) -- | -- Class of types that provide a dynamic traversal. -- class ( Transformable (Dynamic s), Transformable (Dynamic t), -- SetDynamic (Dynamic t) s ~ t DynamicLensLaws s t ) => HasDynamics s t where -- | Access all dynamics. dynamics :: Traversal s t (Dynamic s) (Dynamic t) type HasDynamic' a = HasDynamic a a type HasDynamics' a = HasDynamics a a -- | Access a single dynamic. dynamic' :: (HasDynamic s t, s ~ t) => Lens' s (Dynamic s) dynamic' = dynamic -- | Access all dynamics. dynamics' :: (HasDynamics s t, s ~ t) => Traversal' s (Dynamic s) dynamics' = dynamics #define PRIM_DYNAMIC_INSTANCE(TYPE) \ \ type instance Dynamic TYPE = TYPE; \ type instance SetDynamic a TYPE = a; \ \ instance (Transformable a, a ~ Dynamic a, SetDynamic TYPE a ~ TYPE) \ => HasDynamic TYPE a where { \ dynamic = ($) } ; \ \ instance (Transformable a, a ~ Dynamic a, SetDynamic TYPE a ~ TYPE) \ => HasDynamics TYPE a where { \ dynamics = ($) } ; \ PRIM_DYNAMIC_INSTANCE(()) PRIM_DYNAMIC_INSTANCE(Bool) PRIM_DYNAMIC_INSTANCE(Ordering) PRIM_DYNAMIC_INSTANCE(Char) PRIM_DYNAMIC_INSTANCE(Int) PRIM_DYNAMIC_INSTANCE(Integer) PRIM_DYNAMIC_INSTANCE(Float) PRIM_DYNAMIC_INSTANCE(Double) type instance Dynamic (c,a) = Dynamic a type instance SetDynamic b (c,a) = (c,SetDynamic b a) type instance Dynamic [a] = Dynamic a type instance SetDynamic b [a] = [SetDynamic b a] type instance Dynamic (Maybe a) = Dynamic a type instance SetDynamic b (Maybe a) = Maybe (SetDynamic b a) type instance Dynamic (Either c a) = Dynamic a type instance SetDynamic b (Either c a) = Either c (SetDynamic b a) type instance Dynamic (Event a) = Dynamic a type instance SetDynamic b (Event a) = Event (SetDynamic b a) type instance Dynamic (Placed a) = Dynamic a type instance SetDynamic b (Placed a) = Placed (SetDynamic b a) type instance Dynamic (Note a) = Dynamic a type instance SetDynamic b (Note a) = Note (SetDynamic b a) type instance Dynamic (Voice a) = Dynamic a type instance SetDynamic b (Voice a) = Voice (SetDynamic b a) type instance Dynamic (Track a) = Dynamic a type instance SetDynamic b (Track a) = Track (SetDynamic b a) type instance Dynamic (Score a) = Dynamic a type instance SetDynamic b (Score a) = Score (SetDynamic b a) instance HasDynamic a b => HasDynamic (c, a) (c, b) where dynamic = _2 . dynamic instance HasDynamics a b => HasDynamics (c, a) (c, b) where dynamics = traverse . dynamics instance HasDynamics a b => HasDynamics [a] [b] where dynamics = traverse . dynamics instance HasDynamics a b => HasDynamics (Maybe a) (Maybe b) where dynamics = traverse . dynamics instance HasDynamics a b => HasDynamics (Either c a) (Either c b) where dynamics = traverse . dynamics instance (HasDynamics a b) => HasDynamics (Event a) (Event b) where dynamics = from event . whilstL dynamics instance (HasDynamic a b) => HasDynamic (Event a) (Event b) where dynamic = from event . whilstL dynamic instance (HasDynamics a b) => HasDynamics (Placed a) (Placed b) where dynamics = _Wrapped . whilstLT dynamics instance (HasDynamic a b) => HasDynamic (Placed a) (Placed b) where dynamic = _Wrapped . whilstLT dynamic instance (HasDynamics a b) => HasDynamics (Note a) (Note b) where dynamics = _Wrapped . whilstLD dynamics instance (HasDynamic a b) => HasDynamic (Note a) (Note b) where dynamic = _Wrapped . whilstLD dynamic instance HasDynamics a b => HasDynamics (Voice a) (Voice b) where dynamics = traverse . dynamics instance HasDynamics a b => HasDynamics (Track a) (Track b) where dynamics = traverse . dynamics {- type instance Dynamic (Chord a) = Dynamic a type instance SetDynamic b (Chord a) = Chord (SetDynamic b a) instance HasDynamics a b => HasDynamics (Chord a) (Chord b) where dynamics = traverse . dynamics -} instance (HasDynamics a b) => HasDynamics (Score a) (Score b) where dynamics = _Wrapped . _2 -- into NScore . _Wrapped . traverse . from event -- this needed? . whilstL dynamics type instance Dynamic (Behavior a) = Behavior a type instance SetDynamic b (Behavior a) = b instance ( Transformable a, Transformable b, b ~ Dynamic b, SetDynamic (Behavior a) b ~ Behavior a ) => HasDynamics (Behavior a) b where dynamics = ($) instance ( Transformable a, Transformable b, b ~ Dynamic b, SetDynamic (Behavior a) b ~ Behavior a ) => HasDynamic (Behavior a) b where dynamic = ($) type instance Dynamic (Couple c a) = Dynamic a type instance SetDynamic g (Couple c a) = Couple c (SetDynamic g a) type instance Dynamic (TextT a) = Dynamic a type instance SetDynamic g (TextT a) = TextT (SetDynamic g a) type instance Dynamic (HarmonicT a) = Dynamic a type instance SetDynamic g (HarmonicT a) = HarmonicT (SetDynamic g a) type instance Dynamic (TieT a) = Dynamic a type instance SetDynamic g (TieT a) = TieT (SetDynamic g a) type instance Dynamic (SlideT a) = Dynamic a type instance SetDynamic g (SlideT a) = SlideT (SetDynamic g a) instance (HasDynamics a b) => HasDynamics (Couple c a) (Couple c b) where dynamics = _Wrapped . dynamics instance (HasDynamic a b) => HasDynamic (Couple c a) (Couple c b) where dynamic = _Wrapped . dynamic instance (HasDynamics a b) => HasDynamics (TextT a) (TextT b) where dynamics = _Wrapped . dynamics instance (HasDynamic a b) => HasDynamic (TextT a) (TextT b) where dynamic = _Wrapped . dynamic instance (HasDynamics a b) => HasDynamics (HarmonicT a) (HarmonicT b) where dynamics = _Wrapped . dynamics instance (HasDynamic a b) => HasDynamic (HarmonicT a) (HarmonicT b) where dynamic = _Wrapped . dynamic instance (HasDynamics a b) => HasDynamics (TieT a) (TieT b) where dynamics = _Wrapped . dynamics instance (HasDynamic a b) => HasDynamic (TieT a) (TieT b) where dynamic = _Wrapped . dynamic instance (HasDynamics a b) => HasDynamics (SlideT a) (SlideT b) where dynamics = _Wrapped . dynamics instance (HasDynamic a b) => HasDynamic (SlideT a) (SlideT b) where dynamic = _Wrapped . dynamic -- | -- Associated interval type. -- type Level a = Diff (Dynamic a) -- | -- Class of types that can be transposed. -- type Attenuable a = (HasDynamics a a, VectorSpace (Level a), AffineSpace (Dynamic a), {-IsLevel (Level a), -} IsDynamics (Dynamic a)) -- | -- Transpose up. -- louder :: Attenuable a => Level a -> a -> a louder a = dynamics %~ (.+^ a) -- | -- Transpose down. -- softer :: Attenuable a => Level a -> a -> a softer a = dynamics %~ (.-^ a) -- | -- Transpose down. -- volume :: (Num (Dynamic t), HasDynamics s t, Dynamic s ~ Dynamic t) => Dynamic t -> s -> t volume a = dynamics *~ a -- | -- Transpose down. -- level :: Attenuable a => Dynamic a -> a -> a level a = dynamics .~ a compressor :: Attenuable a => Dynamic a -- ^ Threshold -> Scalar (Level a) -- ^ Ratio -> a -> a compressor = error "Not implemented: compressor" -- -- TODO non-linear fades etc -- -- | -- Fade in. -- fadeIn :: ( HasPosition a, HasDynamics a a, Dynamic a ~ Behavior c, Fractional c ) => Duration -> a -> a fadeIn d x = x & dynamics *~ ((_onset x >-> d) `transform` unit) -- | -- Fade in. -- fadeOut :: ( HasPosition a, HasDynamics a a, Dynamic a ~ Behavior c, Fractional c ) => Duration -> a -> a fadeOut d x = x & dynamics *~ ((d <-< _offset x) `transform` rev unit) newtype DynamicT n a = DynamicT { getDynamicT :: (n, a) } deriving (Eq, Ord, Show, Typeable, Functor, Applicative, Monad, Comonad, Transformable, Monoid, Semigroup) instance (Monoid n, Num a) => Num (DynamicT n a) where (+) = liftA2 (+) (*) = liftA2 (*) (-) = liftA2 (-) abs = fmap abs signum = fmap signum fromInteger = pure . fromInteger instance (Monoid n, Fractional a) => Fractional (DynamicT n a) where recip = fmap recip fromRational = pure . fromRational instance (Monoid n, Floating a) => Floating (DynamicT n a) where pi = pure pi sqrt = fmap sqrt exp = fmap exp log = fmap log sin = fmap sin cos = fmap cos asin = fmap asin atan = fmap atan acos = fmap acos sinh = fmap sinh cosh = fmap cosh asinh = fmap asinh atanh = fmap atanh acosh = fmap acos instance (Monoid n, Enum a) => Enum (DynamicT n a) where toEnum = pure . toEnum fromEnum = fromEnum . extract instance (Monoid n, Bounded a) => Bounded (DynamicT n a) where minBound = pure minBound maxBound = pure maxBound -- instance (Monoid n, Num a, Ord a, Real a) => Real (DynamicT n a) where -- toRational = toRational . extract -- -- instance (Monoid n, Real a, Enum a, Integral a) => Integral (DynamicT n a) where -- quot = liftA2 quot -- rem = liftA2 rem -- toInteger = toInteger . extract instance Wrapped (DynamicT p a) where type Unwrapped (DynamicT p a) = (p, a) _Wrapped' = iso getDynamicT DynamicT instance Rewrapped (DynamicT p a) (DynamicT p' b) type instance Dynamic (DynamicT p a) = p type instance SetDynamic p' (DynamicT p a) = DynamicT p' a instance (Transformable p, Transformable p') => HasDynamic (DynamicT p a) (DynamicT p' a) where dynamic = _Wrapped . _1 instance (Transformable p, Transformable p') => HasDynamics (DynamicT p a) (DynamicT p' a) where dynamics = _Wrapped . _1 deriving instance (IsPitch a, Monoid n) => IsPitch (DynamicT n a) deriving instance (IsInterval a, Monoid n) => IsInterval (DynamicT n a) instance (IsDynamics n, Monoid a) => IsDynamics (DynamicT n a) where fromDynamics l = DynamicT (fromDynamics l, mempty) deriving instance Reversible a => Reversible (DynamicT p a) instance (Tiable n, Tiable a) => Tiable (DynamicT n a) where isTieEndBeginning (DynamicT (_,a)) = isTieEndBeginning a toTied (DynamicT (d,a)) = (DynamicT (d1,a1), DynamicT (d2,a2)) where (a1,a2) = toTied a (d1,d2) = toTied d -- JUNK -- | -- View just the dynamices in a voice. -- vdynamic :: ({-SetDynamic (Dynamic t) s ~ t,-} HasDynamic a a, HasDynamic a b) => Lens (Voice a) (Voice b) (Voice (Dynamic a)) (Voice (Dynamic b)) vdynamic = lens (fmap $ view dynamic) (flip $ zipVoiceWithNoScale (set dynamic)) -- vdynamic = through dynamic dynamic addDynCon :: ( HasPhrases s t a b, HasDynamic a a, HasDynamic a b, Dynamic a ~ d, Dynamic b ~ Ctxt d ) => s -> t addDynCon = over (phrases.vdynamic) withContext