chopBy?

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:

_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:

(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


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:

(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?