Envelopes and LocalIn

All the help files and tutorials have the Out.ar like this:

Out.ar(out, sig * env)

where you multiply the signal by the envelope you want to apply to it. I’ve been doing that sort of fine so far, but now when using LocaIn abd LocalOut, I am having weird issues, and I’m not sure if this is a bug, or just that I don’t understand what’s happening.

Here, I have not applied env1 to anything, but it is still applied to the Synth when I play it.

(
SynthDef(\what, {
	arg freq=200, gate=1, out=0, amp=0.5, neg=1e-2;
	var in, env, sig, del, lo, li, env1, env2;
	env1 = EnvGen.ar(Env.new([0,1,0],[0.001,0.1]), doneAction:2);
	//env2 = EnvGen.ar(Env.new([0,1,1,0],[0.001,1,1]),gate, doneAction:2);
	in = LocalIn.ar(2);
	del = DelayN.ar( 
		    LeakDC.ar(
			in), 1, neg);
	sig = LPF.ar(
		Trig1.ar( //takes any signal and when 0-1, outputs "1", otherwise 0's
			Amplitude.kr(del, 5, 120)
			* 1.5 + del + neg - (Dust.ar(1)), 4e-3)
		* 0.1+del*0.99, 1200); // LPF in and frequency
	LocalOut.ar(sig);
	Out.ar(out, in);
}).play;
)

Very weird to me.

My end goal was to have an envelope around the Dust.ar first, before it goes through the feedback, so that the trigger is only triggered once, like one impulse (I couldn’t find any other Ugen that just triggers one time…I’m sure I’m missing something here) but then I was going to apply env2 to the whole thing ( Out.ar(out, sig * env2)

I’d really like to use a lot of envelopes inside a synthdef for sound shaping but maybe this isn’t possible?

Here “applied” is ambivalent. You don’t multiply the ugen but it’s yet running and doneAction has the consequence of freeing the synth. You could use the EnvGen with the (default) doneAction 0 and a DetectSilence for freeing, that way you use the natural decay and don’t need a second envelope:

(
SynthDef(\what, {
	arg freq=200, gate=1, out=0, amp=0.5, neg=1e-2;
	var in, env, sig, del, lo, li, env1, env2;
	env1 = EnvGen.ar(Env.new([0,1,0],[0.001,0.1]));
	//env2 = EnvGen.ar(Env.new([0,1,1,0],[0.001,1,1]),gate, doneAction:2);
	in = LocalIn.ar(2);
	del = DelayN.ar( 
		    LeakDC.ar(
			in), 1, neg);
	sig = LPF.ar(
		Trig1.ar( //takes any signal and when 0-1, outputs "1", otherwise 0's
			Amplitude.kr(del, 5, 120)
			* 1.5 + del + neg - (Dust.ar(1) * env1), 4e-3)
		* 0.1+del*0.99, 1200); // LPF in and frequency
	LocalOut.ar(sig);
	DetectSilence.ar(sig, doneAction: 2);
	Out.ar(out, in);
}).play;
)

Well, that seems to work in this example, I haven’t gone into the details of your feedback setup. Depending on its structure you might well want to have a second envelope !

I thought the envelope would not apply done action unless the envelope was actually triggered.

If you change the env1 to Env.new([0,0,0],[0,1,0]) etc. (setting the levels to all 0’s) it still lets the Dust come through.

I wish I could explain better:

I’m trying to just have 1 impulse, like one Dust particle, enveloped so no more play…the feedback loop happens, then I could apply an overall envelope at the end to shape the sound in a Pbind, etc.

I hope that makes sense.

I appreciate it though, I didn’t know the doneAction would happens and the Env would be running regardless of being triggered.

Then maybe like this

(
SynthDef(\what, {
	arg freq=200, gate=1, out=0, amp=0.5, neg=1e-2;
	var in, env, sig, del, lo, li, env1, env2;
	// env1 = EnvGen.ar(Env.new([0,1,0],[0.001,0.1]));
	env2 = EnvGen.ar(Env.new([0,1,1,0],[0.001,1,1]), gate, doneAction:2);
	in = LocalIn.ar(2);
	del = DelayN.ar( 
		    LeakDC.ar(
			in), 1, neg);
	sig = LPF.ar(
		Trig1.ar( //takes any signal and when 0-1, outputs "1", otherwise 0's
			Amplitude.kr(del, 5, 120)
			* 1.5 + del + neg - Impulse.ar(0), 4e-3)
		* 0.1+del*0.99, 1200); // LPF in and frequency
	LocalOut.ar(sig);
	// DetectSilence.ar(sig, doneAction: 2);
	Out.ar(out, sig * env2 * amp);
}).play;
)

@dkmayer After some tinkering I found that this feedback loop produces the sound even when I set the envelope to all 0’s, so the envelope is indeed working. I just dont understand feedback I guess, that’s all. Different issue.

Wait, @dkmayer why did you put Impulse.ar(0)? How does that work as an Impulse with 0 frequency?

The envelope is triggered – the default gate is nonzero, so the default behavior is to run the envelope.

The initial question is about UGens taking effect or not depending on their usage as an input to another unit.

Many UGens are pure, meaning they take inputs and produce an output, and have no other side effects. There’s a class for that: PureUGen. Because a pure UGen’s only result is its output, then… if that unit doesn’t feed into a nonpure unit’s input, then its output is pointless. So the SynthDef optimization step will delete pure chains where the output goes nowhere. (Many pure UGens are not labeled as pure in the system – there’s an issue logged for that.)

SynthDef(\test, {
    var a = SinOsc.ar(440);
    var b = LFTri.ar(220);
    Out.ar(0, b);
}).dumpUGens;

I’m pretty sure a will disappear.

What’s a non-pure UGen? This is a UGen that has any kind of side effect – changes anything in the system beyond just having an output. Out isn’t pure because it changes the contents of a bus. RecordBuf changes the contents of a buffer. Poll posts output. SendReply emits an OSC message. FreeSelf stops a synth node. FFT and PV units modify buffer contents. Even noise UGens can’t be considered pure because they change the state of a random number generator. These are all side effects.

An envelope generator has the power to stop a synth node. So it isn’t pure. So it doesn’t matter whether you used its signal output anywhere. It can have a side effect, so it can’t be removed. That it exists is enough.

hjh

Triggers once

{ Impulse.ar(0) }.plot(0.0003)

VERY interesting, thank you both.

I kinda feel bad asking so many questions on this forum, but I feel like at this stage I have to have a little hand-holding until I get a better birds-eye-view…This is my first programming language. Again I really appreciate yalls input. I promise I’m not lazy! I actually will sit here and read help docs and tutorials, and have every SC book / paper there is, but I just go cross-eyed after a while trying to figure certain things out on my own. I will try to post less though.

That .dumpUGens method is going to help me decipher things I think.

Regarding the Impulse.ar(0) at zero frequency producing sound in the feedback loop, I found out it produces a 1 at the beginning no matter what! Super useful!!!

{Impulse.ar(0)}.plot(0.001)

(EDIT ah yeah just figured that out at the same time, thanks @dkmayer ! )

You’re doing fine from my pov. I’m reading along here on the beach and learning stuff from the answers – thanks, James and Daniel, for your tireless efforts! – despite having dabbled with sc for over a decade now.

Alot of it, btw, has more to do with DSP than programming per se, so even an experienced coder(*) would have these questions.

Cheers,
eddi

(*) coming from other programming languages, i mean

1 Like