[SOLVED] True ADSR with TriggerOff() method?

The AdEnv has the Trigger() method that starts the envelope (A = attack). Then the rest of the process() is handled by the set time(s).

That means you must know beforehand how long the note is. There is no TriggerOff() so the envelope enters Release ®.

I’d like an ADSR that I can control like how I control a note on a keyboard. Keypress = Trigger(), then I lift my finder and send a TriggerOff() so the note enters the Release phase.

Does this makes sense or have I misunderstood something?

1 Like

You are correct. The note should remain in the sustain phase, possibly with sustain droop during the hold time.

I haven’t tried AdEnv so surprised it doesn’t do that.

1 Like

Oh, I found it!

I looked before at the Adsr class, but didn’t read it carefully enough. The Adsr.Process() method has a boolean argument that is the gate!

float Adsr::Process (bool gate)
Processes one sample through the filter and returns one sample.
Parameters
gate - trigger the envelope, hold it to sustain

Thanks for your answer, @MikeDB!

1 Like

So I have been using the ADSR on a guitar effect to smoothly ramp a pitch change and it works pretty well, but sometimes if I strum a chord before the ADSR completes, it triggers the change quickly and sounds a little glitchy. I am using the gate argument as it’s used in the ADSR example patch, but I am not sure I fully understand how it works. Were you able to get it working to your satisfaction @StaffanMelin? If so, any tips or guidance?

1 Like

I got it to work as I wanted, but I don’t know if it will be of use for you as I used it to control oscillators. But I’ll give you a description anyway, maybe it might help! :slight_smile:

OK, so I run a bunch of oscillators. Two of them use the Adsr class. That means I don’t Trigger() their envelopes when I start a new note like I do with the ones that use the AdEnv class.

This is some code from my AudioCallback():

    ProcessTick();

		for (int j = 0; j < MAX_LEAD; j++)
		{
			env_out = leadAEnv[j].Process(seqNotesGate[j]);
		    leadOsc[j].SetAmp(env_out);
		    lead_out[j] = leadOsc[j].Process();
		    leadLPF[j].Process(lead_out[j]);
		    lead_out[j] = leadLPF[j].Low();
		}

On this line

		env_out = leadAEnv[j].Process(seqNotesGate[j]);

I have a boolean array that tells the envelope object (in leadAEnv[]) whether it

  • should start the envelope (the gate is True for the first time)
  • go forward and stay in Sustain (the gate is still True)
  • leave Sustain and enter Release/idle (the gate is False)

The function

ProcessTick();

is a simple MIDI engine that counts when it is time to play a new note:

leadOsc[j].SetFreq(mtof(aNote));
seqNotesGate[j] = true;
//leadAEnv[j].Trigger();

(You can see that I have some leftovers from when I used AdEnv.)

And here is the code where I setup the envelope:

	leadAEnv[j].Init(gSamplerate);
	leadAEnv[j].SetTime(ADSR_SEG_ATTACK, .01);
	leadAEnv[j].SetTime(ADSR_SEG_DECAY, .01);
	leadAEnv[j].SetTime(ADSR_SEG_RELEASE, .4);
	leadAEnv[j].SetSustainLevel(1.f);

I hope it helps! :slight_smile:

1 Like

@bretvh
This is the classic polysynth conundrum - how do you decide if it’s a new note played or someone extending an existing note. One technique I do sometimes is to leave the ADSR running in its decay mode but also trigger another ADSR from the start of the attack mode. Give it a try - it may solve your glitching … or maybe not

2 Likes

That’s a great idea, thanks so much! I

This is super helpful, I really appreciate you taking the time to put this example together for me!

1 Like

No problem! :slight_smile:

If you want the whole code (not finished yet) I have a thread here: OscPocketD - Portable music tool (sequencing drums and synths)

Good luck!

1 Like