{-# LANGUAGE FlexibleContexts #-} {-# OPTIONS_GHC -Wall #-} -------------------------------------------------------------------------------- -- | -- Module : HarmTrace.Audio.AnnotationParser -- Copyright : (c) 2010-2012 Universiteit Utrecht, 2012 University of Oxford -- License : GPL3 -- -- Maintainer : bash@cs.uu.nl, jpm@cs.ox.ac.uk -- Stability : experimental -- Portability : non-portable -- -- Summary: Parses textual ground-truth Chord annotations, such as the ones -- found at: -------------------------------------------------------------------------------- module HarmTrace.Audio.AnnotationParser ( parseAnnotationData , parseKeyAnnotationData ) where import HarmTrace.Audio.DataParser (pNumData) import HarmTrace.Base.MusicTime import HarmTrace.Base.MusicRep import HarmTrace.Base.Parsing import HarmTrace.Base.ChordTokenizer ( pRoot, pChord) -- perhaps this file should be moved to the tokeniser module, because it is -- is very related to tokenising -------------------------------------------------------------------------------- -- Parse MIREX style chord annotations -------------------------------------------------------------------------------- -- | Parses a chord annotation. parseAnnotationData :: Parser [TimedData ChordLabel] parseAnnotationData = pListSep_ng pLineEnd pChordSegment <* pLineEnd <* (pLineEnd `opt` "\n") -- | Parses the onset, offset and chordlabel on one line pChordSegment :: Parser (TimedData ChordLabel) pChordSegment = timedData' <$> pNumData <* pSpaceTab <*> pNumData <* pSpaceTab <*> pChord -------------------------------------------------------------------------------- -- Keys -------------------------------------------------------------------------------- -- | Parses a 'Key' annotation. parseKeyAnnotationData :: Parser [TimedData Key] parseKeyAnnotationData = noNoneKey <$> pListSep_ng pLineEnd pKeySegment <* pLineEnd where -- filter the None keys noNoneKey = filter ((/= Note Nothing N) . keyRoot . getData) pKeySegment :: Parser (TimedData Key) pKeySegment = timedData' <$> pNumData <* pSpaceTab <*> pNumData <* pSpaceTab <*> (pKey <|> pKeyNone) pKey :: Parser Key pKey = Key <$ pString "Key" <* pSpaceTab <*> pRoot <*> pMode pKeyNone :: Parser Key pKeyNone = Key (Note Nothing N) MajMode <$ pString "Silence" pMode :: Parser Mode pMode = MajMode <$ pString "" <|> MinMode <$ pString ":minor" <|> MinMode <$ pString ":aeolian" <|> MajMode <$ pString ":major" <|> MinMode <$ pString ":dorian" <|> MajMode <$ pString ":mixolydian" -- this must be solved differently <|> MajMode <$ pString ":modal" -- and this too.... -------------------------------------------------------------------------------- -- General Parsers and Utils -------------------------------------------------------------------------------- timedData' :: NumData -> NumData -> a -> TimedData a timedData' on off chrd = TimedData chrd [Time on, Time off] pSpaceTab :: Parser Char pSpaceTab = pSym ' ' <|> pSym '\t'