diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,15 @@
 # TidalCycles log of changes
 
+## 1.7.5 - Dalbeattie
+   * Minor change to _splice so that it respects if the speed parameter was already declared @onthepeakofnormal
+   * Some tests for chords @cleary
+   * Remove direct semigroups dependency @yaxu
+   * Derive functor for pattern @yaxu
+   * Handle negative ratio shorthands for rationals @ndr_brt
+   * drawLine - draw non-events with periods @yaxu
+   * Parse chord without root note @yaxu
+   * Fix clock sharing between tidal processes @yaxu
+
 ## 1.7.4 - Symonds Yat b
    * Fixes for bipolar waveforms (sine2, etc) @mindofmatthew
    * More playback controls for OSC API @mindofmatthew
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
@@ -285,7 +285,9 @@
 
 _splice :: Int -> Pattern Int -> ControlPattern -> Pattern (Map.Map String Value)
 _splice bits ipat pat = withEvent f (slice (pure bits) ipat pat) # P.unit (pure "c")
-  where f ev = ev {value = Map.insert "speed" (VF d) (value ev)}
+  where f ev = case Map.lookup "speed" (value ev) of
+                        (Just (VF s)) -> ev {value = Map.insert "speed" (VF $ d*s) (value ev)}  -- if there is a speed parameter already present
+                        _ -> 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/ParseBP.hs b/src/Sound/Tidal/ParseBP.hs
--- a/src/Sound/Tidal/ParseBP.hs
+++ b/src/Sound/Tidal/ParseBP.hs
@@ -452,8 +452,8 @@
                                         let v = applySign s f
                                         do TPat_Stack . map (TPat_Atom Nothing . (+ v)) <$> parseChord
                                            <|> return (TPat_Atom Nothing v)
-                                           <|> do TPat_Stack . map (TPat_Atom Nothing) <$> parseChord
-                                           <|> do TPat_Atom Nothing <$> pRatioChar
+                                     <|> do TPat_Stack . map (TPat_Atom Nothing) <$> parseChord
+                                     <|> do TPat_Atom Nothing <$> pRatioChar
 
 pBool :: MyParser (TPat Bool)
 pBool = wrapPos $ do oneOf "t1"
@@ -491,7 +491,7 @@
                    o <- length <$> many (char 'o')
                    let chord' = take i $ drop j $ concatMap (\x -> map (+ x) chord) [0,12..]
                    -- open voiced chords
-                   let chordo' = if o > 0 then
+                   let chordo' = if o > 0 && n > 2 then
                                      [ (chord' !! 0 - 12), (chord' !! 2 - 12), (chord' !! 1) ] ++ reverse (take (length chord' - 3) (reverse chord'))
                                  else chord'
                    return chordo'
@@ -565,22 +565,25 @@
                    return (a, b, c)
 
 pRatio :: MyParser Rational
-pRatio = do s <- sign
-            n <- read <$> many1 digit
-            result <- do char '%'
-                         d <- decimal
-                         return (n%d)
-                      <|>
-                      do char '.'
-                         frac <- many1 digit
-                         -- A hack, but not sure if doing this
-                         -- numerically would be any faster..
-                         return (toRational ((read $ show n ++ "." ++ frac)  :: Double))
-                      <|>
-                      return (n%1)
-            c <- pRatioChar <|> return 1
-            return $ applySign s (result * c)
-         <|> pRatioChar
+pRatio = do 
+  s <- sign
+  r <- do n <- read <$> many1 digit
+          result <- do char '%'
+                       d <- decimal
+                       return (n%d)
+                    <|>
+                    do char '.'
+                       frac <- many1 digit
+                       -- A hack, but not sure if doing this
+                       -- numerically would be any faster..
+                       return (toRational ((read $ show n ++ "." ++ frac) :: Double))
+                    <|>
+                    return (n%1)
+          c <- pRatioChar <|> return 1
+          return (result * c)
+        <|> 
+        pRatioChar
+  return $ applySign s r
 
 pRatioChar :: Fractional a => MyParser a
 pRatioChar = do char 'w'
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
@@ -53,17 +53,12 @@
 
 -- | A datatype representing events taking place over time
 data Pattern a = Pattern {query :: State -> [Event a]}
-  deriving Generic
+  deriving (Generic, Functor)
+
 instance NFData a => NFData (Pattern a)
 
 -- type StateMap = Map.Map String (Pattern Value)
 type ControlPattern = Pattern ValueMap
-
--- * Functor
-
-instance Functor Pattern where
-  -- | apply a function to all the values in a pattern
-  fmap f p = p {query = fmap (fmap f) . query p}
 
 -- * Applicative and friends
 
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
@@ -188,12 +188,12 @@
         s = stepcount pat
         rs = toRational s
         drawLevel :: [Event Char] -> String
-        drawLevel [] = replicate s ' '
-        drawLevel (e:es) = map f $ take s $ zip (drawLevel es ++ repeat ' ') (drawEvent e ++ repeat ' ')
-        f (' ', x) = x
+        drawLevel [] = replicate s '.'
+        drawLevel (e:es) = map f $ take s $ zip (drawLevel es ++ repeat '.') (drawEvent e ++ repeat '.')
+        f ('.', x) = x
         f (x, _) = x
         drawEvent :: Event Char -> String
-        drawEvent ev = replicate (floor $ rs * evStart) ' '
+        drawEvent ev = replicate (floor $ rs * evStart) '.'
                        ++ (value ev:replicate (floor (rs * (evStop - evStart)) - 1) '-')
           where evStart = start $ wholeOrPart ev
                 evStop = stop $ wholeOrPart ev
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
@@ -469,6 +469,8 @@
          forM_ ms $ \ m -> send (sListen stream) cx m `E.catch` \ (e :: E.SomeException) -> do
            hPutStrLn stderr $ "Failed to send. Is the '" ++ oName target ++ "' target running? " ++ show e
 
+     when (tempo /= tempo') $ T.sendTempo tempo'
+
      (tempo', sMap'') `seq` return (tempo', sMap'')
   where modifyState :: ((T.Tempo, ValueMap) -> IO (T.Tempo, ValueMap)) -> IO ()
         modifyState io = E.mask $ \restore -> do
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
@@ -46,6 +46,14 @@
                    }
   deriving Show
 
+instance Eq Tempo where
+  (==) t t' = and [(atTime t)  == (atTime t'),
+                   (atCycle t) == (atCycle t'),
+                   (cps t)     == (cps t'),
+                   (paused t)  == (paused t'),
+                   (nudged t)  == (nudged t')
+                  ]
+
 data State = State {ticks   :: Int,
                     start   :: O.Time,
                     nowTimespan :: (O.Time, O.Time),
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
@@ -21,7 +21,7 @@
 -}
 
 tidal_version :: String
-tidal_version = "1.7.4"
+tidal_version = "1.7.5"
 
 tidal_status :: IO ()
 tidal_status = tidal_status_string >>= putStrLn 
diff --git a/test/Sound/Tidal/ChordsTest.hs b/test/Sound/Tidal/ChordsTest.hs
new file mode 100644
--- /dev/null
+++ b/test/Sound/Tidal/ChordsTest.hs
@@ -0,0 +1,55 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Sound.Tidal.ChordsTest where
+
+import TestUtils
+import Test.Microspec
+
+import Prelude hiding ((<*), (*>))
+
+import Sound.Tidal.Pattern
+
+run :: Microspec ()
+run =
+  describe "Sound.Tidal.Chords" $ do
+    describe "chord" $ do
+        describe "chord length adjustments" $ do
+            it "can remove notes from the end of the list when length given is less than the standard chord length" $ do
+                compareP (Arc 0 1)
+                    ("'major'1")
+                    ("[0]" :: Pattern Note)
+            it "can do nothing when the length given is the same as the standard chord length" $ do
+                compareP (Arc 0 1)
+                    ("'major'3")
+                    ("[0, 4, 7]" :: Pattern Note)
+            it "can append chord notes at higher octaves to the list when length given is greater than the standard chord length" $ do
+                compareP (Arc 0 1)
+                    ("'major'5")
+                    ("[0, 4, 7, 12, 16]" :: Pattern Note)
+        describe "open voiced chords" $ do
+            it "can subtract 12 from the first and third element of a list, and sort them in ascending numerical order" $ do
+                compareP (Arc 0 1)
+                    ("'major'o")
+                    ("[-12, -5, 4]" :: Pattern Note)
+            it "not crash if chord length is < 3" $ do
+                compareP (Arc 0 1)
+                    ("'five'o")
+                    ("[0, 7]" :: Pattern Note)
+        describe "chord inversions" $ do
+            it "can add 12 to the first element of a list, and sort in ascending numeric order (1st inversion)" $ do
+                compareP (Arc 0 1)
+                    ("'major'i")
+                    ("[4, 7, 12]" :: Pattern Note)
+            it "can add 12 to the first two elements of a list, and sort in ascending numeric order (2nd inversion)" $ do
+                compareP (Arc 0 1)
+                    ("'major'ii")
+                    ("[7, 12, 16]" :: Pattern Note)
+            it "can add 12 to the first three elements of a list, and sort in ascending numeric order (3rd inversion)" $ do
+                compareP (Arc 0 1)
+                    ("'major'iii")
+                    ("[12, 16, 19]" :: Pattern Note)
+        describe "edge cases" $ do
+            it "gracefully handle an inversion when there are more inversions than notes in the chord (4th inversion of a 3 note chord)" $ do
+                compareP (Arc 0 1)
+                    ("'major'iiii")
+                    ("[16, 19, 24]" :: Pattern Note)
diff --git a/test/Sound/Tidal/ParseTest.hs b/test/Sound/Tidal/ParseTest.hs
--- a/test/Sound/Tidal/ParseTest.hs
+++ b/test/Sound/Tidal/ParseTest.hs
@@ -127,6 +127,10 @@
         compareP (Arc 0 2)
           ("c'major e'minor f'dim7" :: Pattern Int)
           ("c e f" + "'major 'minor 'dim7")
+      it "can parse note chords" $ do
+        compareP (Arc 0 2)
+          ("c'major c'minor" :: Pattern Note)
+          ("'major 'minor")
       it "handle trailing and leading whitespaces" $ do
         compareP (Arc 0 1)
           ("  bd  " :: Pattern String)
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
@@ -330,11 +330,17 @@
           ("t f f f f f f f" :: Pattern Bool)
 
     describe "binaryN" $ do
-      it "convert a number to a pattern of boolean of specified length" $ do
+      it "converts a number to a pattern of boolean of specified length" $ do
         compareP (Arc 0 1)
           (binaryN 4 "8")
           ("t f f f" :: Pattern Bool)
-      it "convert a number to a pattern of boolean of specified patternable length" $ do
+      it "converts a number to a pattern of boolean of specified patternable length" $ do
         compareP (Arc 0 2)
           (binaryN "<4 8>" "8")
           (cat ["t f f f", "f f f f t f f f"] :: Pattern Bool)
+
+    describe "off" $ do
+      it "superimposes and shifts pattern" $ do
+        compareP (Arc 0 1)
+          (off "-e" id $ s "0")
+          (superimpose ("e" <~) $ s "0")
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -8,6 +8,7 @@
 import Sound.Tidal.PatternTest
 import Sound.Tidal.ControlTest
 import Sound.Tidal.ScalesTest
+import Sound.Tidal.ChordsTest
 import Sound.Tidal.StreamTest
 import Sound.Tidal.UITest
 import Sound.Tidal.UtilsTest
@@ -21,6 +22,7 @@
   Sound.Tidal.PatternTest.run
   Sound.Tidal.ControlTest.run
   Sound.Tidal.ScalesTest.run
+  Sound.Tidal.ChordsTest.run
   Sound.Tidal.StreamTest.run
   Sound.Tidal.UITest.run
   Sound.Tidal.UtilsTest.run
diff --git a/tidal.cabal b/tidal.cabal
--- a/tidal.cabal
+++ b/tidal.cabal
@@ -1,5 +1,5 @@
 name:                tidal
-version:             1.7.4
+version:             1.7.5
 synopsis:            Pattern language for improvised music
 description:         Tidal is a domain specific language for live coding patterns.
 homepage:            http://tidalcycles.org/
@@ -64,9 +64,6 @@
     , primitive < 0.8
     , random < 1.3
 
-  if !impl(ghc >= 8.4.1)
-    build-depends: semigroups >= 0.18 && < 0.20
-
 test-suite tests
   type: exitcode-stdio-1.0
   main-is: Test.hs
@@ -79,6 +76,7 @@
                  Sound.Tidal.ParseTest
                  Sound.Tidal.PatternTest
                  Sound.Tidal.ScalesTest
+                 Sound.Tidal.ChordsTest
                  Sound.Tidal.StreamTest
                  Sound.Tidal.UITest
                  Sound.Tidal.UtilsTest
