{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE OverloadedStrings #-} {-# 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 parts. -- ------------------------------------------------------------------------------------- module Music.Score.Part ( -- ** Articulation type functions Part, SetPart, -- ** Accessing parts HasParts(..), HasPart(..), HasPart', HasParts', part', parts', -- * Listing parts allParts, -- * Extracting parts extracted, extractedWithInfo, extractPart, extractParts, extractPartsWithInfo, -- * Manipulating parts -- * Part representation PartT(..), -- Part, -- HasPart(..), -- HasPart', -- PartT(..), -- getParts, (), rcat, ) where import Control.Applicative import Control.Comonad import Control.Lens hiding (parts, transform) import Control.Monad.Plus -- import Data.Default import Data.Foldable import Data.Functor.Couple import qualified Data.List as List import qualified Data.List as List import Data.Ord (comparing) import Data.PairMonad import Data.Ratio import Data.Semigroup import Data.Traversable import Data.Typeable import Music.Dynamics.Literal import Music.Pitch.Literal import Music.Score.Ties import Music.Score.Internal.Util (through) import Music.Time import Music.Time.Internal.Transform -- | -- Parts type. -- type family Part (s :: *) :: * -- Part s = a -- | -- Part type. -- type family SetPart (b :: *) (s :: *) :: * -- Part b s = t -- | -- Class of types that provide a single part. -- class (HasParts s t) => HasPart s t where -- | Part type. part :: Lens s t (Part s) (Part t) -- | -- Class of types that provide a part traversal. -- class (Transformable (Part s), Transformable (Part t) -- , SetPart (Part t) s ~ t ) => HasParts s t where -- | Part type. parts :: Traversal s t (Part s) (Part t) type HasPart' a = HasPart a a type HasParts' a = HasParts a a -- | -- Part type. -- part' :: (HasPart s t, s ~ t) => Lens' s (Part s) part' = part -- | -- Part type. -- parts' :: (HasParts s t, s ~ t) => Traversal' s (Part s) parts' = parts type instance Part Bool = Bool type instance SetPart a Bool = a instance (b ~ Part b, Transformable b) => HasPart Bool b where part = ($) instance (b ~ Part b, Transformable b) => HasParts Bool b where parts = ($) type instance Part Ordering = Ordering type instance SetPart a Ordering = a instance (b ~ Part b, Transformable b) => HasPart Ordering b where part = ($) instance (b ~ Part b, Transformable b) => HasParts Ordering b where parts = ($) type instance Part () = () type instance SetPart a () = a instance (b ~ Part b, Transformable b) => HasPart () b where part = ($) instance (b ~ Part b, Transformable b) => HasParts () b where parts = ($) type instance Part Int = Int type instance SetPart a Int = a instance HasPart Int Int where part = ($) instance HasParts Int Int where parts = ($) type instance Part Integer = Integer type instance SetPart a Integer = a instance HasPart Integer Integer where part = ($) instance HasParts Integer Integer where parts = ($) type instance Part Float = Float type instance SetPart a Float = a instance HasPart Float Float where part = ($) instance HasParts Float Float where parts = ($) type instance Part (c,a) = Part a type instance SetPart b (c,a) = (c,SetPart b a) type instance Part [a] = Part a type instance SetPart b [a] = [SetPart b a] type instance Part (Maybe a) = Part a type instance SetPart b (Maybe a) = Maybe (SetPart b a) type instance Part (Either c a) = Part a type instance SetPart b (Either c a) = Either c (SetPart b a) type instance Part (Aligned a) = Part a type instance SetPart b (Aligned a) = Aligned (SetPart b a) instance HasParts a b => HasParts (Aligned a) (Aligned b) where parts = _Wrapped . parts instance HasPart a b => HasPart (c, a) (c, b) where part = _2 . part instance HasParts a b => HasParts (c, a) (c, b) where parts = traverse . parts instance HasParts a b => HasParts [a] [b] where parts = traverse . parts instance HasParts a b => HasParts (Maybe a) (Maybe b) where parts = traverse . parts instance HasParts a b => HasParts (Either c a) (Either c b) where parts = traverse . parts type instance Part (Event a) = Part a type instance SetPart g (Event a) = Event (SetPart g a) instance (HasPart a b) => HasPart (Event a) (Event b) where part = from event . whilstL part instance (HasParts a b) => HasParts (Event a) (Event b) where parts = from event . whilstL parts type instance Part (Note a) = Part a type instance SetPart g (Note a) = Note (SetPart g a) instance (HasPart a b) => HasPart (Note a) (Note b) where part = from note . whilstLD part instance (HasParts a b) => HasParts (Note a) (Note b) where parts = from note . whilstLD parts -- | -- List all the parts -- allParts :: (Ord (Part a), HasParts' a) => a -> [Part a] allParts = List.nub . List.sort . toListOf parts -- | -- List all the parts -- extractPart :: (Eq (Part a), HasPart' a) => Part a -> Score a -> Score a extractPart = extractPartG extractPartG :: (Eq (Part a), MonadPlus f, HasPart' a) => Part a -> f a -> f a extractPartG p x = head $ (\p s -> filterPart (== p) s) <$> [p] <*> return x -- | -- List all the parts -- extractParts :: (Ord (Part a), HasPart' a) => Score a -> [Score a] extractParts = extractPartsG extractPartsG :: ( MonadPlus f, HasParts' (f a), HasPart' a, Part (f a) ~ Part a, Ord (Part a) ) => f a -> [f a] extractPartsG x = (\p s -> filterPart (== p) s) <$> allParts x <*> return x filterPart :: (MonadPlus f, HasPart a a) => (Part a -> Bool) -> f a -> f a filterPart p = mfilter (\x -> p (x ^. part)) extractPartsWithInfo :: (Ord (Part a), HasPart' a) => Score a -> [(Part a, Score a)] extractPartsWithInfo x = zip (allParts x) (extractParts x) extracted :: (Ord (Part a), HasPart' a{-, HasPart a b-}) => Iso (Score a) (Score b) [Score a] [Score b] extracted = iso extractParts mconcat extractedWithInfo :: (Ord (Part a), Ord (Part b), HasPart' a, HasPart' b) => Iso (Score a) (Score b) [(Part a, Score a)] [(Part b, Score b)] extractedWithInfo = iso extractPartsWithInfo $ mconcat . fmap (uncurry $ set parts') newtype PartT n a = PartT { getPartT :: (n, a) } deriving (Eq, Ord, Show, Typeable, Functor, Applicative, Comonad, Monad, Transformable) instance Wrapped (PartT p a) where type Unwrapped (PartT p a) = (p, a) _Wrapped' = iso getPartT PartT instance Rewrapped (PartT p a) (PartT p' b) type instance Part (PartT p a) = p type instance SetPart p' (PartT p a) = PartT p' a instance (Transformable p, Transformable p') => HasPart (PartT p a) (PartT p' a) where part = _Wrapped . _1 instance (Transformable p, Transformable p') => HasParts (PartT p a) (PartT p' a) where parts = _Wrapped . _1 instance (IsPitch a, Enum n) => IsPitch (PartT n a) where fromPitch l = PartT (toEnum 0, fromPitch l) instance (IsDynamics a, Enum n) => IsDynamics (PartT n a) where fromDynamics l = PartT (toEnum 0, fromDynamics l) instance Reversible a => Reversible (PartT p a) where rev = fmap rev instance Tiable a => Tiable (PartT n a) where isTieEndBeginning (PartT (_,a)) = isTieEndBeginning a toTied (PartT (v,a)) = (PartT (v,b), PartT (v,c)) where (b,c) = toTied a type instance Part (Segment a) = Segment (Part a) type instance SetPart (Segment g) (Segment a) = Segment (SetPart g a) instance (HasPart a a, HasPart a b) => HasParts (Segment a) (Segment b) where parts = through part part instance (HasPart a a, HasPart a b) => HasPart (Segment a) (Segment b) where part = through part part type instance Part (Behavior a) = Behavior (Part a) type instance SetPart (Behavior g) (Behavior a) = Behavior (SetPart g a) instance (HasPart a a, HasPart a b) => HasParts (Behavior a) (Behavior b) where parts = through part part instance (HasPart a a, HasPart a b) => HasPart (Behavior a) (Behavior b) where part = through part part type instance Part (Score a) = Part a type instance SetPart g (Score a) = Score (SetPart g a) instance (HasParts a b) => HasParts (Score a) (Score b) where parts = _Wrapped . _2 -- into NScore . _Wrapped . traverse . from event -- this needed? . whilstL parts type instance Part (Voice a) = Part a type instance SetPart g (Voice a) = Voice (SetPart g a) instance (HasParts a b) => HasParts (Voice a) (Voice b) where parts = _Wrapped . traverse . _Wrapped -- this needed? . whilstLD parts infixr 6 -- | -- Concatenate parts. -- rcat :: (HasParts' a, Enum (Part a)) => [Score a] -> Score a rcat = List.foldr () mempty -- | -- Similar to '<>', but increases parts in the second part to prevent collision. -- () :: (HasParts' a, Enum (Part a)) => Score a -> Score a -> Score a a b = a <> moveParts offset b where -- max voice in a + 1 offset = succ $ maximum' 0 $ fmap fromEnum $ toListOf parts a -- | -- Move down one voice (all parts). -- moveParts :: (Integral b, HasParts' a, Enum (Part a)) => b -> Score a -> Score a moveParts x = parts %~ (successor x) -- | -- Move top-part to the specific voice (other parts follow). -- moveToPart :: (Enum b, HasParts' a, Enum (Part a)) => b -> Score a -> Score a moveToPart v = moveParts (fromEnum v) iterating :: (a -> a) -> (a -> a) -> Int -> a -> a iterating f g n | n < 0 = f . iterating f g (n + 1) | n == 0 = id | n > 0 = g . iterating f g (n - 1) successor :: (Integral b, Enum a) => b -> a -> a successor n = iterating pred succ (fromIntegral n) maximum' :: (Ord a, Foldable t) => a -> t a -> a maximum' z = option z getMax . foldMap (Option . Just . Max)