Wavetable synthesis
I’m currently learning the basics of wavetable synthesis with SuperCollider, and I will gather my notes and my first musical sketches below. I started to learn with this excellent video by Eli Fieldsteel, who takes part of his material in the documentation of the Shaper class.
It all begins with the creation of a wavetable:
~sig = Signal.newClear(513);
(
~sig.waveFill({
arg x, y, i;
// i.linlin(0, 512, -1, 1);
// sin(x);
sin(x.cubed * 20);
}, 0, 1);
~sig.plot;
~w = ~sig.asWavetableNoWrap;
~b = Buffer.loadCollection(s, ~w);
)
We create an instance of Signal, we fill it with the waveFill method, we transform it into an instance of Wavetable, and then load it into a Buffer. The expression sin(x.cubed * 20) used to fill the Signal was written arbitrarily and I really love the sound that it produces.
Alterations and interpolations
(
~sigB = Signal.fill(256, {
|i|
var t = i / 255.0;
t + (0.1 * (max(t, 0.1) - 0.1) * sin(2pi * t * 80 + sin(2pi * 25.6 * t)));
});
)
(
~sigA.waveFill({
arg x, y, i;
// i.linlin(0, 512, -1, 1);
// sin(x);
sin(x.cubed * 20);
}, 0, 1);
)
~w = ~sigB.asWavetableNoWrap;
~sigA = Signal.newClear(513);
~sigB = Signal.newClear(513);
~sigC = Signal.newClear(513);
~sigB.size;
~sigC = (~sigA * 0.75) + (~sigB * 0.25);
~sigC = (~sigA * 0.9) * (~sigB * 0.1);
~sigC = (~sigA * 1) * (~sigB * 0.15);
~sigC = ~sigA * ~newSig;
~sigC.overDub(~sigB);
~sigA.plot;
~sigB.plot;
~sigC.plot;
~sigB;
~sigC = ~sigA.blend(~sigB, 2);
(~sigB + (~sigA * 0.1)).plot;
~sigC = (~sigB + (~sigA * 0.1));
(
~sigB = Signal.fill(513, { |i|
var t = i/512.0;
t + (0.1 * (max(t, 0.1) - 0.1) * sin(2pi * t * 80 + sin(2pi * 25.6 * t)))
});
)
~newSig = Array.interpolation(513, 0, 1);
~newSig.fill(Array.interpolation(513, 0, 1));
~newSig = Signal.newClear(513);
~newSig;
Signal[1, 2, 3, 4].blend(Signal[5, 5, 5, 0], 2);
~sigArr = {|i| ~sigA.blend(~sigB, i.linlin(0, 16, 1, 1.5));}!16;
~sigArr = {|i| (~sigB + (~sigA * i.linlin(0, 16, 0.1, 1)));}!16;
~sigArr[15].plot;
~wvArr = {|i| ~sigArr[i].asWavetableNoWrap;}!~sigArr.size;
~bArr = {|i| Buffer.loadCollection(s, ~wvArr[i]);}!~wvArr.size;
~b.bufnum;
Collections of signals
Creation of sixteen different signals by making sixteen different interpolations between two original signals:
// We create an array filled with 16 instances of Signal.
// Each instance is a different blend between ~sigA and ~sigB.
~sigArr = {|i| ~sigA.blend(~sigB, i.linlin(0, 16, 1, 1.5));}!16;
// We create an array with all those signals stored as Wavetables.
~wavArr = {|i| ~sigArr[i].asWavetableNoWrap;}!~sigArr.size;
// One last array, with those wavetables stored as buffers.
~bufArr = {|i| Buffer.loadCollection(s, ~wavArr[i]);}!~wavArr.size;
The transformation from ~sigArr to ~bufArr could also be made by skipping one step:
(
~bufArr = {
|i|
Buffer.loadCollection(s, ~sigArr[i].asWavetableNoWrap);
}!~sigArr.size;
)