
{-# LANGUAGE ConstraintKinds            #-}
{-# LANGUAGE DeriveDataTypeable         #-}
# LANGUAGE DeriveFoldable              #
{-# LANGUAGE DeriveFunctor              #-}
{-# LANGUAGE DeriveTraversable          #-}
# LANGUAGE FlexibleContexts            #
# LANGUAGE FlexibleInstances           #
# LANGUAGE GeneralizedNewtypeDeriving #
# LANGUAGE MultiParamTypeClasses       #
# LANGUAGE ScopedTypeVariables         #
# LANGUAGE TypeFamilies                #

-------------------------------------------------------------------------------------
-- |
  Copyright    : ( c )   2012 - 2014
--
-- License     : BSD-style
--
  Maintainer   : 
-- Stability   : experimental
  Portability : non - portable ( TF ,  )
--
-- Provides clefs as meta-data.
--
-- /Warning/ Experimental module.
--
-------------------------------------------------------------------------------------

module Music.Score.Meta.Clef (
        -- * Clef type
        Clef(..),

        -- ** Adding clefs to scores
        clef,
        clefDuring,

        -- ** Extracting clefs
        withClef,
  ) where

import           Control.Lens              (view)
import           Control.Monad.Plus
import           Data.Foldable             (Foldable)
import qualified Data.Foldable             as F
import qualified Data.List                 as List
import           Data.Map                  (Map)
import qualified Data.Map                  as Map
import           Data.Maybe
import           Data.Semigroup
import           Data.Set                  (Set)
import qualified Data.Set                  as Set
import           Data.String
import           Data.Traversable          (Traversable)
import qualified Data.Traversable          as T
import           Data.Typeable

import           Music.Pitch.Literal
import           Music.Score.Meta
import           Music.Score.Part
import           Music.Score.Pitch
import           Music.Score.Internal.Util
import           Music.Time
import           Music.Time.Reactive

data Clef = GClef | CClef | FClef
    deriving (Eq, Ord, Show, Typeable)

instance IsPitch Clef where
  fromPitch l
    | l == c    = CClef
    | l == f    = FClef
    | otherwise = GClef

-- | Set clef of the given score.
clef :: (HasMeta a, HasPosition a) => Clef -> a -> a
clef c x = clefDuring (_era x) c x

-- | Set clef of the given part of a score.
clefDuring :: HasMeta a => Span -> Clef -> a -> a
clefDuring s c = addMetaNote $ view event (s, (Option $ Just $ Last c))

-- | Extract the clef in from the given score, using the given default clef.
withClef :: Clef -> (Clef -> Score a -> Score a) -> Score a -> Score a
withClef def f = withMeta (f . fromMaybe def . fmap getLast . getOption)


# LANGUAGE ConstraintKinds            #
# LANGUAGE DeriveDataTypeable         #
# LANGUAGE DeriveFunctor              #
# LANGUAGE DeriveTraversable          #
-----------------------------------------------------------------------------------
 |

 License     : BSD-style

 Stability   : experimental

 Provides clefs as meta-data.

 /Warning/ Experimental module.

-----------------------------------------------------------------------------------
 * Clef type
 ** Adding clefs to scores
 ** Extracting clefs
 | Set clef of the given score.
 | Set clef of the given part of a score.
 | Extract the clef in from the given score, using the given default clef.

# LANGUAGE DeriveFoldable              #
# LANGUAGE FlexibleContexts            #
# LANGUAGE FlexibleInstances           #
# LANGUAGE GeneralizedNewtypeDeriving #
# LANGUAGE MultiParamTypeClasses       #
# LANGUAGE ScopedTypeVariables         #
# LANGUAGE TypeFamilies                #

  Copyright    : ( c )   2012 - 2014
  Maintainer   : 
  Portability : non - portable ( TF ,  )

module Music.Score.Meta.Clef (
        Clef(..),

        clef,
        clefDuring,

        withClef,
  ) where

import           Control.Lens              (view)
import           Control.Monad.Plus
import           Data.Foldable             (Foldable)
import qualified Data.Foldable             as F
import qualified Data.List                 as List
import           Data.Map                  (Map)
import qualified Data.Map                  as Map
import           Data.Maybe
import           Data.Semigroup
import           Data.Set                  (Set)
import qualified Data.Set                  as Set
import           Data.String
import           Data.Traversable          (Traversable)
import qualified Data.Traversable          as T
import           Data.Typeable

import           Music.Pitch.Literal
import           Music.Score.Meta
import           Music.Score.Part
import           Music.Score.Pitch
import           Music.Score.Internal.Util
import           Music.Time
import           Music.Time.Reactive

data Clef = GClef | CClef | FClef
    deriving (Eq, Ord, Show, Typeable)

instance IsPitch Clef where
  fromPitch l
    | l == c    = CClef
    | l == f    = FClef
    | otherwise = GClef

clef :: (HasMeta a, HasPosition a) => Clef -> a -> a
clef c x = clefDuring (_era x) c x

clefDuring :: HasMeta a => Span -> Clef -> a -> a
clefDuring s c = addMetaNote $ view event (s, (Option $ Just $ Last c))

withClef :: Clef -> (Clef -> Score a -> Score a) -> Score a -> Score a
withClef def f = withMeta (f . fromMaybe def . fmap getLast . getOption)

