Experimenting with a new way to do FM Synthesis in Tidal

SuperCollider code:

(
s.waitForBoot {

	~dirt.free;
	~dirt = SuperDirt.new(2, s);
	~numberOfOrbits = 12;

	//FM
	~numberOfOperators = 6;
	~fmbuses = ({Bus.audio(s,2)}!(~numberOfOperators-1));
	(
		SynthDef(\fmsine,{ |out,freq=440,speed=1,fmamp=0,fmin=1,gain=1,pan=0.5,sustain=1,decay=0|
			var env, sound, fm, buses;
			buses = [out]++~fmbuses;
			env = EnvGen.ar(Env.pairs([[0,0],[0.007,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -3),
				timeScale:sustain, doneAction:2);
			freq = freq*speed.abs;
			fm = In.ar(Select.kr(fmin,buses),2)*freq*fmamp;
			sound = SinOsc.ar(freq+fm,0,env)*gain;
			Out.ar(out,
				DirtPan.ar(sound, ~dirt.numChannels, pan, env)
			)
		}).add;
	);

	s.sync;
	~dirt.start(57120, 0!~numberOfOrbits++[0]++~fmbuses);
};
);

Haskell:

let fmin i amp = (# pI "fmin" i) . (# pF "fmamp" amp)
    fmout o = orbit (12+o)
    fm output = (# s "fmsine") . (# fmout output)

Tidal example:

d1 $ stack[
    fm 0 $ fmin 1 6 $ note "<0 7 12 19>" # octave 3
    ,fm 1 $ fmin 2 16 $ sometimes (jux (|+ note 12)) $ note "0(7,16)" # shape 0.5 # release 0.2 # legato 4
    ,fm 1 $ fmin 3 6 $ note "<0 7>*16?" # octave 3 # speed 7 # pan rand # attack 0.15 # gain 1.2
    ,fm 2 $ note "[12 ~] [<~ 0> 7]"
    ,fm "[3|2|1]" $ note "7*4?" # octave 7
]

Audio of the example, adding one element of the stack (so, one line of code) at a time:

The idea is having the final 6 orbits reserved for FM Synthesis, let's call them channels for now. Channel 0 is the one you can hear, and the rest of them work as modulators. And you can make all these channels interact with each other.

In the Tidal code you see this:
fm 0 -> outputs to FM channel 0
fm 0 $ fmin 1 6 -> outputs to channel 0, modulating the frequency using channel 1, and the modulation amplitude is 6.

The modulation is stereo; and outputs, inputs and mod amplitudes can be pattern'd. And because every channel is a SuperDirt orbit you can use all the effects like reverb, distortion, etc.

7 Likes

This is super interesting...

It seems a little more accessible than the superfm syntax albeit less flexible (that's usually the way)

Do you have any audio/video samples of it in action?

1 Like

there you goo,, edited the post and added audio of the example given above

1 Like

Hello,
Looks rad, hyped to give it a go.
Do you think at some point we could lower the number of operators, and do some PM over some samples or other synthdefs playing on orbits 1 and 2?
Thank you, have a nice day

1 Like

About the number of operators:
-I just changed the code in the post and made it more understandable, you should easily be able to change the amount of operators.

About modulating using other synthdefs/samples:
The fmout function still works on any pattern, so yes.
You could also have it happen simultaneously:

d1 $ fm 0 $ fmin 1 20 $ note "<0 7 3 7>" # octave 3
d2 $ superimpose ((# fmout 1) . (sometimes (ply 2))) $ s "bd*2"
1 Like

Awesome, thanks a lot !