Monthly Archives: September 2012

Patterns again

Back to patterns in Haskell, an unruly puzzle that’s run through the last few years of my life, trying to work out how I want to represent my music.  Here’s the current state of my types:

  data Pattern a = Sequence {arc :: Range -> [Event a]}
                 | Signal {at :: Rational -> [a]}
  type Event a = (Range, a)
  type Range = (Rational, Rational)

A Range is a time range, with a start (onset) and duration.  An Event is of some type a, that occurs over a Range.  A Pattern can be instantiated either as a Sequence or Signal.  These are directly equivalent to the distinction between digital and analogue, or discrete and continuous.  A Sequence is a set of discrete events (with start and duration) occurring within a given range, and a Signal is a set of values for a given position in time.  In other words, both are represented as functions from time to values, but Sequence is for representing a set of events which have beginnings and ends, and Range is for a continuously varying set of values.

This is a major improvement on my previous version, simply because the types are significantly simpler, which makes the code significantly easier to work with.  This simplicity is due to the structure of patterns being represented entirely with functional composition, so is closer to my (loose) understanding of functional reactive programming..

The Functor definition is straightforward enough:

  mapSnd f (x,y) = (x,f y)
  instance Functor Pattern where
    fmap f (Sequence a) = Sequence $ fmap (fmap (mapSnd f)) a
    fmap f (Signal a) = Signal $ fmap (fmap f) a

The Applicative definition allows signals and patterns to be combined in in a fairly reasonable manner too, although I imagine this could be tidied up a fair bit:

  instance Applicative Pattern where
    pure x = Signal $ const [x]
    (Sequence fs) <*> (Sequence xs) = 
      Sequence $ \r -> concatMap
                       (\((o,d),x) -> map
                                      (\(r', f) -> (r', f x))
                                      (
                                        filter
                                        (\((o',d'),_) -> (o' >= o) && (o' < (o+d)))
                                        (fs r)
                                      )
                       )
                       (xs r)
  (Signal fs) <*> (Signal xs) = Signal $ \t -> (fs t) <*> (xs t)
  (Signal fs) <*> px@(Sequence _) = 
    Signal $ \t -> concatMap (\(_, x) -> map (\f -> f x) (fs t)) (at' px t)
  (Sequence fs) <*> (Signal xs) = 
    Sequence $ \r -> concatMap (\((o,d), f) -> 
                                map (\x -> ((o,d), f x)) (xs o)) (fs r)

In the Pattern datatype, time values are represented using Rational numbers, where each whole number represents the start of a metrical cycle, i.e. something like a bar.  Therefore, concatenating patterns involves ‘playing’ one cycle from each pattern within every cycle:

  cat :: [Pattern a] -> Pattern a
  cat ps = combine $ map (squash l) (zip [0..] ps)
    where l = length ps
  squash :: Int -> (Int, Pattern a) -> Pattern a
  squash n (i, p) = Sequence $ \r -> concatMap doBit (bits r)
    where o' = (fromIntegral i)%(fromIntegral n)
          d' = 1%(fromIntegral n)
          cycle o = (fromIntegral $ floor o)
          subR o = ((cycle o) + o', d')
          doBit (o,d) = mapFsts scaleOut $ maybe [] ((arc p) . scaleIn) (subRange (o,d) (subR o))
          scaleIn (o,d) = (o-o',d* (fromIntegral n))
          scaleOut (o,d) = ((cycle o)+o'+ ((o-(cycle o))/(fromIntegral n)), d/ (fromIntegral n))
  subRange :: Range -> Range -> Maybe Range
  subRange (o,d) (o',d') | d'' > 0 = Just (o'', d'')
                       | otherwise = Nothing
    where o'' = max o (o')
          d'' = (min (o+d) (o'+d')) - o''
  -- chop range into ranges of unit cycles
  bits :: Range -> [Range]
  bits (_, 0) = []
  bits (o, d) = (o,d'):bits (o+d',d-d')
    where d' = min ((fromIntegral $ (floor o) + 1) - o) d

Well this code could definitely be improved..

If anyone is interested the code is on github, but is not really ready for public consumption yet.  Now I can get back to making music with it though, more on that elsewhere, soon, maybe under a new pseudonym..

Upcoming events in September

7/8th September 2012, Leeds – Live Interfaces

As my first act as research fellow at ICSRiM, I’m chairing this conference on live interaction in performance technology, two days of papers and performances, including a (free) club night.  The quality of submissions has been fantastic, and we have people coming from 11 different countries outside the UK, can’t wait!

10th September, Slovenia – ICMC 2012

Then I’m off to give a paper on Live notation at the International Computer Music Conference with Hester Reeve.   Looking forward to hanging out in Ljubljana, hope to spend some time in the kiberpapa while I’m there (Sunday-Thursday).

16th September, Germany – Documenta festival

This isn’t 100% confirmed, but the book Speaking Code will be launched at Documenta festival, and while I can’t be there, I will still be live coding there.  More on this once it’s done..

17th September, Goldsmiths – Graduation

Although I was done with this back in November 2011, this is the final step where I get to wear the stupid clothes.  Hoo.

25th September, Leeds – Psychogeography Pecha Kucha

I’ll be trying to argue for computer programming being a form of psychogeography in 20 slides over 6.66 minutes. Drop me a line if you’re interested and I’ll pass on the room info once I know..  The event is organised by Tina Richardson.

29th September, Sheffield – Do It Thissen

Happy to be performing in the exhibition about post-punk Sheffield, I’ll be somehow re-interpreting a wall of 7″ record sleeve cover art.  Neil Webb and Ron Wright will be playing too, and Sensoria will be launching their musical map. Register here for a free beer!