Patterning function parameters

Is there a way to use functional interfaces on patterns of functions?

I need something like arp, but with fixed length arpeggio patterns independent from the number of notes in the chord in order to better combine with existing rhythm patterns. So arp's predefined arpeggio strategies won't work. With arpWith, it can be easily done, but now there doesn't seem to be a way to apply a pattern of multiple arpeggio strategies (as possible with arp, e.g. arp "<up down>").

I can create patterns out of functional arpeggio strategies using listToPat, e.g.

up notes = notes
down notes = reverse notes
updown notes = init notes ++ init (reverse notes)
downup notes = init (reverse notes) ++ init notes
fixarp length strategy notes = take length $ concat $ repeat $ strategy notes
pat1 = listToPat [fixarp 8 updown, fixarp 8 downup]

But there seems to be no obvious way to apply these patterns.

Any ideas?

1 Like


  • I think this is an example where two concepts of "pattern" are hard to reconcile (implicit structure: pattern as function from time (span) to value, explicit structure: as list of events) (as far as I understand, tidal-2 plans to make these two more alike)

  • I checked the following (for tidal-1) with ghci (so it's type-correct) but did not listen to any, so you might need to replace innerJoin with some other join (of the same type), etc.

Now: your pat1 has this type:

pat1 :: Pattern ([a] -> [a])

so it is a pattern of functions (from list-of-a to list-of-a). you can "apply" that to a pattern of list-of-a, using the "(applicatve) application operator" (<*>), see 2. below.

  1. (for creating a non-trivial Pattern [a])
split n p = segment 1 $ sequence $ map (\i -> pure (i%n) ~> p) [0 .. n-1]

e.g., this should give blocks of random numbers

fast 3 $ split 3 $ irand 8
    (0>β…‘)-β…“|[2,1,2]      -- *
   (β…“>⁴₉)-β…”|[3,7,2]  -- *
   (β…”>⁷₉)-1|[4,6,3]   -- *

(I hope that only * are audible)

  1. "apply" (but using operator (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b  -- instantiate  f = Pattern here

pat1 <*> (split 3 $ irand 8)

it :: Num a => Pattern [a]

so you have a pattern of list-of-numbers (notes)

  1. you still need to declare how to make that into a pattern of (single) notes that you can play/hear. Perhaps
(innerJoin . fmap listToPat ) $ pat1 <*> (split 3 $ irand 8)


innerJoin . fmap listToPat :: Pattern [a] -> Pattern a

Here is a concrete example. With your def. of pat1, does this look like what you wanted?

d1 $ ( ( pat1 <*> mapM n [-12,2,-8,9 ]) >>= listToPat)
  # s "superpiano" # room 1 # size 0.8

where the monadic bind (>>=) hides the innerJoin I mentioned.

it''s too simple in the sense that the arpeggio pattern is applied to a fixed sequence. I will try to add an example for randomisation.

[EDIT] you can "pattern" the pattern though, as in

d1 $ ( (sometimes rev  pat1  <*> mapM  n [-12,2,-8,9 ]) >>= listToPat)
  # s "superpiano" # room 1 # size 0.8

[EDIT] with my function split mentioned above, and import Data.List(sort), try

d1 $ 
  ( n $ scale "major" 
  $ (pat1 <*>   --  "applicative application" of arpeggio pattern, to ...
      (slow 4                        -- use each random event four times
    $ fmap sort                     -- list of four random numbers in increasing order
   $ split 4 $ irand 30 - 15   -- list of four random numbers
   ) >>= listToPat ) )
  # s "superpiano" # room 1 # size 0.8

rendered audio: tidal/code/app-app-arp.ogg Β· master Β· waldmann / computer-mu Β· GitLab , complete source code: tidal/code/app-app-arp.tidal Β· master Β· waldmann / computer-mu Β· GitLab