Cellular Automata: Pattern classes and UGens

Hi everyone. I managed to resurrect an old project of mine (2009 ish) and to compile the UGens. Pattern classes aside these are some noisy stuff but I hear them in new light after 10+ years!

what

  1. UGens (CA1, CA2) and
  2. Patterns (Pca1, Pca2) classes

implementing elementary cellular automata

i hope you enjoy it.

11 Likes

just put up a video demoing potential use of the pattern stuff

2 Likes

I guess this only works in OSX? I get an error when compiling.

Looks really cool though! Nice work.

Hey. I can check on my Windows machine. What error is it? The UGen binary is macos but you can compile one from source.

hey, im having the same issues. can you explain how the compiling process is done on a windows maschine? thanks alot :slight_smile:

The class library (Pca1, Pca2) i used in the above video works just fine on Windows.
Now, if you want to use the UGens, compiling them … is a much more involved process.

found an excellent instruction:

I’ll try to build on my win machine when i have time and share the binary.

another note to installation:
you may need to create an Extensions folder manually if you do not have one. otherwise Quarks will not be able to install the class files.

Small detail: Actually quarks are downloaded into downloaded-quarks and installed by adding them to the language-configuration “include” directory list. Quarks don’t use the Extensions directory at all.

UGens should go into extensions.

hjh

1 Like

Thanks James. Is it not advisable use quarks to install libraries which include UGens then?

The Ambisonics Toolkit is a reasonable model here – a quark provides the SC classes, and the UGen binaries come from somewhere else. (In the case of ATK, the UGens are in sc3-plugins, but that’s not a requirement.)

There have been discussions about how to make things easier, but I don’t recall anything concrete coming of them.

The one other option you could consider might be to bundle binaries in the quark, and adjust the ServerOptions ugenPluginsPath – but the behavior of this property is a little tricky. If it’s empty, the server will use hardcoded default locations (per platform), but if it’s provided, that the server will skip the default locations – so, if one of your classes is changing this property, you would be responsible for filling in the default locations as well :woozy_face: … so not a lot of people take this approach.

hjh

(PS Did I meet you in Seoul some years ago? Glitchy stuff made by playing binary executable file data?)

hey, ive just used the Pca1 Pattern Class now and was trying to implement your Routine from the Youtube Tutorial in a Pbind and need some help.

(
SynthDef(\test, {
	arg out=0, pan=0, amp=0.35, freq=150;
	var env = EnvGen.kr(Env.perc(0.01,0.85), doneAction:2);
	var sig = Saw.ar(freq);
	sig = Pan2.ar(sig, pan, amp);
	Out.ar(out, sig);
}).add;
)

(
Pdef(\test,
	Pbind(
		\instrument, \test,

		\dur, 1,

		\cellular, Pn(Plazy {|event|
			Pca1({2.rand}!9, 90)
		}, inf),

		\root, 0,
		\octave, 5,
		\scale, Scale.lydian,
/*
		\degree, Pn(Plazy {|event|
				event[\cellular].do { |gate, i|
					if(gate == 1, {
						i + event[\scale].degrees
					});
				}
			}, inf).trace,
*/
		\degree, Pn(Plazy {|event|
			event[\cellular] * event[\scale].degrees
		},inf).trace,
		
		\amp, 0.05,
	)
).play;
)

I think when the result of Pca1 is just multiplied with the Scale degrees its not yielding the same results. Especially when you increase the size of the Pca1 array you dont get higher note values, as you did in the Tutorial.
Do you have an idea how i can implement the Routine for the Scale mapping of Pca1 in a Pbind?
I was also trying with Prout and loop but i dont need the waittime. it should always give a new value with each new duration.
thanks alot :slight_smile:

yes, we met in Seoul indeed! the glitchy stuff :wink: i hope we can meet somewhere again.

hi.

this works for me;

(
SynthDef(\test, {
	arg out=0, pan=0, amp=0.35, freq=150;
	var env = EnvGen.kr(Env.perc(0.01,0.85), doneAction:2);
	var sig = Saw.ar(freq);
	sig = Pan2.ar(sig, pan, amp);
	Out.ar(out, sig);
}).add;
)
// add this
(
~d2k = { |degree, mode|
	var size = mode.size;
	var deg = degree.asInteger;
	12 * deg.div(size) + mode[deg%size];
};
)
(
Pdef(\test,
	Pbind(
		\instrument, \test,
		\dur, 1,
		\cellular, Pn(Plazy {|event|
			Pca1({2.rand}!12, 90)
		}, inf),
		\root, 0,
		\octave, 5,
		\scale, Scale.lydian,
		\degree, Pn(Plazy {|event|
			var list = List[];
			event[\cellular].do { |cell,i|
				if(cell == 1, {
					list.add(~d2k.(i, event[\scale].degrees)) 
				});
			};
			// return
			list
		}, inf).trace,
		\amp, 0.05,
	)
).play;
)

because how degreeToKey is handled in Patterns is different,
i use my own ~d2k function and iterate inside Plazy…

I don’t use patterns anymore so not sure if this is the best way but it does the job!

1 Like

thank you. its working great :slight_smile:

when i put Pca1 withinf the pattern gets stuck after a while. it should be on 1 when its inside a Pn(Plazy right?

		\cellular, Pn(Plazy {|event|
			Pca1({2.rand}!12, 90, inf)
		},inf).trace,

compare:

\cellular, Pn(Plazy {|event|
    			Pca1({2.rand}!12, 90, 1)
    		},inf).trace,

actually you dont need the plazy there:

(
SynthDef(\test, {
	arg out=0, pan=0, amp=0.35, freq=150;
	var env = Env.perc.kr(2);
	var sig = Saw.ar(freq);
	sig = Pan2.ar(sig, pan, amp * env);
	Out.ar(out, sig);
}).add;

~d2k = { |degree, mode|
	var size = mode.size;
	var deg = degree.asInteger;
	12 * deg.div(size) + mode[deg%size];
};
)
(
Pdef(\test,
	Pbind(
		\instrument, \test,
		\dur, 0.1,
		\cellular, Pca1({2.rand}!12, 110, inf),
		\root, 0,
		\octave, 5,
		\scale, Scale.lydian,
		\degree, Plazy({ |e|
			var list = List[];
			e[\cellular].do { |cell,i|
				if(cell == 1, {
					list.add(~d2k.(i, e[\scale].degrees)) 
				});
			};
			// return
			list
		}).loop.trace,
		\amp, 0.05,
	)
).play;
)

you can also use .loop instead of Pn(…, inf)

hey, thanks for the help again. i thought i would use it so i can acces the \rules key and sequence it separately.

\rules, Pseq([Pn(90, 10), Pn(110, 3)], inf),
\cellular, Pn(Plazy {|event|
	Pca1(Array.fill(12, { |i| 2.rand }), event[\rules], 1)
}, inf),

if you just want to hook a pattern to rule you can just do it:

w = Pca1(Array.fill(480, { |i| 2.rand }), Pbrown(0,255,5).stutter(Pbrown(1,80,4))).plot(800);

Thanks alot. Do you have an idea for a Function which could Transform an Array with midi notes for example a G Dorian Voicing [31,43,57,64,70,76,77], to an Array of 0 and 1 to Act as the initial cell for the cellular automata?

i’d assign a number to a scale and then convert that to binary digits to get array of bits:

var g_dorian = 255;
g_dorian.asBinaryDigits(numOfBitsYouWant)