{-# LANGUAGE OverloadedStrings #-} module SSML(styleToSSML, postorder) where import Text.XML import qualified Data.Text as Txt import Data.Map import Data.Maybe (isNothing, fromMaybe) import qualified Data.Map as M import Data.CSS.StyleTree import SpeechStyle styleToSSML :: StyleTree SpeechStyle -> Element styleToSSML = Element "{http://www.w3.org/2001/10/synthesis}speak" M.empty . styleToNodes styleToNodes :: StyleTree SpeechStyle -> [Node] styleToNodes = Prelude.map style . postorder styleToSSML' styleToSSML' SpeechStyle { speak = False } _ = [] styleToSSML' self@SpeechStyle {content = ""} children = el "prosody" [ ("rhapsode:pseudo", pseudoEl self), ("volume", volume self), ("rate", rate self), ("pitch", pitch2txt <$> pitch self), ("range", pitch2txt <$> range self) ] $ el "prosody" [ ("volume", unit2txt <$> volumeAdjust self), ("rate", unit2txt <$> rateAdjust self), ("pitch", unit2txt <$> (pitchAdjust =<< pitch self)), ("range", unit2txt <$> (pitchAdjust =<< range self)) ] $ el "emphasis" [("level", stress self)] $ el "say-as" [("interpret-as", speakAs self)] $ el "tts:style" [ ("field", (\_ -> "punctuation") <$> speakAs self), ("mode", (\b -> if b then "all" else "none") <$> punctuation self) ] $ buildVoices (reverse $ voices self) $ buildBox self children styleToSSML' style childs = styleToSSML' style {content = ""} ( pseudo "before" ++ [NodeContent $ content style] ++ pseudo "after") where pseudo n = [child | child@(NodeElement (Element _ attrs _)) <- childs, M.lookup "rhapsode:pseudo" attrs == Just n] buildVoices (Voice name:voices) children = el "voice" [("name", Just name)] $ buildVoices voices children buildVoices (VoicePattern age gender variant:voices) children = el "voice" [ ("age", Txt.pack <$> show <$> age), ("gender", Just gender), ("variant", Txt.pack <$> show <$> variant) ] $ buildVoices voices children buildVoices [] children = children buildBox self childs = concat [ breakEl $ pauseBefore self, audioEl $ cueBefore self, breakEl $ restBefore self, el "mark" [("name", marker self)] [], childs, breakEl $ restAfter self, audioEl $ cueAfter self, breakEl $ pauseAfter self ] breakEl self = el "break" [("strength", strength self), ("time", unit2txt <$> time self)] [] audioEl NoCue = [] audioEl self = el "prosody" [("volume", unit2txt <$> cueVolume self)] $ el "audio" [("src", Just $ src self)] [] -- support postorder :: (a -> [b] -> [b]) -> StyleTree a -> [StyleTree b] postorder cb (StyleTree self children) = [StyleTree self' children' | self' <- cb self $ Prelude.map style children'] where children' = concat $ Prelude.map (postorder cb) children el :: Name -> [(Name, Maybe Txt.Text)] -> [Node] -> [Node] el n attrs children | all (isNothing . snd) attrs = children | otherwise = [NodeElement $ Element { elementName = n, elementAttributes = M.fromList [(k, v) | (k, Just v) <- attrs], elementNodes = children }] relativeUnit n | n < 0 = Txt.pack (show n) | otherwise = Txt.pack ('+':show n) unit2txt (Unit' unit n) = relativeUnit n `Txt.append` unit pitch2txt (Pitch kw _) = kw pitch2txt (Absolute (Unit' unit n)) = Txt.pack (show n) `Txt.append` unit pitch2txt (Relative n) = unit2txt n