module Music.Score.Pitch (
Pitch,
SetPitch,
Interval,
HasPitch(..),
HasPitches(..),
HasPitch',
HasPitches',
pitch',
pitches',
PitchPair,
AffinePair,
Transposable,
up,
down,
above,
below,
octavesUp,
octavesDown,
_15va,
_8va,
_8vb,
_15vb,
invertPitches,
highest,
lowest,
meanPitch,
) where
import Control.Applicative
import Control.Lens hiding (above, below, transform)
import Control.Monad (MonadPlus (..), ap, join, liftM,
mfilter)
import Data.AffineSpace
import Data.AffineSpace.Point
import Data.Foldable (Foldable)
import Data.Functor.Couple
import qualified Data.List as List
import Data.Ratio
import Data.Semigroup
import Data.String
import Data.Monoid.Average
import Data.Traversable (Traversable)
import Data.Typeable
import Data.VectorSpace hiding (Sum)
import Data.Set (Set)
import Data.Map (Map)
import Data.Sequence (Seq)
import qualified Data.Set as Set
import qualified Data.Map as Map
import qualified Data.Sequence as Seq
import Music.Pitch.Literal
import Music.Score.Harmonics
import Music.Score.Part
import Music.Score.Slide
import Music.Score.Text
import Music.Score.Ties
import Music.Score.Phrases
import Music.Time
import Music.Time.Internal.Transform
type family Pitch (s :: *) :: *
type family SetPitch (b :: *) (s :: *) :: *
class HasPitches s t => HasPitch s t where
pitch :: Lens s t (Pitch s) (Pitch t)
class (Transformable (Pitch s),
Transformable (Pitch t),
SetPitch (Pitch t) s ~ t) => HasPitches s t where
pitches :: Traversal s t (Pitch s) (Pitch t)
type HasPitch' a = HasPitch a a
type HasPitches' a = HasPitches a a
pitch' :: HasPitch' s => Lens' s (Pitch s)
pitch' = pitch
pitches' :: HasPitches' s => Traversal' s (Pitch s)
pitches' = pitches
#define PRIM_PITCH_INSTANCE(TYPE) \
\
type instance Pitch TYPE = TYPE; \
type instance SetPitch a TYPE = a; \
\
instance (Transformable a, a ~ Pitch a) \
=> HasPitch TYPE a where { \
pitch = ($) } ; \
\
instance (Transformable a, a ~ Pitch a) \
=> HasPitches TYPE a where { \
pitches = ($) } ; \
PRIM_PITCH_INSTANCE(())
PRIM_PITCH_INSTANCE(Bool)
PRIM_PITCH_INSTANCE(Ordering)
PRIM_PITCH_INSTANCE(Char)
PRIM_PITCH_INSTANCE(Int)
PRIM_PITCH_INSTANCE(Integer)
PRIM_PITCH_INSTANCE(Float)
PRIM_PITCH_INSTANCE(Double)
type instance Pitch (c,a) = Pitch a
type instance SetPitch b (c,a) = (c,SetPitch b a)
type instance Pitch [a] = Pitch a
type instance SetPitch b [a] = [SetPitch b a]
type instance Pitch (Map k a) = Pitch a
type instance SetPitch b (Map k a) = Map k (SetPitch b a)
type instance Pitch (Seq a) = Pitch a
type instance SetPitch b (Seq a) = Seq (SetPitch b a)
type instance Pitch (Maybe a) = Pitch a
type instance SetPitch b (Maybe a) = Maybe (SetPitch b a)
type instance Pitch (Either c a) = Pitch a
type instance SetPitch b (Either c a) = Either c (SetPitch b a)
type instance Pitch (Event a) = Pitch a
type instance SetPitch b (Event a) = Event (SetPitch b a)
type instance Pitch (Placed a) = Pitch a
type instance SetPitch b (Placed a) = Placed (SetPitch b a)
type instance Pitch (Note a) = Pitch a
type instance SetPitch b (Note a) = Note (SetPitch b a)
type instance Pitch (Voice a) = Pitch a
type instance SetPitch b (Voice a) = Voice (SetPitch b a)
type instance Pitch (Track a) = Pitch a
type instance SetPitch b (Track a) = Track (SetPitch b a)
type instance Pitch (Score a) = Pitch a
type instance SetPitch b (Score a) = Score (SetPitch b a)
type instance Pitch (Aligned a) = Pitch a
type instance SetPitch b (Aligned a) = Aligned (SetPitch b a)
instance HasPitches a b => HasPitches (Aligned a) (Aligned b) where
pitches = _Wrapped . pitches
instance HasPitch a b => HasPitch (c, a) (c, b) where
pitch = _2 . pitch
instance HasPitches a b => HasPitches (c, a) (c, b) where
pitches = traverse . pitches
instance (HasPitches a b) => HasPitches (Event a) (Event b) where
pitches = from event . whilstL pitches
instance (HasPitch a b) => HasPitch (Event a) (Event b) where
pitch = from event . whilstL pitch
instance (HasPitches a b) => HasPitches (Placed a) (Placed b) where
pitches = _Wrapped . whilstLT pitches
instance (HasPitch a b) => HasPitch (Placed a) (Placed b) where
pitch = _Wrapped . whilstLT pitch
instance (HasPitches a b) => HasPitches (Note a) (Note b) where
pitches = _Wrapped . whilstLD pitches
instance (HasPitch a b) => HasPitch (Note a) (Note b) where
pitch = _Wrapped . whilstLD pitch
instance HasPitches a b => HasPitches [a] [b] where
pitches = traverse . pitches
instance HasPitches a b => HasPitches (Seq a) (Seq b) where
pitches = traverse . pitches
instance HasPitches a b => HasPitches (Map k a) (Map k b) where
pitches = traverse . pitches
instance HasPitches a b => HasPitches (Maybe a) (Maybe b) where
pitches = traverse . pitches
instance HasPitches a b => HasPitches (Either c a) (Either c b) where
pitches = traverse . pitches
instance HasPitches a b => HasPitches (Voice a) (Voice b) where
pitches = traverse . pitches
instance HasPitches a b => HasPitches (Track a) (Track b) where
pitches = traverse . pitches
instance (HasPitches a b) => HasPitches (Score a) (Score b) where
pitches =
_Wrapped . _2
. _Wrapped
. traverse
. from event
. whilstL pitches
type instance Pitch (Sum a) = Pitch a
type instance SetPitch b (Sum a) = Sum (SetPitch b a)
instance HasPitches a b => HasPitches (Sum a) (Sum b) where
pitches = _Wrapped . pitches
type instance Pitch (Behavior a) = Behavior a
type instance SetPitch b (Behavior a) = b
instance (Transformable a, Transformable b, b ~ Pitch b) => HasPitches (Behavior a) b where
pitches = ($)
instance (Transformable a, Transformable b, b ~ Pitch b) => HasPitch (Behavior a) b where
pitch = ($)
type instance Pitch (Couple c a) = Pitch a
type instance SetPitch g (Couple c a) = Couple c (SetPitch g a)
type instance Pitch (TextT a) = Pitch a
type instance SetPitch g (TextT a) = TextT (SetPitch g a)
type instance Pitch (HarmonicT a) = Pitch a
type instance SetPitch g (HarmonicT a) = HarmonicT (SetPitch g a)
type instance Pitch (TieT a) = Pitch a
type instance SetPitch g (TieT a) = TieT (SetPitch g a)
type instance Pitch (SlideT a) = Pitch a
type instance SetPitch g (SlideT a) = SlideT (SetPitch g a)
instance (HasPitches a b) => HasPitches (Couple c a) (Couple c b) where
pitches = _Wrapped . pitches
instance (HasPitch a b) => HasPitch (Couple c a) (Couple c b) where
pitch = _Wrapped . pitch
instance (HasPitches a b) => HasPitches (TextT a) (TextT b) where
pitches = _Wrapped . pitches
instance (HasPitch a b) => HasPitch (TextT a) (TextT b) where
pitch = _Wrapped . pitch
instance (HasPitches a b) => HasPitches (HarmonicT a) (HarmonicT b) where
pitches = _Wrapped . pitches
instance (HasPitch a b) => HasPitch (HarmonicT a) (HarmonicT b) where
pitch = _Wrapped . pitch
instance (HasPitches a b) => HasPitches (TieT a) (TieT b) where
pitches = _Wrapped . pitches
instance (HasPitch a b) => HasPitch (TieT a) (TieT b) where
pitch = _Wrapped . pitch
instance (HasPitches a b) => HasPitches (SlideT a) (SlideT b) where
pitches = _Wrapped . pitches
instance (HasPitch a b) => HasPitch (SlideT a) (SlideT b) where
pitch = _Wrapped . pitch
type Interval a = Diff (Pitch a)
type PitchPair v w = (Num (Scalar v), IsInterval v, IsPitch w)
type AffinePair v w = (VectorSpace v, AffineSpace w)
type Transposable a = (
HasPitches' a,
AffinePair (Interval a) (Pitch a),
PitchPair (Interval a) (Pitch a)
)
up :: Transposable a => Interval a -> a -> a
up v = pitches %~ (.+^ v)
down :: Transposable a => Interval a -> a -> a
down v = pitches %~ (.-^ v)
above :: (Semigroup a, Transposable a) => Interval a -> a -> a
above v x = x <> up v x
below :: (Semigroup a, Transposable a) => Interval a -> a -> a
below v x = x <> down v x
invertPitches :: Transposable a => Pitch a -> a -> a
invertPitches p = pitches %~ reflectThrough p
octavesUp :: Transposable a => Scalar (Interval a) -> a -> a
octavesUp n = up (_P8^*n)
octavesDown :: Transposable a => Scalar (Interval a) -> a -> a
octavesDown n = down (_P8^*n)
_15va :: Transposable a => a -> a
_15va = octavesUp 2
_8va :: Transposable a => a -> a
_8va = octavesUp 1
_8vb :: Transposable a => a -> a
_8vb = octavesDown 1
_15vb :: Transposable a => a -> a
_15vb = octavesDown 2
highest :: (HasPitches' a, Ord (Pitch a)) => a -> Maybe (Pitch a)
highest = maximumOf pitches'
lowest :: (HasPitches' a, Ord (Pitch a)) => a -> Maybe (Pitch a)
lowest = minimumOf pitches'
meanPitch :: (HasPitches' a, Fractional (Pitch a)) => a -> Maybe (Pitch a)
meanPitch = maybeAverage . Average . toListOf pitches'