Long envelopes on Busses, or something else?

Hi everyone.

I’m trying out different composition styles, and right now I’m trying to figure out a way to control the different aspects of the song with long envelopes. Something to control the volume of each element (drums, synth, etc.), each having it’s own Bus. So you could fade in smoothly, then after 4 bars, cut the Bus completely, then have it come back at some point, etc. while other sounds are being controlled by their own envelope.

So you’d basically start off with all elements of the song playing at once, then have the busses subtractively (that a word?) controlling the song. Like one Synth and Bus would be like this, but the problem is, this just doesn’t seem to work. It will fade in then just stay there:

~ampbus = Bus.audio(s,2);
SynthDef(\string, { arg i_out, freq = 360, gate = 1, pan, amp=0.1;
    var out, eg, fc, osc, a, b, w;
    fc = LinExp.kr(LFNoise1.kr(Rand(0.25,0.4)), -1,1,500,2000);
    osc = Mix.fill(8, { LFSaw.ar(freq * [Rand(0.99,1.01),Rand(0.99,1.01)], 0, amp) }).distort * 0.2;
    eg = EnvGen.kr(Env.asr(1,1,1), gate, doneAction: Done.freeSelf);
    out = eg * RLPF.ar(osc, fc, 0.1);
    #a, b = out;
    Out.ar(i_out, Mix.ar(PanAz.ar(4, [a, b], [pan, pan+0.3])));

Pdef(\testPbind, Pbind(\instrument, \string, \dur, 1, \out, ~ampbus)).play;

SynthDef(\env, {
	arg out=0, in=0, gate=1;
	var env, levels, times, curves;
	in = In.ar(in,2);
	levels = \levels.kr([0,1,0]);
	times = \times.kr([1,1]);
	curves = \curves.kr([5,-5]);
	env = EnvGen.ar(Env.new(levels,times,curves), gate);
	Out.ar(out, in * env);

~ampsyn = Synth(\env, [\in, ~ampbus,\levels, [0,0.5,1,1,0,0,1,1,0], \times, [7,1,16,0,4,0.001,8,0]]);

I don’t have to use busses per say. I’m open to anything that can smoothly do this. Like if there was a way to do it with Patterns, or functions, Spawners, anything…that would be fine too. Any ideas appreciated!

Quick question…

Is there an advantage in using:

doneAction: Done.freeSelf // over doneAction: 2 ?

If it’s for clarity, then respect.

Oh, I use doneAction:2…I just threw that SynthDef in there (I didn’t make it) as it was smaller than what I was really working with. I think that’s just being explicit with the class I could be wrong, but looks the same in the help files

poison0ak I hope I can be some help and understood your question.

Using pattern (Pseq,…) in events allow you to set the number of bar to play an instance of your synth.

for example

// this will play 8 bars of your synth
Pbind(\instrument, \string, \dur, Pseq([4/1],8))

//by adding \type you control which bar of your event will play the synth with \note and not play with \rest
Pbind(\instrument, \string, \dur, Pseq([4/1],8),\type,Pseq([\note,note,\note,\note,\rest,\rest,\rest],inf))

after to create envelope for smooth fading I would either implement envelope in \string synth or if you want something progressing over time then send your signal to an envelope/synth

hope this help =D

Interesting. I often use explicit syntax for clarity.

ar & kr is a shortcut for the ubiquitous EnvGen wrap, and also, there’s EnvGate

The doc examples are relevant to fade control… though I also have the same interest, in having a setup for specific bus/tracks.

I dont see why you can’t have a fuction with |bus, fade| that will Bus.set(\amp, env) to go from one to zero in fade seconds

One issue here is that this is implicitly limiting your envelope to two segments – but then your Synth() expression is trying to create eight segments. As is, this won’t work.

You’ll have to preallocate the largest number of segments you expect to use. Note that it isn’t necessary to use all of the segments in every Synth instance. If you pass the envelope as an array, then the number of segments is one of the parameters (filled in for you).

SynthDef(\env, {
	arg out=0, in=0, gate=1;
	var env, envspec;
	in = In.ar(in,2);
	// this allows 9 levels, 8 times, 8 curves
	envspec = \env.kr(Env.newClear(8).asArray);
	env = EnvGen.ar(envspec, gate);
	Out.ar(out, in * env);

~ampsyn = Synth(\env, [\in, ~ampbus,
	\env, Env([0, 0.5, 1, 1, 0, 0, 1, 1, 0], [7, 1, 16, 0, 4, 0.001, 8, 0])

We can take a look at the /s_new messages produced for different sizes of envelopes:

Synth.basicNew(\env).newMsg(args: [
	\env, Env([0, 0.5, 1, 1, 0, 0, 1, 1, 0], [7, 1, 16, 0, 4, 0.001, 8, 0])
-> [ 9, env, 1000, 0, 1, env, [, 0, 8, -99, -99, 0.5, 7, 1, 0, 1, 1, 1, 0, 1, 16, 1, 0, 0, 0, 1, 0, 0, 4, 1, 0, 1, 0.001, 1, 0, 1, 8, 1, 0, 0, 0, 1, 0, ] ]

Synth.basicNew(\env).newMsg(args: [\in, ~ampbus,
	\env, Env([0, 0.5, 1, 1, 0], [7, 1, 16, 0])
-> [ 9, env, 1001, 0, 1, env, [, 0, 4, -99, -99, 0.5, 7, 1, 0, 1, 1, 1, 0, 1, 16, 1, 0, 0, 0, 1, 0, ] ]

In the first case, the env begins with 0, 8 – that’s the initial level and number of segments. In the second, it’s 0, 4 – so the EnvGen would then process four segments and stop, even though it physically has enough inputs for 8 segments.


Thank you,
That DOES help. I do like that as it’s pretty easy, but it doesn’t really solve being able to do fades, curves, and more granular control of amplitude.

Now that is pretty cool.

I like that a lot, I didn’t know you could do control names with Classes in them (.asArray, I see)

Very cool, I appreciate this so much as always @jamshark70

@Rainer I will also work on a function like that, as it seems like a very elegant solution. If you come up with one first let me know :slight_smile:

@jamshark70 I see how the rest of the msg is the times and levels laced together, but what about those -99’s?

Another thing, I see you create an array of 8 for Env, but what about the \times array?

Also, I see where I might run into a problem with starting all of them at the same time and quantizing. I’m wondering if this would be less accurate than say, using patterns,

Sorry for all the questions

It’s not – it’s a NamedControl whose default is an array. The array happens to be generated by Env methods, but NamedControl doesn’t care where the array comes from.

releaseNode and loopNode

I don’t quite understand – if you pass a whole Env, then it already includes times, so there would be no need for a separate \times array.

The 8 is the number of envelope segments. Each segment consists of a target level (that’s important! everybody overlooks this at first), a time, and a curve. That’s 8 target levels, 8 times, 8 curves. But the envelope has to start somewhere, so there is one more level, used only once at the beginning and never used again. For Env.newClear(8), then, you can supply up to 9 levels, 8 times, and 8 curves.

I’m not clear about the scenario you’re thinking of, here.

I personally dislike the idea of running a control pattern outputting dozens of set messages per second. I know others on the forum recommend it, but if it’s meant to be a continuous control signal, I’d prefer to run it at control rate rather than sampling at a rate of, oh, 50 per second. My opinion, to take or leave :laughing: