diff --git a/BootTidal.hs b/BootTidal.hs
--- a/BootTidal.hs
+++ b/BootTidal.hs
@@ -27,6 +27,7 @@
     nudgeAll = streamNudgeAll tidal
     all = streamAll tidal
     resetCycles = streamResetCycles tidal
+    setCycle = streamSetCycle tidal
     setcps = asap . cps
     getcps = streamGetcps tidal
     getnow = streamGetnow tidal
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,19 +1,17 @@
 # TidalCycles log of changes
 
-## 1.9.2
-
+## 1.9.2 - Siteswap c
 Same with 1.9.1, but now with new tidal-link version 1.0.1
 
-## 1.9.1
-
+## 1.9.1 - Siteswap b
 A quick release to set specific tidal-link version 1.0 in tidal.cabal. Stack
 seems to want this.
 
-## 1.9.0
+## 1.9.0 - Siteswap
 
-## What's Changed
+### What's Changed
 
-### General enhancements
+#### General enhancements
 * Rename linux binary name by @ndr-brt in https://github.com/tidalcycles/Tidal/pull/911
 * Fix echo by @ndr-brt in https://github.com/tidalcycles/Tidal/pull/910
 * If first argument of euclid is negative, apply euclidInv by @polymorphicengine in https://github.com/tidalcycles/Tidal/pull/916
@@ -21,39 +19,37 @@
 * Make chunk reverse direction with negative number by @ndr-brt in https://github.com/tidalcycles/Tidal/pull/918
 * overhaul of the chord parser by @polymorphicengine in https://github.com/tidalcycles/Tidal/pull/931
 
-### New ableton link support
+#### New ableton link support
 * Use ableton link for scheduling by @Zalastax in https://github.com/tidalcycles/Tidal/pull/898
 * tidal-link: add link source files to extra-source-files, fixes #924 by @yaxu in https://github.com/tidalcycles/Tidal/pull/925
 * Use target latency in all send modes by @Zalastax in https://github.com/tidalcycles/Tidal/pull/927
 * Rename cCyclesPerBeat -> cBeatsPerCycle by @Zalastax in https://github.com/tidalcycles/Tidal/pull/939
 
-### Emacs plugin updates
+#### Emacs plugin updates
 * formatting fixes in tidal.el by @zzkt in https://github.com/tidalcycles/Tidal/pull/932
 * a window-excursion for tidal.el by @zzkt in https://github.com/tidalcycles/Tidal/pull/933
 * autoloads for tidal.el by @zzkt in https://github.com/tidalcycles/Tidal/pull/934
 * avoid race in loading bootscript during restart by @zzkt in https://github.com/tidalcycles/Tidal/pull/937
 
-### Tidal-parse (estuary) updates
+#### Tidal-parse (estuary) updates
 * Various updates to tidal-parse by @dktr0 in https://github.com/tidalcycles/Tidal/pull/913 and  https://github.com/tidalcycles/Tidal/pull/941
 
-### Maintenance
+#### Maintenance
 * Increase upper bounds of text dependency by @yaxu in https://github.com/tidalcycles/Tidal/pull/948
 * Use system-cxx-std-lib by @Zalastax in https://github.com/tidalcycles/Tidal/pull/944
 * Use c++ extra library for MacOS by @giuseppelillo in https://github.com/tidalcycles/Tidal/pull/946
 
-## New Contributors
+### New Contributors
 * @Zalastax made their first contribution in https://github.com/tidalcycles/Tidal/pull/898
 * @zzkt made their first contribution in https://github.com/tidalcycles/Tidal/pull/932
 * @giuseppelillo made their first contribution in https://github.com/tidalcycles/Tidal/pull/946
 
 **Full Changelog**: https://github.com/tidalcycles/Tidal/compare/v1.8.0...v1.9.0
 
-## 1.8.1
-
+## 1.8.1 - Sanquhar b
 * Removed executable from tidal.cabal file (while latest ghc on windows fails to build it)
 
 ## 1.8.0 - Sanquhar
-
 * move tidal-listener code by @polymorphicengine in #885
 * Fix a typo incurred (I assume) by a filename change. by @JeffreyBenjaminBrown in #886
 * Hide contexts from Events per default by @polymorphicengine in #887
@@ -68,7 +64,6 @@
 Commit list: https://github.com/tidalcycles/Tidal/compare/1.7.10...v1.8.0
 
 ## 1.7.10 - Tama b
-
 * Derive RealFrac for Note by @ndr-brt in https://github.com/tidalcycles/Tidal/pull/876
 * Add timescale and timewin control params by @yaxu in https://github.com/tidalcycles/Tidal/pull/878
 * deriving typeclass memberships for ID by @polymorphicengine in https://github.com/tidalcycles/Tidal/pull/879
@@ -112,152 +107,149 @@
 **Full Changelog**: https://github.com/tidalcycles/Tidal/compare/1.7.8...1.7.9
 
 ## 1.7.8 - Ayatakedai
-   * Add pattern id to patterns as _id_, and send it with /code/highlights
+* Add pattern id to patterns as _id_, and send it with /code/highlights
 
 ## 1.7.7 - Caramel wafer
-   * Support hosc 0.19 in test suite @yaxu
+* Support hosc 0.19 in test suite @yaxu
 
 ## 1.7.6 - Tunnocks
-   * Fix dot shorthand in int patterns so floating point numbers raise an error @ndr-brt
-   * Support factors in ratio shorthand for rational patterns @ndr-brt
-   * support hosc 0.19 @yaxu
+* Fix dot shorthand in int patterns so floating point numbers raise an error @ndr-brt
+* Support factors in ratio shorthand for rational patterns @ndr-brt
+* support hosc 0.19 @yaxu
 
 ## 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
+* 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
-   * Disable bus variants for MIDI controls @mindofmatthew
+* Fixes for bipolar waveforms (sine2, etc) @mindofmatthew
+* More playback controls for OSC API @mindofmatthew
+* Disable bus variants for MIDI controls @mindofmatthew
 
 ## 1.7.3 - Symonds Yat
-   * Signed ratio shorthands now supported @ndr_brt
-   * OSC API - mute/unmute stream @mindofmatthew
-   * improve performance of playFor/seqP @yaxu
-   * Expand tests with autodiscovered laws @RSWilli
-   * Add `getState` to BootTidal @mindofmatthew
-   * add fadeTime / fadeInTime / fadeOutTime params for grain envelopes @yaxu
-   * Fix for nrpnn and nrpnv params @yaxu
-   * Disable busses for MIDI parameters @mindofmatthew
+* Signed ratio shorthands now supported @ndr_brt
+* OSC API - mute/unmute stream @mindofmatthew
+* improve performance of playFor/seqP @yaxu
+* Expand tests with autodiscovered laws @RSWilli
+* Add `getState` to BootTidal @mindofmatthew
+* add fadeTime / fadeInTime / fadeOutTime params for grain envelopes @yaxu
+* Fix for nrpnn and nrpnv params @yaxu
+* Disable busses for MIDI parameters @mindofmatthew
    
 ## 1.7.2 - IKLECTIK c
-   * tidal-parse additions and improved errors, haskellish dependency fix @dktr0
-   * spring cleaning and delinting, recreated Time.hs, renamed ControlMap toValueMAp @yaxu
-   * start of [major refactoring of chords](https://club.tidalcycles.org/t/rfc-working-on-making-chord-naming-chordlist-more-consistent/2717/56) @cleary
-   * fix `.` mininotation operator @zudov
-   * stateful event parameters, for counting @yaxu
-   * Move some stuff from BootTidal.hs to the tidal library, to reduce dependencies there @yaxu
+* tidal-parse additions and improved errors, haskellish dependency fix @dktr0
+* spring cleaning and delinting, recreated Time.hs, renamed ControlMap toValueMAp @yaxu
+* start of [major refactoring of chords](https://club.tidalcycles.org/t/rfc-working-on-making-chord-naming-chordlist-more-consistent/2717/56) @cleary
+* fix `.` mininotation operator @zudov
+* stateful event parameters, for counting @yaxu
+* Move some stuff from BootTidal.hs to the tidal library, to reduce dependencies there @yaxu
 
 ## 1.7.1 - IKLECTIK b
-        * Fix stack build @yaxu
-        * Add tidal_status command @yaxu
-	* Add cVerbose config setting (default on) @yaxu
-	* Fix for emacs plugin @jwaldmann
-	* Snowball bugfix @yaxu
-	* Migrate to github actions, tested against additional ghc versions @ndr_brt
-	* Fix mininotation bug - allow leading/trailing spaces @ndr_brt
-	* Make linger work with negative numbers (to linger on end of cycle rather than start) @yaxu
-	* Friendlier startup messages @yaxu
-	* Compatibility with ghc 9.0.1 @yaxu
+* Fix stack build @yaxu
+* Add tidal_status command @yaxu
+* Add cVerbose config setting (default on) @yaxu
+* Fix for emacs plugin @jwaldmann
+* Snowball bugfix @yaxu
+* Migrate to github actions, tested against additional ghc versions @ndr_brt
+* Fix mininotation bug - allow leading/trailing spaces @ndr_brt
+* Make linger work with negative numbers (to linger on end of cycle rather than start) @yaxu
+* Friendlier startup messages @yaxu
+* Compatibility with ghc 9.0.1 @yaxu
 
 ## 1.7 - IKLECTIK
-	* Added drum aliases from GM2 percussion spec to `drum` function @lvm
-	* `getcps` helper function now in BootTidal.hs @yaxu
-	* `getnow` helper function back in BootTidal.hs (returns current cycle) @bgold-cosmos
-	* Developments towards tidal api, @yaxu et al
-	* `coarse` parameter is now floating point @lwlsn
-	* `irand` parameter now patternable @ndr-brt
- 	* `note` now produces its own type to avoid conflicts between parsing note names and duration shorthands  @ndr-brt
-	* Numerous tidal-parse improvements and additions @dktr0 et al
-	* `grain` function for combining begin and end (in terms of begin and duration) @khoparzi
-	* Added missing pB and pR functions @thgrund
-	* Emacs plugin bugfixes @jwaldmann
-	* `binaryN` parameters now fully patternable @ndr-brt
-	* `press` and `pressBy` functions for syncopation @yaxu
-	* `bite`'s first parameter is now patternable @ndr-brt
-	* Most SuperDirt control/effect parameters can now be modified while a sound is playing, using 'bus' functions. @telefon + @yaxu
-	* Sound.Tidal.Params is now generated by a script in bin/generate-params.hs @yaxu
-	* `qtrigger` is now an alias for `ctrigger`, which now quantises to the _next_ cycle (via ceiling) @thgund / @yaxu
-	* There is now also `ftrigger` and `rtrigger` for floor (previous) and round (nearest) cycle
-	* `whenmod`'s first two parameters are now rationals, and patternable. @th-four / @yaxu
-        * `brand` and `brandBy` for continuous patterns of boolean values @yaxu
-        * Two-way protocol between Tidal and SuperDirt, initially to receive available busses @telefon / @yaxu
-        * bipolar waveforms - sine2, square2, tri2, saw2, cosine2 @yaxu
+* Added drum aliases from GM2 percussion spec to `drum` function @lvm
+* `getcps` helper function now in BootTidal.hs @yaxu
+* `getnow` helper function back in BootTidal.hs (returns current cycle) @bgold-cosmos
+* Developments towards tidal api, @yaxu et al
+* `coarse` parameter is now floating point @lwlsn
+* `irand` parameter now patternable @ndr-brt
+* `note` now produces its own type to avoid conflicts between parsing note names and duration shorthands  @ndr-brt
+* Numerous tidal-parse improvements and additions @dktr0 et al
+* `grain` function for combining begin and end (in terms of begin and duration) @khoparzi
+* Added missing pB and pR functions @thgrund
+* Emacs plugin bugfixes @jwaldmann
+* `binaryN` parameters now fully patternable @ndr-brt
+* `press` and `pressBy` functions for syncopation @yaxu
+* `bite`'s first parameter is now patternable @ndr-brt
+* Most SuperDirt control/effect parameters can now be modified while a sound is playing, using 'bus' functions. @telefon + @yaxu
+* Sound.Tidal.Params is now generated by a script in bin/generate-params.hs @yaxu
+* `qtrigger` is now an alias for `ctrigger`, which now quantises to the _next_ cycle (via ceiling) @thgund / @yaxu
+* There is now also `ftrigger` and `rtrigger` for floor (previous) and round (nearest) cycle
+* `whenmod`'s first two parameters are now rationals, and patternable. @th-four / @yaxu
+* `brand` and `brandBy` for continuous patterns of boolean values @yaxu
+* Two-way protocol between Tidal and SuperDirt, initially to receive available busses @telefon / @yaxu
+* bipolar waveforms - sine2, square2, tri2, saw2, cosine2 @yaxu
   
 
 ## 1.6.1 - We are not DJs
-	* Patternise first parameter of chunk @lwlsn
-	* Patternise fit parameter @bgold-cosmos
-	* Increase upper bounds of random @yaxu
-	* Switch travis to ubuntu bionic @yaxu
+* Patternise first parameter of chunk @lwlsn
+* Patternise fit parameter @bgold-cosmos
+* Increase upper bounds of random @yaxu
+* Switch travis to ubuntu bionic @yaxu
 
 ## 1.6.0 - Keep live coding live
-	* Rollback to previous pattern on parse error @jwaldmann
-	* Increased strictness to catch parse errors earlier @jwaldmann @yaxu
-	* Support for superdirt 'panic' @yaxu
-	* Increase hosc upper bounds to admin 0.18
-	* New function 'splat' @yaxu
-	* `quantise` now uses round, add qfloor, qceiling variants and qround alis @lwlsn
-	* Add ghc 8.8.3 to travis @jwaldmann
-	* Switch `substruct` to use binary pattern @yaxu
+* Rollback to previous pattern on parse error @jwaldmann
+* Increased strictness to catch parse errors earlier @jwaldmann @yaxu
+* Support for superdirt 'panic' @yaxu
+* Increase hosc upper bounds to admin 0.18
+* New function 'splat' @yaxu
+* `quantise` now uses round, add qfloor, qceiling variants and qround alis @lwlsn
+* Add ghc 8.8.3 to travis @jwaldmann
+* Switch `substruct` to use binary pattern @yaxu
 
 ## 1.5.2 - Rivelin
-        * Fix streamAll
+* Fix streamAll
 
 ## 1.5.1 - Blacka Moor
-	* Bugfix splice
+* Bugfix splice
 
 ## 1.5.0 - Active travel
-	* 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
+* 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,
-	  with friends `drawLine` and `drawLineSz` for drawing multiple cycles @yaxu
-	* Fixes and expansions of ratio aliases - s should be a sixteenth @mxmxyz, w is now 1, f is now 0.2
-	* Simplify definition of `accumulate` using scanl @benjwadams
-	* The first parameter of `someCyclesBy` is now patternable @bgold-cosmos
+* Simplify 'show'ing of patterns @yaxu
+* New `draw` function for drawing a pattern of single characters as a text-based diagram, with friends `drawLine` and `drawLineSz` for drawing multiple cycles @yaxu
+* Fixes and expansions of ratio aliases - s should be a sixteenth @mxmxyz, w is now 1, f is now 0.2
+* Simplify definition of `accumulate` using scanl @benjwadams
+* The first parameter of `someCyclesBy` is now patternable @bgold-cosmos
 
 ## 1.4.8 - Limerick
-        * Add ratio shorthand to floating point patterns @yaxu
-        * Support fractional scales, add Arabic scales @quakehead
-        * Additions to tidal-parse including support from overgain, overshape adn rot @dktr0
-        * Move prompt-cont setting to end of BootTidal.hs (older versions of Haskell crash out at this point) @ndr-brt
-## 1.4.7 - Bleep
+* Add ratio shorthand to floating point patterns @yaxu
+* Support fractional scales, add Arabic scales @quakehead
+* Additions to tidal-parse including support from overgain, overshape adn rot @dktr0
+* Move prompt-cont setting to end of BootTidal.hs (older versions of Haskell crash out at this point) @ndr-brt
 
-	* Fix BootTidal.hs - make loadable in atom @bgold-cosmos
-	* More additions to tidal-parse @dktr0
+## 1.4.7 - Bleep
+* Fix BootTidal.hs - make loadable in atom @bgold-cosmos
+* More additions to tidal-parse @dktr0
 
 ## 1.4.6 - Megatron
-
-	* Experimental ratio shorthand ref #573 @yaxu
-	* Store mininotation source location(s) in events ref #245 @yaxu
-	* Add more things to tidal-parse @dktr0 @yaxu
-	* Separate out haskell parser from tidal-parse into new hackage module called 'haskellish' @dktr0
-	* Support patterning polyrhythmic % steps in mininotation @yaxu
-	* Fixes to emacs plugin (tidal.el) @xmacex
-	* New parameters for freq, overgain, overshape, and missing midi params including the new nrpn ones @yaxu
+* Experimental ratio shorthand ref #573 @yaxu
+* Store mininotation source location(s) in events ref #245 @yaxu
+* Add more things to tidal-parse @dktr0 @yaxu
+* Separate out haskell parser from tidal-parse into new hackage module called 'haskellish' @dktr0
+* Support patterning polyrhythmic % steps in mininotation @yaxu
+* Fixes to emacs plugin (tidal.el) @xmacex
+* New parameters for freq, overgain, overshape, and missing midi params including the new nrpn ones @yaxu
 
 ## 1.4.5 - Porter Brook
-
 * Mini notation - `@` (and its alias `_`) now accepts rational relative durations. E.g. `a b@0.5 c d` to make `b` have a half step (that would be the same as `a@2 b c@2 c@d`). This can also be patterned `a b@<0.5 2> c d` @yaxu #435
 * Experimental `reset` function - stick in a pattern so it acts as though the cycle number was reset to 0, from the next cycle @yaxu
 * Bugfix for setR in BootTidal.hs @yaxu
@@ -270,7 +262,6 @@
 * Many tidal-parse updates @dktr0
 
 ## 1.4.4 - Chee Dale
-
 * wrandcat (weighted randcat) @yaxu
 * MIDI Sysex support #558 @yaxu
 * Elements in an Open Sound Control path address can now be patterned #557
@@ -280,39 +271,31 @@
 * Add power pattern operators |**, **| and |**| @yaxu
 
 ## 1.4.3 - Stanage Edge
-
 * Fix for xfade / xfadein transition
 * New function plyWith
 
 ## 1.4.2 - Higger Tor
-
 * Fix for 'nudge'
 
 ## 1.4.1 - Carl Wark
-
 * improvements to handling of cps changes @yaxu #501
 * fix for parameter patterning in 'range' @yaxu #547
 
 ## 1.4.0 - Padley Gorge
-
 * fix representation to handle continuous and analog events properly @yaxu
 
 ## 1.3.0 - rolled back to 1.1.2
 
 ## 1.2.0 - Hunters Bar
-
 * Simplify <* and *>, removing any distinction between analogue and digital patterns
 
 ## 1.1.2 - Eccy Road
-
 * Usability fix for `binary` / `binaryN` (use squeezeJoin on input pattern)
 
 ## 1.1.1 - Chelsea Park
-
 * Usability fixes for `binary` / `binaryN` / `ascii` @yaxu
 
 ## 1.1.0 - Brincliffe Edge
-
 * `binary` and `ascii` functions for playing with bit patterns @yaxu
 * support chord inversions in chord parser @bgold-cosmos
 * skip ticks when system clock jumps @yaxu
@@ -331,7 +314,6 @@
 * minitidal refactor, support for parsing more of tidal, tests @dktr0
 
 ## 1.0.14 - IICON
-
 * 'chew' - like bite, but speeds playback rate up and down
 * variable probability for ? in mini notation
 * chooseBy takes modulo of index to avoid out of bounds errors
@@ -339,32 +321,29 @@
 * Fix dependencies for parsec/colour
 
 ## 1.0.13 - 🐝⌛️🦋 #2
-
 * Simplify espgrid support - @yaxu
 
 ## 1.0.12 - 🐝⌛️🦋
-
 * Fix ESPGrid support - @dktr0
 * Add 'snowball' function - @XiNNiW
 
 ## 1.0.11 - Cros Bríde
-
 2019-04-17  Alex McLean  <alex@slab.org>
-	* Add `bite` function for slicing patterns (rather than samples)
-	* Tweak tidal.el to attempt to infer location of default BootTidal.hs
-	* Skip time (forward or backward) if the reference clock jumps suddenly
-	* Fix `fit` - @bgold-cosmos
-	* Remove 'asap'
-	* Add cB for boolean control input
-	* `pickF` for choosing between functions with a pattern of integers
-	* `select` for choosing between list of patterns with a floating point pattern
-	* `squeeze` for choosing between list of patterns with a pattern of integers, where patterns are squeezed into the integer event duration
-	* `splice` for choosing between slices of a pattern, where the slices are squeezed into event duration
-	* Ord and Eq instances for value type @bgold-cosmos
-	* `trigger` - support for resetting envelopes on evaluation
-	* Support for rational event values
-	* Tweak how `*>` and `<*` deal with analog patterns
-	* Caribiner link bridge support
+* Add `bite` function for slicing patterns (rather than samples)
+* Tweak tidal.el to attempt to infer location of default BootTidal.hs
+* Skip time (forward or backward) if the reference clock jumps suddenly
+* Fix `fit` - @bgold-cosmos
+* Remove 'asap'
+* Add cB for boolean control input
+* `pickF` for choosing between functions with a pattern of integers
+* `select` for choosing between list of patterns with a floating point pattern
+* `squeeze` for choosing between list of patterns with a pattern of integers, where patterns are squeezed into the integer event duration
+* `splice` for choosing between slices of a pattern, where the slices are squeezed into event duration
+* Ord and Eq instances for value type @bgold-cosmos
+* `trigger` - support for resetting envelopes on evaluation
+* Support for rational event values
+* Tweak how `*>` and `<*` deal with analog patterns
+* Caribiner link bridge support
 
 ## 1.0.10 - This machine also kills fascists
 * Add exports to Sound.Tidal.Scales for `getScale` and `scaleTable`
@@ -378,10 +357,8 @@
 * `djf` control ready for new superdirt dj filter @yaxu
 * `getScale` for handrolling/adding scales to `scale` function	* Add `djf` control for upcoming superdirt dj filter @yaxu
 
-## 1.0.8 (trying to get back to doing these, 
-## see also https://tidalcycles.org/index.php/Changes_in_Tidal_1.0.x 
-## for earlier stuff)
-
+## 1.0.8 (trying to get back to doing these)
+**See also https://tidalcycles.org/index.php/Changes_in_Tidal_1.0.x for earlier stuff)**
 * Add 'to', 'toArg' and 'from' controls for new superdirt routing experiments - @telephon
 * Fixes for squeezeJoin (nee unwrap') - @bgold-cosmos
 * Simplify `cycleChoose`, it is now properly discrete (one event per cycle) - @yaxu
@@ -398,7 +375,6 @@
 * fix for `sometimesBy` - @yaxu
 
 ## 0.9.10 (and earlier missing versions from this log)
-
 * arpg, a function to arpeggiate
 * within', an alternate within with a different approach to time, following discussion here https://github.com/tidalcycles/Tidal/issues/313
 * sine et al are now generalised so can be used as double or rational patterns
@@ -415,7 +391,6 @@
 ## 0.9.7
 
 ### Enhancements
-
 * The `note` pattern parameter is no longer an alias for `midinote`,
   but an independent parameter for supercollider to handle (in a manner
   similar to `up`)
@@ -423,14 +398,12 @@
 ## 0.9.6
 
 ### Enhancements
-
 * Added `chord` for chord patterns and `scaleP` for scale patterns
 * The `n` pattern parameter is now floating point
 
 ## 0.9.5
 
 ### Enhancements
-
 * Added `hurry` which both speeds up the sound and the pattern by the given amount.
 * Added `stripe` which repeats a pattern a given number of times per
   cycle, with random but contiguous durations.
@@ -444,14 +417,12 @@
 ## 0.9.4
 
 ### Fixes
-
 * Swapped `-` for `..` in ranges as quick fix for issue with parsing negative numbers
 * Removed overloaded list thingie for now, unsure whether it's worth the dependency
 
 ## 0.9.3
 
 ### Enhancements
-
 * The sequence parser can now expand ranges, e.g. `"0-3 4-2"` is
   equivalent to `"[0 1 2 3] [4 3 2]"`
 * Sequences can now be described using list syntax, for example `sound ["bd", "sn"]` is equivalent to `sound "bd sn"`. They *aren't* lists though, so you can't for example do `sound (["bd", "sn"] ++ ["arpy", "cp"])` -- but can do `sound (append ["bd", "sn"]  ["arpy", "cp"])`
@@ -462,6 +433,5 @@
 * The start of automatic testing for a holy bug-free future
 
 ### Fixes
-
 * Fixed bug that was causing events to double up or get lost,
   e.g. where `rev` was combined with certain other functions.
diff --git a/bench/Memory/Tidal/UIB.hs b/bench/Memory/Tidal/UIB.hs
--- a/bench/Memory/Tidal/UIB.hs
+++ b/bench/Memory/Tidal/UIB.hs
@@ -2,8 +2,7 @@
 
 import Weigh 
 import Tidal.Inputs 
-import Sound.Tidal.UI
-import Sound.Tidal.Core
+import Sound.Tidal.Context
 
 fixB :: Weigh () 
 fixB = 
diff --git a/bench/Speed/Tidal/UIB.hs b/bench/Speed/Tidal/UIB.hs
--- a/bench/Speed/Tidal/UIB.hs
+++ b/bench/Speed/Tidal/UIB.hs
@@ -4,8 +4,7 @@
 
 import Criterion.Main
 import Tidal.Inputs
-import Sound.Tidal.Core
-import Sound.Tidal.UI 
+import Sound.Tidal.Context
 
 fixB :: [Benchmark]
 fixB = 
diff --git a/src/Sound/Tidal/Chords.hs b/src/Sound/Tidal/Chords.hs
--- a/src/Sound/Tidal/Chords.hs
+++ b/src/Sound/Tidal/Chords.hs
@@ -95,6 +95,8 @@
 minor11 = [0,3,7,10,14,17]
 minor13 :: Num a => [a]
 minor13 = [0,3,7,10,14,17,21]
+minorMajor7 :: Num a => [a]
+minorMajor7 = [0,3,7,11]
 -- other chords
 one :: Num a => [a]
 one = [0]
@@ -233,6 +235,9 @@
               ("minor13", minor13),
               ("min13", minor13),
               ("m13", minor13),
+              ("minorMajor7", minorMajor7),
+              ("minMaj7", minorMajor7),
+              ("mmaj7", minorMajor7),
               ("one", one),
               ("1", one),
               ("five", five),
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
@@ -29,6 +29,7 @@
 
 import Sound.Tidal.Pattern
 import Sound.Tidal.Core
+import Sound.Tidal.Stream (patternTimeID)
 import Sound.Tidal.UI
 import qualified Sound.Tidal.Params as P
 import Sound.Tidal.Utils
@@ -412,38 +413,68 @@
 msec :: Fractional a => Pattern a -> Pattern a
 msec p = (realToFrac . (/1000) <$> cF 1 "_cps") *| p
 
-triggerWith :: Show a => (Time -> Time) -> a -> Pattern b -> Pattern b
-triggerWith f k pat = pat {query = q}
-  where q st = query (rotR (offset st) pat) st
-        offset st = fromMaybe 0 $ do v <- Map.lookup ctrl (controls st)
-                                     return (f $ fromMaybe 0 $ getR v)
-        ctrl = "_t_" ++ show k
-
-trigger :: Show a => a -> Pattern b -> Pattern b
+-- | Align the start of a pattern with the time a pattern is evaluated,
+-- rather than the global start time. Because of this, the pattern will
+-- probably not be aligned to the pattern grid.
+trigger :: Pattern a -> Pattern a
 trigger = triggerWith id
 
-ctrigger :: Show a => a -> Pattern b -> Pattern b
-ctrigger = triggerWith $ (fromIntegral :: Int -> Rational) . ceiling
-
-qtrigger :: Show a => a -> Pattern b -> Pattern b
+-- | (Alias @__qt__@) Quantise trigger. Aligns the start of the pattern
+-- with the next cycle boundary. For example, this pattern will fade in
+-- starting with the next cycle after the pattern is evaluated:
+-- 
+-- @
+-- d1 $ qtrigger $ s "hh(5, 8)" # amp envL
+-- @
+-- 
+-- Note that the pattern will start playing immediately. The /start/ of the
+-- pattern aligns with the next cycle boundary, but events will play before
+-- if the pattern has events at negative timestamps (which most loops do).
+-- These events can be filtered out, for example:
+-- 
+-- @
+-- d1 $ qtrigger $ filterWhen (>= 0) $ s "hh(5, 8)"
+-- @
+qtrigger :: Pattern a -> Pattern a
 qtrigger = ctrigger
 
-rtrigger :: Show a => a -> Pattern b -> Pattern b
+qt :: Pattern a -> Pattern a
+qt = qtrigger
+
+-- | Ceiling trigger. Aligns the start of a pattern to the next cycle
+-- boundary, just like 'qtrigger'.
+ctrigger :: Pattern a -> Pattern a
+ctrigger = triggerWith $ (fromIntegral :: Int -> Rational) . ceiling
+
+-- | Rounded trigger. Aligns the start of a pattern to the nearest cycle
+-- boundary, either next or previous.
+rtrigger :: Pattern a -> Pattern a
 rtrigger = triggerWith $ (fromIntegral :: Int -> Rational) . round
 
-ftrigger :: Show a => a -> Pattern b -> Pattern b
+-- | Floor trigger. Aligns the start of a pattern to the previous cycle
+-- boundary.
+ftrigger :: Pattern a -> Pattern a
 ftrigger = triggerWith $ (fromIntegral :: Int -> Rational) . floor
 
-qt :: Show a => a -> Pattern b -> Pattern b
-qt = qtrigger
+-- | (Alias @__mt__@) Mod trigger. Aligns the start of a pattern to the
+-- next cycle boundary where the cycle is evenly divisible by a given
+-- number. 'qtrigger' is equivalent to @mtrigger 1@.
+mtrigger :: Int -> Pattern a -> Pattern a
+mtrigger n = triggerWith $ fromIntegral . nextMod
+  where nextMod t = n * ceiling (t / (fromIntegral n))
 
-reset :: Show a => a -> Pattern b -> Pattern b
-reset k pat = pat {query = q}
-  where q st = query (rotR (offset st) $ when (<=0) (const silence) pat) st
-        f = (fromIntegral :: Int -> Rational) . floor
-        offset st = fromMaybe 0 $ do p <- Map.lookup ctrl (controls st)
-                                     return (f $ fromMaybe 0 $ getR p)
-        ctrl = "_t_" ++ show k
+mt :: Int -> Pattern a -> Pattern a
+mt = mtrigger
+
+-- | This aligns the start of a pattern to some value relative to the
+-- time the pattern is evaluated. The provided function maps the evaluation
+-- time (on the global cycle clock) to a new time, and then @triggerWith@
+-- aligns the pattern's start to the time that's returned.
+triggerWith :: (Time -> Time) -> Pattern a -> Pattern a
+triggerWith f pat = pat {query = q}
+  where q st = query (rotR (offset st) pat) st
+        offset st = fromMaybe 0 $ f
+                      <$> (Map.lookup patternTimeID (controls st) >>= getR)
 
 splat :: Pattern Int -> ControlPattern -> ControlPattern -> ControlPattern
 splat slices epat pat = chop slices pat # bite 1 (const 0 <$> pat) epat
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
@@ -29,10 +29,6 @@
 
 -- ** Elemental patterns
 
--- | An empty pattern
-silence :: Pattern a
-silence = empty
-
 -- | Takes a function from time to values, and turns it into a 'Pattern'.
 sig :: (Time -> a) -> Pattern a
 sig f = Pattern q
@@ -347,67 +343,14 @@
 (~>) :: Pattern Time -> Pattern a -> Pattern a
 (~>) = tParam rotR
 
--- | Speed up a pattern by the given time pattern
-fast :: Pattern Time -> Pattern a -> Pattern a
-fast = tParam _fast
-
 -- | Slow down a pattern by the factors in the given time pattern, 'squeezing'
 -- the pattern to fit the slot given in the time pattern
-fastSqueeze :: Pattern Time -> Pattern a -> Pattern a
-fastSqueeze = tParamSqueeze _fast
-
--- | An alias for @fast@
-density :: Pattern Time -> Pattern a -> Pattern a
-density = fast
-
-_fast :: Time -> Pattern a -> Pattern a
-_fast rate pat | rate == 0 = silence
-               | rate < 0 = rev $ _fast (negate rate) pat
-               | otherwise = withResultTime (/ rate) $ withQueryTime (* rate) pat
-
--- | Slow down a pattern by the given time pattern
-slow :: Pattern Time -> Pattern a -> Pattern a
-slow = tParam _slow
-_slow :: Time -> Pattern a -> Pattern a
-_slow 0 _ = silence
-_slow r p = _fast (1/r) p
-
--- | Slow down a pattern by the factors in the given time pattern, 'squeezing'
--- the pattern to fit the slot given in the time pattern
 slowSqueeze :: Pattern Time -> Pattern a -> Pattern a
 slowSqueeze = tParamSqueeze _slow
 
 -- | An alias for @slow@
 sparsity :: Pattern Time -> Pattern a -> Pattern a
 sparsity = slow
-
--- | @rev p@ returns @p@ with the event positions in each cycle
--- reversed (or mirrored).
-rev :: Pattern a -> Pattern a
-rev p =
-  splitQueries $ p {
-    query = \st -> map makeWholeAbsolute $
-      mapParts (mirrorArc (midCycle $ arc st)) $
-      map makeWholeRelative
-      (query p st
-        {arc = mirrorArc (midCycle $ arc st) (arc st)
-        })
-    }
-  where makeWholeRelative :: Event a -> Event a
-        makeWholeRelative e@Event {whole = Nothing} = e
-        makeWholeRelative (Event c (Just (Arc s e)) p'@(Arc s' e') v) =
-          Event c (Just $ Arc (s'-s) (e-e')) p' v
-        makeWholeAbsolute :: Event a -> Event a
-        makeWholeAbsolute e@Event {whole = Nothing} = e
-        makeWholeAbsolute (Event c (Just (Arc s e)) p'@(Arc s' e') v) =
-          Event c (Just $ Arc (s'-e) (e'+s)) p' v
-        midCycle :: Arc -> Time
-        midCycle (Arc s _) = sam s + 0.5
-        mapParts :: (Arc -> Arc) -> [Event a] -> [Event a]
-        mapParts f es = (\(Event c w p' v) -> Event c w (f p') v) <$> es
-        -- | Returns the `mirror image' of a 'Arc' around the given point in time
-        mirrorArc :: Time -> Arc -> Arc
-        mirrorArc mid' (Arc s e) = Arc (mid' - (e-mid')) (mid'+(mid'-s))
 
 {- | Plays a portion of a pattern, specified by a time arc (start and end time).
 The new resulting pattern is played over the time period of the original pattern:
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
@@ -73,24 +73,49 @@
 pX :: String -> Pattern [Word8] -> ControlPattern
 pX name = fmap (Map.singleton name . VX)
 
-pStateF :: String -> String -> (Maybe Double -> Double) -> ControlPattern
-pStateF name sName update = pure $ Map.singleton name $ VState statef
+pStateF ::
+  String -> -- ^ A parameter, e.g. `note`; a
+  -- `String` recognizable by a `ValueMap`.
+  String -> -- ^ Identifies the cycling state pattern.
+  -- Can be anything the user wants.
+  (Maybe Double -> Double) ->
+  ControlPattern
+pStateF name sName update =
+  pure $ Map.singleton name $ VState statef
   where statef :: ValueMap -> (ValueMap, Value)
-        statef sMap = (Map.insert sName v sMap, v) 
-          where v = VF $ update $ (Map.lookup sName sMap) >>= getF
+        statef sMap = (Map.insert sName v sMap, v)
+          where v = VF $ update
+                    $ Map.lookup sName sMap >>= getF
 
-pStateList :: String -> String -> [Value] -> ControlPattern
-pStateList name sName xs = pure $ Map.singleton name $ VState statef
-  where statef :: ValueMap -> (ValueMap, Value)
-        statef sMap = (Map.insert sName (VList $ tail looped) sMap, head looped) 
-          where xs' = fromMaybe xs ((Map.lookup sName sMap) >>= getList)
-                -- do this instead of a cycle, so it can get updated with the a list
-                looped | null xs' = xs
-                       | otherwise = xs'
+-- | `pStateList` is made with cyclic lists in mind,
+-- but it can even "cycle" through infinite lists.
+pStateList ::
+  String -> -- ^ A parameter, e.g. `note`; a
+  -- `String` recognizable by a `ValueMap`.
+  String -> -- ^ Identifies the cycling state pattern.
+  -- Can be anything the user wants.
+  [Value] -> -- ^ The list to cycle through.
+  ControlPattern
+pStateList name sName xs =
+  pure $ Map.singleton name $ VState statef
+  where
+    statef :: ValueMap -> (ValueMap, Value)
+    statef sMap = ( Map.insert sName
+                    (VList $ tail looped) sMap
+                  , head looped)
+      where xs' = fromMaybe xs
+                  $ Map.lookup sName sMap >>= getList
+            -- do this instead of a cycle, so it can get updated with the a list
+            looped | null xs' = xs
+                   | otherwise = xs'
 
+-- | A wrapper for `pStateList` that accepts a `[Double]`
+-- rather than a `[Value]`.
 pStateListF :: String -> String -> [Double] -> ControlPattern
 pStateListF name sName = pStateList name sName . map VF
 
+-- | A wrapper for `pStateList` that accepts a `[String]`
+-- rather than a `[Value]`.
 pStateListS :: String -> String -> [String] -> ControlPattern
 pStateListS name sName = pStateList name sName . map VS
 
@@ -200,9 +225,7 @@
 accelerateCountTo name ipat = innerJoin $ (\i -> pStateF "accelerate" name (maybe 0 ((`mod'` i) . (+1)))) <$> ipat
 
 acceleratebus :: Pattern Int -> Pattern Double -> ControlPattern
-acceleratebus busid pat = (pF "accelerate" pat) # (pI "^accelerate" busid)
-acceleraterecv :: Pattern Int -> ControlPattern
-acceleraterecv busid = pI "^accelerate" busid
+acceleratebus _ _ = error $ "Control parameter 'accelerate' can't be sent to a bus."
 
 -- | like @gain@, but linear.
 amp :: Pattern Double -> ControlPattern
@@ -283,9 +306,7 @@
 beginCountTo name ipat = innerJoin $ (\i -> pStateF "begin" name (maybe 0 ((`mod'` i) . (+1)))) <$> ipat
 
 beginbus :: Pattern Int -> Pattern Double -> ControlPattern
-beginbus busid pat = (pF "begin" pat) # (pI "^begin" busid)
-beginrecv :: Pattern Int -> ControlPattern
-beginrecv busid = pI "^begin" busid
+beginbus _ _ = error $ "Control parameter 'begin' can't be sent to a bus."
 
 -- | Spectral binshift
 binshift :: Pattern Double -> ControlPattern
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
@@ -519,20 +519,20 @@
 parseChord :: (Enum a, Num a) => MyParser [a]
 parseChord = do char '\''
                 name <- many1 $ letter <|> digit
-                let chord = fromMaybe [0] $ lookup name chordTable
+                let foundChord = fromMaybe [0] $ lookup name chordTable
                 do char '\''
                    notFollowedBy space <?> "chord range or 'i' or 'o'"
-                   let n = length chord
+                   let n = length foundChord
                    i <- option n (fromIntegral <$> integer)
                    j <- length <$> many (char 'i')
                    o <- length <$> many (char 'o')
-                   let chord' = take i $ drop j $ concatMap (\x -> map (+ x) chord) [0,12..]
+                   let chord' = take i $ drop j $ concatMap (\x -> map (+ x) foundChord) [0,12..]
                    -- open voiced chords
                    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'
-                  <|> return chord
+                  <|> return foundChord
 
 parseNote :: Num a => MyParser a
 parseNote = do n <- notenum
@@ -684,7 +684,7 @@
 parseModOpen = char 'o' >> return Open
 
 parseModRange :: MyParser Modifier
-parseModRange = parseIntNote >>= \i -> return $ Range $ fromIntegral i
+parseModRange = parseIntNote >>= \i -> return $ Range $ fromIntegral (i :: Integer)
 
 parseModifiers :: MyParser [Modifier]
 parseModifiers = (many1 parseModOpen) <|> parseModDrop <|> (fmap pure parseModRange) <|> try parseModInvNum <|> (many1 parseModInv)  <?> "modifier"
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
@@ -67,8 +67,36 @@
 instance Applicative Pattern where
   -- | Repeat the given value once per cycle, forever
   pure v = Pattern $ \(State a _) ->
-    map (\a' -> Event (Context []) (Just a') (sect a a') v) $ cycleArcsInArc a
+    map (\a' -> Event
+                (Context [])
+                (Just a')
+                (sect a a')
+                v)
+    $ cycleArcsInArc a
 
+  -- | In each of `a <*> b`, `a <* b` and `a *> b`
+  -- (using the definitions from this module, not the Prelude),
+  -- the time structure of the result
+  -- depends on the structures of both `a` and `b`.
+  -- They all result in `Event`s with identical `part`s and `value`s.
+  -- However, their `whole`s are different.
+  --
+  -- For instance, `listToPat [(+1), (+2)] <*> "0 10 100"`
+  -- gives the following 4-`Event` cycle:
+  -- > (0>⅓)|1
+  -- > (⅓>½)|11
+  -- > (½>⅔)|12
+  -- > (⅔>1)|102
+  -- If we use `<*` instead, we get this:
+  -- > (0>⅓)-½|1
+  -- > 0-(⅓>½)|11
+  -- > (½>⅔)-1|12
+  -- > ½-(⅔>1)|102
+  -- And if we use `*>`, we get this:
+  -- >   (0>⅓)|1
+  -- > (⅓>½)-⅔|11
+  -- > ⅓-(½>⅔)|12
+  -- >   (⅔>1)|102
   (<*>) = applyPatToPatBoth
 
 -- | Like <*>, but the 'wholes' come from the left
@@ -199,7 +227,7 @@
 squeezeJoin pp = pp {query = q}
   where q st = concatMap
           (\e@(Event c w p v) ->
-             mapMaybe (munge c w p) $ query (compressArc (cycleArc $ wholeOrPart e) v) st {arc = p}
+             mapMaybe (munge c w p) $ query (focusArc (wholeOrPart e) v) st {arc = p}
           )
           (query pp st)
         munge oContext oWhole oPart (Event iContext iWhole iPart v) =
@@ -342,11 +370,14 @@
         atanh _ = noOv "atanh"
 
 ------------------------------------------------------------------------
--- * Internal functions
+-- * Internal/fundamental functions
 
 empty :: Pattern a
 empty = Pattern {query = const []}
 
+silence :: Pattern a
+silence = empty
+
 queryArc :: Pattern a -> Arc -> [Event a]
 queryArc p a = query p $ State a Map.empty
 
@@ -375,6 +406,10 @@
 withQueryTime :: (Time -> Time) -> Pattern a -> Pattern a
 withQueryTime f pat = withQueryArc (\(Arc s e) -> Arc (f s) (f e)) pat
 
+-- | Apply a function to the control values of the query
+withQueryControls :: (ValueMap -> ValueMap) -> Pattern a -> Pattern a
+withQueryControls f pat = pat { query = query pat . (\(State a m) -> State a (f m))}
+
 -- | @withEvent f p@ returns a new @Pattern@ with each event mapped over
 -- function @f@.
 withEvent :: (Event a -> Event b) -> Pattern a -> Pattern b
@@ -427,6 +462,35 @@
 compressArcTo :: Arc -> Pattern a -> Pattern a
 compressArcTo (Arc s e) = compressArc (Arc (cyclePos s) (e - sam s))
 
+focusArc :: Arc -> Pattern a -> Pattern a
+focusArc (Arc s e) p = (cyclePos s) `rotR` (_fast (1/(e-s)) p)
+
+
+-- | Speed up a pattern by the given time pattern
+fast :: Pattern Time -> Pattern a -> Pattern a
+fast = tParam _fast
+
+-- | Slow down a pattern by the factors in the given time pattern, 'squeezing'
+-- the pattern to fit the slot given in the time pattern
+fastSqueeze :: Pattern Time -> Pattern a -> Pattern a
+fastSqueeze = tParamSqueeze _fast
+
+-- | An alias for @fast@
+density :: Pattern Time -> Pattern a -> Pattern a
+density = fast
+
+_fast :: Time -> Pattern a -> Pattern a
+_fast rate pat | rate == 0 = silence
+               | rate < 0 = rev $ _fast (negate rate) pat
+               | otherwise = withResultTime (/ rate) $ withQueryTime (* rate) pat
+
+-- | Slow down a pattern by the given time pattern
+slow :: Pattern Time -> Pattern a -> Pattern a
+slow = tParam _slow
+_slow :: Time -> Pattern a -> Pattern a
+_slow 0 _ = silence
+_slow r p = _fast (1/r) p
+
 _fastGap :: Time -> Pattern a -> Pattern a
 _fastGap 0 _ = empty
 _fastGap r p = splitQueries $
@@ -448,6 +512,33 @@
 rotR :: Time -> Pattern a -> Pattern a
 rotR t = rotL (negate t)
 
+-- | @rev p@ returns @p@ with the event positions in each cycle
+-- reversed (or mirrored).
+rev :: Pattern a -> Pattern a
+rev p =
+  splitQueries $ p {
+    query = \st -> map makeWholeAbsolute $
+      mapParts (mirrorArc (midCycle $ arc st)) $
+      map makeWholeRelative
+      (query p st
+        {arc = mirrorArc (midCycle $ arc st) (arc st)
+        })
+    }
+  where makeWholeRelative :: Event a -> Event a
+        makeWholeRelative e@Event {whole = Nothing} = e
+        makeWholeRelative (Event c (Just (Arc s e)) p'@(Arc s' e') v) =
+          Event c (Just $ Arc (s'-s) (e-e')) p' v
+        makeWholeAbsolute :: Event a -> Event a
+        makeWholeAbsolute e@Event {whole = Nothing} = e
+        makeWholeAbsolute (Event c (Just (Arc s e)) p'@(Arc s' e') v) =
+          Event c (Just $ Arc (s'-e) (e'+s)) p' v
+        midCycle :: Arc -> Time
+        midCycle (Arc s _) = sam s + 0.5
+        mapParts :: (Arc -> Arc) -> [Event a] -> [Event a]
+        mapParts f es = (\(Event c w p' v) -> Event c w (f p') v) <$> es
+        -- | Returns the `mirror image' of a 'Arc' around the given point in time
+        mirrorArc :: Time -> Arc -> Arc
+        mirrorArc mid' (Arc s e) = Arc (mid' - (e-mid')) (mid'+(mid'-s))
 
 -- | Mark values in the first pattern which match with at least one
 -- value in the second pattern.
diff --git a/src/Sound/Tidal/Safe/Boot.hs b/src/Sound/Tidal/Safe/Boot.hs
--- a/src/Sound/Tidal/Safe/Boot.hs
+++ b/src/Sound/Tidal/Safe/Boot.hs
@@ -19,6 +19,7 @@
     along with this library.  If not, see <http://www.gnu.org/licenses/>.
 -}
 
+{-# OPTIONS_GHC -Wno-missing-signatures #-}
 {-# language NoMonomorphismRestriction #-}
 
 module Sound.Tidal.Safe.Boot where
@@ -52,7 +53,7 @@
 jumpIn i t = transition True (Sound.Tidal.Transition.jumpIn t) i
 jumpIn' i t = transition True (Sound.Tidal.Transition.jumpIn' t) i
 jumpMod i t = transition True (Sound.Tidal.Transition.jumpMod t) i
-mortal i lifespan release = transition True (Sound.Tidal.Transition.mortal lifespan release) i
+mortal i lifespan releaseTime = transition True (Sound.Tidal.Transition.mortal lifespan releaseTime) i
 interpolate i = transition True (Sound.Tidal.Transition.interpolate) i
 interpolateIn i t = transition True (Sound.Tidal.Transition.interpolateIn t) i
 clutch i = transition True (Sound.Tidal.Transition.clutch) i
diff --git a/src/Sound/Tidal/Safe/Context.hs b/src/Sound/Tidal/Safe/Context.hs
--- a/src/Sound/Tidal/Safe/Context.hs
+++ b/src/Sound/Tidal/Safe/Context.hs
@@ -21,6 +21,8 @@
 
 {-# language GeneralizedNewtypeDeriving #-}
 {-# language NoMonomorphismRestriction #-}
+{-# OPTIONS_GHC -Wno-missing-signatures #-}
+{-# OPTIONS_GHC -Wno-unused-top-binds #-}
 
 module Sound.Tidal.Safe.Context
   ( Op () -- do not export constructor,
diff --git a/src/Sound/Tidal/Simple.hs b/src/Sound/Tidal/Simple.hs
--- a/src/Sound/Tidal/Simple.hs
+++ b/src/Sound/Tidal/Simple.hs
@@ -22,10 +22,10 @@
 module Sound.Tidal.Simple where
 
 import Sound.Tidal.Control (chop, hurry)
-import Sound.Tidal.Core ((#), (|*), (<~), silence, rev)
+import Sound.Tidal.Core ((#), (|*), (<~))
 import Sound.Tidal.Params (crush, gain, pan, speed, s)
 import Sound.Tidal.ParseBP (parseBP_E)
-import Sound.Tidal.Pattern (ControlPattern)
+import Sound.Tidal.Pattern (ControlPattern, silence, rev)
 import GHC.Exts ( IsString(..) )
 
 instance {-# OVERLAPPING #-} IsString ControlPattern where
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
@@ -34,18 +34,18 @@
 import Foreign.C.Types
 import           System.IO (hPutStrLn, stderr)
 
-import qualified Sound.OSC.FD as O
+import qualified Sound.Osc.Fd as O
+import qualified Sound.Osc.Time.Timeout as O
 import qualified Network.Socket          as N
 
 import           Sound.Tidal.Config
-import           Sound.Tidal.Core (stack, silence, (#))
+import           Sound.Tidal.Core (stack, (#))
 import           Sound.Tidal.ID
 import qualified Sound.Tidal.Link as Link
 import           Sound.Tidal.Params (pS)
 import           Sound.Tidal.Pattern
 import qualified Sound.Tidal.Tempo as T
 import           Sound.Tidal.Utils ((!!!))
--- import qualified Sound.OSC.Datum as O
 import           Data.List (sortOn)
 import           System.Random (getStdRandom, randomR)
 import           Sound.Tidal.Show ()
@@ -59,7 +59,7 @@
                       sStateMV :: MVar ValueMap,
                       -- sOutput :: MVar ControlPattern,
                       sLink :: Link.AbletonLink,
-                      sListen :: Maybe O.UDP,
+                      sListen :: Maybe O.Udp,
                       sPMapMV :: MVar PlayMap,
                       sActionsMV :: MVar [T.TempoAction],
                       sGlobalFMV :: MVar (ControlPattern -> ControlPattern),
@@ -67,7 +67,7 @@
                      }
 
 data Cx = Cx {cxTarget :: Target,
-              cxUDP :: O.UDP,
+              cxUDP :: O.Udp,
               cxOSCs :: [OSC],
               cxAddr :: N.AddrInfo,
               cxBusAddr :: Maybe N.AddrInfo
@@ -256,13 +256,13 @@
                            else
                              hPutStrLn stderr "Can't handshake with SuperCollider without control port."
 
-sendO :: Bool -> (Maybe O.UDP) -> Cx -> O.Message -> IO ()
+sendO :: Bool -> (Maybe O.Udp) -> Cx -> O.Message -> IO ()
 sendO isBusMsg (Just listen) cx msg = O.sendTo listen (O.Packet_Message msg) (N.addrAddress addr)
   where addr | isBusMsg && isJust (cxBusAddr cx) = fromJust $ cxBusAddr cx
              | otherwise = cxAddr cx
 sendO _ Nothing cx msg = O.sendMessage (cxUDP cx) msg
 
-sendBndl :: Bool -> (Maybe O.UDP) -> Cx -> O.Bundle -> IO ()
+sendBndl :: Bool -> (Maybe O.Udp) -> Cx -> O.Bundle -> IO ()
 sendBndl isBusMsg (Just listen) cx bndl = O.sendTo listen (O.Packet_Bundle bndl) (N.addrAddress addr)
   where addr | isBusMsg && isJust (cxBusAddr cx) = fromJust $ cxBusAddr cx
              | otherwise = cxAddr cx
@@ -332,11 +332,10 @@
                             defaultValue _ = Nothing
 
 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
+playStack pMap = stack . (map pattern) . (filter active) . Map.elems $ pMap
+  where active pState = if hasSolo pMap
+                        then solo pState
+                        else not (mute pState)
 
 toOSC :: [Int] -> ProcessedEvent -> OSC -> [(Double, Bool, O.Message)]
 toOSC busses pe osc@(OSC _ _)
@@ -400,16 +399,21 @@
         ident = fromMaybe "unknown" $ Map.lookup "_id_" (value $ peEvent pe) >>= getS
         ts = (peOnWholeOrPartOsc pe) + nudge -- + latency
 
+patternTimeID :: String
+patternTimeID = "_t_pattern"
+
 -- Used for Tempo callback
-updatePattern :: Stream -> ID -> ControlPattern -> IO ()
-updatePattern stream k pat = do
+updatePattern :: Stream -> ID -> Time -> ControlPattern -> IO ()
+updatePattern stream k !t pat = do
   let x = queryArc pat (Arc 0 0)
   pMap <- seq x $ takeMVar (sPMapMV stream)
   let playState = updatePS $ Map.lookup (fromID k) pMap
   putMVar (sPMapMV stream) $ Map.insert (fromID k) playState pMap
   where updatePS (Just playState) = do playState {pattern = pat', history = pat:(history playState)}
         updatePS Nothing = PlayState pat' False False [pat']
-        pat' = pat # pS "_id_" (pure $ fromID k)
+        patControls = Map.singleton patternTimeID (VR t)
+        pat' = withQueryControls (Map.union patControls)
+                 $ pat # pS "_id_" (pure $ fromID k)
 
 processCps :: T.LinkOperations -> [Event ValueMap] -> IO [ProcessedEvent]
 processCps ops = mapM processEvent
@@ -542,7 +546,7 @@
 -- Send events early using timestamp in the OSC bundle - used by Superdirt
 -- Send events early by adding timestamp to the OSC message - used by Dirt
 -- Send events live by delaying the thread
-send :: Maybe O.UDP -> Cx -> Double -> Double -> (Double, Bool, O.Message) -> IO ()
+send :: Maybe O.Udp -> Cx -> Double -> Double -> (Double, Bool, O.Message) -> IO ()
 send listen cx latency extraLatency (time, isBusMsg, m)
   | oSchedule target == Pre BundleStamp = sendBndl isBusMsg listen cx $ O.Bundle timeWithLatency [m]
   | oSchedule target == Pre MessageStamp = sendO isBusMsg listen cx $ addtime m
@@ -551,7 +555,7 @@
                                     sendO isBusMsg listen cx m
                    return ()
     where addtime (O.Message mpath params) = O.Message mpath ((O.int32 sec):((O.int32 usec):params))
-          ut = O.ntpr_to_ut timeWithLatency
+          ut = O.ntpr_to_posix timeWithLatency
           sec :: Int
           sec = floor ut
           usec :: Int
@@ -565,8 +569,11 @@
 streamNudgeAll s nudge = T.setNudge (sActionsMV s) nudge
 
 streamResetCycles :: Stream -> IO ()
-streamResetCycles s =T.resetCycles (sActionsMV s)
+streamResetCycles s = streamSetCycle s 0
 
+streamSetCycle :: Stream -> Time -> IO ()
+streamSetCycle s cyc = T.setCycle cyc (sActionsMV s)
+
 hasSolo :: Map.Map k PlayState -> Bool
 hasSolo = (>= 1) . length . filter solo . Map.elems
 
@@ -652,7 +659,7 @@
 streamSetR :: Stream -> String -> Pattern Rational -> IO ()
 streamSetR = streamSet
 
-openListener :: Config -> IO (Maybe O.UDP)
+openListener :: Config -> IO (Maybe O.Udp)
 openListener c
   | cCtrlListen c = catchAny run (\_ -> do verbose c "That port isn't available, perhaps another Tidal instance is already listening on that port?"
                                            return Nothing
@@ -686,16 +693,16 @@
                                                         return ()
           where 
             bufferIndices [] = []
-            bufferIndices (x:xs') | x == (O.ASCII_String $ O.ascii "&controlBusIndices") = catMaybes $ takeWhile isJust $ map O.datum_integral xs'
+            bufferIndices (x:xs') | x == (O.AsciiString $ O.ascii "&controlBusIndices") = catMaybes $ takeWhile isJust $ map O.datum_integral xs'
                                   | otherwise = bufferIndices xs'
         -- External controller commands
         act (O.Message "/ctrl" (O.Int32 k:v:[]))
           = act (O.Message "/ctrl" [O.string $ show k,v])
-        act (O.Message "/ctrl" (O.ASCII_String k:v@(O.Float _):[]))
+        act (O.Message "/ctrl" (O.AsciiString k:v@(O.Float _):[]))
           = add (O.ascii_to_string k) (VF (fromJust $ O.datum_floating v))
-        act (O.Message "/ctrl" (O.ASCII_String k:O.ASCII_String v:[]))
+        act (O.Message "/ctrl" (O.AsciiString k:O.AsciiString v:[]))
           = add (O.ascii_to_string k) (VS (O.ascii_to_string v))
-        act (O.Message "/ctrl" (O.ASCII_String k:O.Int32 v:[]))
+        act (O.Message "/ctrl" (O.AsciiString k:O.Int32 v:[]))
           = add (O.ascii_to_string k) (VI (fromIntegral v))
         -- Stream playback commands
         act (O.Message "/mute" (k:[]))
@@ -722,7 +729,7 @@
                      putMVar (sStateMV stream) $ Map.insert k v sMap
                      return ()
         withID :: O.Datum -> (ID -> IO ()) -> IO ()
-        withID (O.ASCII_String k) func = func $ (ID . O.ascii_to_string) k
+        withID (O.AsciiString k) func = func $ (ID . O.ascii_to_string) k
         withID (O.Int32 k) func = func $ (ID . show) k
         withID _ _ = return ()
 ctrlResponder _ _ _ = return ()
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
@@ -6,7 +6,7 @@
 
 import Control.Concurrent.MVar
 import qualified Sound.Tidal.Pattern as P
-import qualified Sound.OSC.FD as O
+import qualified Sound.Osc.Fd as O
 import Control.Concurrent (forkIO, ThreadId, threadDelay)
 import Control.Monad (when)
 import qualified Data.Map.Strict as Map
@@ -20,7 +20,6 @@
 import Data.Int(Int64)
 
 import Sound.Tidal.StreamTypes
-import Sound.Tidal.Core (silence)
 
 {-
     Tempo.hs - Tidal's scheduler
@@ -40,13 +39,13 @@
     along with this library.  If not, see <http://www.gnu.org/licenses/>.
 -}
 
-instance Show O.UDP where
+instance Show O.Udp where
   show _ = "-unshowable-"
 
 type TransitionMapper = P.Time -> [P.ControlPattern] -> P.ControlPattern
 
 data TempoAction =
-  ResetCycles
+  SetCycle P.Time
   | SingleTick P.ControlPattern
   | SetNudge Double
   | StreamReplace ID P.ControlPattern
@@ -54,7 +53,6 @@
 
 data State = State {ticks    :: Int64,
                     start    :: Link.Micros,
-                    nowEnd   :: Link.Micros,
                     nowArc   :: P.Arc,
                     nudged   :: Double
                    }
@@ -64,7 +62,7 @@
   ActionHandler {
     onTick :: TickState -> LinkOperations -> P.ValueMap -> IO P.ValueMap,
     onSingleTick :: LinkOperations -> P.ValueMap -> P.ControlPattern -> IO P.ValueMap,
-    updatePattern :: ID -> P.ControlPattern -> IO ()
+    updatePattern :: ID -> P.Time -> P.ControlPattern -> IO ()
   }
 
 data LinkOperations =
@@ -78,8 +76,8 @@
     cyclesToBeat :: CDouble -> CDouble
   }
 
-resetCycles :: MVar [TempoAction] -> IO ()
-resetCycles actionsMV = modifyMVar_ actionsMV (\actions -> return $ ResetCycles : actions)
+setCycle :: P.Time -> MVar [TempoAction] -> IO ()
+setCycle cyc actionsMV = modifyMVar_ actionsMV (\actions -> return $ SetCycle cyc : actions)
 
 setNudge :: MVar [TempoAction] -> Double -> IO ()
 setNudge actionsMV nudge = modifyMVar_ actionsMV (\actions -> return $ SetNudge nudge : actions)
@@ -89,6 +87,7 @@
   beat <- Link.beatAtTime ss time (cQuantum config)
   return $! (toRational beat) / (toRational (cBeatsPerCycle config))
 
+-- At what time does the cycle occur according to Link?
 cyclesToTime :: Config -> Link.SessionState -> P.Time -> IO Link.Micros
 cyclesToTime config ss cyc = do
   let beat = (fromRational cyc) * (cBeatsPerCycle config)
@@ -117,11 +116,10 @@
             now <- Link.clock abletonLink
             let startAt = now + processAhead
             Link.requestBeatAtTime sessionState 0 startAt quantum
-            Link.commitAppSessionState abletonLink sessionState
+            Link.commitAndDestroyAppSessionState abletonLink sessionState
             putMVar actionsMV []
             let st = State {ticks = 0,
                        start = now,
-                       nowEnd = logicalTime now 1,
                        nowArc = P.Arc 0 0,
                        nudged = 0
                       }
@@ -178,9 +176,7 @@
                 startCycle = P.stop $ nowArc st
             sessionState <- Link.createAndCaptureAppSessionState abletonLink
             endCycle <- timeToCycles' config sessionState logicalEnd
-            let st' = st {nowArc = P.Arc startCycle endCycle,
-                          nowEnd = logicalEnd
-                        }
+            let st' = st {nowArc = P.Arc startCycle endCycle}
             nowOsc <- O.time
             nowLink <- Link.clock abletonLink
             let ops = LinkOperations {
@@ -213,19 +209,24 @@
           return $! st'
         handleActions :: State -> [TempoAction] -> P.ValueMap -> IO (State, P.ValueMap)
         handleActions st [] streamState = return (st, streamState)
-        handleActions st (ResetCycles : otherActions) streamState =
+        handleActions st (SetCycle cyc : otherActions) streamState =
           do
             (st', streamState') <- handleActions st otherActions streamState
             sessionState <- Link.createAndCaptureAppSessionState abletonLink
 
-            let logicalEnd   = logicalTime (start st') $ ticks st' + 1
-                st'' = st' {
-                          nowArc = P.Arc 0 0,
-                          nowEnd = logicalEnd + frameTimespan
-                        }
             now <- Link.clock abletonLink
-            Link.requestBeatAtTime sessionState 0 now quantum
+            let startAt = now + processAhead
+                beat = (fromRational cyc) * (cBeatsPerCycle config)
+            Link.requestBeatAtTime sessionState beat startAt quantum
             Link.commitAndDestroyAppSessionState abletonLink sessionState
+
+                  
+            let st'' = st' {
+                  ticks = 0,
+                  start = now,
+                  nowArc = P.Arc cyc cyc
+                  }
+
             return (st'', streamState')
         handleActions st (SingleTick pat : otherActions) streamState =
           do
@@ -269,10 +270,8 @@
                 sessionState <- Link.createAndCaptureAppSessionState abletonLink
                 cyc <- timeToCycles' config sessionState now
                 Link.destroySessionState sessionState
-                -- put pattern id and change time in control input
-                let streamState'' = Map.insert ("_t_all") (P.VR $! cyc) $ Map.insert ("_t_" ++ fromID k) (P.VR $! cyc) streamState'
-                (updatePattern ac) k pat
-                return (st', streamState'')
+                (updatePattern ac) k cyc pat
+                return (st', streamState')
               )
               (\(e :: E.SomeException) -> do
                 hPutStrLn stderr $ "Error in pattern: " ++ show e
@@ -284,10 +283,10 @@
             let
               appendPat flag = if flag then (pat:) else id
               updatePS (Just playState) = playState {history = (appendPat historyFlag) (history playState)}
-              updatePS Nothing = PlayState {pattern = silence,
+              updatePS Nothing = PlayState {pattern = P.silence,
                                             mute = False,
                                             solo = False,
-                                            history = (appendPat historyFlag) (silence:[])
+                                            history = (appendPat historyFlag) (P.silence:[])
                                           }
               transition' pat' = do now <- Link.clock abletonLink
                                     ss <- Link.createAndCaptureAppSessionState abletonLink
diff --git a/src/Sound/Tidal/Time.hs b/src/Sound/Tidal/Time.hs
--- a/src/Sound/Tidal/Time.hs
+++ b/src/Sound/Tidal/Time.hs
@@ -38,16 +38,16 @@
 
 -- Utility functions - Time
 
--- | The 'sam' (start of cycle) for the given time value.
+-- | The @sam@ (start of cycle) for the given time value.
 -- Cycles have duration 1, so every integer Time value divides two cycles.
 sam :: Time -> Time
 sam = fromIntegral . (floor :: Time -> Int)
 
--- | Turns a number into a (rational) time value. An alias for 'toRational'.
+-- | Turns a number into a (rational) time value. An alias for @toRational@.
 toTime :: Real a => a -> Rational
 toTime = toRational
 
--- | Turns a (rational) time value into another number. An alias for 'fromRational'.
+-- | Turns a (rational) time value into another number. An alias for @fromRational@.
 fromTime :: Fractional a => Time -> a
 fromTime = fromRational
 
@@ -102,29 +102,36 @@
 cycleArc :: Arc -> Arc
 cycleArc (Arc s e) = Arc (cyclePos s) (cyclePos s + (e-s))
 
--- | Returns the numbers of the cycles that the input Arc overlaps
--- (excluding the input Arc's endpoint, unless it has duration 0 --
+-- | Returns the numbers of the cycles that the input @Arc@ overlaps
+-- (excluding the input @Arc@'s endpoint, unless it has duration 0 --
 -- see "Edge cases" below).
--- The "cycle number" of an Arc is equal to its start value.
--- Thus, for instance, `cyclesInArc (Arc 0 1.5) == [0,1]`.
--- * Edge cases:
---     `cyclesInArc $ Arc 0 1.0001 == [0,1]`
---     `cyclesInArc $ Arc 0 1      == [0]` -- the endpoint is excluded
---     `cyclesInArc $ Arc 1 1      == [1]` -- unless the Arc has duration 0
+-- (The "cycle number" of an @Arc@ is equal to its start value.
+-- Thus, for instance, @cyclesInArc (Arc 0 1.5) == [0,1]@.)
+--
+-- Edge cases:
+-- >  cyclesInArc $ Arc 0 1.0001 == [0,1]
+-- >  cyclesInArc $ Arc 0 1      == [0] -- the endpoint is excluded
+-- >  cyclesInArc $ Arc 1 1      == [1] -- unless the Arc has duration 0
+--
+-- PITFALL: Don't be fooled by the name. The output cycles
+-- are not necessarily completely contained in the input @Arc@,
+-- but they definitely overlap it,
+-- and they include every cycle that overlaps it.
 cyclesInArc :: Integral a => Arc -> [a]
 cyclesInArc (Arc s e)
   | s > e = []
   | s == e = [floor s]
   | otherwise = [floor s .. ceiling e-1]
 
--- | The whole cycles that overlap the input Arc,
--- (excluding its endpoint, unless it has duration 0,
--- similarly to `cyclesInArc` --
--- see that function's description for details).
+-- | This provides exactly the same information as @cyclesInArc@,
+-- except that this represents its output as @Arc@s,
+-- whereas @cyclesInArc@ represents the same information as integral indices.
+-- (The @Arc@ from 0 to 1 corresponds to the index 0,
+-- the one from 1 to 2 has index 1, etc.)
 cycleArcsInArc :: Arc -> [Arc]
 cycleArcsInArc = map (timeToCycleArc . (toTime :: Int -> Time)) . cyclesInArc
 
--- | Splits the given 'Arc' into a list of 'Arc's, at cycle boundaries.
+-- | Splits the given @Arc@ into a list of @Arc@s, at cycle boundaries.
 arcCycles :: Arc -> [Arc]
 arcCycles (Arc s e) | s >= e = []
                 | sam s == sam e = [Arc s e]
@@ -135,7 +142,7 @@
 arcCyclesZW (Arc s e) | s == e = [Arc s e]
                   | otherwise = arcCycles (Arc s e)
 
--- | Similar to 'fmap' but time is relative to the cycle (i.e. the
+-- | Similar to @fmap@ but time is relative to the cycle (i.e. the
 -- sam of the start of the arc)
 mapCycle :: (Time -> Time) -> Arc -> Arc
 mapCycle f (Arc s e) = Arc (sam' + f (s - sam')) (sam' + f (e - sam'))
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
@@ -800,7 +800,7 @@
     distrib' (True:a) (x:b) = x : distrib' a b
     distrib' (False:a) b = False : distrib' a b
     layers = map bjorklund . (zip<*>tail)
-    boolsToPat a b' = flip const <$> filterValues (== True) (fastFromList a) <*> b'
+    boolsToPat a b' = flip const <$> filterValues (== True) (fastFromList a) <* b'
 
 {- | `euclidInv` fills in the blanks left by `e`
  -
@@ -1728,11 +1728,15 @@
               | otherwise = silence
 
 
+-- ghost'' is kept for backwards compatibility
 ghost'' :: Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
-ghost'' a f p = superimpose (((a*2.5) `rotR`) . f) $ superimpose (((a*1.5) `rotR`) . f) p
+ghost'' = ghostWith
 
+ghostWith :: Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a
+ghostWith a f p = superimpose (((a*2.5) `rotR`) . f) $ superimpose (((a*1.5) `rotR`) . f) p
+
 ghost' :: Time -> Pattern ValueMap -> Pattern ValueMap
-ghost' a p = ghost'' a ((|*| P.gain (pure 0.7)) . (|> P.end (pure 0.2)) . (|*| P.speed (pure 1.25))) p
+ghost' a p = ghostWith a ((|*| P.gain (pure 0.7)) . (|> P.end (pure 0.2)) . (|*| P.speed (pure 1.25))) p
 
 ghost :: Pattern ValueMap -> Pattern ValueMap
 ghost = ghost' 0.125
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.9.2"
+tidal_version = "1.9.3"
 
 tidal_status :: IO ()
 tidal_status = tidal_status_string >>= putStrLn 
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
@@ -207,6 +207,9 @@
                       (Event (Context []) (Just $ Arc (2 % 3) (5 % 6)) (Arc (2 % 3) (5 % 6)) "d"),
                       (Event (Context []) (Just $ Arc (5 % 6) (1 % 1)) (Arc (5 % 6) (1 % 1)) "e")
                      ]
+      it "preserves cycle number of inner patterns" $ do
+        (map value $ queryArc (squeezeJoin (pure $ struct "1" $ (sig $ id))) (Arc 3 4))
+          `shouldBe` [3.5]
 
     describe ">>=" $ do
       it "can apply functions to patterns" $ do
diff --git a/test/Sound/Tidal/StreamTest.hs b/test/Sound/Tidal/StreamTest.hs
--- a/test/Sound/Tidal/StreamTest.hs
+++ b/test/Sound/Tidal/StreamTest.hs
@@ -5,7 +5,7 @@
 import Test.Microspec
 import Sound.Tidal.Stream
 import Sound.Tidal.Pattern
-import qualified Sound.OSC.FD as O
+import qualified Sound.Osc.Fd as O
 import qualified Data.Map.Strict as M
 
 run :: Microspec ()
diff --git a/tidal.cabal b/tidal.cabal
--- a/tidal.cabal
+++ b/tidal.cabal
@@ -1,7 +1,7 @@
 cabal-version:       2.0
 
 name:                tidal
-version:             1.9.2
+version:             1.9.3
 synopsis:            Pattern language for improvised music
 description:         Tidal is a domain specific language for live coding patterns.
 homepage:            http://tidalcycles.org/
@@ -55,7 +55,7 @@
       base >=4.8 && <5
     , containers < 0.7
     , colour < 2.4
-    , hosc >= 0.17 && < 0.20
+    , hosc >= 0.20 && < 0.21
     , text < 2.1
     , parsec >= 3.1.12 && < 3.2
     , network < 3.2
@@ -90,7 +90,7 @@
   build-depends:
                 base ==4.*
               , microspec >= 0.2.0.1
-              , hosc >= 0.17 && < 0.20
+              , hosc >= 0.20 && < 0.21
               , containers
               , parsec
               , tidal
diff --git a/tidal.el b/tidal.el
--- a/tidal.el
+++ b/tidal.el
@@ -228,7 +228,7 @@
        ,(format "Send %s $ silence as a single line." name)
        (interactive)
        (tidal-send-string ":{")
-       (tidal-send-string " mapM_ ($ silence) [,name]")
+       (tidal-send-string (concat " mapM_ ($ silence) [" ,name "]"))
        (tidal-send-string ":}"))))
 
 (defun tidal-create-runner (name)
