{-# LANGUAGE OverloadedStrings #-} module Sound.Tidal.MiniTidalTest where import Test.Microspec import Sound.Tidal.MiniTidal import Sound.Tidal.Context as Tidal import Data.Either import Text.ParserCombinators.Parsec (ParseError) import qualified Data.Map.Strict as Map parsesTo :: String -> ControlPattern -> Property parsesTo str p = x `shouldBe` y where x = query <$> miniTidal str <*> Right (State (Arc 0 16) Map.empty) y = Right $ query p $ State (Arc 0 16) Map.empty causesParseError :: String -> Property causesParseError str = isLeft (miniTidal str :: Either ParseError ControlPattern) `shouldBe` True run :: Microspec () run = describe "miniTidal" $ do it "parses the empty string as silence" $ "" `parsesTo` silence it "parses a string containing only spaces as silence" $ " " `parsesTo` silence it "parses a very simple single 's' pattern" $ "s \"bd cp\"" `parsesTo` s "bd cp" it "parses a single 's' pattern that uses angle brackets" $ "s \"\"" `parsesTo` s "" it "parses a single 's' pattern that uses square brackets" $ "s \"[bd sn] cp\"" `parsesTo` s "[bd sn] cp" it "parses a single 's' pattern that uses square brackets and *" $ "s \"[bd sn]*2 cp\"" `parsesTo` s "[bd sn]*2 cp" it "parses a single 's' pattern that uses Bjorklund rhythms" $ "s \"sn(5,16)\"" `parsesTo` s "sn(5,16)" it "parses a literal int as a double pattern" $ "pan 0" `parsesTo` (pan 0) it "parses a literal double as a double pattern" $ "pan 1.0" `parsesTo` (pan 1.0) it "parses a negative literal double as a double pattern" $ "pan (-1.0)" `parsesTo` (pan (-1.0)) it "parses two merged patterns" $ "s \"bd cp\" # pan \"0 1\"" `parsesTo` (s "bd cp" # pan "0 1") it "parses three merged patterns" $ "s \"bd cp\" # pan \"0 1\" # gain \"0.5 0.7\"" `parsesTo` (s "bd cp" # pan "0 1" # gain "0.5 0.7") it "parses three merged patterns, everything in brackets" $ "(s \"bd cp\" # pan \"0 1\" # gain \"0.5 0.7\")" `parsesTo` ((s "bd cp" # pan "0 1" # gain "0.5 0.7")) it "parses three merged patterns, everything in muliple layers of brackets" $ "(((s \"bd cp\" # pan \"0 1\" # gain \"0.5 0.7\")))" `parsesTo` ((((s "bd cp" # pan "0 1" # gain "0.5 0.7")))) it "parses three merged patterns with right associative brackets" $ "s \"bd cp\" # (pan \"0 1\" # gain \"0.5 0.7\")" `parsesTo` (s "bd cp" # (pan "0 1" # gain "0.5 0.7")) it "parses three merged patterns with left associative brackets" $ "(s \"bd cp\" # pan \"0 1\") # gain \"0.5 0.7\"" `parsesTo` ((s "bd cp" # pan "0 1") # gain "0.5 0.7") it "parses simple patterns in brackets applied to ParamPattern functions" $ "s (\"bd cp\")" `parsesTo` (s ("bd cp")) it "parses simple patterns applied to ParamPattern functions with $" $ "s $ \"bd cp\"" `parsesTo` (s $ "bd cp") it "parses addition of simple patterns" $ "n (\"0 1\" + \"2 3\")" `parsesTo` (n ("0 1" + "2 3")) it "parses multiplication of simple patterns as a merged parampattern" $ "s \"arpy*8\" # up (\"3\" * \"2\")" `parsesTo` (s "arpy*8" # up ("3" * "2")) it "parses pan patterns" $ "pan \"0 0.25 0.5 0.75 1\"" `parsesTo` (pan "0 0.25 0.5 0.75 1") it "parses note patterns" $ "note \"0 0.25 0.5 0.75 1\"" `parsesTo` (note "0 0.25 0.5 0.75 1") it "parses sine oscillators" $ "pan sine" `parsesTo` (pan sine) it "parses sine oscillators used in pan patterns" $ "s \"arpy*8\" # pan sine" `parsesTo` (s "arpy*8" # pan sine) it "parses fast transformations of parampatterns" $ "fast 2 $ s \"bd cp\"" `parsesTo` (fast 2 $ s "bd cp") it "parses fast transformations of parampatterns when in brackets" $ "(fast 2) $ s \"bd cp\"" `parsesTo` ((fast 2) $ s "bd cp") it "parses rev transformations of parampatterns" $ "rev $ s \"bd cp\"" `parsesTo` (rev $ s "bd cp") it "parses rev transformations of parampatterns when in brackets" $ "(rev) $ s \"bd cp\"" `parsesTo` ((rev) $ s "bd cp") it "parses jux transformations with transformations in brackets" $ "jux (rev) $ s \"arpy*8\" # up \"0 2 3 5 3 5 7 8\"" `parsesTo` (jux (rev) $ s "arpy*8" # up "0 2 3 5 3 5 7 8") it "parses jux transformations with transformations not in brackets" $ "jux rev $ s \"arpy*8\" # up \"0 2 3 5 3 5 7 8\"" `parsesTo` (jux rev $ s "arpy*8" # up "0 2 3 5 3 5 7 8") it "doesn't parse when a transformation requiring an argument is provided without parens or $ to jux" $ causesParseError "jux fast 2 $ s \"bd*4 cp\"" it "parses multiple fast transformations of parampatterns" $ "fast 2 $ fast 2 $ s \"bd cp\"" `parsesTo` (fast 2 $ fast 2 $ s "bd cp") it "parses an 'every' transformation applied to a simple s pattern" $ "every 2 (fast 2) (s \"bd cp\")" `parsesTo` (every 2 (fast 2) (s "bd cp")) it "parses a transformed pattern merged with a pattern constructed from parampatterning an arithmetic expression on patterns" $ "(every 2 (fast 2) $ s \"arpy*8\") # up (\"[0 4 7 2,16 12 12 16]\" - \"<0 3 5 7>\")" `parsesTo` ((every 2 (fast 2) $ s "arpy*8") # up ("[0 4 7 2,16 12 12 16]" - "<0 3 5 7>")) it "parses a fast transformation applied to a simple (ie. non-param) pattern" $ "up (fast 2 \"<0 2 3 5>\")" `parsesTo` (up (fast 2 "<0 2 3 5>")) it "parses a binary Num function spread over a simple Num pattern" $ "n (spread (+) [2,3,4] \"1 2 3\")" `parsesTo` (n (spread (+) [2,3,4] "1 2 3")) it "parses an $ application spread over partially applied transformations of a non-Control Pattern" $ "n (spread ($) [density 2, rev, slow 2] $ \"1 2 3 4\")" `parsesTo` (n (spread ($) [density 2, rev, slow 2] $ "1 2 3 4")) it "parses an $ application spread over partially applied transformations of a Control Pattern" $ "spread ($) [density 2, rev, slow 2, striate 3] $ sound \"[bd*2 [~ bd]] [sn future]*2 cp jvbass*4\"" `parsesTo` (spread ($) [density 2, rev, slow 2, striate 3] $ sound "[bd*2 [~ bd]] [sn future]*2 cp jvbass*4")