Hi,
.) In general I think it’s more comfortable to use BufRd for waveshaping than Shaper for two reasons:
(a) BufRd avoids the need to fiddle around with the wavetable format.
(b) BufRd allows to choose different interpolation modes including cubic.
There might be performance advantages when using a lot of shapers, though I never encountered a situation where this played a role.
.) I find it interesting to take arbitrary waveforms, including recorded sounds, as a transfer function. I’ve included some examples for this in my last year’s TU Berlin workshop:
https://daniel-mayer.at/materials/Berlin_2020/UOS_2020_TUBerlin.zip
UOS_02_buffer_modulation.scd
.) Alternatively you can define a dynamic waveshaper by a combo of mathematical operators. As an advantage this allows more modulation options as parameters of the shaper can be controlled by signals. E.g. a parametric saturation function by Partice Tarrabia and Bram de Jong
https://www.musicdsp.org/en/latest/Effects/42-soft-saturation.html
// amount must be >= -1 and < 1 !
(
f = { |x, amount = 0|
var k = 2 * amount / (1 - amount);
(1 + k) * x / (1 + (k * x.abs));
};
{ |x| f.(x, 0.5) }.plotGraph(500, -1, 1);
)
{ |x| f.(x, -0.9) }.plotGraph(500, -1, 1);
{ |x| f.(x, 0) }.plotGraph(500, -1, 1);
{ |x| f.(x, 0.9) }.plotGraph(500, -1, 1);
(
SynthDef(\flexShape, { |out = 0, in, mix = 1, amount = 0, amp = 1|
var sig = In.ar(in, 2), k = 2 * amount / (1 - amount);
sig = (1 + k) * sig / (1 + (k * sig.abs));
XOut.ar(out, mix, sig * amp);
}).add;
)
// start silently
y = Synth(\flexShape);
// default amount = 0, no change
x = { SinOsc.ar(300 + [0, 0.1], 0, 0.2) }.play
y.set(\amount, 0.5, \amp, 0.3)
y.set(\amount, 0.9, \amp, 0.1)
x.release;
y.free