Category: haskell

feedforward

Back in the glory days of slub I used to live code with Perl, and wrote a text editor (also in Perl) for it called ‘feedback.pl’. It was a strange thing, where you wrote self-modifying code to store data in the sourcecode for the music you were writing, and therefore visualise it. I’ve been intending to make something similar for tidal for ages,  and took some time to finally start work. I’ve experimented with a weird visual editor for tidal before, and have been fiddling around with a web-based editor as well, but this time decided to write something that worked in the terminal, using the fantastic ncurses framework. This is partly so it’ll run nicely on the Pi Zero, for my ongoing Spicule project, but partly because it just makes sense for a text editor to work in text mode, and it’s good to start from basics without taking on the many assumptions of an existing ‘general purpose’ text editor. I’m just seeing where it takes me but I’m pretty happy with it so far, it has some structured editing around patterns already, some ascii VU meters going on, and every edit is automatically recorded + timestamped. It’s far from being in a usable state, but here’s a quick demo:

You can find it on github but I’m not inviting patches until it’s a bit more fully formed.

Patterns are the time of numbers

Ok this post is going to look quite dry, but is actually very exciting, at least for users of TidalCycles. So first here’s a video demonstrating the simplified syntax the below blurb will allow in a future version (version 1.0, which will probably be released soon after the upcoming 0.9).

If you want to see more videos like this check the playlists on the TidalCycles youtube channel.

Anyway.. Something I’ve noticed at Tidal workshops is that beginners have problems with this sort of code:
density 2 "1 2 3 4"
There’s the pattern 1 2 3 4, denoted by quotes, and the number 2 without quotes. This says ‘make the pattern twice as dense’, so you end up with this every cycle: 1 2 3 4 1 2 3 4.

Fairly straightforward, but why is the 2 a number, not a pattern? With more complicated, higher-order patterns this becomes increasingly unclear. There are ways to treat that number like a pattern:

spread' (density) "2 5" $ "1 2 3 4"
or ..
do n <- "2 5"
   density n "1 2 3 4"

… but now you’re converting between numbers and patterns of numbers instead of engaging with the music you’re making.

So I asked about this on haskell-art, in particular how to make it so a function like density could take either a number, or a pattern of numbers. One suggestion from Henning Thielemann was surprising – that Tidal’s Pattern type could be defined as a Haskell Number.

To cut this short it turned out that simply by evaluating a small amount of very simple code[1], Tidal’s syntax suddenly becomes far more expressive.

Instead of:
d1 $ sound "bass3" # speed "1.2"

you can just do
d1 $ sound "bass3" # speed 1.2

instead of
d1 $ sound "bass3*4" # speed (scale 1.2 3.2 $ ((+) <$> (slow 4 tri1) <*> sine1))
you can just do:
d1 $ sound "bass3*4" # speed ((slow 4 tri1) + sine1 * 2 + 1.2)

instead of
d1 $ up (every 3 ((+12) <$>) "1 8 [7 ~ 4]") # sound "bd"
it’s simply:
d1 $ up (every 3 (+12) "1 8 [7 ~ 4]") # sound "bd"
and with a quick re-jig of the definition of functions like density:

instead of
d1 $ n ((+) <$> ((+) <$> "1 2 3" <*> slow 3 "0 1") <*> slow 2 "3 1") # sound "voodoo"
it’s:
d1 $ n ("1 2 3" + slow 3 "0 1" + slow 2 "3 1") # sound "voodoo"

and much more…

By redefining density and friends, e.g.:

let density tp p = unwrap $ (\tv -> withResultTime (/ tv) $ withQueryTime (* tv) p) <$> tp

It’s then possible to fulfil my original aim:

d1 $ density "1 [2 3] [1 3]/2" $ sound "bd [sn:2 mt]/2"
while still supporting the original syntax:
d1 $ density 1.5 $ sound "bd [sn:2 mt]/2"

Basically, it turns out that if you let Haskell treat patterns of numbers as numbers, it provides extremely expressive means for working with them. This makes sense — patterns of numbers are numbers, just numbers which are polyphonic, and vary over (rational) time.

Lovely. This is a huge and unexpected win, which greatly simplifies pattern combination and manipulation, in the process greatly extending the possibilities that are within reach of a few keystrokes. This renews my suspicion that Haskell is full of much wondrous stuff just waiting to be discovered..

[1] Here’s that ‘small amount of very simple code’, if you want to try this at home:

instance Num a => Num (Pattern a) where
negate = fmap negate
(+) = liftA2 (+)
(*) = liftA2 (*)
fromInteger = pure . fromInteger
abs = fmap abs
signum = fmap signum

instance (Fractional a) => Fractional (Pattern a) where
fromRational = pure . fromRational
(/) = liftA2 (/)

 

Cyclic visualiser

Something I did ages ago on a residency, made a video a while back but forgot to put it here, here it is:

Sound to light for light to sound

xynaaxmue
xynaaxmue

I collaborated with xname on a performance as xynaaxmue on Saturday, audio+video up soon I hope.. xname performs with circuits that turn light into sound, improvising noise using stroboscopic lights. I was live coding with tidalcycles, as ever.

In the past I’ve created flashing patterns on an external monitor for xname’s circuits to feed off, check here for a recording of that one. This time I wanted to control a pair of RGB flash panels over DMX.. I used a tinkerit DMX hat for the arduino, officially retired but you can still find them online and the library is downloadable on github.

I hacked together a Tidal interface the night + morning before the conference, and it worked pretty well.. The Haskell and Arduino code is here.

With everything loaded up, Tidal code like this triggers flashes of light as well as sound:

x2 $ every 2 (slow 2) $ (jux (rev) $ foldEvery [5,7] (slow 2) 
   $ (slowspread (chop) [64,128,32] 
   $ sound "bd*2 [arpy:2 arpy] [mt claus*3] [voodoo ind]"))
  # dur "0.02"
  # nudge (slow 4 sine1)

The basic features:
  • sound – (sample name) is translated into colour in a semi-arbitrary way (a mapping which falls back on some crypto hashing)
  • pan – (kind of) pans between the two lights
  • dur – controls the duration of the flash
  • the flashes have a linear fade, which works across chop and striate
  • it is kind of polyphonic but the colour mixing can be improved.. mixing coloured light seems to get into the realm of philosophy though !

Will update with documentation of the performance itself when it’s up.

Test transmission 20140210

CP0x0d

Here’s Broken, a new two-sided single out on Chordpunch.

Creative Commons Licence
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

cover

Tidal cycles continued

I’ve continued with the Tidal cycles project, pushing forward with at least one cycle per weekday, apart from one day when I made a longer recording (to appear on chordpunch soon). All the audio is downloadable and creative commons licensed (CC-BY), check the descriptions for the tweet-sized tidal code for each cycle, and follow on twitter or soundcloud for updates.

I should note that this is of course inspired by the long-lived sctweets tradition in the supercollider community.

Tidal cycles

I’ve started a twitter feed called @tidalcycles, with minimal tidal programs and their output. I’ll try to add one a day, but lets see how things go. Here’s the first couple:

brak $ let x = "bd [sn [[sn bd] sn]]*1/3" in interlace (sound $ slow 3 $ x) (sound $ every 3 (append "[bd]*6") x)

weave 4 (speed $ (1+) sinewave1) [density 4 $ every 5 ((0.25 <~) . rev) $ striate 16 $ sound"[bd sn/2]/2", sound "bd [~ hc]*3"]

Colourful texture

Texture v.2 is getting interesting now, reminds me of fabric travelling around a loom..

Everything apart from the DSP is implemented in Haskell. The functional approach has worked out particularly well for this visualisation — because musical patterns are represented as functions from time to events (using my Tidal EDSL), it’s trivial to get at future events across the graph of combinators. Still much more to do though.

Vocal

A quick improv from Sheffield:

Here’s the state of my editor at the end:

d1 $ slow 2 $ sound "bd [sn sn bd]/2"

let x = density 2 $ striate' 8 0.75 $ sound (slow 4 $ "[bd bd/4] [ht mt lt]") in
d2 $ stack [every 3 rev $ every 4 (0.75 <~) x
            |+| pan "0.2",
            every 4 rev $ every 3 (0.5 <~) x
            |+| pan "0.8"
           ]
  |+| speed "1"
  |+| shape "0.6"

d4 $ every 4 (density 2) $ echo 0.5 $ brak $ every 3 (0.25 <~) $ sound "[future,odx,bd]*3"
  |+| shape "0.7"


let perc = 0.2 in
d3 $ slow 2 $ whenmod 10 12 (echo 0.25) $ density 2 $ sound (pick <$> "~ [operaesque]" <*> (slow 5 $ run 24))
  |+| slow 16 ((begin $ (*(1-perc)) <$>  sinewave1) |+| (end $ (+perc) <$> sinewave1))
  |+| speed (slow 2 "0.75 0.7")
  |+| pan "0.6"
  |+| shape "0.6"

let perc = 0.2 in
d4 $ slow 3 $ every 2 (rev) $ whenmod 10 12 (echo 0.25) $ density 2 $ sound (pick <$> "~ [operaesque]*3" <*> (slow 10 $ run 16))
  |+| slow 16 ((begin $ (*(1-perc)) <$>  sinewave1) |+| (end $ (+perc) <$> sinewave1))
  |+| speed "0.75"
  |+| pan "0.4"
  |+| vowel "i"

hush

d6 $ whenmod 10 12 (density 2) $ whenmod 12 4 (rev) $ slow 2 $ sound "[futuremono]*3 [odx/3]"


d7 $ whenmod 6 4 (0.25 <~) $ every 4 (density (3/2)) $ slow 2 $ sound "[jungle/2]*2 [jungle/3]*2"
  |+| shape "0.7"


d7 $ (whenmod 2 4 ((|+| speed "0.9") . rev) $ every 2 (0.25 <~) $ sound "odx [sn/2 ~ sn/2]")

d2 silence


d8 $ ((slow 8 $ double (0.25 <~) $ striate 12 $ sound "[diphone2/1 ~ diphone2/3]*4")
  |+| (slow 4 $ speed ((*) <$> "[2 1] 1.5" <*> ((+0) <$> ((+0.4) <$> (slow 4 $ sinewave1))))))
  |+| vowel "i"

d9 $ slow 2 $ sound "[[odx]*4]/3 [[odx]*4 [odx]*8]/3"
  |+| speed "1"
  |+| cutoff "0.04"
  |+| resonance "0.7"
  |+| shape "0.8"

bps 1