Question

I'm trying a use a non-returning envelope (i.e. the segments in it do not return to 0). I'm finding that the envelope env cannot be triggered more than once in the following code:

(
SynthDef(\stupidSynth,
    {
        |t_trig|
        var env, envShape, audio, env2;
        envShape = Env.new([0, 1], [0.5], \sine);
        env = EnvGen.kr(envShape, t_trig);
        env2 = EnvGen.kr(Env.perc, t_trig);
        audio = SinOsc.ar(400 + (env * 100)) * env2 * 0.1;
        Out.ar(0, audio);
    }
).add;
)

(
p = Pmono(*[
    \stupidSynth,
    \t_trig, 1
]
).play;
)

What I was hoping for was that whenever the synth is retriggered, the pitch would get higher and higher. What actually happens is that the first note plays the pitch envelope, and each subsequent note is just at the final (i.e. high) frequency. env is clearly not being retriggered.

I'm not sure why this would be. Envelopes don't have to have returned to 0 before they can be retriggered - it's perfectly possible to retrigger an envelope before it's finished. There's something about my envelope that isn't working.

I'm basically looking for something with the behaviour of Line, but also able to be retriggered and have a customisable curve.

Is what I'm trying to do possible?

Was it helpful?

Solution

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

OTHER TIPS

There is nothing wrong with the envelope. You're thinking as if the envelope should behave as if whenever it gets retriggered, it "adds" its new output to whatever it was outputting before - that's not how envelopes behave. Triggering an envelope always makes it jump to the restarting point (usually the start). There is no concept in Env or EnvGen of a kind of long-term memory of what was output.

Ways to do what you want:

1) Instead of using an envelope to achieve the "memoryfull" behaviour, use something like an integrator followed by a lag:

(
SynthDef(\stupidSynth,
    {
        |t_trig|
        var env, envShape, audio, env2, note;
        note = 67 + Integrator.kr(t_trig * 5).lag(0.2); /* up by 5 semitones at a time */
        env2 = EnvGen.kr(Env.perc, t_trig);
        audio = SinOsc.ar(note.midicps) * env2 * 0.1;
        Out.ar(0, audio);
    }
).add;
)

(
p = Pmono(*[
    \stupidSynth,
    \t_trig, 1
]
).play;
)

2) If you desperately want to use Env to achieve the effect (e.g. for the fine control over shape), then you could separate your synth into two: one which reads the current frequency from a Bus and is a single long-lived synth, and one synthdef which you create multiple instances of and which outputs from an env to the bus. Then whenever you trigger you create a new instance added to the pile of instances for that latter synthdef. (Messy huh.)

3) I bet there's a trick you can do by using the EnvGen as you are doing, but also simply incrementing the base frequency every time you get a trigger. Tricksy but may work fine.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top