packages feed

HarmTrace-0.7: src/HarmTrace/HarmTrace.hs

{-# LANGUAGE GADTs    #-}
{-# LANGUAGE CPP      #-}
{-# OPTIONS_GHC -Wall #-}

module HarmTrace.HarmTrace ( PPOption(..), Grammar(..), GrammarEx(..)
                           , ParseResult(..)
                           , string2Piece, postProc ) where

import HarmTrace.Models.Models
import HarmTrace.Models.Jazz.Main
import HarmTrace.Models.Pop.Main
import HarmTrace.Models.Test.Main
import HarmTrace.HAnTree.ToHAnTree
import HarmTrace.HAnTree.Tree
import HarmTrace.HAnTree.HAn (HFunc (P))
import HarmTrace.HAnTree.PostProcess
import HarmTrace.Base.MusicRep
import HarmTrace.Tokenizer.Tokens as CT
import HarmTrace.Tokenizer.Tokenizer

import Data.Ord (comparing)
import Data.List (minimumBy)

#ifdef AUDIO
-- Audio/Annotation Stuff
import HarmTrace.Audio.Annotations
import HarmTrace.Audio.ChordTypes

import HarmTrace.Base.Parsing (parseDataWithErrors)
#endif

-- Parser stuff
import Text.ParserCombinators.UU
import Text.ParserCombinators.UU.BasicInstances as PC

--------------------------------------------------------------------------------
-- Plugging everything together
--------------------------------------------------------------------------------

data ParseResult a = ParseResult { parsedKey          :: Key
                                 , parsedChordLabels  :: [ChordLabel]
                                 , parsedPiece        :: [a]
                                 , pieceTreeHAn       :: Tree HAn
                                 , nrAmbTrees         :: Int
                                 , tokenizerErrors    :: [Error LineColPos ]
                                 , pieceErrors        :: [Error Int] 
                                 , postProcessing     :: [PPOption]}
  
-- parses s with string2PieceC and merges the deleted chords with the tree
-- (Representable a, GTree (Rep a))
postProc :: (GTree g) => [PPOption] -> ParseResult g -> ParseResult g
postProc opts beforePostProc = beforePostProc { pieceTreeHAn = t } 
  where
  t = selectTree $ map (postProcess fs . gTreeHead) (parsedPiece beforePostProc)
  fs = map opt2Func opts
  opt2Func :: PPOption -> (Tree HAn -> Tree HAn)
  opt2Func RemoveInsertions = removeInsertions 
  opt2Func RemovePDPT       = removePDPT
  opt2Func MergeDelChords   = mergeDelChords (parsedKey beforePostProc)
                                             (pieceErrors beforePostProc)
                                             (parsedChordLabels beforePostProc)
  opt2Func ExpandChordDurations = expandChordDurations

selectTree :: [Tree HAn] -> Tree HAn
selectTree [] = emptyHAnTree
selectTree ts = minimumBy (comparing getNrFuncNodes) ts

getNrFuncNodes :: Tree HAn -> Int
getNrFuncNodes (Node (HAnFunc P) nodes _) = length nodes
getNrFuncNodes _ = error "HarmTrace.hs: not a correctly formed HAn Tree" 
  
postProcess :: [Tree HAn -> Tree HAn] -> Tree HAn -> Tree HAn
postProcess []     tree = tree
postProcess (f:fs) tree = f (postProcess fs tree)

-- Takes a string with line-separated chords of a song and
-- returns all possible parsed pieces, together with error-correction steps
-- taken (on tokenizing and on musical recognition).
string2Piece :: Grammar g -> String -> ParseResult g
string2Piece g s = let
  (PieceLabel key tok, err) = parse ((,) <$> parseSongAbs <*> pEnd)
                                    (createStr (LineColPos 0 0 0) s)
  (trees, err2) = case g of 
                    Jazz -> parse_h ((,) <$> pJazz key <*> pEnd)
                              (createStr 0 (toKeyRelTok key tok))  
                    Pop  -> parse_h ((,) <$> pPop  key <*> pEnd)
                              (createStr 0 (toKeyRelTok key tok))
                    Test -> parse_h ((,) <$> pPieceTest <*> pEnd)
                              (createStr 0 (toKeyRelTok key tok))
  in ParseResult key tok trees emptyHAnTree (length trees) err err2 []


#ifdef AUDIO
--------------------------------------------------------------------------------
-- Parsing audio file ground-truth annotations
--------------------------------------------------------------------------------  

gt2Piece :: (GTree g) => Grammar g -> String -> String -> ParseResult g
gt2Piece g ks cs = let
  (TimedData key _ _:_cs, errK) = parseDataWithErrors parseKeyAnnotationData ks
  (tok, errT) = parseDataWithErrors parseAnnotationData cs
  ppTok       = preProcess tok
  (ts, errP)  = case g of 
                  Jazz -> parse_h ((,) <$> pJazz key <*> pEnd)
                            (createStr 0 (toKeyRelTok key ppTok))  
                  Pop  -> parse_h ((,) <$> pPop  key <*> pEnd)
                            (createStr 0 (toKeyRelTok key ppTok))
                  Test -> parse_h ((,) <$> pPieceTest <*> pEnd)
                            (createStr 0 (toKeyRelTok key ppTok))
  in ParseResult key ppTok ts emptyHAnTree (length ts) (errK ++ errT) errP [] 
#endif