I’m experimenting with wanting with writing music software based on cellular automata. I’m interested in anybody else has experimented with similar things? Most stuff I see when I googled it is based around 100% algorithmic music creation based on 1d cellular automata, but I’m interested in 2d stuff. The closest I can find to that is ORCA, which I love but it technically isn’t a “true” cellular automaton, well, depending on the definition. So far I haven’t implemented much yet because I’m unsure how to proceed. I’m starting with wireworld because it’s a nice and predictable CA, but in itself it’s too slow to make music in it, especially in a livecoding environment. I don’t exactly know what the point of this topic is, but I would love to hear everybody’s thoughts on this. Have you ever experimented with something like this? Even if not, any ideas for how I can proceed and what I need to add to make it a comfortable live coding environment?

3 Likes

The forum search¹ returns :mag: a bunch of hints, with Emergence and Generative Art, Generative sequencers and Generative systems being some more general threads… whether it is a coincidence that all of their names bear the word “gene”, you tell me.

On norns there are Zellen and less-concepts. I don’t have a grid for the former, but the latter is a lot of fun. People have built things on Teletype I think, maybe studying those systems is worth it too.

People will try tell you there are all kinds of reasons to stop doing what you are doing, and rabbithole on something they really think you should rabbithole on. Their motivations are something to be wary of. That’s the zeitgeist and the media ecosystem we have. In any case, the one thing I suggest halt-everything-and-rabbithole-on-this-instead is the Composing with Process podcast by Mark Fell and Joe Gilmore for MACBA, from 2010-2012. My motivations are pure and pristine. I think Composing with Process is a monumental archive for people like us. For you, the most obviously relevant episode would be 8.1 Models of Change, in which they explore CAs as built by Iannis Xanakis in early 1980s, Peter Beyls and others.

I once saw a Bjarni Gunnarson performance which looked like CA and it was a livecoding event, namely ICL 2023. Absolutely great sound though, although I am not adamant what was going on actually. It is an agent based model. Here is a recording of that performance (we heard it on a club sound system, I must say, internet does no justice). Could it have been this system?

I hope those are helpful. What is on your mind, I would love to hear your thoughts :slight_smile:

¹ I :heart: forum search

12 Likes

i fondly remember some early monome scripts that used conway’s game of life- for example:

and these scripts were the first ones to draw me into this world. my art is usually pattern based, but not in the traditional musical way. this more organic way to explore sound, and most of the time to surprise myself was the perfect entry into further exploration both with the monome ecosystem and also the larger world of music and sounds…

4 Likes

Interesting! Will following this.

Type down everything on how you want for it to work and start making small progress by exploring different sound synthesis techniques to translate the patterns generated by the cellular automaton into musical sounds.

Do you want it to integrate with other software or music applications/gear?

Consider integrating the cellular automaton system with existing music software or frameworks, allowing users to combine it with other synthesis methods, effects, or sequencing tools.

I would use Max/MSP for this… Why?

It’s well-suited for real-time music generation and performance, and it provides a range of tools for working with audio, MIDI, and visual elements. You can use Max/MSP’s graphical interface to design your cellular automata and integrate them with sound synthesis and processing.
The learning curve is pretty steep tho and takes some time to understanding the objects and how the DSP is working.

You can possible use PureData or SuperCollider for this. Also JavaScript or Python.

1 Like

I think there is a lot to think about in this direction, Philosophically, poetically, sonically as well as critically, beyond the mechanistic squares-on-a-grid-changing-according-to-a-ruleset.

I’m not sure what I mean precisely, but tapping on to concepts of cell and automation – as a theory of life – is an evocative suggestion, isn’t it?

1 Like

I agree, ORCA, cool as it is, is not a 2d CA system. It’s a livecoding environment that happens to be laid out on a grid.

Less concepts is the most prominent CA example on lines, but it’s 1d.

Anything based on Conway’s game of life is interesting from the point of view of seeing how people try to interpret points in 2d space as music or sound, but the CA itself was not conceived with music in mind, so it’s an odd fit.

For things that fit the bill more closely in this space, you might look at grd: grd | norns community. Grd works with a 2d state, at least. I suspect, though, that when you dig under the hood you’ll find that the underlying CA is 1d, but I’m not sure. It’s an interesting script, though, because the author takes CA as a composition tool very seriously.

And of course, depending on how you look at it, arcologies might be seen as a dedicated 2d musical CA script: arcologies | norns community. OK, maybe not a CA in any strict sense, but it is an interesting example of thinking about how objects in a 2d space might represent sound.

And finally, as another example of representing data in 2d as sound, there’s overwintering: https://norns.community/overwintering. Seriously beautiful.

Thinking about all of these examples, it seems as if the most significant challenge is coming up with a CA that grows/changes in musically interesting ways, instead of just devolving into randomness and/or noise. I think that grd and overwintering are good examples of tackling that question.

1 Like

Something that always strike me about the implementation of generative systems for composition is how loosely coupled the algorithm/signal source is with the representation of that data in sound.

If one is quantizing a signal (in time or value) from some system, are we even “listening” to that system any more? Results and not this question arguably matter more.

I wonder how 2D state of CA could be represented in sound in a way that didn’t abstract away its information into other structures that no longer represent the process.

2 Likes

Hmm yeah after all these replies while I do find it interesting to have a cellular automaton create music, it’s ultimately very difficult. I still want to keep the “no hidden state” property of cellular automata in my system, doing so with cellular automata is too difficult. Thanks for all the input everyone!

I find the structure of 1d elementary CA pretty directly translatable to musical state. Each step in history is just an array of gates.

a binary grid controller makes a great interface for 1D elem CA. it allows at least three dfifferent manipulations:

  • toggle button to set state directly
  • toggle button to change a bit in the 8b rule representation
  • toggle button to change the rule such that that state would have been produced

here is a brief and silly video. it is probably the first grid patch made on norns actually. all those interactions are available. the mapping is that the most recent state simply toggles gates on a bank of sinewaves. sinewaves are tuned to harmonic series here; pitch in this patch could also be set by MIDI or captured audio. simple enough idea.

another mapping i’ve enjoyed is to use specific (maybe arbitrary) history states as (e.g.) drum machine voice patterns.

in both applications, adding an arbitrary pulse delay per cell can afford some more musical flexibility.

another point id make is that the state arrays need to be pretty long to exhibit “classic” behavior, so I always use a window of 8 cells or whatever. (less concepts doesnt so this iirc, just uses a very small state array.) scrubbing the window offset is a useful modulation.

[ed] oh right the silly video

11 Likes

I’m using 1D CA as a pattern sequencer in a commercial synth I just released. It’s great for providing constantly evolving patterns. Specifically, I’m using it to determine event location. The 256 rule sets are available, and the initial conditions can either be a single cell or a randomly generated series of events.

I’ve been interested in CA since I had a program on my first Mac in the 1980s. I had no idea what it was, but I found the little patterns intriguing.

2 Likes

dunno if this qualifies but I got a lot of inspiration from @yota’s (of grd fame) supercoliider process walkthrough video

3 Likes

Norns comes with a cellular automata library for programming, by the way. It’s called elca.

2 Likes

indeed, video above is kind of a demo of that library. (Script code is trivial - I may have thrown it away…) in any case was written before most of norns API existed, so was not a great reference.)

(note the unusual inclusion of set_rule_by_state()!)

1 Like

Regardless of triviality, I want that to a sufficient degree that i have to rewrite it tonight, so shiny

This is exactly what Scott McLaughlin and I tackled a certain time ago. the premise was that we were tired of sonification’s bias - soooooo many pentatonic mappings all sounding the same! My strong opinions on sonification are irrelevant here but they were the trigger to start thinking of ways to refrain from quantizing the space in which the algo was running - a sort of subversion of the idea of cells and proximity and birth, survival, death rules… and thus was born Spectral Conway. I think the paper explains it clearly, but if not, fire your questions away!

Enjoy!

5 Likes

This Nintendo DS music rom uses cellular automata:

4 Likes

Just a little note that the Radio Web Macba website seems to have had a change around, so the old URL to the Composing with Process podcasts isn’t working. This one (a link to a tag for the podcast series) seems to work: COMPOSING WITH PROCESS | Radio Web MACBA | RWM Podcasts.

1 Like

I don’t have much to add except that wireworld could be made to work for this, but as we’ve talked before, you’d need to be able to build wireworld prefabs and include them in the composition easily, a sort of base syntax for a higher level system. From there, connection wireworld to I/O can be done like:

qu-ants is a simple 2 bit reversible automaton that might be worth exploring for livecoding music:

2 Likes

Yep. Love this one. Anyway, there is also PC/Mac version of the sequencer from the same author, Bret Truchan.

You can also check his other work here:

2 Likes

I found old post:

Used it as a reference, then just plain used bits of it to get a 1D CA running on my norns, no sound, outputs first four rows to crow (maybe all to ansible, but have not tested).

Summary
-- 1D Cellular automata
-- v2? imminent gloom
--
--
-- adapted from elcos.lua
-- by zebra


g = grid.connect()

elca = require 'elca'

ca = elca.new()

local g_br = 4
local g_br_strong = 10

local rule_delay = 0
local name = 'rule'
local t_name = name

params:add_separator('1D CA')

params:add_control('rule', 'rule', controlspec.new(1, 256, 'lin', 1, 34, '', 1/256, true))
params:set_action('rule', function(x) ca.rule = x end)

params:add_control('offset', 'offset', controlspec.new(0, 119, 'lin', 1, 0, '', 1/120, false))
params:set_action('offset', function(x) ca.offset = x end)


-- creates and zeros 16x128 slot memory
function no_history()
    col = {}
    history = {}
    for y = 1, 128 do col[y] = 0 end
    for x = 1, 16 do history[x] = col end
end


-- clock function
function forever()
    while true do
        clock.sync (1/4)
        col = ca:window(128)
        table.insert(history, col)
        table.remove(history, 1)
        ca:update()
        -- Eurorack output modes:
        --crow_output_gate()
        crow_output_pulse()
        --crow_ansible_output()
        redraw_all()
    end
end


function init()
    c = clock.run(forever)
    no_history()
    ca.state[9] = 1
end


function g.key(x, y, z)
    y = params:get('offset') + y
    if z == 1 then
        if x == 16 then
            if ca.state[y] == 1 then ca.state[y] = 0 else ca.state[y] = 1 end
        elseif x > 4 then
            -- earlier rows - change the rule such that it would have produced a different value
            -- (and change the state too)
            local col = history[x-1]
            local l, r
            if y == 1 then l = col[128] else l = col[y-1] end
            if y == 128 then r = col[1] else r = col[y+1] end
            local c = col[y]
            local val
            if history[x][y] == 1  then val = 0 else val = 1 end
            history[x][y] = val
            ca.state[y] = c
            ca:set_rule_by_state(history[x][y], l, c, r)
            params:set('rule', ca.rule)
        end
    redraw_all()
    end
end


function key(n, z)
    if z == 1 then
        if n == 3 then
            ca:clear()
            no_history()
            redraw_all()
        end 
    end
end


function enc(n, d)
    if n == 1 then
        params:delta('clock_tempo', d)
        t_name = 'clock_tempo'
        name = 'bpm'
    end
    if n == 2 then
        params:delta('rule', d)
        t_name = 'rule'
        name = 'rule'
        end
    if n == 3 then
        params:delta('offset', d)
        t_name = 'offset'
        name = 'shift'
    end
    redraw_all()
end


function redraw()
    screen.clear()
    screen.font_face(10)
    screen.font_size(32)
    screen.move(1,56)
    screen.text(name .. ': ' .. params:get(t_name))
    if name ~= 'rule' then
        rule_delay = rule_delay + 1
    end
    if rule_delay == 10 then
        name = 'rule'
        t_name = name
        rule_delay = 0
    end
    screen.update()
end

function redraw_grid()
    local val
    for x = 1, 16 do
        if x == 16 then val = g_br_strong else val = g_br end
        local col = history[x]
        local z
        for y = 1, 8 do
            if col[y] == 1 then z = val else z = 0 end
            g:led(x, y, z)
        end
    end
    g:refresh()
end


function redraw_all()
    redraw()
    redraw_grid()
end


function crow_output_gate()
    for y = 1, 4 do 
        local col = history[16]
        local z
        if col[y] == 1 then z = 10 else z = 0 end
        crow.output[y].volts = z
    end
end


function crow_output_pulse()
    for y = 1, 4 do 
        local col = history[16]
        local z
        if col[y] == 1 then
            crow.output[y].action = "pulse(0.005)"
            crow.output[y]()
        end
    end
end


function ansible_crow_output()
    local col = history[16]
    local z
    for y = 1, 4 do 
        if col[y] == 1 then z = 1 else z = 0 end
        crow.ii.ansible.trigger(y, z)
    end
    for y = 5, 4 do 
        if col[y] == 1 then z = 10 else z = 0 end
        crow.ii.ansible.cv(y, z)
    end
end


function cleanup()
    
end

Hope it’s ok to resurrect.

1 Like