SynthMaker

New poly envelope : DAHDSR...

Archive · 2005 37 old posts

From the original SynthMaker forum (2004–2014), with its members’ names and dates.

Shifrin ·

Hi,

I've managed to figure out how to make new poly envelopes (you could use the method I've used to make multipoint envs, loopable envs etc...).

It's a Delay, Attack, Hold, Decay, Sustain, Release envelope. All times are given in samples just like the default ADSR in SM, and sustain is again a value from 0.0 to 1.0.

Here is the file :- DAHDSR-Env.osm

Let me know of any bugs you find, I tested it for a bit and all seemed well but you never know... 😉

Shif.

Tom7777 ·

Nice one 🙂

beno ·

Thanks shif! I was going to have to look into making one of these soon. Thanks for beating me to it. Ben

Shifrin ·

If we had a pow(x,n) function in the code component you could make envelopes with variable slopes for Attack, Decay and Release sections - I have some code for x^n but it would be far too slow for sample rate calculations (I did it more as an exercise) 😉

Shif.

lalo ·

Shifrin wrote: If we had a pow(x,n) function in the code component you could make envelopes with variable slopes for Attack, Decay and Release sections - I have some code for x^n but it would be far too slow for sample rate calculations (I did it more as an exercise) 😉

Shif.

yeah..would be nice to have different slope 🙂

to do custom envelopes a-la sytrus / absynth etc..

lalo

Shifrin ·

lalo wrote: yeah..would be nice to have different slope 🙂

to do custom envelopes a-la sytrus / absynth etc..

An ADSR with modifiable slope for A,D and R sections is on it's way - also I think there is a bug with DAHDSR module - will look into it.

Shif.

lalo ·

cool 🙂

beno ·

Shifrin wrote: lalo wrote: yeah..would be nice to have different slope 🙂

to do custom envelopes a-la sytrus / absynth etc..

An ADSR with modifiable slope for A,D and R sections is on it's way - also I think there is a bug with DAHDSR module - will look into it.

Shif.

Hey Shif, I'm trying to use your DAHDSR and I'm getting a small low level click when the release stages finishes? This may be a problem with my schematic but I was wondering if you've heard this or if this was the bug you were refering to fixing. Ben

Shifrin ·

beno wrote: Hey Shif, I'm trying to use your DAHDSR and I'm getting a small low level click when the release stages finishes? This may be a problem with my schematic but I was wondering if you've heard this or if this was the bug you were refering to fixing. Ben

Weird, I don't get any (even very quiet) clicks after the release stage finishes! The bug I thought I'd found wasn't a bug, I had to rework all the code to apply the pow(x,n) function to the attack, decay and release stages and the bug was something I introduced as a result of that (I still haven't got it working exactly right - it's close but no cigar...)

Strange, if you could post the schematic/.osm file I'll have a look at it!

Shif.

beno ·

ok, let me look through it a bit more myself. If I get fed up I'll post what I have. Cheers. Ben

Shifrin ·

Maybe your hearing is better than mine 😉

Shif.

beno ·

Shifrin wrote: Maybe your hearing is better than mine 😉

Shif.

Well it is low level and I can only hear it with headphones. I can't hear it on my laptop speakers.

Ben

Shifrin ·

I tried it through headphones with the volume up high, didn't hear any clicks at all - anyone else heard clicks after the release stage of this envelope?! Curious!

Shif.

malc ·

I can't hear any clicks with Shif's example, have you modified it in any way Ben? Any cahnce you could post an example so we can try it out.

Malc.

beno ·

I've used shiffs envelope in the SDP sample playback synth I was working on. I think I've narrowed it down to when the release occurs after the end of the wav file so effectively the envelope is being multiplied by nothing. I'll post the schematic a bit later if I can't sort it out. Ben

caleb ·

Shifrin - I hope you don't mind me reviving this thread, but I had decided to have a look at this code to help me understand how to use the Code module a little in SynthMaker.

I would like to get myself to understand your algorithm here because I want to understand how to code ADSRs 😉. Also there is some things I don't quite understand about the Code component that will probably be easily cleared up.

The second thing first.....

I'm not sure I understand how certain local variables get their values in the Code component.

I obviously understand the polyins/outs and monoins/outs as they are like pass by value parameters into a function and the return value(s) respectively.

However, it's the local declarations I have trouble with.

In your ADSR implementation you have declared some local variables called:

sample and val.

Neither of these variables appear to be initialised before being used in expressions/conditional statements.

In the case of sample, it ends up in a conditional statement when attempting to determine which stage of the envelope has been reached. I can I'm guessing work out what sample refers to. I just don't understand how the code component understands what it is. Also, I don't know why you would force the sample value to increment

Similarly with val, it is first used in conditional statements and then it is directed to the output without seeming to have been assigned any value.

Caleb

caleb ·

OMG - I think I just had a revelation.....

If you do not initialise a variable, it is automatically set to 0. In the case of sample and val, this is exactly what you want.

sample is working like a counter in a loop to simulate time passing and val is the value sent out of the output with each "loop" iteration based on which stage the envelope is at etc....

Just out of curiosity though, is this counter particularly accurate? If you dial in an attack of 200 samples (for example) will this counter approach actually create a 200 sample rise in amplitude to the peak volume?

This actually seems quite elegant and I would certainly like to use it as a template to explore more complicated enveloping possibilities.

Caleb

lalo ·

caleb wrote: Just out of curiosity though, is this counter particularly accurate? If you dial in an attack of 200 samples (for example) will this counter approach actually create a 200 sample rise in amplitude to the peak volume?

well...the code run once every sample....so it's sample precise..

lalo

caleb ·

lalo wrote: well...the code run once every sample....so it's sample precise..

lalo

Thanks - that explains it.

Caleb

Shifrin ·

Glad to see you've figured things out 🙂

I was planning on creating a few different envelopes, some with variable slopes (almost done). But time has been my enemy over recent weeks - haven't had much of it spare to play with SM 🙁

Any further questions just ask 🙂

Shif.

caleb ·

Thanks Shifrin. I will have some questions because I'm trying to adapt your algorithm to make a multi-stage, loopable envelope.

If I ever get the thing to work I will post it so everyone can tear it apart. 😉

When I get home tonight I'll post a question about the val is calculated. I think I'm struggling on some of the conditionals in the assignment statement.

Caleb

Shifrin ·

caleb wrote: Thanks Shifrin. I will have some questions because I'm trying to adapt your algorithm to make a multi-stage, loopable envelope.

If I ever get the thing to work I will post it so everyone can tear it apart. 😉

When I get home tonight I'll post a question about the val is calculated. I think I'm struggling on some of the conditionals in the assignment statement.

Caleb

Ok! I'm heading off for the night, but I have an 'easier to follow' version of this for just ADSR - I'll post it tomorrow (don't have it on my .net machine!).

Shif.

Shifrin ·

Here is an ADSR with gate :-

And here is the .osm :-

ADSR-1.0.osm

Incase you were wondering about why the output of the code component is multiplied by that internal SynthMaker ADSR (which is also running through a simple code component) here's why!

AFAIK the poly code only runs with a 'note-on', once a 'note-off' is received the poly section stops. The only expection to this is with SM's internal ADSR's. If the 'hold' input is true then once a 'note-off' is received it triggers the release portion of the envelope. So, in order to get my custom ADSR to have a release section I need to use the internal SM ADSR to ensure the code runs whilst in the release section. Make sense? So I set the internal SM ADSR to have a release section the same length as my code component version, and then I use the other little code component to output a 1.0 as long as SM's internal ADSR is running. This then ensure my code will run too (by multiplying the output of my custom ADSR by it).

Phew!

Here's the code itself :-

polyin gate; polyin a; polyin d; polyin s; polyin r; polyout adsr;

float sample,aStep,dStep,rStep; float relOn,stage,val;

stage = (sample > a)&1 + (sample > (a + d + 1))&1; relOn = (gate < 1)&(sample > 0)&1; stage = (relOn < 1)&stage + (relOn > 0)&3;

aStep = 1.0/(1 + a); dStep = (1.0 - s)/(1 + d); rStep = (relOn < 1)&(val/(1 + r)) + (relOn > 0)&rStep;

adsr = val;

val = val + (stage <= 0)&(stage >= 0)&aStep - (stage <= 1)&(stage >= 1)&dStep - (stage <= 3)&(stage >= 3)&rStep;

sample = sample + 1;

Any questions about any of it just fire away 🙂

Shif.

stefan ·

It should be quite doable to have a multi-stage envelope that basicly is built up by connecting envelope segments in series, could be usable 🙂

caleb ·

I think - in what I have done so far - that the multi-stage envelope isn't really that complicated.

I figured that if all it requires is a counter that gets incremented with each sample then there is no difficulty resetting the counter back to the value after the delay and initial attack you may want to set.

Other than that you just need several more inputs for y values (amp) and x values (samples) that will cover each new point.

Just adapting Shifrin's code I came up with this for the input:

polyin gate; polyin del; polyin attack; polyin y1; polyin x2; polyin y2; polyin x3; polyin y3; polyin x4; polyin y4; polyin x5; polyin y5; polyin x6; polyin y6; polyin release; polyin loop;

Working out the step value seemed fairly logical as well. Again - I pretty much duplicated how Shifrin worked with the initial attack...

aStep = y1/(1 + attack); iStep = (y1>y2)&-1 * (y2/(1+x2)); iiStep = (y2>y3)&-1 * (y3/(1+x3)); iiiStep = (y3>y4)&-1 * (y4/(1+x4)); ivStep = (y4>y5)&-1 * (y5/(1+x5)); vStep = (y5>y6)&-1 * (y6/(1+x6));

The conditional is supposed to work out if the volume is increasing or decreasing compared to the previous y point.

Working out which stage you're in is identical to Shifrin's code with just an increased number of stages.

This all could be incredibly naive so feel free to laugh at me if necessary. But from what I can tell, it should be relatively simple to create any arbitrary number of stages for an envelope.

I included an attack and release as separate values because I imagined that a looped amplitude multi-stage envelope is actually a sustain loop - in which case you actually need a separate attack leading to the first y point. Likewise with the release at the end.

In the case that you were using the envelope purely as a looped modulation source you could always set attack and release to zero to eliminate them from the equation.

Caleb

caleb ·

Shifrin wrote: So, in order to get my custom ADSR to have a release section I need to use the internal SM ADSR to ensure the code runs whilst in the release section. Make sense? So I set the internal SM ADSR to have a release section the same length as my code component version, and then I use the other little code component to output a 1.0 as long as SM's internal ADSR is running. This then ensure my code will run too (by multiplying the output of my custom ADSR by it).

That is freaky!

How the hell did you come up with that logic? I would never have thought to persuade my code module to continue affecting the amplitude just because its output was multiplied by a still functioning SM ADSR.

Do you guys often figure things like this out?

It seems like saying - OK - my module doesn't do anything now because it no longer functions after it receives a note off. However, if I multiply the output signal by the output of a module that is functioning - it will work anyway.

Maybe I just don't look at these things with the right "eyes".

But thanks for the tip. I will try to remember tricks like this when working with code modules.

Caleb

skOre ·

I have come up with things like this from time to time, but yes, the workarounds that come up around here are mind-boggling!

platinumears ·

caleb wrote: Maybe I just don't look at these things with the right "eyes".

I think its just a bit confusing at the moment because certain features are still missing.. at the moment the native ADSR is the only module capable of forcing a section of poly code to continue calculating after the note-off, therefore it has to be part of the code for the workaround (hence the multiply). When SM has proper voice management it should be much easier!

Dan W 😉

Shifrin ·

caleb wrote: aStep = y1/(1 + attack); iStep = (y1>y2)&-1 * (y2/(1+x2)); iiStep = (y2>y3)&-1 * (y3/(1+x3)); iiiStep = (y3>y4)&-1 * (y4/(1+x4)); ivStep = (y4>y5)&-1 * (y5/(1+x5)); vStep = (y5>y6)&-1 * (y6/(1+x6));

The conditional is supposed to work out if the volume is increasing or decreasing compared to the previous y point.

There looks like there code be a problem with the 'conditional'. For example, in iStep, if 'y1 > y2' then the next point is lower hence the multiplication by -1 *but* if 'y1 <= y2' the expression evaluates to 0! So you get 0 * (y2/(1+x2)). You probably need something like :-

iStep = (y1>y2)&-1 * (y2/(1+x2)) + (y1<=y2)&1 * (y2/(1+x2));

Another thing to note for the iStep calculation, the (y2/(1+x2)) calculation is giving you the step size to from '0 to y2' or 'y2 to 0' where you actually want the step size to go from 'y1 to y2'. I think in fact could do away with the conditional and rewrite the line as :-

iStep = (y2 - y1)/(1 + x2);

For example, if y1 was 0.8 and y2 was 0.3 and we wanted this change over 100 samples we'd need a step size of 0.8 - 0.3 / 100, since this change would need to be negative we can get this by 0.3 - 0.8 / 100, that's how the line above works. No conditionals needed! (Incidently, in case you weren't aware, the reason I'm adding 1 to the attack/decay/x's is to stop a division by 0 if any of those values are 0. It has a negligable effect in comparison to the length of the sections)

Does that make sense?

caleb wrote: I included an attack and release as separate values because I imagined that a looped amplitude multi-stage envelope is actually a sustain loop - in which case you actually need a separate attack leading to the first y point. Likewise with the release at the end.

Makes sense to me, it shouldn't be hard to adapt this code to run with multiple sections that loop 🙂

One other thing, this could take up quite some cpu cycles running at samplerate - there is however a hop() construct in SM's code component that I think you could use to make this code exectue only once per a certain number of samples. But that's another exercise!

Shif.

caleb ·

Thanks for that Shifrin.

I hadn't finished implementing this and thought I'd post some of my thoughts in case I was on the wrong track. Looks like I had stuffed a few things up.

I had a feeling there was something wrong with my conditional logic (ie 0 * x), but I put it together before I really understood the bitwise & use. Some other post in the forum had got me corrected on that and I hadn't gone back and reviewed this code afterward.

It was interesting what you said about the "hop" construct. Where are all these nifty functions listed. In the docco, I don't see a mention of it. In fact, in the docco I see only a very very small list of operators and included functions.

Caleb

Shifrin ·

caleb wrote: It was interesting what you said about the "hop" construct. Where are all these nifty functions listed. In the docco, I don't see a mention of it. In fact, in the docco I see only a very very small list of operators and included functions.

The docs don't keep up with the pace of SM's development, there is no mention of the stage(n){...} constructs either AFAIK! Any questions you have about this stuff just ask away 🙂

Shif.

caleb ·

Wow - there's more?!

My question wouldn't be fair Shifrin. It's likely to be "What are all the extra constructs and what do they do?"

😉

I'm trying to build a simple 2 osc subtractive based on CM101 as an exercise so I might just fiddle with the code I'm working on intermittently for this multi-stage envelope.

If I get it working well I might replace one of my ADSRs in the synth I'm working on with it and have a look at the performance of it. If it's dreadful, I may start asking questions about "hop()" for example. 😀

Caleb

infuzion ·

caleb wrote: I'm trying to build a simple 2 osc subtractive based on CM101 as an exercise so I might just fiddle with the code I'm working on intermittently for this multi-stage envelope.

I never heard of the CM101... except for the VSTi on Computer Music CDs... do you mean the CZ101?

caleb ·

infuzion wrote: I never heard of the CM101... except for the VSTi on Computer Music CDs... do you mean the CZ101?

No - I mean the CM101 as on the cover of a Computer Music CD. 😀

Caleb

Shifrin ·

CM101 seems like a good place to start, my first little completed synth was also a simple 2-OSC synth 🙂

Shif.

Tom7777 ·

Its nice to see theres other Computer Music readers on the forum 🙂

infuzion ·

Tom7777 wrote: Its nice to see theres other Computer Music readers on the forum 🙂

Ah yea I was buying them off the shelf when I lived in Italy 6+ years ago. 🙂

Wrote something here? To have a post removed or your name hidden, write to [email protected].

Before your first post

A few rules keep this a friendly place. You agree to them once.

Shown next to what you post, here and in the app. It doesn’t have to be your real name: 3–24 lower-case letters, digits or _ (capitals become lower case, spaces become _).

    Then your post goes up straight away.

    Delete this reply?

    Open it in SynthMaker?

    It goes on the track you’re editing there, in place of that track’s sound, and into My sounds. Your other tracks stay as they are.

    Want to keep that track’s sound? Start a new song in SynthMaker first (Song › New song), then open this.

    Report this reply?

    Only the developer reads reports. The person isn’t told who reported them.

    What’s wrong with it?

    Block this person?

    You won’t see their posts and replies here any more. They aren’t told, and you can unblock them at any time.

    People you’ve blocked

    Their posts and replies are hidden from you. Unblock someone to see them again.

    The community rules

    A few rules keep this a friendly place. Everyone agrees to them once, before their first post.