Or, another example illustrating the relationship to the formula in the website:
// we want an envelope segment from 0 to 1,
// with y = 0.25 at the midpoint
c = ~curve.(0, 0.25, 1); // 2.1972245773362
// with an odd number of samples, (n-1)/2 is the exact midpoint
n = 32769;
// client-side
a = Array.fill(n, { |i| i.lincurve(0, n-1, 0, 1, c) });
// now... compare to the server-side EnvGen,
// with the same curve
s.boot;
b = Buffer.alloc(s, n, 1);
(
z = {
RecordBuf.ar(
EnvGen.ar(
Env([0, 1], [1], c),
timeScale: n * SampleDur.ir
),
b, loop: 0, doneAction: 2
);
Silent.ar(1)
}.play;
)
b.getToFloatArray(wait: -1, action: { |data| d = data });
// plots look the same
[a, d.as(Array)].flop.plot(numChannels: 2);
a[(n-1) div: 2] // 0.25
d[(n-1) div: 2] // 0.24998745322227
Server-side, the envelope segment’s phase may be slightly different from the client-side lincurve array, but practically speaking, nobody is going to notice a deviation that is 4 orders of magnitude smaller than the range.
So – the ~curve
function does produce a valid curve value, and this curve value works for client-side lincurve and curve-style envelope segments. So I suspect that the assertion that it doesn’t seem to be an envelope curve is based on a misunderstanding, somewhere.
I dusted off this old function because it allows SC to implement something that is basically the same as Vital, Serum, Massive, Surge XT etc. etc. curved control-point segments. I don’t think it’s an accident that the curve in all of these environments is based on the y value halfway through the segment – lincurve involves exp(curve) ** normalized_x
, which at the midpoint is exp(curve) ** 0.5
, and, solving for curve, it’s significantly easier to handle this square root than it is to handle any other exponent where 0 < x < 1.
Based on those observations, I’m guessing that they are all using something similar to lincurve… which, if true, would suggest that lincurve-style calculations are quite common in digital synths.
hjh