module Lilypond where import qualified Text.ParserCombinators.Parsec as P import Control.Monad (liftM2, ) import Control.Applicative ((<$)) {- | Convert a monophonic melody in absolute pitch Lilypond notation to live-sequencer notation. E.g. > toNotes "a'4 b,8 c4" -} toNotes :: String -> String toNotes = either (error . show) id . P.parse parseNotes "input string" . filter (flip notElem "~[]") parseNotes :: P.Parser String parseNotes = parseOptional $ P.many parseWhiteSpace +|+ let go = parseOptional $ parseNote +|+ (parseOptional $ P.many1 parseWhiteSpace +|+ go) in go infixr 5 +|+ (+|+) :: Monad m => m [a] -> m [a] -> m [a] (+|+) = liftM2 (++) parseWhiteSpace :: P.Parser Char parseWhiteSpace = P.oneOf " \t\n" parseOptional :: P.Parser String -> P.Parser String parseOptional p = p P.<|> return "[]" parseNote :: P.Parser String parseNote = do name <- P.many1 P.letter addDur <- case name of "r" -> return ("rest " ++) _ -> do octave <- (fmap length $ P.many1 $ P.char '\'') P.<|> (fmap (negate . length) $ P.many $ P.char ',') return $ \dur -> "note " ++ dur ++ " (" ++ name ++ " " ++ show (octave+3) ++ ")" dur <- P.try ("s" <$ P.string "16") P.<|> ("e" <$ P.string "8") P.<|> ("q" <$ P.string "4") P.<|> ("h" <$ P.string "2") P.<|> ("w" <$ P.string "1") dotted <- P.optionMaybe (P.char '.') return $ (addDur $ maybe id (++) ("d" <$ dotted) (dur++"n")) ++ " ++"