As ever, this was a misunderstanding on my part, I found out that the envelope does get retriggered - it's just that it doesn't start at the specified start point. It always starts at the current value. This actually makes sense, since an envelope could be retriggered before it had finished, in which case you wouldn't want it to suddenly jump down to the start point.
So the only problem with the code I posted is that once the envelope has run once, each subsequent time it runs it goes from the current value, which is the envelope's end point, to the envelope's end point - i.e. the envelope doesn't change anything.
The following code demonstrates that the start point is kind of irrelevant and illustrates the kind of behaviour I was after:
(
SynthDef(\test,
{
|freq = 300, on = 1, amp = 0.2, t_pitchEnv = 0, pitchEnvEnd = 1|
var audio, onswitch, pitchEnv;
onswitch = EnvGen.kr(Env.cutoff(5, curve: \exp), on, doneAction:2);
pitchEnv = EnvGen.kr(Env.new([0, pitchEnvEnd], [1], \sine), t_pitchEnv) * freq;
audio = SinOsc.ar(freq + pitchEnv, mul: amp * onswitch);
Out.ar(0, audio ! 2);
}
).add;
)
x = Synth(\test);
x.set(\t_pitchEnv, 1, \pitchEnvEnd, 1);
x.set(\t_pitchEnv, 1, \pitchEnvEnd, 2);
x.set(\t_pitchEnv, 1, \pitchEnvEnd, 1);
x.set(\t_pitchEnv, 1, \pitchEnvEnd, 0);
x.set(\on, 0);