{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving, NoMonomorphismRestriction, ConstraintKinds, FlexibleContexts #-} module Data.Music.Sibelius ( -- * Scores and staves SibeliusScore(..), SibeliusStaff(..), SibeliusSystemStaff(..), SibeliusBar(..), -- * Bar objects SibeliusBarObject(..), isTimeSignature, -- ** Notes SibeliusChord(..), SibeliusNote(..), -- ** Lines SibeliusSlur(..), SibeliusCrescendoLine(..), SibeliusDiminuendoLine(..), -- ** Tuplets SibeliusTuplet(..), SibeliusArticulation(..), readSibeliusArticulation, -- ** Miscellaneous SibeliusClef(..), SibeliusKeySignature(..), SibeliusTimeSignature(..), SibeliusText(..), ) where import Control.Monad.Plus import Control.Applicative import Data.Semigroup import Data.Aeson import qualified Data.HashMap.Strict as HashMap {- setTitle :: String -> Score a -> Score a setTitle = setMeta "title" setComposer :: String -> Score a -> Score a setComposer = setMeta "composer" setInformation :: String -> Score a -> Score a setInformation = setMeta "information" setMeta :: String -> String -> Score a -> Score a setMeta _ _ = id -} data SibeliusScore = SibeliusScore { scoreTitle :: String, scoreComposer :: String, scoreInformation :: String, scoreStaffHeight :: Double, scoreTransposing :: Bool, scoreStaves :: [SibeliusStaff], scoreSystemStaff :: SibeliusSystemStaff } deriving (Eq, Ord, Show) instance FromJSON SibeliusScore where parseJSON (Object v) = SibeliusScore <$> v .: "title" <*> v .: "composer" <*> v .: "information" <*> v .: "staffHeight" <*> v .: "transposing" <*> v .: "staves" <*> v .: "systemStaff" data SibeliusSystemStaff = SibeliusSystemStaff { systemStaffBars :: [SibeliusBar] } deriving (Eq, Ord, Show) instance FromJSON SibeliusSystemStaff where parseJSON (Object v) = SibeliusSystemStaff <$> v .: "bars" data SibeliusStaff = SibeliusStaff { staffBars :: [SibeliusBar], staffName :: String, staffShortName :: String } deriving (Eq, Ord, Show) instance FromJSON SibeliusStaff where parseJSON (Object v) = SibeliusStaff <$> v .: "bars" <*> v .: "name" <*> v .: "shortName" data SibeliusBar = SibeliusBar { barElements :: [SibeliusBarObject] } deriving (Eq, Ord, Show) instance FromJSON SibeliusBar where parseJSON (Object v) = SibeliusBar <$> v .: "elements" data SibeliusBarObject = SibeliusBarObjectText SibeliusText | SibeliusBarObjectClef SibeliusClef | SibeliusBarObjectSlur SibeliusSlur | SibeliusBarObjectCrescendoLine SibeliusCrescendoLine | SibeliusBarObjectDiminuendoLine SibeliusDiminuendoLine | SibeliusBarObjectTimeSignature SibeliusTimeSignature | SibeliusBarObjectKeySignature SibeliusKeySignature | SibeliusBarObjectTuplet SibeliusTuplet | SibeliusBarObjectChord SibeliusChord | SibeliusBarObjectUnknown String -- type deriving (Eq, Ord, Show) -- TODO highlights, lyric, barlines, comment, other lines and symbols isTimeSignature (SibeliusBarObjectTimeSignature _) = True isTimeSignature _ = False instance FromJSON SibeliusBarObject where parseJSON x@(Object v) = case HashMap.lookup "type" v of -- TODO Just "text" -> SibeliusBarObjectText <$> parseJSON x Just "clef" -> SibeliusBarObjectClef <$> parseJSON x Just "slur" -> SibeliusBarObjectSlur <$> parseJSON x Just "cresc" -> SibeliusBarObjectCrescendoLine <$> parseJSON x Just "dim" -> SibeliusBarObjectDiminuendoLine <$> parseJSON x Just "time" -> SibeliusBarObjectTimeSignature <$> parseJSON x Just "key" -> SibeliusBarObjectKeySignature <$> parseJSON x Just "tuplet" -> SibeliusBarObjectTuplet <$> parseJSON x Just "chord" -> SibeliusBarObjectChord <$> parseJSON x Just typ -> SibeliusBarObjectUnknown <$> (return $ show typ) _ -> mempty -- failure: no type field data SibeliusText = SibeliusText { textVoice :: Int, textPosition :: Int, textText :: String, textStyle :: Maybe String } deriving (Eq, Ord, Show) instance FromJSON SibeliusText where parseJSON (Object v) = SibeliusText <$> v .: "voice" <*> v .: "position" <*> v .: "text" <*> v .: "style" data SibeliusClef = SibeliusClef { clefVoice :: Int, clefPosition :: Int, clefStyle :: Maybe String } deriving (Eq, Ord, Show) instance FromJSON SibeliusClef where parseJSON (Object v) = SibeliusClef <$> v .: "voice" <*> v .: "position" <*> v .: "style" data SibeliusSlur = SibeliusSlur { slurVoice :: Int, slurPosition :: Int, slurDuration :: Int, slurStyle :: Maybe String } deriving (Eq, Ord, Show) instance FromJSON SibeliusSlur where parseJSON (Object v) = SibeliusSlur <$> v .: "voice" <*> v .: "position" <*> v .: "duration" <*> v .: "style" data SibeliusCrescendoLine = SibeliusCrescendoLine { crescVoice :: Int, crescPosition :: Int, crescDuration :: Int, crescStyle :: Maybe String } deriving (Eq, Ord, Show) instance FromJSON SibeliusCrescendoLine where parseJSON (Object v) = SibeliusCrescendoLine <$> v .: "voice" <*> v .: "position" <*> v .: "duration" <*> v .: "style" data SibeliusDiminuendoLine = SibeliusDiminuendoLine { dimVoice :: Int, dimPosition :: Int, dimDuration :: Int, dimStyle :: Maybe String } deriving (Eq, Ord, Show) instance FromJSON SibeliusDiminuendoLine where parseJSON (Object v) = SibeliusDiminuendoLine <$> v .: "voice" <*> v .: "position" <*> v .: "duration" <*> v .: "style" data SibeliusTimeSignature = SibeliusTimeSignature { timeVoice :: Int, timePosition :: Int, timeValue :: [Int], timeIsCommon :: Bool, timeIsAllaBreve :: Bool } deriving (Eq, Ord, Show) instance FromJSON SibeliusTimeSignature where parseJSON (Object v) = SibeliusTimeSignature <$> v .: "voice" <*> v .: "position" <*> v .: "value" <*> v .: "common" <*> v .: "allaBreve" data SibeliusKeySignature = SibeliusKeySignature { keyVoice :: Int, keyPosition :: Int, keyMajor :: Bool, keySharps :: Int, keyIsOpen :: Bool } deriving (Eq, Ord, Show) instance FromJSON SibeliusKeySignature where parseJSON (Object v) = SibeliusKeySignature <$> v .: "voice" <*> v .: "position" <*> v .: "major" <*> v .: "sharps" <*> v .: "isOpen" data SibeliusTuplet = SibeliusTuplet { tupletVoice :: Int, tupletPosition :: Int, tupletDuration :: Int, tupletPlayedDuration :: Int, tupletValue :: [Int] } deriving (Eq, Ord, Show) instance FromJSON SibeliusTuplet where parseJSON (Object v) = SibeliusTuplet <$> v .: "voice" <*> v .: "position" <*> v .: "duration" <*> v .: "playedDuration" <*> v .: "value" data SibeliusArticulation = UpBow | DownBow | Plus | Harmonic | Marcato | Accent | Tenuto | Wedge | Staccatissimo | Staccato deriving (Eq, Ord, Show, Enum) readSibeliusArticulation :: String -> Maybe SibeliusArticulation readSibeliusArticulation = go where go "upbow" = Just UpBow go "downBow" = Just DownBow go "plus" = Just Plus go "harmonic" = Just Harmonic go "marcato" = Just Marcato go "accent" = Just Accent go "tenuto" = Just Tenuto go "wedge" = Just Wedge go "staccatissimo" = Just Staccatissimo go "staccato" = Just Staccato go _ = Nothing data SibeliusChord = SibeliusChord { chordPosition :: Int, chordDuration :: Int, chordVoice :: Int, chordArticulations :: [SibeliusArticulation], -- TODO chordSingleTremolos :: Int, chordDoubleTremolos :: Int, chordAcciaccatura :: Bool, chordAppoggiatura :: Bool, chordNotes :: [SibeliusNote] } deriving (Eq, Ord, Show) instance FromJSON SibeliusChord where parseJSON (Object v) = SibeliusChord <$> v .: "position" <*> v .: "duration" <*> v .: "voice" <*> fmap (mmapMaybe readSibeliusArticulation) (v .: "articulations") <*> v .: "singleTremolos" <*> v .: "doubleTremolos" <*> v .: "acciaccatura" <*> v .: "appoggiatura" <*> v .: "notes" data SibeliusNote = SibeliusNote { notePitch :: Int, noteDiatonicPitch :: Int, noteAccidental :: Int, noteTied :: Bool, noteStyle :: Maybe Int -- not String? } deriving (Eq, Ord, Show) instance FromJSON SibeliusNote where parseJSON (Object v) = SibeliusNote <$> v .: "pitch" <*> v .: "diatonicPitch" <*> v .: "accidental" <*> v .: "tied" <*> v .: "style"