Hello

Hope you’re all going well.

Like many, I stumbled upon the works of Roland Kayn and the whole cybernetics movement with the 2008 reissue of his 3 LPs long Simultan.

I was amazed at how different, richer, more diverse it sounded compared to the works of early electronic pionneers using east or west coast synthesis.
The boxset includes diagrams and photos of the analog computer used for these compositions, and the liner notes mention the use of feedback loops.

I would recommend anyone interested to read the article on Wikipedia about Cybernetics, because it’s an example of transdisciplinary movement with researchs on IT, biology, psychology (Palo Alto), among others. I wish there would be more transdisciplinary approaches now !

Anyway, to get back to cybernetics in music, there was also a recent thread on Lines forum, which linked to videos on Youtube by composer La Synthèse Humaine. He uses a Serge modular synthesizer but I thought it would be nice to try and translate his experiments to SuperCollider.

I mentionned that yesterday at the wonderful Notam SC Meetup and people suggested we would start a thread on scsynth.org.
So here we are !

I’ve just started with the first video of La Synthèse Humaine.

  1. Feedback loop with a filter only.
    https://youtu.be/MnYkqlSIr_I?t=177
(
Ndef(\test, {
	var in, sig;
	in = LocalIn.ar(1) * -60.dbamp;
	sig = DFM1.ar(in, \filter_freq.kr(1000, 0.1), \filter_res.kr(0.1, 0.1));
	LocalOut.ar(sig);
	sig.tanh;
}).play;

Spec.add(\filter_freq, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\filter_res,[0, 1.5, 'lin', 0.001, 0.1].asSpec);
)

Ndef(\test).gui;
  1. Feedback loop with sine oscillator
    https://youtu.be/MnYkqlSIr_I?t=268
(
Ndef(\test, {
	var freq, sig;
	freq = LocalIn.ar(1);
	sig = DFM1.ar(SinOsc.ar(freq: freq * \sin_freq.kr(1.0, 0.1)), \filter_freq.kr(1000, 0.1), \filter_res.kr(0.1, 0.1));
	LocalOut.ar(sig);
	sig.tanh;
}).play;

Spec.add(\freq, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\sin_freq, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\filter_freq, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\filter_res,[0, 1.5, 'lin', 0.001, 0.1].asSpec);

Ndef(\test).gui
)
  1. Feedback loop with two sine oscillators and FM synthesis
    https://youtu.be/MnYkqlSIr_I?t=501
(
Ndef(\test, {
	var in, sig, sine1, sine2;
	in = LocalIn.ar(1);
	sine2 = SinOsc.ar(\sin2_freq.kr(440.0));
	sine1 = SinOsc.ar(freq: \sin_freq.kr(440.0) * (1 + (\fm_amount.kr(0) * sine2)) * in);
	sig = DFM1.ar(
		sine1,
		\filter_freq.kr(1000),
		\filter_res.kr(0.1)
	);
	LocalOut.ar(sig);
	LeakDC.ar(sig.tanh);
}).play;

Spec.add(\freq, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\sin_freq, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\sin_freq2, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\fm_amount, [0, 10, 'lin', 0, 0].asSpec);
Spec.add(\filter_freq, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\filter_res,[0, 1.5, 'lin', 0.001, 0.1].asSpec);

Ndef(\test).gui;
)

I am not sure my SC code is faithfull to the videos.
I don’t really know why I’m using the “*” operation with the feedback loop, and not the “+” operation (which was my first guess).
Also, I imagine that the delay introduced by LocalIn / LocalOut has an effect on the sound (phase delay ?) but I can’t really notice it.

Please discuss !

Best

Geoffroy

13 Likes
  1. Peak
    https://youtu.be/oGjpLmFJiT8?t=228

The Serge Peak output sounds a bit like the max of two signals with a slight distortion.
What do you think ?

(
Ndef(\test, {
	var in, sig, osc1, osc2;
	in = LocalIn.ar(1);
	osc1 = SinOsc.ar(freq: \osc1_freq.kr(150)) * \osc1_amp.kr(0.4);
	osc2 = SinOsc.ar(freq: \osc2_freq.kr(448)) * \osc2_amp.kr(-0.3);
	osc1.max(osc2).distort;
}).play;

Spec.add(\osc1_freq, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\osc2_freq, [0.1, 14000, 'exp', 0, 440, "Hz"].asSpec);
Spec.add(\osc1_amp, [-1, 1, 'lin', 0, 0].asSpec);
Spec.add(\osc2_amp, [-1, 1, 'lin', 0, 0].asSpec);

Ndef(\test).gui;
)
3 Likes

Hi there,

here is a contri with a favourite Cross FM patch of mine - this is dumb simple, yet it can keep me busy for hours riding the sliders in tiny steps and wonder at the impredictable results I’m getting: a perfect chaos theory primer in sound


// simple cross-FM, inspired by Joker Nies
(
Ndef(\xfm, { arg freqA = 32, freqB = 9, modAtoB=540, modBtoA=240;
	var fbIn = LocalIn.ar(2);
	var sigs = SinOsc.ar([freqA, freqB] + (fbIn.reverse * [modBtoA, modAtoB]));
	LocalOut.ar(sigs);
	sigs * 0.5;
}).play;

Spec.add(\freqA, [1, 10000, \exp]);
Spec.add(\freqB, [1, 10000, \exp]);
Spec.add(\modBtoA, [0, 1000, 5]);
Spec.add(\modAtoB, [0, 1000, 5]);

Ndef(\xfm).gui;
);

// some chaotic presets that display roughness, instabilities, or
Ndef('xfm').set('freqA', 9.0, 'freqB', 40.0, 'modAtoB', 205,  'modBtoA', 243.64);
Ndef('xfm').set('freqA', 5, 'freqB', 40.0, 'modAtoB', 90.0, 'modBtoA', 155); // try riding the modBtoA slider just slightly with the arrow buttons > find completely different states; hysteresis when returning. Pitch may move in reverse.
Ndef('xfm').set('freqA', 14, 'freqB', 6.69, 'modAtoB', 151, 'modBtoA', 402);

Ndef('xfm').set('freqA', 5, 'freqB', 40.0, 'modAtoB', 90.0, 'modBtoA', 204); // chaotic oscillation between several states

// settling after a short while - press 'send' on the GUI to restart process deterministically
Ndef('xfm').set('freqA', 5.0, 'freqB', 6.36, 'modAtoB', 342.65, 'modBtoA', 448.48);
Ndef('xfm').set('freqA', 223.46, 'freqB', 6.69, 'modAtoB', 70.57, 'modBtoA', 726.15);
Ndef('xfm').set('freqA', 18, 'freqB', 40.0, 'modAtoB', 90.0, 'modBtoA', 172.0);

// ideas to extend:
// - add sample-and-hold
// - more than 2 operators in circle feedback topology

Quite certainly, the delay introduced by LocalIn / LocalOut does have an effect on the sound; one can test different configurations with different blockSizes, and the above feedback patch behaves slightly differently

s.options.blockSize_(64 * 4);
s.options.blockSize_(64); // default
s.options.blockSize_(2);
s.options.blockSize_(1);
s.reboot;

but the question is, different effects in relation to what? The lower we go with the blocksize, the more we approximate the analog world, but it’s clear that in relation to electrons’ flow, 1 sample is wayyy long, and we’ll never get really close to the analog with our digital systems.
So, tuning to the sonic result will usually be all that’s needed.

Bests,
Hannes

1 Like

I tried both, and they create wildly different sounds! In fact, any or all of the “*” in that line can be changed to “+” to get very different sounds. As you have it, the frequency will always modulate between positive and negative values (since in is bipolar), which appears to create a more chaotic sound. Using addition instead of multiplication will result in more of a classic FM sound, as this is the standard technique for FM synthesis to add the modulator to the frequency.

Even in the simplest FM synth with 1 modulator and 1 carrier, using multiplication instead of addition creates a much different sound:

(
Ndef(\freqadd, {// frequency + modulator (classic FM sound)
    var freq = MouseY.kr(20, 4000, 1);
    var mratio = MouseX.kr(1/8, 8, 1);
    var mod = SinOsc.ar(freq * mratio) * freq * mratio * \index.kr(5);
    var car = SinOsc.ar(freq + mod);
    car = LeakDC.ar(car);
    car = Pan2.ar(car, \pan.kr(0), \amp.kr(0.3));
}).play;
)

(
Ndef(\freqmul, {// frequency * modulator (more chaotic sounding)
    var freq = MouseY.kr(20, 4000, 1);
    var mratio = MouseX.kr(1/8, 8, 1);
    var mod = SinOsc.ar(freq * mratio) * freq * mratio * \index.kr(5);
    var car = SinOsc.ar(freq * mod);
    car = LeakDC.ar(car);
    car = Pan2.ar(car, \pan.kr(0), \amp.kr(0.3));
}).play;
)

…or use both addition and multiplication, and cross-feedback them into each other (thanks, weego, for the cross-feedback idea :slight_smile:):

(
Ndef(\crossfeedback, {
    var freq = MouseY.kr(20, 4000, 1);
    var mratio = MouseX.kr(1/8, 8, 1);
    var in = LocalIn.ar(2);
    var mod = SinOsc.ar(freq * mratio) * freq * mratio * \index.kr(5);
    var car = SinOsc.ar([freq * mod * in[1], freq + mod + in[0]]);
    LocalOut.ar(car * \fb.kr([10, 5]));
    car = LeakDC.ar(Mix(car));
    car = Pan2.ar(car, \pan.kr(0), \amp.kr(0.3));
}).play;
)

Crossfeedback with the single sample feedback is super cool. I wouldn’t say it is better than going with the block size, but it has a different flavor.

I started making some single sample feedback versions using Faust (compiled for SC):

https://github.com/spluta/SPSynthTools/tree/master/CrossfeedbackSynthesis

I might still make a quark out of it. There is a nice example in the CrossSineTri help file, but that is the only help file I got to.

The easiest solution would probably be to use Daniel Mayer’s fb1 in the miscellaneous quark, though I haven’t done that myself yet.

Sam