# chopBy?

**URL:** <https://uzu.lurk.org/t/chopby/5210>\
**Category:** TidalCycles\
**Tags:** innards\
**Created:** [30 May 2024 21:30 UTC](https://uzu.lurk.org/t/chopby/5210 "2024-05-30T21:30:29Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![lwlsn](https://uzu.lurk.org/user_avatar/uzu.lurk.org/lwlsn/32/1306_2.png) [@lwlsn](https://uzu.lurk.org/u/lwlsn)\
**Post date:** [30 May 2024 21:30 UTC](https://uzu.lurk.org/t/chopby/5210/1 "2024-05-30T21:30:29Z")

</div>

I'm trying to write an implementation for a `chopBy function` that would be similar to striateBy, that accepts a second parameter like `striateBy` for sample length, but playing bits sequentially like `chop` .

But I can't quite get the right behaviour ..

The first version I wrote:

```haskell
_chopBy :: Int -> Double -> ControlPattern -> ControlPattern
_chopBy n f pat = squeezeJoin $ fmap (chopPart n f) pat

chopPart :: Int -> Double -> ValueMap -> ControlPattern
chopPart n f v = fastcat $ map (pure . rangemap v) slices
  where
    rangemap v (b, e) = Map.union (fromMaybe (makeMap (b,e)) $ merge v (b,e)) v
    merge :: ValueMap -> (Double, Double) -> Maybe ValueMap
    merge v (b, e) = do
      b' <- Map.lookup "begin" v >>= getF
      e' <- Map.lookup "end" v >>= getF
      let d = e' - b'
      return $ makeMap (b' + b*d, b' + e*d)
    makeMap (b,e) = Map.fromList [("begin", VF b), ("end", VF e)]
    slices = map (\i -> (slot * fromIntegral i, slot * fromIntegral i + f)) [0 .. n-1]
    slot = (1 - f) / fromIntegral n

```

Distributes the events amongst the cycle like so:

```haskell
(0>⅛)|begin: 0.0f, end: 0.16666666666666666f, s: "a"
(⅛>¼)|begin: 0.4166666666666667f, end: 0.5833333333333334f, s: "a"
(¼>⅜)|begin: 0.0f, end: 0.16666666666666666f, s: "b"
(⅜>½)|begin: 0.4166666666666667f, end: 0.5833333333333334f, s: "b"
(½>⅝)|begin: 0.0f, end: 0.16666666666666666f, s: "c"
(⅝>¾)|begin: 0.4166666666666667f, end: 0.5833333333333334f, s: "c"
(¾>⅞)|begin: 0.0f, end: 0.16666666666666666f, s: "d"
(⅞>1)|begin: 0.4166666666666667f, end: 0.5833333333333334f, s: "d"

```

But the expected output should evenly divide each part by the specified length, but it looks like the calculation for `b` and `e` in `rangemap` is not handling the positions correctly

I rewrote to try and correct the slicing logic so that each part starts where the previous one ended

```haskell

chopPart :: Int -> Double -> ValueMap -> ControlPattern
chopPart n f v = fastcat $ map (pure . rangemap v) slices
  where
    rangemap v (b, e) = Map.union (fromMaybe (makeMap (b, e)) $ merge v (b, e)) v
    merge :: ValueMap -> (Double, Double) -> Maybe ValueMap
    merge v (b, e) = do
      b' <- Map.lookup "begin" v >>= getF
      e' <- Map.lookup "end" v >>= getF
      let d = e' - b'
      return $ makeMap (b' + b * d, b' + e * d)
    makeMap (b, e) = Map.fromList [("begin", VF b), ("end", VF e)]
    slices = map (\i -> (i * slot, i * slot + f)) [0 .. fromIntegral (n - 1)]
    slot = f

```

which is outputting:

```haskell
(0>⅛)|begin: 0.0f, end: 0.16666666666666666f, s: "a"
(⅛>¼)|begin: 0.16666666666666666f, end: 0.3333333333333333f, s: "a"
(¼>⅜)|begin: 0.0f, end: 0.16666666666666666f, s: "b"
(⅜>½)|begin: 0.16666666666666666f, end: 0.3333333333333333f, s: "b"
(½>⅝)|begin: 0.0f, end: 0.16666666666666666f, s: "c"
(⅝>¾)|begin: 0.16666666666666666f, end: 0.3333333333333333f, s: "c"
(¾>⅞)|begin: 0.0f, end: 0.16666666666666666f, s: "d"
(⅞>1)|begin: 0.16666666666666666f, end: 0.3333333333333333f, s: "d"

```

still not quite the expected behaviour.. and not quite sure where to go next?

---

<div class="post-metadata">

**Author:** ![yaxu](https://uzu.lurk.org/user_avatar/uzu.lurk.org/yaxu/32/2_2.png) [@yaxu](https://uzu.lurk.org/u/yaxu)\
**Post date:** [15 January 2025 11:02 UTC](https://uzu.lurk.org/t/chopby/5210/2 "2025-01-15T11:02:28Z")

</div>

Oh somehow I missed this back in May! Looks useful, did you ever get the behaviour you wanted?

---

<div class="post-metadata">

**Author:** ![lwlsn](https://uzu.lurk.org/user_avatar/uzu.lurk.org/lwlsn/32/1306_2.png) [@lwlsn](https://uzu.lurk.org/u/lwlsn)\
**Post date:** [17 January 2025 18:05 UTC](https://uzu.lurk.org/t/chopby/5210/3 "2025-01-17T18:05:33Z")

</div>

Noo but this reminds me to revisit this!

---

<div class="post-metadata">

**Author:** ![yaxu](https://uzu.lurk.org/user_avatar/uzu.lurk.org/yaxu/32/2_2.png) [@yaxu](https://uzu.lurk.org/u/yaxu)\
**Post date:** [17 January 2025 20:45 UTC](https://uzu.lurk.org/t/chopby/5210/4 "2025-01-17T20:45:04Z")

</div>

Hmm, well looking at the behaviour of the existing striateBy..

```haskell
_striateBy 2 0.5 $ s "a"
(0>½)|begin: 0.0f, end: 0.5f, s: "a"
(½>1)|begin: 0.25f, end: 0.75f, s: "

```

That seems wrong as well?

Looks like an off-by-one error.. I just changed `n` to `n-1` on the last line:

```haskell
_striateBy :: Int -> Double -> ControlPattern -> ControlPattern
_striateBy n f p = fastcat $ map (offset . fromIntegral) [0 .. n-1]
  where offset i = p # P.begin (pure (slot * i) :: Pattern Double) # P.end (pure ((slot * i) + f) :: Pattern Double)
        slot = (1 - f) / fromIntegral (n-1)

```

Now it works better, e.g.:

```haskell
_striateBy 4 0.5 $ s "a"
(0>¼)|begin: 0.0f, end: 0.5f, s: "a"
(¼>½)|begin: 0.16666666666666666f, end: 0.6666666666666666f, s: "a"
(½>¾)|begin: 0.3333333333333333f, end: 0.8333333333333333f, s: "a"
(¾>1)|begin: 0.5f, end: 1.0f, s: "a"

```

Here's a PR which also uses the same mergeplayrange function as `striate`, so that it works within any existing begin/end controls.

I've run out of time now but hopefully this fix helps with fixing chopBy!

---

<div class="post-metadata">

**Author:** ![geikha](https://uzu.lurk.org/user_avatar/uzu.lurk.org/geikha/32/2701_2.png) [@geikha](https://uzu.lurk.org/u/geikha)\
**Post date:** [25 January 2025 19:12 UTC](https://uzu.lurk.org/t/chopby/5210/5 "2025-01-25T19:12:00Z")

</div>

not exactly the same but when I want to do something like that I use my custom `chopAt` function and change the legato of the note:

e.g. `d1 $ chopAt' 8 8 "someloopable" # legato 0.5`

> [@striateAt, chopAt (Custom functions for loop sampling)](https://club.tidalcycles.org/t/striateat-chopat-custom-functions-for-loop-sampling/4870):
>
> Hello! I thought I'd share some of my most used custom functions in some posts since I've been developing a very specific livecoding style: The functions let striateAt str at f = slow at $ striate (fast at $ str) f chopAt str at f = slow at $ chop (fast at $ str) f sloopAt str at f = loopAt at $ striate (fast at $ str) f striateAt' str at f = striateAt (str |\* at) (fmap toRational at) f chopAt' str at f = chopAt (str |\* at) (fmap toRational at) f sloop…

---

<div class="post-metadata">

**Author:** ![yaxu](https://uzu.lurk.org/user_avatar/uzu.lurk.org/yaxu/32/2_2.png) [@yaxu](https://uzu.lurk.org/u/yaxu)\
**Post date:** [26 January 2025 18:28 UTC](https://uzu.lurk.org/t/chopby/5210/6 "2025-01-26T18:28:35Z")

</div>

Looks like I failed to add the link to the striateBy PR: [Fix off-by-one error in striateBy by yaxu · Pull Request #1106 · tidalcycles/Tidal · GitHub](https://github.com/tidalcycles/Tidal/pull/1106)
