Skip to content

Instantly share code, notes, and snippets.

@colinbdclark
Last active January 1, 2016 21:09
Show Gist options
  • Save colinbdclark/8201964 to your computer and use it in GitHub Desktop.
Save colinbdclark/8201964 to your computer and use it in GitHub Desktop.
Flocking version of the first example in the Mark Polishook's SuperCollider FM synthesis tutorial
/*
// Original SuperCollider code.
(
SynthDef("fm1", {
arg bus = 0, freq = 440, carPartial = 1, modPartial = 1, index = 3, mul = 0.05;
// index values usually are between 0 and 24
// carPartial :: modPartial => car/mod ratio
var mod = SinOsc.ar(
freq * modPartial,
0,
freq * index * LFNoise1.kr(freq: 0.2, mul: 0.5, add: 0.5)
);
var car = SinOsc.ar(
freq * carPartial + mod,
0,
mul
);
Out.ar(
bus,
car
);
}).add;
)
Synth("fm1", [\bus, 0, \freq, 440, \carPartial, 1, \modPartial, 2.4]);
Synth("fm1", [\bus, 1, \freq, 442, \carPartial, 1, \modPartial, 2.401]);
*/
// Flocking version.
// This version uses a single synth with different values for the left and right trees of unit generators.
// The SuperCollider version uses two different synths in order to ensure that each channel can be setup
// with different values without having to cut and paste. Infusion's IoC and options merging functionality
// enables this to be done without the overhead of an extra synth.
//
// You can see that there are a number of awkward points with the Flocking version:
// 1. the current inability to share unit generator references, requiring the frequency to be set
// in three separate places in the unit generator tree.
// 2. the inability to define flat "variable names," requiring the use of somewhat awkward EL paths
// (e.g. "mod.freq.mul" instead of "modPartial") and nested options structures when defining options
// overrides (e.g. { modUGenDef: { freq: { mul: 2.4 }}}).
// 3. the user needs to manually set flock.ugen.value to the correct rate; ideally there should be an
// "automatic" rate that enables the unit generator to set its rate based on the rates of its inputs.
//
// These issues will be addressed over time by:
// 1. enabling in-tree references to unit generators so that diamond-shaped graphs can be created
// and ugens can be shared throughout the tree
// 2. a user-defined "flat model" for synths, which enable users to map flat names to nested paths
// (e.g. inputs: { "modPartial": "mod.freq.mul", "freq": ["car.freq.value", "mod.freq.value", "mod.mul.value"] })
// (this also solves #1, though in a less efficient way)
// 3. support for "auto" rate unit generators in the core
fluid.defaults("flock.fmSynth", {
gradeNames: ["flock.synth", "autoInit"],
components: {
left: {
type: "flock.fmSynth.ugens",
options: {
carUGenDef: {
freq: {
value: 440
}
},
modUGenDef: {
freq: {
value: 440,
mul: 2.4
},
mul: {
value: 440
}
}
}
},
right: {
type: "flock.fmSynth.ugens",
options: {
carUGenDef: {
freq: {
value: 442
}
},
modUGenDef: {
freq: {
value: 442,
mul: 2.401
},
mul: {
value: 442
}
}
}
}
},
synthDef: {
ugen: "flock.ugen.out",
sources: [
"{left}.options.ugens",
"{right}.options.ugens"
]
}
});
fluid.defaults("flock.fmSynth.ugens", {
gradeNames: ["fluid.littleComponent", "autoInit"],
carUGenDef: {
id: "car",
ugen: "flock.ugen.sin",
mul: 0.05,
phase: 0,
freq: {
ugen: "flock.ugen.value",
rate: "audio",
value: 440, // freq
mul: 1 // carPartial
add: "{that}.options.modUGenDef"
}
},
modUGenDef: {
id: "mod",
ugen: "flock.ugen.sin",
freq: {
ugen: "flock.ugen.value",
value: 440 // freq
mul: 1 // modPartial
},
phase: 0,
mul: {
ugen: "flock.ugen.value",
value: 440, // freq
mul: {
ugen: "flock.ugen.value",
value: 3 // index
mul: {
ugen: "flock.ugen.lfNoise",
rate: "control",
freq: 0.2,
options: {
interpolation: "linear"
},
mul: 0.5,
add: 0.5
}
}
}
},
ugens: "{that}.options.carUGenDef"
});
var synth = flock.fmSynth();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment