Nasty pop when modulating curve argument of lincurve()

At the moment nothing of this looks wrong or surprising to me. First, I’d rather regard ar, in a modulation context like this, especially when checking things, you want exact calculation.

But also with kr the last two variants sound the same to me (tested on 3.9.3 and 3.11.2).

One guess: there was an update of lincurve with 3.9. Are you running an older SC version? If so, you can try this variant

// this provides the newer version of lincurve for older SC versions with DX UGens
// Credits to Tim Blechmann and Julian Rohrhuber


+ UGen {
	lincurve_3_9 { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax;
		var grow, a, b, scaled, curvedResult;
		if (curve.isNumber and: { abs(curve) < 0.125 }) {
			^this.linlin(inMin, inMax, outMin, outMax, clip)
		};
		grow = exp(curve);
		a = outMax - outMin / (1.0 - grow);
		b = outMin + a;
		scaled = (this.prune(inMin, inMax, clip) - inMin) / (inMax - inMin);

		curvedResult = b - (a * pow(grow, scaled));

		if (curve.rate == \scalar) {
			^curvedResult
		} {
			^Select.perform(this.methodSelectorForRate, abs(curve) >= 0.125, [
				this.linlin(inMin, inMax, outMin, outMax, clip),
				curvedResult
			])
		}
	}
}

+ AbstractFunction {
	lincurve_3_9 { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax;
		^this.composeNAryOp('lincurve_3_9', [inMin, inMax, outMin, outMax, curve, clip])
	}
}

+ SequenceableCollection {
	lincurve_3_9 { arg ... args; ^this.multiChannelPerform('lincurve_3_9', *args) }
}

+ SimpleNumber {
	lincurve_3_9 { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax;
		var grow, a, b, scaled;
		switch(clip,
			\minmax, {
				if (this <= inMin, { ^outMin });
				if (this >= inMax, { ^outMax });
			},
			\min, {
				if (this <= inMin, { ^outMin });
			},
			\max, {
				if (this >= inMax, { ^outMax });
			}
		);
		if (abs(curve) < 0.001) {
			// If the value should be clipped, it has already been clipped (above).
			// If we got this far, then linlin does not need to do any clipping.
			// Inlining the formula here makes it even faster.
			^(this-inMin)/(inMax-inMin) * (outMax-outMin) + outMin;
		};

		grow = exp(curve);
		a = outMax - outMin / (1.0 - grow);
		b = outMin + a;
		scaled = (this - inMin) / (inMax - inMin);

		^b - (a * pow(grow, scaled));
	}
}

FWIW, I’ve described the math of lincurve here: