diff --git a/BootTidal.hs b/BootTidal.hs
--- a/BootTidal.hs
+++ b/BootTidal.hs
@@ -11,11 +11,13 @@
 tidal <- startTidal (superdirtTarget {oLatency = 0.1, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cFrameTimespan = 1/20})
 
 :{
-let p = streamReplace tidal
+let only = (hush >>)
+    p = streamReplace tidal
     hush = streamHush tidal
     list = streamList tidal
     mute = streamMute tidal
     unmute = streamUnmute tidal
+    unmuteAll = streamUnmuteAll tidal
     solo = streamSolo tidal
     unsolo = streamUnsolo tidal
     once = streamOnce tidal
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,19 @@
 # TidalCycles log of changes
 
+## 1.5.0 - 
+	* Export drawLineSz @mxmxyz
+	* tidal-parse additions (bite, splice, pickF, select, squeeze; fixed slice) @dktr0
+	* New, more efficient pseudorandom number generator @dktr0
+	* Pattern first someCyclesBy param @bgold-cosmos
+	* Refactored, more flexible OSC targetting @yaxu
+	* Simplify tidal-boot-script in tidal.el @jamagin
+	* Support state substitution in mininotation #530 @yaxu
+	* Pattern first parameter of splice #656 @yaxu
+	* Pattern first parameter of chew @yaxu
+	* add 'x' fraction alias for 1/6 @yaxu
+	* add dfb alias for delayfeedback param, dt for delaytime @yaxu
+	* add unmuteAll and only to BootTidal.hs @yaxu
+
 ## 1.4.9 - Housebound spirit
 	* Simplify 'show'ing of patterns @yaxu
 	* New `draw` function for drawing a pattern of single characters as a text-based diagram,
diff --git a/src/Sound/Tidal/Control.hs b/src/Sound/Tidal/Control.hs
--- a/src/Sound/Tidal/Control.hs
+++ b/src/Sound/Tidal/Control.hs
@@ -13,7 +13,6 @@
 import Sound.Tidal.UI
 import qualified Sound.Tidal.Params as P
 import Sound.Tidal.Utils
-import Sound.Tidal.ParseBP (Parseable, Enumerable, parseBP_E)
 
 {- | `spin` will "spin" a layer up a pattern the given number of times,
 with each successive layer offset in time by an additional `1/n` of a
@@ -264,6 +263,12 @@
 randslice :: Pattern Int -> ControlPattern -> ControlPattern
 randslice = tParam $ \n p -> innerJoin $ (\i -> _slice n i p) <$> irand n
 
+splice :: Pattern Int -> Pattern Int -> ControlPattern -> Pattern (Map.Map String Value)
+splice bits ipat pat = withEvent f (slice bits ipat pat) # P.unit (pure "c")
+  where f ev = ev {value = Map.insert "speed" (VF d) (value ev)}
+          where d = sz / (fromRational $ (wholeStop ev) - (wholeStart ev))
+                sz = 1/(fromIntegral bits)
+
 {- |
 `loopAt` makes a sample fit the given number of cycles. Internally, it
 works by setting the `unit` parameter to "c", changing the playback
@@ -394,324 +399,3 @@
         offset st = fromMaybe (pure 0) $ do p <- Map.lookup ctrl (controls st)
                                             return $ ((f . fromMaybe 0 . getR) <$> p)
         ctrl = "_t_" ++ show k
-
-_getP_ :: (Value -> Maybe a) -> Pattern Value -> Pattern a
-_getP_ f pat = filterJust $ f <$> pat
-
-_getP :: a -> (Value -> Maybe a) -> Pattern Value -> Pattern a
-_getP d f pat = (fromMaybe d . f) <$> pat
-
-_cX :: a -> (Value -> Maybe a) -> String -> Pattern a
-_cX d f s = Pattern $ \(State a m) -> queryArc (maybe (pure d) (_getP d f) $ Map.lookup s m) a
-
-_cX_ :: (Value -> Maybe a) -> String -> Pattern a
-_cX_ f s = Pattern $ \(State a m) -> queryArc (maybe silence (_getP_ f) $ Map.lookup s m) a
-
-cF :: Double -> String -> Pattern Double
-cF d = _cX d getF
-cF_ :: String -> Pattern Double
-cF_ = _cX_ getF
-cF0 :: String -> Pattern Double
-cF0 = _cX 0 getF
-
-cI :: Int -> String -> Pattern Int
-cI d = _cX d getI
-cI_ :: String -> Pattern Int
-cI_ = _cX_ getI
-cI0 :: String -> Pattern Int
-cI0 = _cX 0 getI
-
-cB :: Bool -> String -> Pattern Bool
-cB d = _cX d getB
-cB_ :: String -> Pattern Bool
-cB_ = _cX_ getB
-cB0 :: String -> Pattern Bool
-cB0 = _cX False getB
-
-cR :: Rational -> String -> Pattern Rational
-cR d = _cX d getR
-cR_ :: String -> Pattern Rational
-cR_ = _cX_ getR
-cR0 :: String -> Pattern Rational
-cR0 = _cX 0 getR
-
-cT :: Time -> String -> Pattern Time
-cT = cR
-cT0 :: String -> Pattern Time
-cT0 = cR0
-cT_ :: String -> Pattern Time
-cT_ = cR_
-
-cS :: String -> String -> Pattern String
-cS d = _cX d getS
-cS_ :: String -> Pattern String
-cS_ = _cX_ getS
-cS0 :: String -> Pattern String
-cS0 = _cX "" getS
-
-cP :: (Enumerable a, Parseable a) => String -> Pattern a
-cP s = innerJoin $ parseBP_E <$> (_cX_ getS s)
-
--- Default controller inputs (for MIDI)
-in0 :: Pattern Double
-in0 = cF 0 "0"
-in1 :: Pattern Double
-in1 = cF 0 "1"
-in2 :: Pattern Double
-in2 = cF 0 "2"
-in3 :: Pattern Double
-in3 = cF 0 "3"
-in4 :: Pattern Double
-in4 = cF 0 "4"
-in5 :: Pattern Double
-in5 = cF 0 "5"
-in6 :: Pattern Double
-in6 = cF 0 "6"
-in7 :: Pattern Double
-in7 = cF 0 "7"
-in8 :: Pattern Double
-in8 = cF 0 "8"
-in9 :: Pattern Double
-in9 = cF 0 "9"
-in10 :: Pattern Double
-in10 = cF 0 "10"
-in11 :: Pattern Double
-in11 = cF 0 "11"
-in12 :: Pattern Double
-in12 = cF 0 "12"
-in13 :: Pattern Double
-in13 = cF 0 "13"
-in14 :: Pattern Double
-in14 = cF 0 "14"
-in15 :: Pattern Double
-in15 = cF 0 "15"
-in16 :: Pattern Double
-in16 = cF 0 "16"
-in17 :: Pattern Double
-in17 = cF 0 "17"
-in18 :: Pattern Double
-in18 = cF 0 "18"
-in19 :: Pattern Double
-in19 = cF 0 "19"
-in20 :: Pattern Double
-in20 = cF 0 "20"
-in21 :: Pattern Double
-in21 = cF 0 "21"
-in22 :: Pattern Double
-in22 = cF 0 "22"
-in23 :: Pattern Double
-in23 = cF 0 "23"
-in24 :: Pattern Double
-in24 = cF 0 "24"
-in25 :: Pattern Double
-in25 = cF 0 "25"
-in26 :: Pattern Double
-in26 = cF 0 "26"
-in27 :: Pattern Double
-in27 = cF 0 "27"
-in28 :: Pattern Double
-in28 = cF 0 "28"
-in29 :: Pattern Double
-in29 = cF 0 "29"
-in30 :: Pattern Double
-in30 = cF 0 "30"
-in31 :: Pattern Double
-in31 = cF 0 "31"
-in32 :: Pattern Double
-in32 = cF 0 "32"
-in33 :: Pattern Double
-in33 = cF 0 "33"
-in34 :: Pattern Double
-in34 = cF 0 "34"
-in35 :: Pattern Double
-in35 = cF 0 "35"
-in36 :: Pattern Double
-in36 = cF 0 "36"
-in37 :: Pattern Double
-in37 = cF 0 "37"
-in38 :: Pattern Double
-in38 = cF 0 "38"
-in39 :: Pattern Double
-in39 = cF 0 "39"
-in40 :: Pattern Double
-in40 = cF 0 "40"
-in41 :: Pattern Double
-in41 = cF 0 "41"
-in42 :: Pattern Double
-in42 = cF 0 "42"
-in43 :: Pattern Double
-in43 = cF 0 "43"
-in44 :: Pattern Double
-in44 = cF 0 "44"
-in45 :: Pattern Double
-in45 = cF 0 "45"
-in46 :: Pattern Double
-in46 = cF 0 "46"
-in47 :: Pattern Double
-in47 = cF 0 "47"
-in48 :: Pattern Double
-in48 = cF 0 "48"
-in49 :: Pattern Double
-in49 = cF 0 "49"
-in50 :: Pattern Double
-in50 = cF 0 "50"
-in51 :: Pattern Double
-in51 = cF 0 "51"
-in52 :: Pattern Double
-in52 = cF 0 "52"
-in53 :: Pattern Double
-in53 = cF 0 "53"
-in54 :: Pattern Double
-in54 = cF 0 "54"
-in55 :: Pattern Double
-in55 = cF 0 "55"
-in56 :: Pattern Double
-in56 = cF 0 "56"
-in57 :: Pattern Double
-in57 = cF 0 "57"
-in58 :: Pattern Double
-in58 = cF 0 "58"
-in59 :: Pattern Double
-in59 = cF 0 "59"
-in60 :: Pattern Double
-in60 = cF 0 "60"
-in61 :: Pattern Double
-in61 = cF 0 "61"
-in62 :: Pattern Double
-in62 = cF 0 "62"
-in63 :: Pattern Double
-in63 = cF 0 "63"
-in64 :: Pattern Double
-in64 = cF 0 "64"
-in65 :: Pattern Double
-in65 = cF 0 "65"
-in66 :: Pattern Double
-in66 = cF 0 "66"
-in67 :: Pattern Double
-in67 = cF 0 "67"
-in68 :: Pattern Double
-in68 = cF 0 "68"
-in69 :: Pattern Double
-in69 = cF 0 "69"
-in70 :: Pattern Double
-in70 = cF 0 "70"
-in71 :: Pattern Double
-in71 = cF 0 "71"
-in72 :: Pattern Double
-in72 = cF 0 "72"
-in73 :: Pattern Double
-in73 = cF 0 "73"
-in74 :: Pattern Double
-in74 = cF 0 "74"
-in75 :: Pattern Double
-in75 = cF 0 "75"
-in76 :: Pattern Double
-in76 = cF 0 "76"
-in77 :: Pattern Double
-in77 = cF 0 "77"
-in78 :: Pattern Double
-in78 = cF 0 "78"
-in79 :: Pattern Double
-in79 = cF 0 "79"
-in80 :: Pattern Double
-in80 = cF 0 "80"
-in81 :: Pattern Double
-in81 = cF 0 "81"
-in82 :: Pattern Double
-in82 = cF 0 "82"
-in83 :: Pattern Double
-in83 = cF 0 "83"
-in84 :: Pattern Double
-in84 = cF 0 "84"
-in85 :: Pattern Double
-in85 = cF 0 "85"
-in86 :: Pattern Double
-in86 = cF 0 "86"
-in87 :: Pattern Double
-in87 = cF 0 "87"
-in88 :: Pattern Double
-in88 = cF 0 "88"
-in89 :: Pattern Double
-in89 = cF 0 "89"
-in90 :: Pattern Double
-in90 = cF 0 "90"
-in91 :: Pattern Double
-in91 = cF 0 "91"
-in92 :: Pattern Double
-in92 = cF 0 "92"
-in93 :: Pattern Double
-in93 = cF 0 "93"
-in94 :: Pattern Double
-in94 = cF 0 "94"
-in95 :: Pattern Double
-in95 = cF 0 "95"
-in96 :: Pattern Double
-in96 = cF 0 "96"
-in97 :: Pattern Double
-in97 = cF 0 "97"
-in98 :: Pattern Double
-in98 = cF 0 "98"
-in99 :: Pattern Double
-in99 = cF 0 "99"
-in100 :: Pattern Double
-in100 = cF 0 "100"
-in101 :: Pattern Double
-in101 = cF 0 "101"
-in102 :: Pattern Double
-in102 = cF 0 "102"
-in103 :: Pattern Double
-in103 = cF 0 "103"
-in104 :: Pattern Double
-in104 = cF 0 "104"
-in105 :: Pattern Double
-in105 = cF 0 "105"
-in106 :: Pattern Double
-in106 = cF 0 "106"
-in107 :: Pattern Double
-in107 = cF 0 "107"
-in108 :: Pattern Double
-in108 = cF 0 "108"
-in109 :: Pattern Double
-in109 = cF 0 "109"
-in110 :: Pattern Double
-in110 = cF 0 "110"
-in111 :: Pattern Double
-in111 = cF 0 "111"
-in112 :: Pattern Double
-in112 = cF 0 "112"
-in113 :: Pattern Double
-in113 = cF 0 "113"
-in114 :: Pattern Double
-in114 = cF 0 "114"
-in115 :: Pattern Double
-in115 = cF 0 "115"
-in116 :: Pattern Double
-in116 = cF 0 "116"
-in117 :: Pattern Double
-in117 = cF 0 "117"
-in118 :: Pattern Double
-in118 = cF 0 "118"
-in119 :: Pattern Double
-in119 = cF 0 "119"
-in120 :: Pattern Double
-in120 = cF 0 "120"
-in121 :: Pattern Double
-in121 = cF 0 "121"
-in122 :: Pattern Double
-in122 = cF 0 "122"
-in123 :: Pattern Double
-in123 = cF 0 "123"
-in124 :: Pattern Double
-in124 = cF 0 "124"
-in125 :: Pattern Double
-in125 = cF 0 "125"
-in126 :: Pattern Double
-in126 = cF 0 "126"
-in127 :: Pattern Double
-in127 = cF 0 "127"
-
-splice :: Int -> Pattern Int -> ControlPattern -> Pattern (Map.Map String Value)
-splice bits ipat pat = withEvent f (slice (pure bits) ipat pat) # P.unit "c"
-  where f ev = ev {value = Map.insert "speed" (VF d) (value ev)}
-          where d = sz / (fromRational $ (wholeStop ev) - (wholeStart ev))
-                sz = 1/(fromIntegral bits)
diff --git a/src/Sound/Tidal/Core.hs b/src/Sound/Tidal/Core.hs
--- a/src/Sound/Tidal/Core.hs
+++ b/src/Sound/Tidal/Core.hs
@@ -6,7 +6,7 @@
 
 import           Data.Fixed (mod')
 import qualified Data.Map.Strict as Map
-
+import           Data.Maybe (fromMaybe)
 import           Sound.Tidal.Pattern
 
 -- ** Elemental patterns
@@ -157,7 +157,7 @@
 fromList :: [a] -> Pattern a
 fromList = cat . map pure
 
--- | Turns a list of values into a pattern, playing one of them per cycle.
+-- | Turns a list of values into a pattern, playing all of them per cycle.
 fastFromList :: [a] -> Pattern a
 fastFromList = fastcat . map pure
 
@@ -424,3 +424,315 @@
 whenT test f p = splitQueries $ p {query = apply}
   where apply st | test (start $ arc st) = query (f p) st
                  | otherwise = query p st
+
+_getP_ :: (Value -> Maybe a) -> Pattern Value -> Pattern a
+_getP_ f pat = filterJust $ f <$> pat
+
+_getP :: a -> (Value -> Maybe a) -> Pattern Value -> Pattern a
+_getP d f pat = (fromMaybe d . f) <$> pat
+
+_cX :: a -> (Value -> Maybe a) -> String -> Pattern a
+_cX d f s = Pattern $ \(State a m) -> queryArc (maybe (pure d) (_getP d f) $ Map.lookup s m) a
+
+_cX_ :: (Value -> Maybe a) -> String -> Pattern a
+_cX_ f s = Pattern $ \(State a m) -> queryArc (maybe silence (_getP_ f) $ Map.lookup s m) a
+
+cF :: Double -> String -> Pattern Double
+cF d = _cX d getF
+cF_ :: String -> Pattern Double
+cF_ = _cX_ getF
+cF0 :: String -> Pattern Double
+cF0 = _cX 0 getF
+
+cI :: Int -> String -> Pattern Int
+cI d = _cX d getI
+cI_ :: String -> Pattern Int
+cI_ = _cX_ getI
+cI0 :: String -> Pattern Int
+cI0 = _cX 0 getI
+
+cB :: Bool -> String -> Pattern Bool
+cB d = _cX d getB
+cB_ :: String -> Pattern Bool
+cB_ = _cX_ getB
+cB0 :: String -> Pattern Bool
+cB0 = _cX False getB
+
+cR :: Rational -> String -> Pattern Rational
+cR d = _cX d getR
+cR_ :: String -> Pattern Rational
+cR_ = _cX_ getR
+cR0 :: String -> Pattern Rational
+cR0 = _cX 0 getR
+
+cT :: Time -> String -> Pattern Time
+cT = cR
+cT0 :: String -> Pattern Time
+cT0 = cR0
+cT_ :: String -> Pattern Time
+cT_ = cR_
+
+cS :: String -> String -> Pattern String
+cS d = _cX d getS
+cS_ :: String -> Pattern String
+cS_ = _cX_ getS
+cS0 :: String -> Pattern String
+cS0 = _cX "" getS
+
+-- Default controller inputs (for MIDI)
+in0 :: Pattern Double
+in0 = cF 0 "0"
+in1 :: Pattern Double
+in1 = cF 0 "1"
+in2 :: Pattern Double
+in2 = cF 0 "2"
+in3 :: Pattern Double
+in3 = cF 0 "3"
+in4 :: Pattern Double
+in4 = cF 0 "4"
+in5 :: Pattern Double
+in5 = cF 0 "5"
+in6 :: Pattern Double
+in6 = cF 0 "6"
+in7 :: Pattern Double
+in7 = cF 0 "7"
+in8 :: Pattern Double
+in8 = cF 0 "8"
+in9 :: Pattern Double
+in9 = cF 0 "9"
+in10 :: Pattern Double
+in10 = cF 0 "10"
+in11 :: Pattern Double
+in11 = cF 0 "11"
+in12 :: Pattern Double
+in12 = cF 0 "12"
+in13 :: Pattern Double
+in13 = cF 0 "13"
+in14 :: Pattern Double
+in14 = cF 0 "14"
+in15 :: Pattern Double
+in15 = cF 0 "15"
+in16 :: Pattern Double
+in16 = cF 0 "16"
+in17 :: Pattern Double
+in17 = cF 0 "17"
+in18 :: Pattern Double
+in18 = cF 0 "18"
+in19 :: Pattern Double
+in19 = cF 0 "19"
+in20 :: Pattern Double
+in20 = cF 0 "20"
+in21 :: Pattern Double
+in21 = cF 0 "21"
+in22 :: Pattern Double
+in22 = cF 0 "22"
+in23 :: Pattern Double
+in23 = cF 0 "23"
+in24 :: Pattern Double
+in24 = cF 0 "24"
+in25 :: Pattern Double
+in25 = cF 0 "25"
+in26 :: Pattern Double
+in26 = cF 0 "26"
+in27 :: Pattern Double
+in27 = cF 0 "27"
+in28 :: Pattern Double
+in28 = cF 0 "28"
+in29 :: Pattern Double
+in29 = cF 0 "29"
+in30 :: Pattern Double
+in30 = cF 0 "30"
+in31 :: Pattern Double
+in31 = cF 0 "31"
+in32 :: Pattern Double
+in32 = cF 0 "32"
+in33 :: Pattern Double
+in33 = cF 0 "33"
+in34 :: Pattern Double
+in34 = cF 0 "34"
+in35 :: Pattern Double
+in35 = cF 0 "35"
+in36 :: Pattern Double
+in36 = cF 0 "36"
+in37 :: Pattern Double
+in37 = cF 0 "37"
+in38 :: Pattern Double
+in38 = cF 0 "38"
+in39 :: Pattern Double
+in39 = cF 0 "39"
+in40 :: Pattern Double
+in40 = cF 0 "40"
+in41 :: Pattern Double
+in41 = cF 0 "41"
+in42 :: Pattern Double
+in42 = cF 0 "42"
+in43 :: Pattern Double
+in43 = cF 0 "43"
+in44 :: Pattern Double
+in44 = cF 0 "44"
+in45 :: Pattern Double
+in45 = cF 0 "45"
+in46 :: Pattern Double
+in46 = cF 0 "46"
+in47 :: Pattern Double
+in47 = cF 0 "47"
+in48 :: Pattern Double
+in48 = cF 0 "48"
+in49 :: Pattern Double
+in49 = cF 0 "49"
+in50 :: Pattern Double
+in50 = cF 0 "50"
+in51 :: Pattern Double
+in51 = cF 0 "51"
+in52 :: Pattern Double
+in52 = cF 0 "52"
+in53 :: Pattern Double
+in53 = cF 0 "53"
+in54 :: Pattern Double
+in54 = cF 0 "54"
+in55 :: Pattern Double
+in55 = cF 0 "55"
+in56 :: Pattern Double
+in56 = cF 0 "56"
+in57 :: Pattern Double
+in57 = cF 0 "57"
+in58 :: Pattern Double
+in58 = cF 0 "58"
+in59 :: Pattern Double
+in59 = cF 0 "59"
+in60 :: Pattern Double
+in60 = cF 0 "60"
+in61 :: Pattern Double
+in61 = cF 0 "61"
+in62 :: Pattern Double
+in62 = cF 0 "62"
+in63 :: Pattern Double
+in63 = cF 0 "63"
+in64 :: Pattern Double
+in64 = cF 0 "64"
+in65 :: Pattern Double
+in65 = cF 0 "65"
+in66 :: Pattern Double
+in66 = cF 0 "66"
+in67 :: Pattern Double
+in67 = cF 0 "67"
+in68 :: Pattern Double
+in68 = cF 0 "68"
+in69 :: Pattern Double
+in69 = cF 0 "69"
+in70 :: Pattern Double
+in70 = cF 0 "70"
+in71 :: Pattern Double
+in71 = cF 0 "71"
+in72 :: Pattern Double
+in72 = cF 0 "72"
+in73 :: Pattern Double
+in73 = cF 0 "73"
+in74 :: Pattern Double
+in74 = cF 0 "74"
+in75 :: Pattern Double
+in75 = cF 0 "75"
+in76 :: Pattern Double
+in76 = cF 0 "76"
+in77 :: Pattern Double
+in77 = cF 0 "77"
+in78 :: Pattern Double
+in78 = cF 0 "78"
+in79 :: Pattern Double
+in79 = cF 0 "79"
+in80 :: Pattern Double
+in80 = cF 0 "80"
+in81 :: Pattern Double
+in81 = cF 0 "81"
+in82 :: Pattern Double
+in82 = cF 0 "82"
+in83 :: Pattern Double
+in83 = cF 0 "83"
+in84 :: Pattern Double
+in84 = cF 0 "84"
+in85 :: Pattern Double
+in85 = cF 0 "85"
+in86 :: Pattern Double
+in86 = cF 0 "86"
+in87 :: Pattern Double
+in87 = cF 0 "87"
+in88 :: Pattern Double
+in88 = cF 0 "88"
+in89 :: Pattern Double
+in89 = cF 0 "89"
+in90 :: Pattern Double
+in90 = cF 0 "90"
+in91 :: Pattern Double
+in91 = cF 0 "91"
+in92 :: Pattern Double
+in92 = cF 0 "92"
+in93 :: Pattern Double
+in93 = cF 0 "93"
+in94 :: Pattern Double
+in94 = cF 0 "94"
+in95 :: Pattern Double
+in95 = cF 0 "95"
+in96 :: Pattern Double
+in96 = cF 0 "96"
+in97 :: Pattern Double
+in97 = cF 0 "97"
+in98 :: Pattern Double
+in98 = cF 0 "98"
+in99 :: Pattern Double
+in99 = cF 0 "99"
+in100 :: Pattern Double
+in100 = cF 0 "100"
+in101 :: Pattern Double
+in101 = cF 0 "101"
+in102 :: Pattern Double
+in102 = cF 0 "102"
+in103 :: Pattern Double
+in103 = cF 0 "103"
+in104 :: Pattern Double
+in104 = cF 0 "104"
+in105 :: Pattern Double
+in105 = cF 0 "105"
+in106 :: Pattern Double
+in106 = cF 0 "106"
+in107 :: Pattern Double
+in107 = cF 0 "107"
+in108 :: Pattern Double
+in108 = cF 0 "108"
+in109 :: Pattern Double
+in109 = cF 0 "109"
+in110 :: Pattern Double
+in110 = cF 0 "110"
+in111 :: Pattern Double
+in111 = cF 0 "111"
+in112 :: Pattern Double
+in112 = cF 0 "112"
+in113 :: Pattern Double
+in113 = cF 0 "113"
+in114 :: Pattern Double
+in114 = cF 0 "114"
+in115 :: Pattern Double
+in115 = cF 0 "115"
+in116 :: Pattern Double
+in116 = cF 0 "116"
+in117 :: Pattern Double
+in117 = cF 0 "117"
+in118 :: Pattern Double
+in118 = cF 0 "118"
+in119 :: Pattern Double
+in119 = cF 0 "119"
+in120 :: Pattern Double
+in120 = cF 0 "120"
+in121 :: Pattern Double
+in121 = cF 0 "121"
+in122 :: Pattern Double
+in122 = cF 0 "122"
+in123 :: Pattern Double
+in123 = cF 0 "123"
+in124 :: Pattern Double
+in124 = cF 0 "124"
+in125 :: Pattern Double
+in125 = cF 0 "125"
+in126 :: Pattern Double
+in126 = cF 0 "126"
+in127 :: Pattern Double
+in127 = cF 0 "127"
diff --git a/src/Sound/Tidal/Params.hs b/src/Sound/Tidal/Params.hs
--- a/src/Sound/Tidal/Params.hs
+++ b/src/Sound/Tidal/Params.hs
@@ -160,6 +160,7 @@
 -- | a pattern of numbers from 0 to 1. Sets the length of the delay.
 delaytime :: Pattern Double -> ControlPattern
 delaytime = pF "delaytime"
+
 detune :: Pattern Double -> ControlPattern
 detune = pF "detune"
 
@@ -381,6 +382,10 @@
 -- | formant filter to make things sound like vowels, a pattern of either `a`, `e`, `i`, `o` or `u`. Use a rest (`~`) for no effect.
 vowel :: Pattern String -> ControlPattern
 vowel = pS "vowel"
+
+voweli :: Pattern Int -> ControlPattern
+voweli = pI "vowel"
+
 waveloss :: Pattern Double -> ControlPattern
 waveloss = pF "waveloss"
 
@@ -482,7 +487,7 @@
 lbrick = pF "lbrick"
 
 -- aliases
-att, bpf, bpq, chdecay, ctf, ctfg, delayfb, delayt, det, gat, hg, hpf, hpq, lag, lbd, lch, lcl, lcp, lcr, lfoc, lfoi
+att, bpf, bpq, chdecay, ctf, ctfg, delayfb, dfb, delayt, dt, det, gat, hg, hpf, hpq, lag, lbd, lch, lcl, lcp, lcr, lfoc, lfoi
    , lfop, lht, llt, loh, lpf, lpq, lsn, ohdecay, phasdp, phasr, pit1, pit2, pit3, por, rel, sz, sag, scl, scp
    , scr, sld, std, stt, sus, tdecay, tremdp, tremr, vcf, vco, voi
  :: Pattern Double -> ControlPattern
@@ -493,7 +498,9 @@
 ctf = cutoff
 ctfg = cutoffegint
 delayfb = delayfeedback
+dfb = delayfeedback
 delayt = delaytime
+dt = delaytime
 det = detune
 gat = gate
 hg = hatgrain
diff --git a/src/Sound/Tidal/ParseBP.hs b/src/Sound/Tidal/ParseBP.hs
--- a/src/Sound/Tidal/ParseBP.hs
+++ b/src/Sound/Tidal/ParseBP.hs
@@ -54,6 +54,7 @@
             | TPat_Elongate Rational (TPat a)
             | TPat_Repeat Int (TPat a)
             | TPat_EnumFromTo (TPat a) (TPat a)
+            | TPat_Var String
             deriving (Show)
 
 toPat :: (Parseable a, Enumerable a) => TPat a -> Pattern a
@@ -78,6 +79,7 @@
            base_first | null pats = pure 0
                       | otherwise = pure $ fst $ head pats
    TPat_Seq xs -> snd $ resolve_seq xs
+   TPat_Var s -> getControl s
    _ -> silence
 
 resolve_tpat :: (Enumerable a, Parseable a) => TPat a -> (Rational, Pattern a)
@@ -117,10 +119,14 @@
 parseTPat :: Parseable a => String -> Either ParseError (TPat a)
 parseTPat = parseRhythm tPatParser
 
+cP :: (Enumerable a, Parseable a) => String -> Pattern a
+cP s = innerJoin $ parseBP_E <$> (_cX_ getS s)
+
 class Parseable a where
   tPatParser :: MyParser (TPat a)
   doEuclid :: Pattern Int -> Pattern Int -> Pattern Int -> Pattern a -> Pattern a
-  -- toEuclid :: a ->
+  getControl :: String -> Pattern a
+  getControl _ = silence
 
 class Enumerable a where
   fromTo :: a -> a -> Pattern a
@@ -137,6 +143,7 @@
 instance Parseable Double where
   tPatParser = pDouble
   doEuclid = euclidOff
+  getControl = cF_
 
 instance Enumerable Double where
   fromTo = enumFromTo'
@@ -145,6 +152,7 @@
 instance Parseable String where
   tPatParser = pVocable
   doEuclid = euclidOff
+  getControl = cS_
 
 instance Enumerable String where
   fromTo a b = fastFromList [a,b]
@@ -153,6 +161,7 @@
 instance Parseable Bool where
   tPatParser = pBool
   doEuclid = euclidOffBool
+  getControl = cB_
 
 instance Enumerable Bool where
   fromTo a b = fastFromList [a,b]
@@ -161,6 +170,7 @@
 instance Parseable Int where
   tPatParser = pIntegral
   doEuclid = euclidOff
+  getControl = cI_
 
 instance Enumerable Int where
   fromTo = enumFromTo'
@@ -169,6 +179,7 @@
 instance Parseable Integer where
   tPatParser = pIntegral
   doEuclid = euclidOff
+  getControl = (fmap fromIntegral) . cI_
 
 instance Enumerable Integer where
   fromTo = enumFromTo'
@@ -177,6 +188,7 @@
 instance Parseable Rational where
   tPatParser = pRational
   doEuclid = euclidOff
+  getControl = cR_
 
 instance Enumerable Rational where
   fromTo = enumFromTo'
@@ -294,8 +306,13 @@
 pSingle :: MyParser (TPat a) -> MyParser (TPat a)
 pSingle f = f >>= pRand >>= pMult
 
+pVar :: MyParser (TPat a)
+pVar = wrapPos $ do char '^'
+                    name <- many (letter <|> oneOf "0123456789:.-_") <?> "string"
+                    return $ TPat_Var name
+
 pPart :: Parseable a => MyParser (TPat a) -> MyParser (TPat a)
-pPart f = do pt <- (pSingle f <|> pPolyIn f <|> pPolyOut f) >>= pE >>= pRand
+pPart f = do pt <- (pSingle f <|> pPolyIn f <|> pPolyOut f <|> pVar) >>= pE >>= pRand
              spaces -- TODO is this needed?
              return pt
 
@@ -506,6 +523,8 @@
                     return $ 1/3
              <|> do char 'f'
                     return $ 0.2
+             <|> do char 'x'
+                    return $ 1/6
 
 pRational :: MyParser (TPat Rational)
 pRational = wrapPos $ (TPat_Atom Nothing) <$> pRatio
diff --git a/src/Sound/Tidal/Pattern.hs b/src/Sound/Tidal/Pattern.hs
--- a/src/Sound/Tidal/Pattern.hs
+++ b/src/Sound/Tidal/Pattern.hs
@@ -42,7 +42,7 @@
 data ArcF a = Arc
   { start :: a
   , stop :: a
-  } deriving (Eq, Ord, Functor)
+  } deriving (Eq, Ord, Functor, Show)
 
 type Arc = ArcF Time
 
@@ -723,7 +723,7 @@
 filterValues :: (a -> Bool) -> Pattern a -> Pattern a
 filterValues f p = p {query = filter (f . value) . query p}
 
--- | Turns a pattern of 'Maybe' values in to a pattern of values,
+-- | Turns a pattern of 'Maybe' values into a pattern of values,
 -- dropping the events of 'Nothing'.
 filterJust :: Pattern (Maybe a) -> Pattern a
 filterJust p = fromJust <$> filterValues isJust p
diff --git a/src/Sound/Tidal/Show.hs b/src/Sound/Tidal/Show.hs
--- a/src/Sound/Tidal/Show.hs
+++ b/src/Sound/Tidal/Show.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE TypeSynonymInstances, FlexibleInstances, RecordWildCards #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
-module Sound.Tidal.Show (show, showAll, draw, drawLine) where
+module Sound.Tidal.Show (show, showAll, draw, drawLine, drawLineSz) where
 
 import Sound.Tidal.Pattern
 
diff --git a/src/Sound/Tidal/Stream.hs b/src/Sound/Tidal/Stream.hs
--- a/src/Sound/Tidal/Stream.hs
+++ b/src/Sound/Tidal/Stream.hs
@@ -7,7 +7,7 @@
 import           Control.Concurrent.MVar
 import           Control.Concurrent
 import qualified Data.Map.Strict as Map
-import           Data.Maybe (fromJust, fromMaybe, isJust, catMaybes)
+import           Data.Maybe (fromJust, fromMaybe, catMaybes)
 import qualified Control.Exception as E
 -- import Control.Monad.Reader
 -- import Control.Monad.Except
@@ -27,12 +27,9 @@
 import           System.Random (getStdRandom, randomR)
 import           Sound.Tidal.Show ()
 
-data TimeStamp = BundleStamp | MessageStamp | NoStamp
- deriving (Eq, Show)
-
 data Stream = Stream {sConfig :: Config,
                       sInput :: MVar StateMap,
-                      sOutput :: MVar ControlPattern,
+                      -- sOutput :: MVar ControlPattern,
                       sListenTid :: Maybe ThreadId,
                       sPMapMV :: MVar PlayMap,
                       sTempoMV :: MVar T.Tempo,
@@ -42,90 +39,39 @@
 
 type PatId = String
 
-data Cx = Cx {cxTarget :: OSCTarget,
-              cxUDP :: O.UDP
+data Cx = Cx {cxTarget :: Target,
+              cxUDP :: O.UDP,
+              cxOSCs :: [OSC]
              }
+  deriving (Show)
 
-data OSCTarget = OSCTarget {oName :: String,
-                            oAddress :: String,
-                            oPort :: Int,
-                            oPath :: String,
-                            oShape :: Maybe [(String, Maybe Value)],
-                            oLatency :: Double,
-                            oPreamble :: [O.Datum],
-                            oTimestamp :: TimeStamp
-                           }
-                 deriving Show
+data StampStyle = BundleStamp
+                | MessageStamp
+  deriving (Eq, Show)
 
-superdirtTarget :: OSCTarget
-superdirtTarget = OSCTarget {oName = "SuperDirt",
-                             oAddress = "127.0.0.1",
-                             oPort = 57120,
-                             oPath = "/play2",
-                             oShape = Nothing,
-                             oLatency = 0.02,
-                             oPreamble = [],
-                             oTimestamp = BundleStamp
-                            }
 
-dirtTarget :: OSCTarget
-dirtTarget = OSCTarget {oName = "Dirt",
-                        oAddress = "127.0.0.1",
-                        oPort = 7771,
-                        oPath = "/play",
-                        oShape = Just [("sec", Just $ VI 0),
-                                       ("usec", Just $ VI 0),
-                                       ("cps", Just $ VF 0),
-                                       ("s", Nothing),
-                                       ("offset", Just $ VF 0),
-                                       ("begin", Just $ VF 0),
-                                       ("end", Just $ VF 1),
-                                       ("speed", Just $ VF 1),
-                                       ("pan", Just $ VF 0.5),
-                                       ("velocity", Just $ VF 0.5),
-                                       ("vowel", Just $ VS ""),
-                                       ("cutoff", Just $ VF 0),
-                                       ("resonance", Just $ VF 0),
-                                       ("accelerate", Just $ VF 0),
-                                       ("shape", Just $ VF 0),
-                                       ("kriole", Just $ VI 0),
-                                       ("gain", Just $ VF 1),
-                                       ("cut", Just $ VI 0),
-                                       ("delay", Just $ VF 0),
-                                       ("delaytime", Just $ VF (-1)),
-                                       ("delayfeedback", Just $ VF (-1)),
-                                       ("crush", Just $ VF 0),
-                                       ("coarse", Just $ VI 0),
-                                       ("hcutoff", Just $ VF 0),
-                                       ("hresonance", Just $ VF 0),
-                                       ("bandf", Just $ VF 0),
-                                       ("bandq", Just $ VF 0),
-                                       ("unit", Just $ VS "rate"),
-                                       ("loop", Just $ VF 0),
-                                       ("n", Just $ VF 0),
-                                       ("attack", Just $ VF (-1)),
-                                       ("hold", Just $ VF 0),
-                                       ("release", Just $ VF (-1)),
-                                       ("orbit", Just $ VI 0),
-                                       ("id", Just $ VI 0)
-                                      ],
-                         oLatency = 0.02,
-                         oPreamble = [],
-                         oTimestamp = MessageStamp
-                       }
+data Schedule = Pre StampStyle
+              | Live
+  deriving (Eq, Show)
 
-startStream :: Config -> MVar StateMap -> [OSCTarget] -> IO (MVar ControlPattern, MVar T.Tempo, [Cx])
-startStream config sMapMV targets
-  = do cxs <- mapM (\target -> do u <- O.openUDP (oAddress target) (oPort target)
-                                  return $ Cx {cxUDP = u,
-                                               cxTarget = target
-                                              }
-                   ) targets
-       pMV <- newMVar empty
-       (tempoMV, _) <- T.clocked config $ onTick config sMapMV pMV cxs
-       return $ (pMV, tempoMV, cxs)
+data Target = Target {oName :: String,
+                      oAddress :: String,
+                      oPort :: Int,
+                      oLatency :: Double,
+                      oWindow :: Maybe Arc,
+                      oSchedule :: Schedule
+                     }
+                 deriving Show
 
+data Args = Named {required :: [String]}
+          | ArgList [(String, Maybe Value)]
+         deriving Show
 
+data OSC = OSC {path :: String,
+                args :: Args
+               }
+         deriving Show
+
 data PlayState = PlayState {pattern :: ControlPattern,
                             mute :: Bool,
                             solo :: Bool,
@@ -135,6 +81,93 @@
 
 type PlayMap = Map.Map PatId PlayState
 
+superdirtTarget :: Target
+superdirtTarget = Target {oName = "SuperDirt",
+                          oAddress = "127.0.0.1",
+                          oPort = 57120,
+                          oLatency = 0.2,
+                          oWindow = Nothing,
+                          oSchedule = Pre BundleStamp
+                         }
+
+superdirtShape :: OSC
+superdirtShape = OSC "/play2" $ Named {required = ["s"]}
+
+dirtTarget :: Target
+dirtTarget = Target {oName = "Dirt",
+                     oAddress = "127.0.0.1",
+                     oPort = 7771,
+                     oLatency = 0.02,
+                     oWindow = Nothing,
+                     oSchedule = Pre MessageStamp
+                    }
+
+dirtShape :: OSC
+dirtShape = OSC "/play" $ ArgList [("sec", Just $ VI 0),
+                                   ("usec", Just $ VI 0),
+                                   ("cps", Just $ VF 0),
+                                   ("s", Nothing),
+                                   ("offset", Just $ VF 0),
+                                   ("begin", Just $ VF 0),
+                                   ("end", Just $ VF 1),
+                                   ("speed", Just $ VF 1),
+                                   ("pan", Just $ VF 0.5),
+                                   ("velocity", Just $ VF 0.5),
+                                   ("vowel", Just $ VS ""),
+                                   ("cutoff", Just $ VF 0),
+                                   ("resonance", Just $ VF 0),
+                                   ("accelerate", Just $ VF 0),
+                                   ("shape", Just $ VF 0),
+                                   ("kriole", Just $ VI 0),
+                                   ("gain", Just $ VF 1),
+                                   ("cut", Just $ VI 0),
+                                   ("delay", Just $ VF 0),
+                                   ("delaytime", Just $ VF (-1)),
+                                   ("delayfeedback", Just $ VF (-1)),
+                                   ("crush", Just $ VF 0),
+                                   ("coarse", Just $ VI 0),
+                                   ("hcutoff", Just $ VF 0),
+                                   ("hresonance", Just $ VF 0),
+                                   ("bandf", Just $ VF 0),
+                                   ("bandq", Just $ VF 0),
+                                   ("unit", Just $ VS "rate"),
+                                   ("loop", Just $ VF 0),
+                                   ("n", Just $ VF 0),
+                                   ("attack", Just $ VF (-1)),
+                                   ("hold", Just $ VF 0),
+                                   ("release", Just $ VF (-1)),
+                                   ("orbit", Just $ VI 0),
+                                   ("id", Just $ VI 0)
+                                  ]
+
+startStream :: Config -> [(Target, [OSC])] -> IO Stream
+startStream config oscmap 
+  = do cxs <- mapM (\(target, os) -> do u <- O.openUDP (oAddress target) (oPort target)
+                                        return $ Cx {cxUDP = u, cxTarget = target, cxOSCs = os}
+                   ) oscmap
+
+       sMapMV <- newMVar Map.empty
+       pMapMV <- newMVar Map.empty
+       globalFMV <- newMVar id
+       listenTid <- ctrlListen sMapMV config
+       tempoMV <- newEmptyMVar
+       let stream = Stream {sConfig = config,
+                            sInput = sMapMV,
+                            sListenTid = listenTid,
+                            sPMapMV = pMapMV,
+                            sTempoMV = tempoMV,
+                            sGlobalFMV = globalFMV,
+                            sCxs = cxs
+                           }
+       _ <- T.clocked config tempoMV $ onTick stream
+       return stream
+
+startTidal :: Target -> Config -> IO Stream
+startTidal target config = startStream config [(target, [superdirtShape])]
+
+startMulti :: [Target] -> Config -> IO ()
+startMulti _ _ = putStrLn $ "startMulti has been removed, please check the latest documentation on tidalcycles.org"
+
 toDatum :: Value -> O.Datum
 toDatum (VF x) = O.float x
 toDatum (VI x) = O.int32 x
@@ -144,67 +177,65 @@
 toDatum (VB False) = O.int32 (0 :: Int)
 toDatum (VX xs) = O.Blob $ O.blob_pack xs
 
-toData :: OSCTarget -> Event ControlMap -> Maybe [O.Datum]
-toData target e
-  | isJust (oShape target) = fmap (fmap toDatum) $ sequence $ map (\(n,v) -> Map.lookup n (value e) <|> v) (fromJust $ oShape target)
-  | otherwise = Just $ concatMap (\(n,v) -> [O.string n, toDatum v]) $ Map.toList $ value e
+toData :: OSC -> Event ControlMap -> Maybe [O.Datum]
+toData (OSC {args = ArgList as}) e = fmap (fmap toDatum) $ sequence $ map (\(n,v) -> Map.lookup n (value e) <|> v) as
+toData (OSC {args = Named rqrd}) e
+  | hasRequired rqrd = Just $ concatMap (\(n,v) -> [O.string n, toDatum v]) $ Map.toList $ value e
+  | otherwise = Nothing
+  where hasRequired [] = True
+        hasRequired xs = null $ filter (not . (`elem` ks)) xs
+        ks = Map.keys (value e)
 
-substitutePath :: String -> ControlMap -> String
-substitutePath path cm = parse path
-  where parse [] = []
+substitutePath :: String -> ControlMap -> Maybe String
+substitutePath str cm = parse str
+  where parse [] = Just []
         parse ('{':xs) = parseWord xs
-        parse (x:xs) = x:(parse xs)
+        parse (x:xs) = do xs' <- parse xs
+                          return (x:xs')
         parseWord xs | b == [] = getString cm a
-                     | otherwise = getString cm a ++ parse (tail b)
+                     | otherwise = do v <- getString cm a
+                                      xs' <- parse (tail b)
+                                      return $ v ++ xs'
           where (a,b) = break (== '}') xs
 
-getString :: ControlMap -> String -> String
-getString cm s = fromMaybe "" $ do v <- Map.lookup s cm
-                                   return $ simpleShow v
-                                    where simpleShow :: Value -> String
-                                          simpleShow (VS str) = str
-                                          simpleShow (VI i) = show i
-                                          simpleShow (VF f) = show f
-                                          simpleShow (VR r) = show r
-                                          simpleShow (VB b) = show b
-                                          simpleShow (VX xs) = show xs
+getString :: ControlMap -> String -> Maybe String
+getString cm s = defaultValue $ simpleShow <$> Map.lookup s cm
+                      where simpleShow :: Value -> String
+                            simpleShow (VS str) = str
+                            simpleShow (VI i) = show i
+                            simpleShow (VF f) = show f
+                            simpleShow (VR r) = show r
+                            simpleShow (VB b) = show b
+                            simpleShow (VX xs) = show xs
+                            (_, dflt) = break (== '=') s
+                            defaultValue :: Maybe String -> Maybe String
+                            defaultValue Nothing | null dflt = Nothing
+                                                 | otherwise = Just $ tail dflt
+                            defaultValue x = x
 
-toMessage :: Config -> Double -> OSCTarget -> T.Tempo -> Event (Map.Map String Value) -> Maybe O.Message
-toMessage config t target tempo e = do vs <- toData target addExtra
-                                       return $ O.Message (substitutePath (oPath target) (value e)) $ oPreamble target ++ vs
-  where on = sched tempo $ start $ wholeOrPart e
-        off = sched tempo $ stop $ wholeOrPart e
-        cm = value e
-        identifier = ((if (start $ wholeOrPart e) == (start $ part e) then "X" else ">")
-                      ++ show (start $ wholeOrPart e)
-                      ++ "-"
-                      ++ show (stop $ wholeOrPart e)
-                      ++ "-"
-                      ++ getString cm "n"
-                      ++ "-"
-                      ++ getString cm "note"
-                      ++ "-"
-                      ++ getString cm "s"
-                     )
-        delta = off - on
-        messageStamp = oTimestamp target == MessageStamp
-        -- If there is already cps in the event, the union will preserve that.
-        addExtra = (\v -> (Map.union v $ Map.fromList (extra messageStamp)
-                          )) <$> e
-        addIdentifier | cSendParts config = (("id", VS identifier):)
-                      | otherwise = id
-        extra False = addIdentifier [("cps", (VF $ T.cps tempo)),
-                                     ("delta", VF delta),
-                                     ("cycle", VF (fromRational $ start $ wholeOrPart e))
-                                    ]
-        extra True = timestamp ++ (extra False)
-        timestamp = [("sec", VI sec),
-                     ("usec", VI usec)
-                    ]
-        ut = O.ntpr_to_ut t
-        sec = floor ut
-        usec = floor $ 1000000 * (ut - (fromIntegral sec))
+playStack :: PlayMap -> ControlPattern
+playStack pMap = stack $ map pattern active
+  where active = filter (\pState -> if hasSolo pMap
+                                    then solo pState
+                                    else not (mute pState)
+                        ) $ Map.elems pMap
 
+toOSC :: Double -> Event ControlMap -> T.Tempo -> OSC -> Maybe (Double, O.Message)
+toOSC latency e tempo osc = do vs <- toData osc addExtra
+                               mungedPath <- substitutePath (path osc) (value e)
+                               return (ts, O.Message mungedPath vs)
+       where on = sched tempo $ start $ wholeOrPart e
+             off = sched tempo $ stop $ wholeOrPart e
+             delta = off - on
+             -- If there is already cps in the event, the union will preserve that.
+             addExtra = (\v -> (Map.union v extra)) <$> e
+             extra = Map.fromList [("cps", (VF $ T.cps tempo)),
+                                   ("delta", VF delta),
+                                   ("cycle", VF (fromRational $ start $ wholeOrPart e))
+                                  ]
+             ts = on + nudge + latency
+             nudge = fromJust $ getF $ fromMaybe (VF 0) $ Map.lookup "nudge" $ value e
+
 doCps :: MVar T.Tempo -> (Double, Maybe Value) -> IO ()
 doCps tempoMV (d, Just (VF cps)) = do _ <- forkIO $ do threadDelay $ floor $ d * 1000000
                                                        -- hack to stop things from stopping !
@@ -213,59 +244,105 @@
                                       return ()
 doCps _ _ = return ()
 
-onTick :: Config -> MVar StateMap -> MVar ControlPattern -> [Cx] -> MVar T.Tempo -> T.State -> IO ()
-onTick config sMapMV pMV cxs tempoMV st =
-  do p <- readMVar pMV
-     sMap <- readMVar sMapMV
-     tempo <- takeMVar tempoMV
-     let frameEnd = snd $ T.nowTimespan st
+onTick :: Stream -> T.State -> IO ()
+onTick stream st
+  = do doTick False stream st
+
+processCps :: T.Tempo -> [Event ControlMap] -> ([(T.Tempo, Event ControlMap)], T.Tempo)
+processCps t [] = ([], t)
+-- If an event has a tempo change, that affects the following events..
+processCps t (e:evs) = (((t', e):es'), t'')
+  where cps' = do x <- Map.lookup "cps" $ value e
+                  getF x
+        t' = (maybe t (\newCps -> T.changeTempo' t newCps (eventPartStart e)) cps')
+        (es', t'') = processCps t' evs
+
+streamOnce :: Stream -> ControlPattern -> IO ()
+streamOnce st p = do i <- getStdRandom $ randomR (0, 8192)
+                     streamFirst st $ rotL (toRational (i :: Int)) p
+
+streamFirst :: Stream -> ControlPattern -> IO ()
+streamFirst stream pat = do now <- O.time
+                            tempo <- readMVar (sTempoMV stream)
+                            pMapMV <- newMVar $ Map.singleton "fake"
+                                      (PlayState {pattern = pat,
+                                                  mute = False,
+                                                  solo = False,
+                                                  history = []
+                                                 }
+                                      )
+                            let cps = T.cps tempo
+                                state = T.State {T.ticks = 0,
+                                                 T.start = now,
+                                                 T.nowTimespan = (now, now + (1/cps)),
+                                                 T.nowArc = (Arc 0 1)
+                                                }
+                            doTick True (stream {sPMapMV = pMapMV}) state
+
+doTick :: Bool -> Stream -> T.State -> IO ()
+doTick fake stream st =
+  do tempo <- takeMVar (sTempoMV stream)
+     pMap <- readMVar (sPMapMV stream)
+     sMap <- readMVar (sInput stream)
+     -- putStrLn $ show st
+     let config = sConfig stream
+         cxs = sCxs stream
+         cycleNow = T.timeToCycles tempo $ T.start st
+         -- If a 'fake' tick, it'll be aligned with cycle zero
+         pat | fake = withResultTime (+ cycleNow) $ playStack pMap
+             | otherwise = playStack pMap
+         frameEnd = snd $ T.nowTimespan st
+         -- add cps to state
          sMap' = Map.insert "_cps" (pure $ VF $ T.cps tempo) sMap
-         es = sortOn (start . part) $ filterOns $ query p (State {arc = T.nowArc st, controls = sMap'})
-         filterOns | cSendParts config = id
-                   | otherwise = filter eventHasOnset
-           -- there should always be a whole (due to the eventHasOnset filter)
+         filterOns = filter eventHasOnset
+         extraLatency | fake = 0
+                      | otherwise = cFrameTimespan config + T.nudged tempo
+         --filterOns | cSendParts config = id
+         --          | otherwise = filter eventHasOnset
+         es = sortOn (start . part) $ filterOns $ query pat (State {arc = T.nowArc st,
+                                                                    controls = sMap'
+                                                                   }
+                                                            )
+         -- TODO onset is calculated in toOSC as well..
          on e tempo'' = (sched tempo'' $ start $ wholeOrPart e)
-         eventNudge e = fromJust $ getF $ fromMaybe (VF 0) $ Map.lookup "nudge" $ value e
-         processCps :: T.Tempo -> [Event ControlMap] -> ([(T.Tempo, Event ControlMap)], T.Tempo)
-         processCps t [] = ([], t)
-         -- If an event has a tempo change, that affects the following
-         -- events..
-         processCps t (e:evs) = (((t', e):es'), t'')
-           where cps' = do x <- Map.lookup "cps" $ value e
-                           getF x
-                 t' = (maybe t (\newCps -> T.changeTempo' t newCps (eventPartStart e)) cps')
-                 (es', t'') = processCps t' evs
-         latency target = oLatency target + cFrameTimespan config + T.nudged tempo
          (tes, tempo') = processCps tempo es
-     mapM_ (\(Cx target udp) -> (do let ms = catMaybes $ map (\(t, e) -> do let nudge = eventNudge e
-                                                                            let onset = on e t
-                                                                            m <- toMessage config (onset + nudge + latency target) target tempo e
-                                                                            -- drop events that have gone out of frame (due to tempo
-                                                                            -- changes during the frame)
-                                                                            if (onset < frameEnd)
-                                                                              then Just (onset + nudge, m)
-                                                                              else  Nothing
-                                                             ) tes
-                                    E.catch (mapM_ (send target (latency target) udp) ms)
-                                )
-                       (\(e ::E.SomeException)
-                        -> putStrLn $ "Failed to send. Is the '" ++ oName target ++ "' target running? " ++ show e
-                       )
+     mapM_ (\cx@(Cx target _ oscs) ->
+              (do let latency = oLatency target + extraLatency
+                      ms = concatMap (\(t, e) ->
+                                        if (fake || (on e t) < frameEnd)
+                                        then catMaybes $ map (toOSC latency e t) oscs
+                                        else []
+                                     ) tes
+                  E.catch $ mapM_ (send cx) ms
+              )
+              (\(e ::E.SomeException)
+                -> putStrLn $ "Failed to send. Is the '" ++ oName target ++ "' target running? " ++ show e
+              )
            ) cxs
-     putMVar tempoMV tempo'
+     putMVar (sTempoMV stream) tempo'
      return ()
 
-send :: O.Transport t => OSCTarget -> Double -> t -> (Double, O.Message) -> IO ()
-send target latency u (time, m)
-  | oTimestamp target == BundleStamp = O.sendBundle u $ O.Bundle (time + latency) [m]
-  | oTimestamp target == MessageStamp = O.sendMessage u m
+send :: Cx -> (Double, O.Message) -> IO ()
+send cx (time, m)
+  | oSchedule target == Pre BundleStamp = O.sendBundle u $ O.Bundle time [m]
+  | oSchedule target == Pre MessageStamp = O.sendMessage u $ addtime m
   | otherwise = do _ <- forkIO $ do now <- O.time
-                                    threadDelay $ floor $ ((time+latency) - now) * 1000000
+                                    threadDelay $ floor $ (time - now) * 1000000
                                     O.sendMessage u m
                    return ()
+    where addtime (O.Message mpath params) = O.Message mpath ((O.int32 sec):((O.int32 usec):params))
+          ut = O.ntpr_to_ut time
+          sec :: Int
+          sec = floor ut
+          usec :: Int
+          usec = floor $ 1000000 * (ut - (fromIntegral sec))
+          u = cxUDP cx
+          target = cxTarget cx
+         -- latency target = oLatency target + cFrameTimespan config + T.nudged tempo
 
 sched :: T.Tempo -> Rational -> Double
-sched tempo c = ((fromRational $ c - (T.atCycle tempo)) / T.cps tempo) + (T.atTime tempo)
+sched tempo c = ((fromRational $ c - (T.atCycle tempo)) / T.cps tempo)
+                + (T.atTime tempo)
 
 -- Interaction
 
@@ -285,12 +362,13 @@
                   let hs = hasSolo pMap
                   putStrLn $ concatMap (showKV hs) $ Map.toList pMap
   where showKV :: Bool -> (PatId, PlayState) -> String
-        showKV True  (k, (PlayState _  _ True _)) = k ++ " - solo\n"
+        showKV True  (k, (PlayState {solo = True})) = k ++ " - solo\n"
         showKV True  (k, _) = "(" ++ k ++ ")\n"
-        showKV False (k, (PlayState _ False _ _)) = k ++ "\n"
+        showKV False (k, (PlayState {solo = False})) = k ++ "\n"
         showKV False (k, _) = "(" ++ k ++ ") - muted\n"
 
 -- Evaluation of pat is forced so exceptions are picked up here, before replacing the existing pattern.
+
 streamReplace :: Show a => Stream -> a -> ControlPattern -> IO ()
 streamReplace s k !pat
   = E.catch (do let x = queryArc pat (Arc 0 0)
@@ -305,7 +383,6 @@
                 pMap <- seq x $ takeMVar $ sPMapMV s
                 let playState = updatePS $ Map.lookup (show k) pMap
                 putMVar (sPMapMV s) $ Map.insert (show k) playState pMap
-                calcOutput s
                 return ()
           )
     (\(e :: E.SomeException) -> hPutStrLn stderr $ "Error in pattern: " ++ show e
@@ -328,45 +405,6 @@
 streamUnsolo :: Show a => Stream -> a -> IO ()
 streamUnsolo s k = withPatId s (show k) (\x -> x {solo = False})
 
-streamOnce :: Stream -> ControlPattern -> IO ()
-streamOnce st p = do i <- getStdRandom $ randomR (0, 8192)
-                     streamFirst st $ rotL (toRational (i :: Int)) p
-
-streamFirst :: Stream -> ControlPattern -> IO ()
-streamFirst st p
-  = do sMap <- readMVar (sInput st)
-       tempo <- readMVar (sTempoMV st)
-       now <- O.time
-       let fakeTempo = T.Tempo {T.cps = T.cps tempo,
-                                T.atCycle = 0,
-                                T.atTime = now,
-                                T.paused = False,
-                                T.nudged = 0
-                               }
-           sMap' = Map.insert "_cps" (pure $ VF $ T.cps tempo) sMap
-           es = filter eventHasOnset $ query p (State {arc = (Arc 0 1),
-                                                       controls = sMap'
-                                                      }
-                                               )
-           -- there should always be a whole (due to the eventHasOnset filter)
-           at e = sched fakeTempo $ start $ wholeOrPart e
-           -- there should always be a whole (due to the eventHasOnset filter)
-           on e = sched tempo $ start $ wholeOrPart e
-           cpsChanges = map (\e -> (on e - now, Map.lookup "cps" $ value e)) es
-           config = sConfig st
-           messages target =
-             catMaybes $ map (\e -> do m <- toMessage config (at e + (oLatency target)) target fakeTempo e
-                                       return $ (at e, m)
-                             ) es
-       mapM_ (\(Cx target udp) ->
-                 E.catch (mapM_ (send target (oLatency target) udp) (messages target))
-                 (\(e ::E.SomeException)
-                   -> putStrLn $ "Failed to send. Is the '" ++ oName target ++ "' target running? " ++ show e
-                 )
-             ) (sCxs st)
-       mapM_ (doCps $ sTempoMV st) cpsChanges
-       return ()
-
 withPatId :: Stream -> PatId -> (PlayState -> PlayState) -> IO ()
 withPatId s k f = withPatIds s [k] f
 
@@ -375,26 +413,21 @@
   = do playMap <- takeMVar $ sPMapMV s
        let pMap' = foldr (Map.update (\x -> Just $ f x)) playMap ks
        putMVar (sPMapMV s) pMap'
-       calcOutput s
        return ()
 
 -- TODO - is there a race condition here?
 streamMuteAll :: Stream -> IO ()
-streamMuteAll s = do modifyMVar_ (sOutput s) $ return . const silence
-                     modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {mute = True})
+streamMuteAll s = modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {mute = True})
 
 streamHush :: Stream -> IO ()
-streamHush s = do modifyMVar_ (sOutput s) $ return . const silence
-                  modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {pattern = silence, history = silence:history x})
+streamHush s = modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {pattern = silence, history = silence:history x})
 
 streamUnmuteAll :: Stream -> IO ()
-streamUnmuteAll s = do modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {mute = False})
-                       calcOutput s
-
+streamUnmuteAll s = modifyMVar_ (sPMapMV s) $ return . fmap (\x -> x {mute = False})
 
 streamAll :: Stream -> (ControlPattern -> ControlPattern) -> IO ()
 streamAll s f = do _ <- swapMVar (sGlobalFMV s) f
-                   calcOutput s
+                   return ()
 
 streamSet :: Valuable a => Stream -> String -> Pattern a -> IO ()
 streamSet s k pat = do sMap <- takeMVar $ sInput s
@@ -416,37 +449,6 @@
 
 streamSetR :: Stream -> String -> Pattern Rational -> IO ()
 streamSetR = streamSet
-
-calcOutput :: Stream -> IO ()
-calcOutput s = do pMap <- readMVar $ sPMapMV s
-                  globalF <- (readMVar $ sGlobalFMV s)
-                  _ <- swapMVar (sOutput s) $ globalF $ toPat $ pMap
-                  return ()
-  where toPat pMap =
-          stack $ map pattern $ filter (\pState -> if hasSolo pMap
-                                                   then solo pState
-                                                   else not (mute pState)
-                                       ) (Map.elems pMap)
-
-startTidal :: OSCTarget -> Config -> IO Stream
-startTidal target config = startMulti [target] config
-
-startMulti :: [OSCTarget] -> Config -> IO Stream
-startMulti targets config =
-  do sMapMV <- newMVar (Map.empty :: StateMap)
-     listenTid <- ctrlListen sMapMV config
-     (pMV, tempoMV, cxs) <- startStream config sMapMV targets
-     pMapMV <- newMVar Map.empty
-     globalFMV <- newMVar id
-     return $ Stream {sConfig = config,
-                      sInput = sMapMV,
-                      sListenTid = listenTid,
-                      sOutput = pMV,
-                      sPMapMV = pMapMV,
-                      sTempoMV = tempoMV,
-                      sGlobalFMV = globalFMV,
-                      sCxs = cxs
-                     }
 
 ctrlListen :: MVar StateMap -> Config -> IO (Maybe ThreadId)
 ctrlListen sMapMV c
diff --git a/src/Sound/Tidal/Tempo.hs b/src/Sound/Tidal/Tempo.hs
--- a/src/Sound/Tidal/Tempo.hs
+++ b/src/Sound/Tidal/Tempo.hs
@@ -34,6 +34,7 @@
                     nowArc  :: P.Arc,
                     starting :: Bool
                    }
+  deriving Show
 
 changeTempo :: MVar Tempo -> (O.Time -> Tempo -> Tempo) -> IO Tempo
 changeTempo tempoMV f = do t <- O.time
@@ -60,7 +61,7 @@
 
 defaultCps :: O.Time
 defaultCps = 0.5625
-  
+
 defaultTempo :: O.Time -> O.UDP -> N.SockAddr -> Tempo
 defaultTempo t local remote = Tempo {atTime   = t,
                                      atCycle  = 0,
@@ -89,23 +90,23 @@
 getCurrentCycle t = (readMVar t) >>= (cyclesNow) >>= (return . toRational)
 -}
 
-clocked :: Config -> (MVar Tempo -> State -> IO ()) -> IO (MVar Tempo, [ThreadId])
-clocked config callback
+clocked :: Config -> MVar Tempo -> (State -> IO ()) -> IO [ThreadId]
+clocked config tempoMV callback
   = do s <- O.time
        -- TODO - do something with thread id
        _ <- serverListen config
-       (tempoMV, listenTid) <- clientListen config s
+       listenTid <- clientListen config tempoMV s
        let st = State {ticks = 0,
                        start = s,
                        nowTimespan = (s, s + frameTimespan),
                        nowArc = P.Arc 0 0,
                        starting = True
                       }
-       clockTid <- forkIO $ loop tempoMV st
-       return (tempoMV, [listenTid, clockTid])
+       clockTid <- forkIO $ loop st
+       return [listenTid, clockTid]
   where frameTimespan :: Double
         frameTimespan = cFrameTimespan config
-        loop tempoMV st =
+        loop st =
           do -- putStrLn $ show $ nowArc ts
              tempo <- readMVar tempoMV               
              t <- O.time
@@ -130,15 +131,15 @@
                            starting = not (synched tempo)
                           }
              when ahead $ writeError $ "skip: " ++ show (actualTick - ticks st)
-             callback tempoMV st'
+             callback st'
              {-putStrLn ("actual tick: " ++ show actualTick
                        ++ " old tick: " ++ show (ticks st)
                        ++ " new tick: " ++ show newTick
                       )-}
-             loop tempoMV st'
+             loop st'
 
-clientListen :: Config -> O.Time -> IO (MVar Tempo, ThreadId)
-clientListen config s =
+clientListen :: Config -> MVar Tempo -> O.Time -> IO (ThreadId)
+clientListen config tempoMV s =
   do -- Listen on random port
      let tempoClientPort = cTempoClientPort config
          hostname = cTempoAddr config
@@ -148,13 +149,13 @@
      let (N.SockAddrInet _ a) = N.addrAddress remote_addr
          remote = N.SockAddrInet (fromIntegral port) a
          t = defaultTempo s local remote
+     putMVar tempoMV t
      -- Send to clock port from same port that's listened to
      O.sendTo local (O.p_message "/hello" []) remote
      -- Make tempo mvar
-     tempoMV <- newMVar t
      -- Listen to tempo changes
      tempoChild <- forkIO $ listenTempo local tempoMV
-     return (tempoMV, tempoChild)
+     return tempoChild
 
 sendTempo :: Tempo -> IO ()
 sendTempo tempo = O.sendTo (localUDP tempo) (O.p_bundle (atTime tempo) [m]) (remoteAddr tempo)
diff --git a/src/Sound/Tidal/Transition.hs b/src/Sound/Tidal/Transition.hs
--- a/src/Sound/Tidal/Transition.hs
+++ b/src/Sound/Tidal/Transition.hs
@@ -28,7 +28,6 @@
      pat' <- transition' $ appendPat (not historyFlag) (history playState)
      let pMap' = Map.insert (show patId) (playState {pattern = pat'}) pMap
      putMVar (sPMapMV stream) pMap'
-     calcOutput stream
      return ()
   where
     appendPat flag = if flag then (pat:) else id
diff --git a/src/Sound/Tidal/UI.hs b/src/Sound/Tidal/UI.hs
--- a/src/Sound/Tidal/UI.hs
+++ b/src/Sound/Tidal/UI.hs
@@ -5,14 +5,13 @@
 import           Prelude hiding ((<*), (*>))
 
 import           Data.Char (digitToInt, isDigit, ord)
-import           Data.Bits (testBit, Bits)
+import           Data.Bits (testBit, Bits, xor, shiftL, shiftR)
 -- import           System.Random (randoms, mkStdGen)
-import           System.Random.MWC
-import           Control.Monad.ST
-import           Control.Monad.Primitive (PrimState, PrimMonad)
-import qualified Data.Vector as V
-import           Data.Word (Word32)
-import           Data.Ratio ((%),numerator,denominator)
+-- import           Control.Monad.ST
+-- import           Control.Monad.Primitive (PrimState, PrimMonad)
+-- import qualified Data.Vector as V
+-- import           Data.Word (Word32)
+import           Data.Ratio ((%))
 import           Data.List (sort, sortOn, findIndices, elemIndex, groupBy, transpose, intercalate, findIndex)
 import           Data.Maybe (isJust, fromJust, fromMaybe, mapMaybe)
 import qualified Data.Text as T
@@ -29,21 +28,33 @@
 -- * UI
 
 -- | Randomisation
-timeToSeed :: (PrimMonad m, Real a) => a -> m (Gen (PrimState m))
-timeToSeed x = do
-  let x' = toRational (x*x) / 1000000
-  let n' = fromIntegral $ numerator x'
-  let d' = fromIntegral $ denominator x'
-  initialize (V.fromList [n',d'] :: V.Vector Word32)
 
-timeToRand :: RealFrac a => a -> Double
-timeToRand x = runST $ do seed <- timeToSeed x
-                          uniform seed
+-- cf. George Marsaglia (2003). "Xorshift RNGs". Journal of Statistical Software 8:14.
+-- https://www.jstatsoft.org/article/view/v008i14
+xorwise :: Int -> Int
+xorwise x =
+  let a = xor (shiftL x 13) x
+      b = xor (shiftR a 17) a
+  in xor (shiftL b 5) b
 
-timeToRands :: RealFrac a => a -> Int -> [Double]
-timeToRands x n = V.toList $ runST $ do seed <- timeToSeed x
-                                        uniformVector seed n
+-- stretch 300 cycles over the range of [0,2**29 == 536870912) then apply the xorshift algorithm
+timeToIntSeed :: RealFrac a => a -> Int
+timeToIntSeed = xorwise . truncate . (* 536870912) . snd . (properFraction :: (RealFrac a => a -> (Int,a))) . (/ 300)
 
+intSeedToRand :: Fractional a => Int -> a
+intSeedToRand = (/ 536870912) . realToFrac . (`mod` 536870912)
+
+timeToRand :: (RealFrac a, Fractional b) => a -> b
+timeToRand = intSeedToRand . timeToIntSeed
+
+timeToRands :: (RealFrac a, Fractional b) => a -> Int -> [b]
+timeToRands t n = timeToRands' (timeToIntSeed t) n
+
+timeToRands' :: Fractional a => Int -> Int -> [a]
+timeToRands' seed n
+  | n <= 0 = []
+  | otherwise = (intSeedToRand seed) : (timeToRands' (xorwise seed) (n-1))
+
 {-|
 
 `rand` generates a continuous pattern of (pseudo-)random numbers between `0` and `1`.
@@ -80,7 +91,7 @@
 @
 -}
 rand :: Fractional a => Pattern a
-rand = Pattern (\(State a@(Arc s e) _) -> [Event (Context []) Nothing a (realToFrac $ timeToRand $ (e + s)/2)])
+rand = Pattern (\(State a@(Arc s e) _) -> [Event (Context []) Nothing a (realToFrac $ (timeToRand ((e + s)/2) :: Double))])
 
 {- | Just like `rand` but for whole numbers, `irand n` generates a pattern of (pseudo-) random whole numbers between `0` to `n-1` inclusive. Notably used to pick a random
 samples from a folder:
@@ -262,7 +273,7 @@
 {- | @someCyclesBy@ is a cycle-by-cycle version of @sometimesBy@. It has a
 `someCycles = someCyclesBy 0.5` alias -}
 someCyclesBy :: Pattern Double -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
-someCyclesBy pd f p = do {d <- pd; _someCyclesBy d f p}
+someCyclesBy pd f pat = innerJoin $ (\d -> _someCyclesBy d f pat) <$> pd
 
 _someCyclesBy :: Double -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
 _someCyclesBy x = when test
@@ -1069,13 +1080,13 @@
 {- | @runMarkov n tmat xi seed@ generates a Markov chain (as a list) of length @n@
 using the transition matrix @tmat@ starting from initial state @xi@, starting
 with random numbers generated from @seed@
-Each entry in the chain is the index of state (starting from zero). 
+Each entry in the chain is the index of state (starting from zero).
 Each row of the matrix will be automatically normalized. For example:
 @
 runMarkov 8 [[2,3], [1,3]] 0 0
 @
 will produce a two-state chain 8 steps long, from initial state @0@, where the
-transition probability from state 0->0 is 2/5, 0->1 is 3/5, 1->0 is 1/4, and 
+transition probability from state 0->0 is 2/5, 0->1 is 3/5, 1->0 is 1/4, and
 1->1 is 3/4.  -}
 runMarkov :: Int -> [[Double]] -> Int -> Time -> [Int]
 runMarkov n tp xi seed = reverse $ (iterate (markovStep $ renorm) [xi])!! (n-1) where
@@ -1102,7 +1113,7 @@
 markovPat = tParam2 _markovPat
 
 _markovPat :: Int -> Int -> [[Double]] -> Pattern Int
-_markovPat n xi tp = splitQueries $ Pattern (\(State a@(Arc s _) _) -> 
+_markovPat n xi tp = splitQueries $ Pattern (\(State a@(Arc s _) _) ->
   queryArc (listToPat $ runMarkov n tp xi (sam s)) a)
 
 {-|
@@ -1298,7 +1309,7 @@
   splitQueries $ Pattern (\(State a@(Arc s _) _) -> events a $ sam s)
   where events a seed = mapMaybe toEv $ zip arcs shuffled
           where shuffled = map snd $ sortOn fst $ zip rs [0 .. (n'-1)]
-                rs = timeToRands seed n'
+                rs = timeToRands seed n' :: [Double]
                 arcs = zipWith Arc fractions (tail fractions)
                 fractions = map (+ (sam $ start a)) [0, 1 / fromIntegral n' .. 1]
                 toEv (a',v) = do a'' <- subArc a a'
@@ -1344,7 +1355,7 @@
 -- | @arpeggiate@ finds events that share the same timespan, and spreads
 -- them out during that timespan, so for example @arpeggiate "[bd,sn]"@
 -- gets turned into @"bd sn"@. Useful for creating arpeggios/broken chords.
-arpeggiate :: Pattern a -> Pattern a 
+arpeggiate :: Pattern a -> Pattern a
 arpeggiate = arpWith id
 
 -- | Shorthand alias for arpeggiate
@@ -1813,10 +1824,10 @@
 snowball :: Int -> (Pattern a -> Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
 snowball depth combinationFunction f pattern = cat $ take depth $ scanl combinationFunction pattern $ iterate f pattern
 
-{- @soak@ | 
+{- @soak@ |
     applies a function to a pattern and cats the resulting pattern,
     then continues applying the function until the depth is reached
-    this can be used to create a pattern that wanders away from 
+    this can be used to create a pattern that wanders away from
     the original pattern by continually adding random numbers
     d1 $ note (scale "hexDorian" mutateBy (+ (range -1 1 $ irand 2)) 8 $ "0 1 . 2 3 4") # s "gtr"
 -}
@@ -1825,7 +1836,7 @@
 
 deconstruct :: Int -> Pattern String -> String
 deconstruct n p = intercalate " " $ map showStep $ toList p
-  where 
+  where
     showStep :: [String] -> String
     showStep [] = "~"
     showStep [x] = x
@@ -1866,10 +1877,14 @@
              return (Event (combineContexts [ci,co]) (Just w') p' v)
         munge _ _ _ _ = Nothing
 
-chew :: Int -> Pattern Int -> ControlPattern  -> ControlPattern
-chew n ipat pat = (squeezeJoinUp $ zoompat <$> ipat) |/ P.speed (pure $ fromIntegral n)
+_chew :: Int -> Pattern Int -> ControlPattern  -> ControlPattern
+_chew n ipat pat = (squeezeJoinUp $ zoompat <$> ipat) |/ P.speed (pure $ fromIntegral n)
   where zoompat i = zoom (i'/(fromIntegral n), (i'+1)/(fromIntegral n)) (pat)
            where i' = fromIntegral $ i `mod` n
+
+-- TODO maybe _chew could pattern the first parameter directly..
+chew :: Pattern Int -> Pattern Int -> ControlPattern  -> ControlPattern
+chew npat ipat pat = innerJoin $ (\n -> _chew n ipat pat) <$> npat
 
 __binary :: Data.Bits.Bits b => Int -> b -> [Bool]
 __binary n num = map (testBit num) $ reverse [0 .. n-1]
diff --git a/src/Sound/Tidal/Version.hs b/src/Sound/Tidal/Version.hs
--- a/src/Sound/Tidal/Version.hs
+++ b/src/Sound/Tidal/Version.hs
@@ -1,4 +1,4 @@
 module Sound.Tidal.Version where
 
 tidal_version :: String
-tidal_version = "1.4.9"
+tidal_version = "1.5.0"
diff --git a/test/Sound/Tidal/PatternTest.hs b/test/Sound/Tidal/PatternTest.hs
--- a/test/Sound/Tidal/PatternTest.hs
+++ b/test/Sound/Tidal/PatternTest.hs
@@ -9,7 +9,6 @@
 
 import           Data.Ratio
 
-import           Sound.Tidal.Control
 import           Sound.Tidal.Core
 import           Sound.Tidal.Pattern
 import           Sound.Tidal.UI
diff --git a/test/Sound/Tidal/UITest.hs b/test/Sound/Tidal/UITest.hs
--- a/test/Sound/Tidal/UITest.hs
+++ b/test/Sound/Tidal/UITest.hs
@@ -81,25 +81,25 @@
     describe "rand" $ do
       it "generates a (pseudo-)random number between zero & one" $ do
         it "at the start of a cycle" $
-          (queryArc rand (Arc 0 0)) `shouldBe` [Event (Context []) Nothing (Arc 0 0) (0.5000844 :: Float)]
+          (queryArc rand (Arc 0 0)) `shouldBe` [Event (Context []) Nothing (Arc 0 0) (0 :: Float)]
         it "at 1/4 of a cycle" $
-          (queryArc rand (Arc 0.25 0.25)) `shouldBe` 
-            [Event (Context []) Nothing (Arc 0.25 0.25) (0.8587171 :: Float)]
+          (queryArc rand (Arc 0.25 0.25)) `shouldBe`
+            [Event (Context []) Nothing (Arc 0.25 0.25) (0.6295689214020967:: Float)]
         it "at 3/4 of a cycle" $
-          (queryArc rand (Arc 0.75 0.75)) `shouldBe` 
-          [Event (Context []) Nothing (Arc 0.75 0.75) (0.7277789 :: Float)]
+          (queryArc rand (Arc 0.75 0.75)) `shouldBe`
+          [Event (Context []) Nothing (Arc 0.75 0.75) (0.20052618719637394 :: Float)]
 
     describe "range" $ do
       describe "scales a pattern to the supplied range" $ do
         describe "from 3 to 4" $ do
           it "at the start of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0 0)) `shouldBe` 
+            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0 0)) `shouldBe`
               [Event (Context []) Nothing (Arc 0 0) (3 :: Float)]
           it "at 1/4 of a cycle" $
             (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0.25  0.25)) `shouldBe`
               [Event (Context []) Nothing (Arc 0.25 0.25) (3.25 :: Float)]
           it "at 3/4 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0.75 0.75)) `shouldBe` 
+            (queryArc (Sound.Tidal.UI.range 3 4 saw) (Arc 0.75 0.75)) `shouldBe`
               [Event (Context []) Nothing (Arc 0.75 0.75) (3.75 :: Float)]
 
         describe "from -1 to 1" $ do
@@ -109,21 +109,21 @@
 
         describe "from 4 to 2" $ do
           it "at the start of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0 0)) `shouldBe` 
+            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0 0)) `shouldBe`
               [Event (Context []) Nothing (Arc 0 0) (4 :: Float)]
           it "at 1/4 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0.25 0.25)) `shouldBe` 
+            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0.25 0.25)) `shouldBe`
               [Event (Context []) Nothing (Arc 0.25 0.25) (3.5 :: Float)]
           it "at 3/4 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0.75 0.75)) `shouldBe` 
+            (queryArc (Sound.Tidal.UI.range 4 2 saw) (Arc 0.75 0.75)) `shouldBe`
               [Event (Context []) Nothing (Arc 0.75 0.75) (2.5 :: Float)]
 
         describe "from 10 to 10" $ do
           it "at 1/2 of a cycle" $
-            (queryArc (Sound.Tidal.UI.range 10 10 saw) (Arc 0.5 0.5)) `shouldBe` 
+            (queryArc (Sound.Tidal.UI.range 10 10 saw) (Arc 0.5 0.5)) `shouldBe`
               [Event (Context []) Nothing (Arc 0.5 0.5) (10 :: Float)]
 
-    describe "rot" $ do 
+    describe "rot" $ do
       it "rotates values in a pattern irrespective of structure" $
         property $ comparePD (Arc 0 2)
           (rot 1 "a ~ b c" :: Pattern String)
@@ -182,7 +182,7 @@
         compareP (Arc 0 1)
           (euclidFull 3 8 "bd" silence)
           ("bd(3,8)" :: Pattern String)
-          
+
     describe "snowball" $ do
       let testPattern = ("1 2 3 4"::Pattern Int)
       it "acummulates a transform version of a pattern and appends the result - addition" $ do
@@ -264,9 +264,9 @@
           ("0" |+ chooseBy (sig fromRational) [0,1,2,3])
           ("2"::Pattern Int)
 
-    describe "arpeggiate" $ do 
-      it "can arpeggiate" $ do 
-         compareP (Arc 0 1) 
+    describe "arpeggiate" $ do
+      it "can arpeggiate" $ do
+         compareP (Arc 0 1)
            (arpeggiate ("[bd, sn] [hh:1, cp]" :: Pattern String))
            ("bd sn hh:1 cp" :: Pattern String)
       it "can arpeggiate" $ do
diff --git a/tidal.cabal b/tidal.cabal
--- a/tidal.cabal
+++ b/tidal.cabal
@@ -1,5 +1,5 @@
 name:                tidal
-version:             1.4.9
+version:             1.5.0
 synopsis:            Pattern language for improvised music
 -- description:
 homepage:            http://tidalcycles.org/
@@ -56,7 +56,6 @@
     , text < 1.3
     , parsec >= 3.1.12 && < 3.2
     , network < 3.2
-    , mwc-random < 0.15
     , vector < 0.13
     , bifunctors < 5.6
     , transformers >= 0.5 && < 0.5.7
@@ -96,13 +95,13 @@
 
 benchmark bench-speed
   type:             exitcode-stdio-1.0
-  main-is:          Main.hs 
+  main-is:          Main.hs
   hs-source-dirs:   bench/Speed
   other-modules: Tidal.PatternB
                  Tidal.CoreB
                  Tidal.UIB
                  Tidal.Inputs
-  build-depends:    
+  build-depends:
                 base == 4.*
               , criterion
               , tidal
@@ -112,10 +111,10 @@
 
 benchmark bench-memory
   type:    exitcode-stdio-1.0
-  main-is: Main.hs 
-  hs-source-dirs: bench/Memory 
+  main-is: Main.hs
+  hs-source-dirs: bench/Memory
   other-modules: Tidal.UIB
-                 Tidal.Inputs 
+                 Tidal.Inputs
   build-depends:
                base == 4.*
              , weigh
diff --git a/tidal.el b/tidal.el
--- a/tidal.el
+++ b/tidal.el
@@ -66,7 +66,7 @@
              ("separator" . "\\")
              ))
           ((or (string-equal system-type "darwin") (string-equal system-type "gnu/linux"))
-           '(("path" . "ghc-pkg field -f ~/.cabal/store/ghc-$(ghc --numeric-version)/package.db tidal data-dir")
+           '(("path" . "ghc-pkg field tidal data-dir")
              ("separator" . "/")
              ))
           )
