music-score-1.7: src/Music/Score/Export/ArticulationNotation.hs
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-------------------------------------------------------------------------------------
-- |
-- Copyright : (c) Hans Hoglund 2012-2014
--
-- License : BSD-style
--
-- Maintainer : hans@hanshoglund.se
-- Stability : experimental
-- Portability : non-portable (TF,GNTD)
--
-------------------------------------------------------------------------------------
module Music.Score.Export.ArticulationNotation (
Slur(..),
Mark(..),
ArticulationNotation(..),
notateArticulation,
) where
import Data.Semigroup
import Data.Functor.Context
import Control.Lens -- ()
import Music.Score.Articulation
import Music.Score.Instances
import Music.Score.Ties
import Music.Time
-- TODO need NoSlur etc?
data Slur = NoSlur | BeginSlur | EndSlur
deriving (Eq, Ord, Show)
-- data CrescDim = NoCrescDim | BeginCresc | EndCresc | BeginDim | EndDim
data Mark = NoMark | Staccato | MoltoStaccato | Marcato | Accent | Tenuto
deriving (Eq, Ord, Show)
instance Monoid Slur where
mempty = NoSlur
mappend NoSlur a = a
mappend a NoSlur = a
mappend a _ = a
instance Monoid Mark where
mempty = NoMark
mappend NoMark a = a
mappend a NoMark = a
mappend a _ = a
newtype ArticulationNotation
= ArticulationNotation { getArticulationNotation :: ([Slur], [Mark]) }
instance Wrapped ArticulationNotation where
type Unwrapped ArticulationNotation = ([Slur], [Mark])
_Wrapped' = iso getArticulationNotation ArticulationNotation
instance Rewrapped ArticulationNotation ArticulationNotation
type instance Articulation ArticulationNotation = ArticulationNotation
instance Transformable ArticulationNotation where
transform _ = id
instance Tiable ArticulationNotation where
toTied (ArticulationNotation (beginEnd, marks))
= (ArticulationNotation (beginEnd, marks),
ArticulationNotation (mempty, mempty))
instance Monoid ArticulationNotation where
mempty = ArticulationNotation ([], [])
ArticulationNotation ([], []) `mappend` y = y
x `mappend` ArticulationNotation ([], []) = x
x `mappend` y = x
-- TODO add slurs if separation is below some value...
getSeparationMarks :: Double -> [Mark]
getSeparationMarks = fst . getSeparationMarks'
hasSlur' :: Double -> Bool
hasSlur' = snd . getSeparationMarks'
getSeparationMarks' :: Double -> ([Mark], Bool)
getSeparationMarks' x
| x <= (-1) = ([], True)
| (-1) < x && x < 1 = ([], False)
| 1 <= x && x < 2 = ([Staccato], False)
| 2 <= x = ([MoltoStaccato], False)
getAccentMarks :: Double -> [Mark]
getAccentMarks x
| x <= (-1) = []
| (-1) < x && x < 1 = []
| 1 <= x && x < 2 = [Accent]
| 2 <= x = [Marcato]
| otherwise = []
hasSlur y = hasSlur' (realToFrac $ view separation $ y)
allMarks y = getSeparationMarks (realToFrac $ view separation $ y) <> getAccentMarks (realToFrac $ view accentuation $ y)
notateArticulation :: (Ord a, a ~ (Sum Double, Sum Double)) => Ctxt a -> ArticulationNotation
notateArticulation (Nothing, y, Nothing) = ArticulationNotation ([], allMarks y)
notateArticulation (Just x, y, Nothing) = ArticulationNotation (if hasSlur x && hasSlur y then [EndSlur] else [], allMarks y)
notateArticulation (Nothing, y, Just z) = ArticulationNotation (if hasSlur y && hasSlur z then [BeginSlur] else [], allMarks y)
notateArticulation (Just x, y, Just z) = ArticulationNotation (slur3 x y z, allMarks y)
where
slur3 x y z = case (hasSlur x, hasSlur y, hasSlur z) of
(True, True, True) -> [{-ContSlur-}]
(False, True, True) -> [BeginSlur]
(True, True, False) -> [EndSlur]
_ -> []