Thresholded envelope follower that produces values in a predefined range?

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

I want to write a thresholded envelope follower that produces values in the range [a,b].
That is, it reads an input signal, takes the envelope and then maps the values it generates to the range [a,b] so that the max peak amplitude in the interval gets the value b and the min peak amplitude in the interval gets the value a. And all values between retain their ratios in some sense. Also this should work for continuous-time signals.

This application is typical if one wanted to e.g. make parameter modulation that generates the envelope from an audio signal. One'd want to e.g. control the parameter in the constrained range of [a,b] c [param_min, param_max], but read the envelope from the peaks of the audio (above some threshold).

Any ideas?
Last edited by soundmodel on Sat Aug 29, 2015 8:17 am, edited 1 time in total.

Post

In that case, you may need to also make an envelope follower on the min and max envelope. Just make sure that their attack is faster and the release slower than your envelope follower, and then apply the transform on the signal on the fly.
Not sure how well that would sound.

Post

Oh you mean that one'd need two thresholds? To generate two envelopes and then the range will be calculated by scaling the distance abs( max_env - min_env ) to the range [a,b]?

Post

No threshold, just two envelope followers to catch min and max, and then another envelope follower followed by a scaling parameter. Actually min and max have to have opposite coeffs, fast attack, slow release for max, and slow attack and fast release for min.

Post

How are they supposed the catch min and max?
Or is it just a matter of rough approximation?

Post

I could also use any kind of envelope that somehow produces e.g. the range [0,1] of values for the envelope.
However, this might be trivial since abs(digital audio signal) is often in [0,1].

Post

Fluky wrote:How are they supposed the catch min and max?
Or is it just a matter of rough approximation?
With an attack of 0, the ar filter will always catch the max. Same for a release of 0 for the min. Then you get an approximate interval min, max for each sample. Then you just need to transform the interval in 0,1 and then a, b and apply the transform on the actual envelope.
The only filters missing in atk are output=1/input and output = input1 + output2 ×output3, but really easy to create.
I don't have the time to write this down now, maybe this evening.

Post

Fluky wrote:I could also use any kind of envelope that somehow produces e.g. the range [0,1] of values for the envelope.
However, this might be trivial since abs(digital audio signal) is often in [0,1].
Always, expect for signals that are too loud, before a compressor or a limiter!

Post

So does AudioTK's attack release filter somehow produce different results if I just scale it to [a,b]?
It does produce values in the range [0,1] and uses the full bandwidth to create the envelope?
If I want to threshold, then should I threshold the audio before inputting it to the filter?

Post

No, youndon't get different results, the filter itself is the same. The pipeline is different.
As for threshold, it also depends on your workflow...

Post

OK, let's suppose we have InvertFilter that does output = 1/input and let's assume that powerFilter is the filter giving the envelope you want to compute.
I'm not adding the code for setting the sampling rates or the main AR filter parameters.

Code: Select all

ATK::AttackReleaseFilter<double> mainARFilter;
attackReleaseFilter.set_input_port(0, &powerFilter, 0);

ATK::AttackReleaseFilter<double> minARFilter;
minARFilter.set_input_port(0, &attackReleaseFilter, 0);
minARFilter.set_attack(exp(1/(window_size * sampling_rate)));
minARFilter.set_release(0);

ATK::AttackReleaseFilter<double> maxARFilter;
maxARFilter.set_input_port(0, &attackReleaseFilter, 0);
maxARFilter.set_attack(0);
maxARFilter.set_release(exp(1/(window_size * sampling_rate)));

ATK::VolumeFilter<double> negativeFilter;
negativeFilter.set_input_port(0, &minARFilter, 0);
negativeFilter.set_volume(-1);

ATK::SumFilter<double> amplitudeFilter; // compute max - min
amplitudeFilter.set_input_port(0, &maxARFilter, 0);
amplitudeFilter.set_input_port(1, &negativeFilter, 0);

ATK::InvertFilter<double> invertFilter;
invertFilter.set_input_port(0, &amplitudeFilter, 0);

ATK::ApplyGain<double> applyGainFilter; // applies the factor so that the envelope lies in [0, 1]
applyGainFilter.set_input_port(0, &attackReleaseFilter, 0);
applyGainFilter.set_input_port(0, &invertFilter, 0);

ATK::OffsetVolumeFilter<double> offsetVolume;
offsetVolume.set_input_port(0, &applyGainFilter, 0);
offsetVolume.set_volume(b-a);
offsetVolume.set_offset(a);
And at the output of offsetVolumeFilter, you get your envelope in [a, b].

Post

Fluky wrote: That is, it reads an input signal, takes the envelope and then maps the values it generates to the range [a,b] so that the max peak amplitude in the interval gets the value b and the min peak amplitude in the interval gets the value a. And all values between retain their ratios in some sense.
What is, how long, is the interval? Anything other than a full in-place read (which means non-realtime use) is going to generate non-linearities. It would be easy to read the full stream and find min and max values...
Otherwise plan on having very very non-linear response to this interval.
The usual method of clamping a range is to use limiting. It can be hard clipping, soft clipping, even dynamic gain reduction. This is obviously non-linear but it does not require in-place processing.
If the [a,b] range limit was to vary, whatever varies it will also generate non-linearities.
And depending on what exactly you are attempting to do, non-linear processing "destroys" the input data set. I never use hard-clipping because of that.
A threshold value presents a problem because the signal cannot be on both sides at one time. Soft thresholds are preferred because they limit distortion.

Post

Yes, I agree, which is why I didn't even try to make this case (and the latency could be quite high). I guess there are cases where you want to have an adaptative signal transform, so that's what I did.

Post

It's an interesting idea, I gotta give him credit :)

Post

Message deleted.

Post Reply

Return to “DSP and Plugin Development”