module Sound.Audacity.Project.Track.Label (
T (Cons, name_, height_, minimized_, track_),
deflt,
toXML,
intervalToXML,
tracksFromXML,
parse,
parseInterval,
labelName,
labeltrackName,
) where
import qualified Sound.Audacity.LabelTrack as LabelTrack
import qualified Sound.Audacity.XML.Attribute as Attr
import qualified Sound.Audacity.XML.Parser as Parser
import qualified Sound.Audacity.XML as XML
import qualified Text.HTML.Tagchup.Tag as Tag
import qualified Text.HTML.Tagchup.Tag.Match as TagMatch
import qualified Text.XML.Basic.Name.MixedCase as Name
import Text.Printf (printf)
import qualified Control.Monad.Trans.State as MS
import qualified Control.Monad.Trans.Maybe as MM
import qualified Control.Monad.Exception.Synchronous as ME
import Control.Applicative (many, (<*))
import qualified Data.NonEmpty.Mixed as NonEmptyM
import qualified Data.NonEmpty as NonEmpty
import Data.Maybe (mapMaybe)
data T =
Cons {
name_ :: String,
height_ :: Int,
minimized_ :: Bool,
track_ :: LabelTrack.T Double String
}
deriving (Show)
deflt :: T
deflt =
Cons {
name_ = "",
height_ = 100,
minimized_ = False,
track_ = LabelTrack.empty
}
toXML :: T -> [[Tag.T Name.T String]]
toXML x =
XML.tag "labeltrack" x
(Attr.string "name" name_ :
Attr.int "numlabels" (length . LabelTrack.decons . track_) :
Attr.int "height" height_ :
Attr.bool "minimized" minimized_ :
[])
$
map intervalToXML (LabelTrack.decons $ track_ x)
intervalToXML :: LabelTrack.Interval Double String -> [Tag.T Name.T String]
intervalToXML ((from,to), title) =
(Tag.open labelName $
XML.attr "t" (printf "%.9f" from) :
XML.attr "t1" (printf "%.9f" to) :
XML.attr "title" title :
[]) :
Tag.close labelName :
[]
maybeExc ::
MM.MaybeT (ME.Exceptional Parser.Message) a ->
Maybe (ME.Exceptional Parser.Message a)
maybeExc (MM.MaybeT act) =
case act of
ME.Exception msg -> Just $ ME.Exception msg
ME.Success ma -> fmap ME.Success ma
tracksFromXML :: [Tag.T Name.T String] -> ME.Exceptional Parser.Message [T]
tracksFromXML =
sequence . mapMaybe (maybeExc . MS.evalStateT parse . NonEmpty.flatten) .
snd . NonEmptyM.segmentBefore (TagMatch.open (labeltrackName==) (const True))
parse :: Parser.T T
parse = do
attrs <- Parser.tagOpen labeltrackName
name <- Parser.lookupAttr "name" attrs
height <- Parser.lookupAttrRead "height" attrs
minimized <- Parser.lookupAttrBool "minimized" attrs
Parser.skipSpaces
intervals <- many (parseInterval <* Parser.skipSpaces)
Parser.tagClose labeltrackName
return $
Cons {
name_ = name,
height_ = height,
minimized_ = minimized,
track_ = LabelTrack.Cons intervals
}
parseInterval :: Parser.T (LabelTrack.Interval Double String)
parseInterval = do
attrs <- Parser.tagOpen labelName
from <- Parser.lookupAttrRead "t" attrs
to <- Parser.lookupAttrRead "t1" attrs
title <- Parser.lookupAttr "title" attrs
Parser.tagClose labelName
return ((from, to), title)
labelName :: Tag.Name Name.T
labelName = Tag.Name $ Name.Cons "label"
labeltrackName :: Tag.Name Name.T
labeltrackName = Tag.Name $ Name.Cons "labeltrack"