Thresholded envelope follower that produces values in a predefined range?
-
- KVRian
- Topic Starter
- 1097 posts since 28 May, 2010 from Finland
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?
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.
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
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.
Not sure how well that would sound.
-
- KVRian
- Topic Starter
- 1097 posts since 28 May, 2010 from Finland
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]?
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
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.
-
- KVRian
- Topic Starter
- 1097 posts since 28 May, 2010 from Finland
How are they supposed the catch min and max?
Or is it just a matter of rough approximation?
Or is it just a matter of rough approximation?
-
- KVRian
- Topic Starter
- 1097 posts since 28 May, 2010 from Finland
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].
However, this might be trivial since abs(digital audio signal) is often in [0,1].
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
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.Fluky wrote:How are they supposed the catch min and max?
Or is it just a matter of rough approximation?
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.
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
Always, expect for signals that are too loud, before a compressor or a limiter!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].
-
- KVRian
- Topic Starter
- 1097 posts since 28 May, 2010 from Finland
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?
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?
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
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...
As for threshold, it also depends on your workflow...
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
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.
And at the output of offsetVolumeFilter, you get your envelope in [a, b].
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, &litudeFilter, 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);
-
- KVRAF
- 7402 posts since 17 Feb, 2005
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...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.
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.
-
- KVRian
- 1379 posts since 26 Apr, 2004 from UK
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.
-
- KVRian
- Topic Starter
- 1097 posts since 28 May, 2010 from Finland