Synthèse à tables d’ondes

Esquisses musicales et notes éparses.
8 avril 2019

Je suis présentement en train d’apprendre les rudiments de la synthèse à tables d’ondes (“wavetable synthesis”) avec SuperCollider, et je vais rassembler ci-dessous mes notes de travail et mes premières esquisses musicales. J’ai commencé mon apprentissage grâce à cette excellente vidéo de Eli Fieldsteel, qui lui-même prend une part de son matériel dans la documentation de la classe Shaper.

Tout commence par la création d’une table d’ondes :

~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);
)

On crée tout d’abord un Signal, on le remplit avec la méthode waveFill, puis on le transforme en Wavetable, puis en Buffer. L’expression sin(x.cubed * 20) qui remplit le Signal a été écrite arbitrairement après plusieurs essais, et j’aime beaucoup le son qu’elle produit.

Altérations et 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 de signaux

Création de seize signaux différents qui représentent seize différentes interpolations entre deux signaux originaux :

// 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;

La transformation de ~sigArr vers ~bufArr pourrait aussi être faite avec une étape en moins :

(
~bufArr = {
    |i| 
    Buffer.loadCollection(s, ~sigArr[i].asWavetableNoWrap);
}!~sigArr.size;
)