Need an envelope follower. Your slew limiter isn't quite doing it! #334
Replies: 95 comments
-
You need an "is idle" or "is silent" check for your slew limiters or you need to provide access to last out value. |
Beta Was this translation helpful? Give feedback.
-
alright gonna subclass. |
Beta Was this translation helpful? Give feedback.
-
tested, it only works for on/off signals. Do I need to have two slew limiters, one for rise/fall detection, the other to actually rise and fall only after the other one is finished falling? hmmmmmmmmmmmm class EnvelopeFollower
{
public:
EnvelopeFollower()
{
delayTrigger.setTriggerFunction([this]() { doSkip = false; });
}
~EnvelopeFollower() = default;
void setSampleRate(double v)
{
slewLimiter.setSampleRate(v);
delayTrigger.setSampleRate(v);
}
double getSample(double v)
{
double incomingAbsoluteValue = abs(v);
bool valueIsRising = incomingAbsoluteValue > lastAbsoluteValue;
lastAbsoluteValue = incomingAbsoluteValue;
if (valueIsRising)
{
doSkip = true;
delayTrigger.restart();
heldAbsoluteValue = std::max(heldAbsoluteValue, incomingAbsoluteValue);
}
else if (!doSkip)
{
heldAbsoluteValue = incomingAbsoluteValue;
}
currentSlewedValue = slewLimiter.getSample(heldAbsoluteValue);
delayTrigger.incrememt();
return currentSlewedValue;
}
bool isIdle()
{
return currentSlewedValue <= 1.e-6;
}
void setAttackTime(double v)
{
slewLimiter.setAttackTime(v*1000.0);
}
void setHoldTime(double v)
{
delayTrigger.setSeconds(v);
}
void setDecayTime(double v)
{
slewLimiter.setReleaseTime(v*1000.0);
}
RAPT::rsSlewRateLimiter<double, double> slewLimiter;
DelayedTrigger delayTrigger;
bool doSkip = false;
double heldAbsoluteValue = 0;
double lastAbsoluteValue = 0;
double currentSlewedValue = 0;
}; |
Beta Was this translation helpful? Give feedback.
-
bah, tried a bunch of different things. Can't get a hold function to clean up some of the signal. robin i need an envelope followerrrrrrrrrrrrrrrrrrrr 😢 I want to get some nice plucky envelopes if possible, maybe a more advanced transient detector is what I need, or just a good hold function. |
Beta Was this translation helpful? Give feedback.
-
i added a class rsSlewRateLimiterWithHold - but did not yet try it. will do now.. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
is this for realtime purposes? because if not, i could use the non-realtime envelope detection code that i have recently written |
Beta Was this translation helpful? Give feedback.
-
realtime. I'm working on FMD and need an envelope follower to open/close the filter. |
Beta Was this translation helpful? Give feedback.
-
is hold time in seconds? |
Beta Was this translation helpful? Give feedback.
-
milliseconds - to be consistent with attack and release parameters |
Beta Was this translation helpful? Give feedback.
-
hmmmmm, I might want to go with a treshold-based envelope trigger. No matter what the settings are, you can't get a plucky envelope, and I've tried yours, Cytomic The Drop and Tone2 FilterBank3 envelope followers. They are all similar in that way. Edit: But definitely still will use the envelope follower in a larger product where I can have trigger-based and envelope following options. Edit: I dunno, still trying to decide what to do. |
Beta Was this translation helpful? Give feedback.
-
ok made a decision, envelope follower it is. |
Beta Was this translation helpful? Give feedback.
-
It is possible to get plucky envelopes, you just need a plucky input signal. Not ideal. I'm playing with Cytomic The Drop and they have a trigger system and a "sense" knob. It seems like a transient detector with a sense amount. Yep, that would be ideal. And it has a switch to go from envelope follower to transient detector. Edit: Do you have a realtime transient detector lying around I can throw in? |
Beta Was this translation helpful? Give feedback.
-
hmm...not currently in the rs-met codebase. i have some verrrry old legacy code lying around where i did something like that: |
Beta Was this translation helpful? Give feedback.
-
........wait, somehow it's not happening anymore. I'll let you know if it comes up again. |
Beta Was this translation helpful? Give feedback.
-
smells like the infamous denormal issue is rearing its ugly head again? actually, this is supposed to be dealt once and for all with on the level of jura::AudioPlugin::processBlock |
Beta Was this translation helpful? Give feedback.
-
Could you throw in hold/attack/decay features in the next few weeks? New flower child filter is almost finished. |
Beta Was this translation helpful? Give feedback.
-
into which class? my attack/decay-filter based envelope that the most recent talk is about? or into the envelope follower? |
Beta Was this translation helpful? Give feedback.
-
ok - i have implemented the sustain for the rsAttackDecayEnvelope which is based on rsAttackDecayFilter (which in turn is based on my rsModalFilterWithAttack with zero frequency). this is what i get - a sort of smooth ADSR - no slope discontinuities at the transitions from attack to decay and from sustain to release: looks like we are almost coming full circle to an ADSR envelope generator - not quite, because as it stands, we will always have R==D - decay and release times are equal. but i actually think, it would be no big deal to lift that restriction. there is a little gotcha though: changing the sustain from zero to some higher value, the location of the peak wanders (it occurs later) and it's height increases. i'm afraid, figuring out compensation formulas for this is a formidable math challenge and perhaps it's not even desirable to compensate this? maybe this coupling is "musical"? dunno. ....aaand it's smoother than standard ADSRs |
Beta Was this translation helpful? Give feedback.
-
here i made a plot to show this effect - attack = 50, decay = 100, sustain = 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 in the black curve, the peak occurs exactly at sample 50 (as ordered by the attack parameter) and has height 1. with increasing sustain, location and height of the peak increases |
Beta Was this translation helpful? Give feedback.
-
ooo nice envlope shapes. yeah I was talking about the envelope follower |
Beta Was this translation helpful? Give feedback.
-
ahh - ok - i see. you mean in rsEnvelopeFollower2, you need more flexibility with regard to setting up the embedded rsSlewRateLimiterWithHold? currently, we just have rsEnvelopeFollower2::setInputFrequency which in turn calls updateSmoothingFilters, which in turn sets the embedded slewLimiter object to hard-coded settings (which i determined by some (quick) trial and error). you want more detailed access to these internal parameters? |
Beta Was this translation helpful? Give feedback.
-
ok - i'll look into it tomorrow. looks actually like a trivial task - i think, i'll just make the hard-coded 0.1 and 10.0 factors (attack is 1/10 of a cycle, release is 10 cycles) settable members - and may do the same for the hold parameter, too |
Beta Was this translation helpful? Give feedback.
-
It seems that the rsEnvelopeFollower2 is not going to 0 after getting a signal. This bug only happens if attack time is non-zero. |
Beta Was this translation helpful? Give feedback.
-
You haven't made progress on envelope follower 2 so I had the idea to use the AttackDecayFilter to get separate attack/decay time and it's just not behaving. It's as if the modulation goes up and down constantly like a sinewave and the output is sending some extreme values. Also, don't worry about a hold time feature. I'm going to slap on a tempo-synced sample and hold and call it a day. Going to see if I can just add a separate attack/decay time on envelope follower 2 now by making those functions locally. |
Beta Was this translation helpful? Give feedback.
-
Alright, I got it kind of working, It's buggy, getting some strange startup values and then some sudden reduction in output when changing timing. I still like having the slew rate limiter hold time control. You should implement attack/decay time. I set the smoothing filters to be the max frequency (min time) of the attack and release time. Works pretty well. |
Beta Was this translation helpful? Give feedback.
-
Ok, I figured out one bug. If the slewLimiter.getSample() function receives zeros, the output stops changing in value so the value is held. This means, as soon as EnvelopeFollower2 stops receiving a signal, the envelope stops decaying. This is made more obvious with less decay time. |
Beta Was this translation helpful? Give feedback.
-
HMMMM... alright I'm including gibbs and smooth knobs on Flower Child Filter for the envelope follower. Lots of fun to play with the frequencies of the minmax and post filter and get gurgling or smooth envelopes. |
Beta Was this translation helpful? Give feedback.
-
I'm using your slew limiter to create an envelope follower, but it suffers from "gurgly modulation" where, for example, the individual peaks of a sawtooth causes undesirable modulation. I think a simple hold function would work. Rise and then do not fall until x seconds have passed.
Beta Was this translation helpful? Give feedback.
All reactions