grame-cncm / faustlibraries

The Faust libraries
https://faustlibraries.grame.fr
191 stars 62 forks source link

Naming conventions for amplitude analysis functions #33

Closed dariosanfilippo closed 4 years ago

dariosanfilippo commented 4 years ago

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

josmithiii commented 4 years ago

Hi Dario,

Below is our previous thread.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used. I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith jos@ccrma.stanford.edu wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith jos@ccrma.stanford.edu wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith jos@ccrma.stanford.edu wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps benoitdelemps.add@gmail.com writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01))); gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01): ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo notifications@github.com wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ .

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

dariosanfilippo commented 4 years ago

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii notifications@github.com wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith jos@ccrma.stanford.edu wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith jos@ccrma.stanford.edu wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith <jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps benoitdelemps.add@gmail.com writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo <notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ .

josmithiii commented 4 years ago

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo notifications@github.com wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii notifications@github.com wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith jos@ccrma.stanford.edu wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith jos@ccrma.stanford.edu wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps benoitdelemps.add@gmail.com writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620094395, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQZKFKUMTSXM6HR2J6EAL3ROWXK3ANCNFSM4MR4YWGQ .

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

josmithiii commented 4 years ago

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith jos@ccrma.stanford.edu wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo notifications@github.com wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii notifications@github.com wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith jos@ccrma.stanford.edu wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith <jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps benoitdelemps.add@gmail.com writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

dariosanfilippo commented 4 years ago

On Mon, 27 Apr 2020 at 19:30, josmithiii notifications@github.com wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith jos@ccrma.stanford.edu wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii notifications@github.com wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith jos@ccrma.stanford.edu wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps benoitdelemps.add@gmail.com writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ .

josmithiii commented 4 years ago

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo notifications@github.com wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii notifications@github.com wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith jos@ccrma.stanford.edu wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii notifications@github.com wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps benoitdelemps.add@gmail.com writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ .

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

dariosanfilippo commented 4 years ago

All great.

Thanks a lot for your time, Julius.

If helpful, I can do a pull-request with what we discussed.

Best, Dario

On Mon, 27 Apr 2020 at 23:19, josmithiii notifications@github.com wrote:

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

  • Julius

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo < notifications@github.com> wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii notifications@github.com wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith jos@ccrma.stanford.edu wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii notifications@github.com wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at

https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps benoitdelemps.add@gmail.com writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620240723, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHG3I2AAMOIKMGWB2LIPLU3ROXZHLANCNFSM4MR4YWGQ .

josmithiii commented 4 years ago

Sounds great, thanks!

On Mon, Apr 27, 2020 at 2:52 PM Dario Sanfilippo notifications@github.com wrote:

All great.

Thanks a lot for your time, Julius.

If helpful, I can do a pull-request with what we discussed.

Best, Dario

On Mon, 27 Apr 2020 at 23:19, josmithiii notifications@github.com wrote:

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

  • Julius

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo < notifications@github.com> wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii notifications@github.com wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith < jos@ccrma.stanford.edu> wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii < notifications@github.com> wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at

https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps <benoitdelemps.add@gmail.com

writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620240723 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AHG3I2AAMOIKMGWB2LIPLU3ROXZHLANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620255180, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQZKFPJZBGCCCOEFZRVAKLROX5BTANCNFSM4MR4YWGQ .

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

sletz commented 4 years ago

Can this be closed then ?

dariosanfilippo commented 4 years ago

I believe we did everything we discussed so I closed it.

Dario

On Tue, 28 Apr 2020 at 15:15, Stéphane Letz notifications@github.com wrote:

Can this be closed then ?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620599518, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHG3I2GUAZ35OW4DKQ7IJ3LRO3JGRANCNFSM4MR4YWGQ .

josmithiii commented 4 years ago

Hi again,

Right now we have

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass

On second thought, I think we should use the exponential time-constant "tau" instead of t60:

ms_envelope(tau, x) = x*x : si.smooth(ba.tau2pole(tau)); // one-pole lowpass

My reasoning is that what we care about is the _effectivelength of the one-pole lowpass impulse response, and tau is the "equivalent rectangular width" of an exponential decay. That is, the area under an exponential decaying down from 1 is tau. This pairs better with the rect variants that specify length also. Using seconds in this one and samples in the other is bothersome, but it feels right to me, since the rect length must be an integer. Thus ms_envelope(tau, x) corresponds approximately to ms_envelope_rect(int(tau*SR), x). I suppose we could change the _rect variants to take length in seconds, but then internally it will have to multiply by the sampling rate. In general, it is good to start with the lowest-level parameters and build up higher level APIs that are more user friendly. However, it is also tempting to skip lower level APIs that nobody really wants to see, such as ms_envelope(poleRadius,x). Ultimately people can define them when they need them. I vote for APIs that are easiest to document, use, and keep straight.

On Mon, Apr 27, 2020 at 2:18 PM Julius Smith jos@ccrma.stanford.edu wrote:

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

  • Julius

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo < notifications@github.com> wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii notifications@github.com wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith jos@ccrma.stanford.edu wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii notifications@github.com wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at

https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps benoitdelemps.add@gmail.com writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ .

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

dariosanfilippo commented 4 years ago

Hi, Julius.

On Wed, 29 Apr 2020 at 02:12, josmithiii notifications@github.com wrote:

Hi again,

Right now we have

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass

On second thought, I think we should use the exponential time-constant "tau" instead of t60:

ms_envelope(tau, x) = x*x : si.smooth(ba.tau2pole(tau)); // one-pole lowpass

My reasoning is that what we care about is the _effectivelength of the one-pole lowpass impulse response, and tau is the "equivalent rectangular width" of an exponential decay. That is, the area under an exponential decaying down from 1 is tau. This pairs better with the rect variants that specify length also.

I understand.

Using seconds in this one and samples in the other is bothersome, but it feels right to me, since the rect length must be an integer.

I also think it's fine.

Thus ms_envelope(tau, x) corresponds approximately to ms_envelope_rect(int(tau*SR), x).

I initially proposed exp(-w(1/frame_sec)) for the coefficient as it closely matches the charging and discharging times of the filter. In my intuitive thinking, reaching the final measurement after a time that was ~frame_sec was desirable. The t60 coefficient was very close to exp(-w(1/frame_sec)).

With the code below, I tested the step response of the systems:

import("stdfaust.lib"); mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; process = 1-(1@960) <: mean(time*ma.SR), lptau(time), lpt60(time);

The SR is 96000; the step is 960 samples; the frame length is .01 seconds.

You can see the plotted response of mean (red), lptau (yellow), and lpt60 (green) here: https://www.dropbox.com/s/vgzxp6rhgw7gh09/tau_step_response.png?dl=0.

At n = 959, we have that mean is 1, tau is ~.632, and t60 is ~.999. At n = 1919, mean is 0, tau is ~.233, and t60 is ~.001. So mean and t60 are definitely more similar at the final points. Is this something that we should consider?

I suppose we could change the _rect

variants to take length in seconds, but then internally it will have to multiply by the sampling rate. In general, it is good to start with the lowest-level parameters and build up higher level APIs that are more user friendly. However, it is also tempting to skip lower level APIs that nobody really wants to see, such as ms_envelope(poleRadius,x). Ultimately people can define them when they need them. I vote for APIs that are easiest to document, use, and keep straight.

Personally, in my Faust libraries that I use for my music, I decided to have everything in seconds, from delay lines to time parameters such as these ones as I sometimes must work at different samplerates and I try to keep consistent behaviours. I generally agree with what you say about API.

Cheers, Dario

  • Julius

On Mon, Apr 27, 2020 at 2:18 PM Julius Smith jos@ccrma.stanford.edu wrote:

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

  • Julius

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo < notifications@github.com> wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii notifications@github.com wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith <jos@ccrma.stanford.edu

wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii <notifications@github.com

wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at

https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps benoitdelemps.add@gmail.com writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620918415, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHG3I2DSBIPTCCHSNS7KDITRO5WEZANCNFSM4MR4YWGQ .

sletz commented 4 years ago

So Dario, are you going to prepare a new PR ?

josmithiii commented 4 years ago

Hi Dario,

Nice test. However, I think the following test is also important:

mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; //previously process = 1-(1@960) <: mean(timema.SR), lptau(time), lpt60(time); process = os.osc(1/(0.1time1.5)) : abs <: _, mean(timema.SR), lptau(time), lpt60(time); // f2o0 tenv.dsp // plot(faustout(1:1000,:),'linewidth',2) // legend('input','mean','tau','t60');

It produces the attached plot (hope it makes it through, but the above matlab in comments will regenerate it). As you can see, tau gives more similar ripple to mean. t60 reaches steady state much faster, but its ripple is large. It's effectively much less averaging. The tau case is sluggish, but that's the downside of an exponentially fading memory, and why we like having rect as an alternative. In periodic cases like this, rect has highly variable ripple depending on length. My first try was with osc frequency 1000, and the ripple was flat in steady state because the rect included an integer number of periods. The funny formula for freq above is to avoid that. In general, the average ripple for rect should be about half of what is shown, which is comparable to the tau ripple.

I am now in favor of using seconds for all.

Thanks,

On Tue, Apr 28, 2020 at 6:20 PM Dario Sanfilippo notifications@github.com wrote:

Hi, Julius.

On Wed, 29 Apr 2020 at 02:12, josmithiii notifications@github.com wrote:

Hi again,

Right now we have

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass

On second thought, I think we should use the exponential time-constant "tau" instead of t60:

ms_envelope(tau, x) = x*x : si.smooth(ba.tau2pole(tau)); // one-pole lowpass

My reasoning is that what we care about is the _effectivelength of the one-pole lowpass impulse response, and tau is the "equivalent rectangular width" of an exponential decay. That is, the area under an exponential decaying down from 1 is tau. This pairs better with the rect variants that specify length also.

I understand.

Using seconds in this one and samples in the other is bothersome, but it feels right to me, since the rect length must be an integer.

I also think it's fine.

Thus ms_envelope(tau, x) corresponds approximately to ms_envelope_rect(int(tau*SR), x).

I initially proposed exp(-w(1/frame_sec)) for the coefficient as it closely matches the charging and discharging times of the filter. In my intuitive thinking, reaching the final measurement after a time that was ~frame_sec was desirable. The t60 coefficient was very close to exp(-w(1/frame_sec)).

With the code below, I tested the step response of the systems:

import("stdfaust.lib"); mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; process = 1-(1@960) <: mean(time*ma.SR), lptau(time), lpt60(time);

The SR is 96000; the step is 960 samples; the frame length is .01 seconds.

You can see the plotted response of mean (red), lptau (yellow), and lpt60 (green) here: https://www.dropbox.com/s/vgzxp6rhgw7gh09/tau_step_response.png?dl=0.

At n = 959, we have that mean is 1, tau is ~.632, and t60 is ~.999. At n = 1919, mean is 0, tau is ~.233, and t60 is ~.001. So mean and t60 are definitely more similar at the final points. Is this something that we should consider?

I suppose we could change the _rect

variants to take length in seconds, but then internally it will have to multiply by the sampling rate. In general, it is good to start with the lowest-level parameters and build up higher level APIs that are more user friendly. However, it is also tempting to skip lower level APIs that nobody really wants to see, such as ms_envelope(poleRadius,x). Ultimately people can define them when they need them. I vote for APIs that are easiest to document, use, and keep straight.

Personally, in my Faust libraries that I use for my music, I decided to have everything in seconds, from delay lines to time parameters such as these ones as I sometimes must work at different samplerates and I try to keep consistent behaviours. I generally agree with what you say about API.

Cheers, Dario

  • Julius

On Mon, Apr 27, 2020 at 2:18 PM Julius Smith jos@ccrma.stanford.edu wrote:

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

  • Julius

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo < notifications@github.com> wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii notifications@github.com wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith < jos@ccrma.stanford.edu

wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii < notifications@github.com

wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at

https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps < benoitdelemps.add@gmail.com> writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620918415 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AHG3I2DSBIPTCCHSNS7KDITRO5WEZANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620937641, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQZKFLHECIPRNYGZVKXZATRO56GHANCNFSM4MR4YWGQ .

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

dariosanfilippo commented 4 years ago

Hi, Julius.

On Wed, 29 Apr 2020 at 15:30, josmithiii notifications@github.com wrote:

Hi Dario,

Nice test. However, I think the following test is also important:

mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; //previously process = 1-(1@960) <: mean(timema.SR), lptau(time), lpt60(time); process = os.osc(1/(0.1time1.5)) : abs <: _, mean(timema.SR), lptau(time), lpt60(time); // f2o0 tenv.dsp // plot(faustout(1:1000,:),'linewidth',2) // legend('input','mean','tau','t60');

That's right.

It produces the attached plot (hope it makes it through, but the above matlab in comments will regenerate it). As you can see, tau gives more similar ripple to mean. t60 reaches steady state much faster, but its ripple is large.

It's effectively much less averaging.

Yes, the trade-off of reaching the value fast is to be less accurate in the final calculation.

The tau case is sluggish, but that's the downside of an exponentially fading memory, and why we like having rect as an alternative. In periodic cases like this, rect has highly variable ripple depending on length. My first try was with osc frequency 1000, and the ripple was flat in steady state because the rect included an integer number of periods. The funny formula for freq above is to avoid that. In general, the average ripple for rect should be about half of what is shown, which is comparable to the tau ripple.

I understand.

Just to have a full perspective on the matter, there is yet another way to calculate the coefficient that I found in Zölzer 2008. The lowpass design, in this case, is a negative feedback around a (backward Euler's) integrator. He sets the integrator's cutoff to 1-exp(-2.2/SR*t). You can see the response of this system with your test with the code below; it seems to be in between tau and t60, and apparently the ripples are the most similar to moving average while the system, with the step response, reaches the top value at about the same time.

import("stdfaust.lib"); mean(period, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)) with { length = period ma.SR : rint; }; lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); lptz(tz, x) = ((x - _) : (1 - zolzer(tz)) : fi.pole(1)) ~ with { zolzer(t) = exp(-2.2/(ma.SRt)); }; time = .01; process = os.osc(1/(0.1time*1.5)) : abs <: , mean(time), lptau(time), lpt60(time), lptz(time); //process = 1-1@(rint(time*ma.SR)) <: _, mean(time), lptau(time), lpt60(time), lptz(time); // step response

I am now in favor of using seconds for all.

If you say that the ripples should be about half, then we can stick to tau. We may also consider having all the options, provided that we find adequate names for the functions to distinguish between their functionalities.

For example, having a fast response can be useful for automatic gain control, despite the ripples may cause some intermodulation distortion. So perhaps one design could guarantee to reach the final value at the expected time, while the other could guarantee precision (smaller ripples).

As soon as we decide how to proceed, I can do another pull-request with the envelope functions and I'd change mean as you saw above, using rint for the closest int.

Best, Dario

Thanks,

  • Julius

On Tue, Apr 28, 2020 at 6:20 PM Dario Sanfilippo <notifications@github.com

wrote:

Hi, Julius.

On Wed, 29 Apr 2020 at 02:12, josmithiii notifications@github.com wrote:

Hi again,

Right now we have

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass

On second thought, I think we should use the exponential time-constant "tau" instead of t60:

ms_envelope(tau, x) = x*x : si.smooth(ba.tau2pole(tau)); // one-pole lowpass

My reasoning is that what we care about is the _effectivelength of the one-pole lowpass impulse response, and tau is the "equivalent rectangular width" of an exponential decay. That is, the area under an exponential decaying down from 1 is tau. This pairs better with the rect variants that specify length also.

I understand.

Using seconds in this one and samples in the other is bothersome, but it feels right to me, since the rect length must be an integer.

I also think it's fine.

Thus ms_envelope(tau, x) corresponds approximately to ms_envelope_rect(int(tau*SR), x).

I initially proposed exp(-w(1/frame_sec)) for the coefficient as it closely matches the charging and discharging times of the filter. In my intuitive thinking, reaching the final measurement after a time that was ~frame_sec was desirable. The t60 coefficient was very close to exp(-w(1/frame_sec)).

With the code below, I tested the step response of the systems:

import("stdfaust.lib"); mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; process = 1-(1@960) <: mean(time*ma.SR), lptau(time), lpt60(time);

The SR is 96000; the step is 960 samples; the frame length is .01 seconds.

You can see the plotted response of mean (red), lptau (yellow), and lpt60 (green) here: https://www.dropbox.com/s/vgzxp6rhgw7gh09/tau_step_response.png?dl=0.

At n = 959, we have that mean is 1, tau is ~.632, and t60 is ~.999. At n

1919, mean is 0, tau is ~.233, and t60 is ~.001. So mean and t60 are definitely more similar at the final points. Is this something that we should consider?

I suppose we could change the _rect

variants to take length in seconds, but then internally it will have to multiply by the sampling rate. In general, it is good to start with the lowest-level parameters and build up higher level APIs that are more user friendly. However, it is also tempting to skip lower level APIs that nobody really wants to see, such as ms_envelope(poleRadius,x). Ultimately people can define them when they need them. I vote for APIs that are easiest to document, use, and keep straight.

Personally, in my Faust libraries that I use for my music, I decided to have everything in seconds, from delay lines to time parameters such as these ones as I sometimes must work at different samplerates and I try to keep consistent behaviours. I generally agree with what you say about API.

Cheers, Dario

  • Julius

On Mon, Apr 27, 2020 at 2:18 PM Julius Smith jos@ccrma.stanford.edu wrote:

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

  • Julius

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo < notifications@github.com> wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii notifications@github.com wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith < jos@ccrma.stanford.edu

wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii < notifications@github.com

wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at

https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps < benoitdelemps.add@gmail.com> writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list

Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III < jos@ccrma.stanford.edu> Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620918415

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2DSBIPTCCHSNS7KDITRO5WEZANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620937641 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAQZKFLHECIPRNYGZVKXZATRO56GHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621207160, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHG3I2AKB2N6YKA663I3QTDRPATWHANCNFSM4MR4YWGQ .

josmithiii commented 4 years ago

The Zölzer 2008 algorithm looks great! Let's include it!

In general, I agree with keeping all cases, using a consistent naming convention and API.

Looking good . . .

On Wed, Apr 29, 2020 at 7:41 AM Dario Sanfilippo notifications@github.com wrote:

Hi, Julius.

On Wed, 29 Apr 2020 at 15:30, josmithiii notifications@github.com wrote:

Hi Dario,

Nice test. However, I think the following test is also important:

mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; //previously process = 1-(1@960) <: mean(timema.SR), lptau(time), lpt60(time); process = os.osc(1/(0.1time1.5)) : abs <: _, mean(timema.SR), lptau(time), lpt60(time); // f2o0 tenv.dsp // plot(faustout(1:1000,:),'linewidth',2) // legend('input','mean','tau','t60');

That's right.

It produces the attached plot (hope it makes it through, but the above matlab in comments will regenerate it). As you can see, tau gives more similar ripple to mean. t60 reaches steady state much faster, but its ripple is large.

It's effectively much less averaging.

Yes, the trade-off of reaching the value fast is to be less accurate in the final calculation.

The tau case is sluggish, but that's the downside of an exponentially fading memory, and why we like having rect as an alternative. In periodic cases like this, rect has highly variable ripple depending on length. My first try was with osc frequency 1000, and the ripple was flat in steady state because the rect included an integer number of periods. The funny formula for freq above is to avoid that. In general, the average ripple for rect should be about half of what is shown, which is comparable to the tau ripple.

I understand.

Just to have a full perspective on the matter, there is yet another way to calculate the coefficient that I found in Zölzer 2008. The lowpass design, in this case, is a negative feedback around a (backward Euler's) integrator. He sets the integrator's cutoff to 1-exp(-2.2/SR*t). You can see the response of this system with your test with the code below; it seems to be in between tau and t60, and apparently the ripples are the most similar to moving average while the system, with the step response, reaches the top value at about the same time.

import("stdfaust.lib"); mean(period, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)) with { length = period ma.SR : rint; }; lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); lptz(tz, x) = ((x - _) : (1 - zolzer(tz)) : fi.pole(1)) ~ with { zolzer(t) = exp(-2.2/(ma.SRt)); }; time = .01; process = os.osc(1/(0.1time*1.5)) : abs <: , mean(time), lptau(time), lpt60(time), lptz(time); //process = 1-1@(rint(time*ma.SR)) <: _, mean(time), lptau(time), lpt60(time), lptz(time); // step response

I am now in favor of using seconds for all.

If you say that the ripples should be about half, then we can stick to tau. We may also consider having all the options, provided that we find adequate names for the functions to distinguish between their functionalities.

For example, having a fast response can be useful for automatic gain control, despite the ripples may cause some intermodulation distortion. So perhaps one design could guarantee to reach the final value at the expected time, while the other could guarantee precision (smaller ripples).

As soon as we decide how to proceed, I can do another pull-request with the envelope functions and I'd change mean as you saw above, using rint for the closest int.

Best, Dario

Thanks,

  • Julius

On Tue, Apr 28, 2020 at 6:20 PM Dario Sanfilippo < notifications@github.com

wrote:

Hi, Julius.

On Wed, 29 Apr 2020 at 02:12, josmithiii notifications@github.com wrote:

Hi again,

Right now we have

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass

On second thought, I think we should use the exponential time-constant "tau" instead of t60:

ms_envelope(tau, x) = x*x : si.smooth(ba.tau2pole(tau)); // one-pole lowpass

My reasoning is that what we care about is the _effectivelength of the one-pole lowpass impulse response, and tau is the "equivalent rectangular width" of an exponential decay. That is, the area under an exponential decaying down from 1 is tau. This pairs better with the rect variants that specify length also.

I understand.

Using seconds in this one and samples in the other is bothersome, but it feels right to me, since the rect length must be an integer.

I also think it's fine.

Thus ms_envelope(tau, x) corresponds approximately to ms_envelope_rect(int(tau*SR), x).

I initially proposed exp(-w(1/frame_sec)) for the coefficient as it closely matches the charging and discharging times of the filter. In my intuitive thinking, reaching the final measurement after a time that was ~frame_sec was desirable. The t60 coefficient was very close to exp(-w(1/frame_sec)).

With the code below, I tested the step response of the systems:

import("stdfaust.lib"); mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; process = 1-(1@960) <: mean(time*ma.SR), lptau(time), lpt60(time);

The SR is 96000; the step is 960 samples; the frame length is .01 seconds.

You can see the plotted response of mean (red), lptau (yellow), and lpt60 (green) here: https://www.dropbox.com/s/vgzxp6rhgw7gh09/tau_step_response.png?dl=0.

At n = 959, we have that mean is 1, tau is ~.632, and t60 is ~.999. At n

1919, mean is 0, tau is ~.233, and t60 is ~.001. So mean and t60 are definitely more similar at the final points. Is this something that we should consider?

I suppose we could change the _rect

variants to take length in seconds, but then internally it will have to multiply by the sampling rate. In general, it is good to start with the lowest-level parameters and build up higher level APIs that are more user friendly. However, it is also tempting to skip lower level APIs that nobody really wants to see, such as ms_envelope(poleRadius,x). Ultimately people can define them when they need them. I vote for APIs that are easiest to document, use, and keep straight.

Personally, in my Faust libraries that I use for my music, I decided to have everything in seconds, from delay lines to time parameters such as these ones as I sometimes must work at different samplerates and I try to keep consistent behaviours. I generally agree with what you say about API.

Cheers, Dario

  • Julius

On Mon, Apr 27, 2020 at 2:18 PM Julius Smith <jos@ccrma.stanford.edu

wrote:

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

  • Julius

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo < notifications@github.com> wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii < notifications@github.com> wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith < jos@ccrma.stanford.edu

wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii < notifications@github.com

wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at

https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps < benoitdelemps.add@gmail.com> writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list

Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list

Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III < jos@ccrma.stanford.edu> Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III <jos@ccrma.stanford.edu

Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub <https://github.com/grame-cncm/faustlibraries/issues/33 , or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620918415

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2DSBIPTCCHSNS7KDITRO5WEZANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620937641

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFLHECIPRNYGZVKXZATRO56GHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621207160 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AHG3I2AKB2N6YKA663I3QTDRPATWHANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621255818, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQZKFPXUKHGNR6ADQF2CCLRPA4CXANCNFSM4MR4YWGQ .

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

dariosanfilippo commented 4 years ago

Great.

So I'd suggest implementing a set of averaging algorithms and I guess that maths.lib would be a good place to keep them. These ones would all the averaging periods in seconds.

The averaging algorithms would be:

The functions names could be:

The definitions would be:

avg_rect(period, x) = x : ba.slidingMean(rint(period ma.SR)); avg_tau(period, x) = x : si.smooth(ba.tau2pole(period)); avg_t60(period, x) = x : si.smooth(ba.tau2pole(period / 6.91)); avgta(period, x) = loop ~ with { loop(fb) = (x - fb) ta + fb; ta = 1 - exp(-2.2 / (ma.SR * period)); }; // I'm not using fi.pole to save a one-sample delay

If these look fine, I'll proceed with the PR.

Best, Dario

On Wed, 29 Apr 2020 at 18:13, josmithiii notifications@github.com wrote:

The Zölzer 2008 algorithm looks great! Let's include it!

In general, I agree with keeping all cases, using a consistent naming convention and API.

Looking good . . .

  • Julius

On Wed, Apr 29, 2020 at 7:41 AM Dario Sanfilippo <notifications@github.com

wrote:

Hi, Julius.

On Wed, 29 Apr 2020 at 15:30, josmithiii notifications@github.com wrote:

Hi Dario,

Nice test. However, I think the following test is also important:

mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; //previously process = 1-(1@960) <: mean(timema.SR), lptau(time), lpt60(time); process = os.osc(1/(0.1time1.5)) : abs <: _, mean(timema.SR), lptau(time), lpt60(time); // f2o0 tenv.dsp // plot(faustout(1:1000,:),'linewidth',2) // legend('input','mean','tau','t60');

That's right.

It produces the attached plot (hope it makes it through, but the above matlab in comments will regenerate it). As you can see, tau gives more similar ripple to mean. t60 reaches steady state much faster, but its ripple is large.

It's effectively much less averaging.

Yes, the trade-off of reaching the value fast is to be less accurate in the final calculation.

The tau case is sluggish, but that's the downside of an exponentially fading memory, and why we like having rect as an alternative. In periodic cases like this, rect has highly variable ripple depending on length. My first try was with osc frequency 1000, and the ripple was flat in steady state because the rect included an integer number of periods. The funny formula for freq above is to avoid that. In general, the average ripple for rect should be about half of what is shown, which is comparable to the tau ripple.

I understand.

Just to have a full perspective on the matter, there is yet another way to calculate the coefficient that I found in Zölzer 2008. The lowpass design, in this case, is a negative feedback around a (backward Euler's) integrator. He sets the integrator's cutoff to 1-exp(-2.2/SR*t). You can see the response of this system with your test with the code below; it seems to be in between tau and t60, and apparently the ripples are the most similar to moving average while the system, with the step response, reaches the top value at about the same time.

import("stdfaust.lib"); mean(period, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)) with { length = period ma.SR : rint; }; lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); lptz(tz, x) = ((x - _) : (1 - zolzer(tz)) : fi.pole(1)) ~ with { zolzer(t) = exp(-2.2/(ma.SRt)); }; time = .01; process = os.osc(1/(0.1time*1.5)) : abs <: , mean(time), lptau(time), lpt60(time), lptz(time); //process = 1-1@(rint(time*ma.SR)) <: _, mean(time), lptau(time), lpt60(time), lptz(time); // step response

I am now in favor of using seconds for all.

If you say that the ripples should be about half, then we can stick to tau. We may also consider having all the options, provided that we find adequate names for the functions to distinguish between their functionalities.

For example, having a fast response can be useful for automatic gain control, despite the ripples may cause some intermodulation distortion. So perhaps one design could guarantee to reach the final value at the expected time, while the other could guarantee precision (smaller ripples).

As soon as we decide how to proceed, I can do another pull-request with the envelope functions and I'd change mean as you saw above, using rint for the closest int.

Best, Dario

Thanks,

  • Julius

On Tue, Apr 28, 2020 at 6:20 PM Dario Sanfilippo < notifications@github.com

wrote:

Hi, Julius.

On Wed, 29 Apr 2020 at 02:12, josmithiii notifications@github.com wrote:

Hi again,

Right now we have

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass

On second thought, I think we should use the exponential time-constant "tau" instead of t60:

ms_envelope(tau, x) = x*x : si.smooth(ba.tau2pole(tau)); // one-pole lowpass

My reasoning is that what we care about is the _effectivelength of the one-pole lowpass impulse response, and tau is the "equivalent rectangular width" of an exponential decay. That is, the area under an exponential decaying down from 1 is tau. This pairs better with the rect variants that specify length also.

I understand.

Using seconds in this one and samples in the other is bothersome, but it feels right to me, since the rect length must be an integer.

I also think it's fine.

Thus ms_envelope(tau, x) corresponds approximately to ms_envelope_rect(int(tau*SR), x).

I initially proposed exp(-w(1/frame_sec)) for the coefficient as it closely matches the charging and discharging times of the filter. In my intuitive thinking, reaching the final measurement after a time that was ~frame_sec was desirable. The t60 coefficient was very close to exp(-w(1/frame_sec)).

With the code below, I tested the step response of the systems:

import("stdfaust.lib"); mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; process = 1-(1@960) <: mean(time*ma.SR), lptau(time), lpt60(time);

The SR is 96000; the step is 960 samples; the frame length is .01 seconds.

You can see the plotted response of mean (red), lptau (yellow), and lpt60 (green) here: https://www.dropbox.com/s/vgzxp6rhgw7gh09/tau_step_response.png?dl=0 .

At n = 959, we have that mean is 1, tau is ~.632, and t60 is ~.999. At n

1919, mean is 0, tau is ~.233, and t60 is ~.001. So mean and t60 are definitely more similar at the final points. Is this something that we should consider?

I suppose we could change the _rect

variants to take length in seconds, but then internally it will have to multiply by the sampling rate. In general, it is good to start with the lowest-level parameters and build up higher level APIs that are more user friendly. However, it is also tempting to skip lower level APIs that nobody really wants to see, such as ms_envelope(poleRadius,x). Ultimately people can define them when they need them. I vote for APIs that are easiest to document, use, and keep straight.

Personally, in my Faust libraries that I use for my music, I decided to have everything in seconds, from delay lines to time parameters such as these ones as I sometimes must work at different samplerates and I try to keep consistent behaviours. I generally agree with what you say about API.

Cheers, Dario

  • Julius

On Mon, Apr 27, 2020 at 2:18 PM Julius Smith < jos@ccrma.stanford.edu

wrote:

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

  • Julius

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo < notifications@github.com> wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii < notifications@github.com> wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith < jos@ccrma.stanford.edu

wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii < notifications@github.com

wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at

https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps < benoitdelemps.add@gmail.com> writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list

Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list

Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III < jos@ccrma.stanford.edu> Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list

Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III < jos@ccrma.stanford.edu

Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33 , or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620918415

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2DSBIPTCCHSNS7KDITRO5WEZANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620937641

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFLHECIPRNYGZVKXZATRO56GHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621207160

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2AKB2N6YKA663I3QTDRPATWHANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621255818 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AAQZKFPXUKHGNR6ADQF2CCLRPA4CXANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621312763, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHG3I2H7A5S672DCSVSLB63RPBGZ3ANCNFSM4MR4YWGQ .

josmithiii commented 4 years ago

I can see them going into either maths.lib or envelopes.lib

I like all the names except:

I would prefer avg_rect over avg_lin.

Does Zolzer 2008 cite an original source? It would be nice to have a better name than "ta". My copy of Zolzer is locked up in my closed campus office where I can't access it!

On Wed, Apr 29, 2020 at 10:20 AM Dario Sanfilippo notifications@github.com wrote:

Great.

So I'd suggest implementing a set of averaging algorithms and I guess that maths.lib would be a good place to keep them. These ones would all the averaging periods in seconds.

The averaging algorithms would be:

  • moving average;
  • exponential based on tau;
  • exponential based on t_60;
  • exponential based on t_a (as defined in Zölzer 2008, t_a = t_90 - t_10 = 2.2*tau).

The functions names could be:

  • avg_lin or avg_rect;
  • avg_tau;
  • avg_t60;
  • avg_ta.

The definitions would be:

avg_rect(period, x) = x : ba.slidingMean(rint(period ma.SR)); avg_tau(period, x) = x : si.smooth(ba.tau2pole(period)); avg_t60(period, x) = x : si.smooth(ba.tau2pole(period / 6.91)); avgta(period, x) = loop ~ with { loop(fb) = (x - fb) ta + fb; ta = 1 - exp(-2.2 / (ma.SR * period)); }; // I'm not using fi.pole to save a one-sample delay

If these look fine, I'll proceed with the PR.

Best, Dario

On Wed, 29 Apr 2020 at 18:13, josmithiii notifications@github.com wrote:

The Zölzer 2008 algorithm looks great! Let's include it!

In general, I agree with keeping all cases, using a consistent naming convention and API.

Looking good . . .

  • Julius

On Wed, Apr 29, 2020 at 7:41 AM Dario Sanfilippo < notifications@github.com

wrote:

Hi, Julius.

On Wed, 29 Apr 2020 at 15:30, josmithiii notifications@github.com wrote:

Hi Dario,

Nice test. However, I think the following test is also important:

mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; //previously process = 1-(1@960) <: mean(timema.SR), lptau(time), lpt60(time); process = os.osc(1/(0.1time1.5)) : abs <: _, mean(timema.SR), lptau(time), lpt60(time); // f2o0 tenv.dsp // plot(faustout(1:1000,:),'linewidth',2) // legend('input','mean','tau','t60');

That's right.

It produces the attached plot (hope it makes it through, but the above matlab in comments will regenerate it). As you can see, tau gives more similar ripple to mean. t60 reaches steady state much faster, but its ripple is large.

It's effectively much less averaging.

Yes, the trade-off of reaching the value fast is to be less accurate in the final calculation.

The tau case is sluggish, but that's the downside of an exponentially fading memory, and why we like having rect as an alternative. In periodic cases like this, rect has highly variable ripple depending on length. My first try was with osc frequency 1000, and the ripple was flat in steady state because the rect included an integer number of periods. The funny formula for freq above is to avoid that. In general, the average ripple for rect should be about half of what is shown, which is comparable to the tau ripple.

I understand.

Just to have a full perspective on the matter, there is yet another way to calculate the coefficient that I found in Zölzer 2008. The lowpass design, in this case, is a negative feedback around a (backward Euler's) integrator. He sets the integrator's cutoff to 1-exp(-2.2/SR*t). You can see the response of this system with your test with the code below; it seems to be in between tau and t60, and apparently the ripples are the most similar to moving average while the system, with the step response, reaches the top value at about the same time.

import("stdfaust.lib"); mean(period, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)) with { length = period ma.SR : rint; }; lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); lptz(tz, x) = ((x - _) : (1 - zolzer(tz)) : fi.pole(1)) ~ with { zolzer(t) = exp(-2.2/(ma.SRt)); }; time = .01; process = os.osc(1/(0.1time*1.5)) : abs <: , mean(time), lptau(time), lpt60(time), lptz(time); //process = 1-1@(rint(time*ma.SR)) <: _, mean(time), lptau(time), lpt60(time), lptz(time); // step response

I am now in favor of using seconds for all.

If you say that the ripples should be about half, then we can stick to tau. We may also consider having all the options, provided that we find adequate names for the functions to distinguish between their functionalities.

For example, having a fast response can be useful for automatic gain control, despite the ripples may cause some intermodulation distortion. So perhaps one design could guarantee to reach the final value at the expected time, while the other could guarantee precision (smaller ripples).

As soon as we decide how to proceed, I can do another pull-request with the envelope functions and I'd change mean as you saw above, using rint for the closest int.

Best, Dario

Thanks,

  • Julius

On Tue, Apr 28, 2020 at 6:20 PM Dario Sanfilippo < notifications@github.com

wrote:

Hi, Julius.

On Wed, 29 Apr 2020 at 02:12, josmithiii <notifications@github.com

wrote:

Hi again,

Right now we have

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass

On second thought, I think we should use the exponential time-constant "tau" instead of t60:

ms_envelope(tau, x) = x*x : si.smooth(ba.tau2pole(tau)); // one-pole lowpass

My reasoning is that what we care about is the _effectivelength of the one-pole lowpass impulse response, and tau is the "equivalent rectangular width" of an exponential decay. That is, the area under an exponential decaying down from 1 is tau. This pairs better with the rect variants that specify length also.

I understand.

Using seconds in this one and samples in the other is bothersome, but it feels right to me, since the rect length must be an integer.

I also think it's fine.

Thus ms_envelope(tau, x) corresponds approximately to ms_envelope_rect(int(tau*SR), x).

I initially proposed exp(-w(1/frame_sec)) for the coefficient as it closely matches the charging and discharging times of the filter. In my intuitive thinking, reaching the final measurement after a time that was ~frame_sec was desirable. The t60 coefficient was very close to exp(-w(1/frame_sec)).

With the code below, I tested the step response of the systems:

import("stdfaust.lib"); mean(length, x) = x - x@max(1, length) : fi.pole(1.0 - 1.0e-10) : /(float(length)); lptau(tau, x) = x : si.smooth(ba.tau2pole(tau)); lpt60(t60, x) = x : si.smooth(ba.tau2pole(t60/6.91)); time = .01; process = 1-(1@960) <: mean(time*ma.SR), lptau(time), lpt60(time);

The SR is 96000; the step is 960 samples; the frame length is .01 seconds.

You can see the plotted response of mean (red), lptau (yellow), and lpt60 (green) here:

https://www.dropbox.com/s/vgzxp6rhgw7gh09/tau_step_response.png?dl=0 .

At n = 959, we have that mean is 1, tau is ~.632, and t60 is ~.999. At n

1919, mean is 0, tau is ~.233, and t60 is ~.001. So mean and t60 are definitely more similar at the final points. Is this something that we should consider?

I suppose we could change the _rect

variants to take length in seconds, but then internally it will have to multiply by the sampling rate. In general, it is good to start with the lowest-level parameters and build up higher level APIs that are more user friendly. However, it is also tempting to skip lower level APIs that nobody really wants to see, such as ms_envelope(poleRadius,x). Ultimately people can define them when they need them. I vote for APIs that are easiest to document, use, and keep straight.

Personally, in my Faust libraries that I use for my music, I decided to have everything in seconds, from delay lines to time parameters such as these ones as I sometimes must work at different samplerates and I try to keep consistent behaviours. I generally agree with what you say about API.

Cheers, Dario

  • Julius

On Mon, Apr 27, 2020 at 2:18 PM Julius Smith < jos@ccrma.stanford.edu

wrote:

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

I would write something like

ms_envelope(t60, x) = x*x : si.smooth(ba.tau2pole(t60/6.91)); // one-pole lowpass rms_envelope = ms_envelope : sqrt;

The term "t60" is common in artificial reverberation. It's the time to decay by 60 dB.

In addition to these one-pole recursively filtered smoothers, moving-average versions would also be nice to have, e.g.:

ms_envelope_rect(length, x) = x*x : mean(length) with { mean(length,x) = x - x@max(1,int(length)) : fi.pole(1.0-1.0e-10) : /(float(int(length))); // small leakage to avoid possible growing roundoff error };

  • Julius

...

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

On Mon, Apr 27, 2020 at 11:02 AM Dario Sanfilippo < notifications@github.com> wrote:

On Mon, 27 Apr 2020 at 19:30, josmithiii < notifications@github.com> wrote:

How about these names?:

peak_envelope rms_envelope ms_envelope abs_envelope

Their meanings should be obvious ! :-)

Those are perfect.

abs_envelope could also be l1_envelope, referring to the "L1 Norm". But then we would also need l2_envelope for the rms case, and arguably peak_envelope is also l_infinity_envelope, so I vote against the norm-based names and only propose the above list. Not defining envelope_follower means it can be set to any of the above (and more).

Right, agreed on this too.

Would you be in favour of using rms_envelope(frame_sec, x) = x*x : lp1p(1/frame) : sqrt; ?

What would you use for the coeff. calculation to set the frame? I find that using exp(-w(1/frame_sec)) works quite well and is reasonably cheap.

Thanks, Dario

  • Julius

On Mon, Apr 27, 2020 at 10:23 AM Julius Smith < jos@ccrma.stanford.edu

wrote:

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

According to this (a source I used myself), "envelope follower" can mean either rms or peak based, and probably other methods as well:

http://www.nicolascollins.com/texts/electronotes.pdf

  • Julius

On Mon, Apr 27, 2020 at 9:30 AM Dario Sanfilippo < notifications@github.com> wrote:

Hey, Julius.

On Mon, 27 Apr 2020 at 16:33, josmithiii < notifications@github.com

wrote:

Hi Dario,

Below is our previous thread.

Great, thanks.

I am fine with "peak envelope", if that name is at least reasonably well established. (It's also a good functional name.)

I've seen it around more than a few times between electronic musicians and DSP people. In publications, I think that they generally call it "peak measurement", as in [Zölzer 2008] and [Giannoulis 2012]. I think that "peak envelope" is generally a good name as it renders both the facts that there is a peak measurement and that a peak-based envelope is generated.

I vote strongly against "balancing function". I have been in the field of computer music (with Dodge and Jerse) for more than four decades, and I have never seen or heard it used.

I agree. I think that they called it that way only for the specific case in which they were compensating for the amplitude loss after the filter stage.

I vote for "RMS envelope", as "RMS level" is very firmly and widely established, so audio people of all kinds will readily understand it.

Perhaps for "rms_envelope" we can use

rms_envelope(frame_sec, x) = x*x : some-1pole-lowpass(1/frame_sec) : sqrt; ?

For the signals that are rectified and low-passed we could perhaps use "envelope_follower" ?

Also note that "peak and rms envelope" pairs well with "peak and rms meters", which are also very widely established.

In my opinion, we should not break old code. Instead, after amp_follower, just provide a new synonym:

peak_envelope = amp_follower;

Sure, that's good.

shouldn't the RMS functions be moved in the analyzers library?

Why not the library envelopes.lib ?

The way I see it, envelopes.lib generates envelopes out of nothing, whereas analyzers.lib extracts information out of something. I'm also thinking a bit ahead: the RMS correlates to the perceptual intensity of signals, and I was planning on adding a zero-crossing rate function for noisiness as well as a spectral tendency function, so it could be nice to have them together.

Mine are only suggestions and I am not voting strongly for anything in particular, so I'll be happy with any decisions.

Dario

  • Julius

Earlier thread: From: Julius Smith jos@ccrma.stanford.edu Thu, Jul 18, 2019, 5:43 PM Reply to all to Dario Yes, this is a fundamental trade-off. I normally set it as close as I can to human perception (according to critical bands of hearing). Then there can be more processing beyond that, which of course happens in the brain.

On Thu, Jul 18, 2019 at 2:24 PM Dario Sanfilippo

sanfilippo.dario@gmail.com wrote:

I did try it for onset detection but it's not stable enough when you push the responsiveness high, which is what you'd need for small transients. There's a tradeoff: the faster the responsiveness, the more significant the oscillation around the equilibrium point. I can't remember what the stability limit is but setting the analysis above 10ms (100Hz as the parameter is in Hz) it's less stable and reliable. I guess that the Gabor limit applies to time-domain measurements too and not just FFT.

I can perform some tests and plot the results if you're interested.

D

On Thu, 18 Jul 2019 at 23:06, Julius Smith < jos@ccrma.stanford.edu> wrote:

That's a nice dynamic "brightness follower" - good for transient detection, e.g.

On Thu, Jul 18, 2019 at 1:01 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu

wrote:

I believe the power below balances the power above, IIRC

In my algorithm, yes. I do high_spectrum_rms - low_spectrum_rms. So the sign of the difference tells towards which direction the crossover cutoff should move, and the magnitude tells how far from the equilibrium it is. As a typical negative feedback configuration, the system finds a dynamical equilibrium point and minimally oscillates around the equal-power cutoff.

So I'll change my writings and I'll talk about power when discussing RMS. Thanks for the hint.

Dario

On Thu, Jul 18, 2019 at 11:50 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

Yes, it was a typo: I meant MEDIAN against AVERAGE.

I perfectly understand that studying the code might be too much.

As I said, the algorithm simply finds the cutoff of the crossover where the RMS values of the outputs are the same. So it is a balancing point, which would make think of a centroid, but I'm not too sure.

Thanks, Dario

On Thu, 18 Jul 2019 at 20:44, Julius Smith < jos@ccrma.stanford.edu

wrote:

Mean and average normally mean the same thing.

RMS is the square root of the average power, not energy.

Happy to answer any specific questions, but studying code goes outside my time allotment for email (I spend WAY too much time on email!)

On Wed, Jul 17, 2019 at 3:57 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

On Thu, 18 Jul 2019 at 00:35, Julius Smith < jos@ccrma.stanford.edu> wrote:

Hmmm, I have never heard the term "spectral tendency". A very common term is "spectral centroid". Are they related?

Well, the centroid is one form of spectral tendency. I did formalise the algorithm with difference equations for an article but my math understanding is not good enough to determine if it's a weighted mean or a weighted average (centroid).

The algorithm is an adaptive mechanism that finds the cutoff of a crossover whose RMS of the two outputs is roughly equal. So it is a balancing point, and intuitively I'd say it's like a spectral centroid, but I believe I compared the FFT centroid and my algorithm and they don't quite match in all cases. A guy from the music DSP list claimed that it is a weighted median but he didn't explain why.

I'm attaching the Faust code of the algorithms without dependencies. Perhaps if you have a look at the diagram you can see if it's more of a weighted median or average. If you could explain why that would be great.

Thanks a lot, Dario

I should have seen "balance function" since I own a copy of Dodge and Jerse, but it appears not to have taken hold. I think "average magnitude" would be a nice name.

With Zolzer's use of peak envelope, I am happy to switch to that.

It occurs to me that max(peakEnvelope, averageMagnitude) could be nice to use, blending longer-term averaging with peak sensitivity.

On Wed, Jul 17, 2019 at 1:41 PM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

For the name peak envelope, we could reference Zölzer's DASP from 2008, page 229. For the rectifier followed by a LP, we could reference Dodge and Jerse's Computer Music, page 181. They call it "balance function" and they describe it as an approximation of average power. Usually, I see RMS being linked to the average energy. So we might choose names based on those references.

Also, as an alternative technique to that implemented in the libraries for RMS calculation, the input can be squares, averaged with a one-pole LP, and then passed through sqrt. For this, we can reference Zölzer too.

I designed a spectral tendency algorithm which is in my libraries that works with a 1p1z crossover, 3 rms units (like those I described above), an integrator, and a couple more multiplications. I must say I'm really happy of how well it works given the computational non-aggressiveness. I'm attaching a couple of plots here to give you an idea. Perhaps we can add that in analyzers.lib? Of course, I can implement a version without dependencies on my other libraries.

The plots show two tests with a 1k sine and white noise at 96kHz. The responsiveness of the system is 15Hz

Cheers, Dario

On Wed, 17 Jul 2019 at 21:46, Julius Smith < jos@ccrma.stanford.edu> wrote:

I like the name "peak envelope", but I have never seen it. However, my knowledge comes from my analog synth DIY days in the 1970s! I never got deeply into compression/limiting/mastering/etc., in part because two other faculty at CCRMA have an entire course on it, plus associated research.

An absolute value can be called a "full-wave rectifier", done in analog using a diode bridge. Lowpassing that is the standard AC-to-DC conversion for power supplies (plus a voltage regulator chip nowadays). It could be called "root mean abs" (RMA) but I've never seen that either. People seem to use it interchangeably with RMS, but it's L1 norm instead of L2 which matters sometimes.

It would be great if someone wanted to overhaul the names in the Faust libraries to make them ideal. We would introduce the new names and retire the old names to a compatibility include.

Cheers,

  • Julius

On Wed, Jul 17, 2019 at 2:27 AM Dario Sanfilippo sanfilippo.dario@gmail.com wrote:

Hi, Julius.

I was gonna suggest that too; I usually combine it with a 1-pole LP at the end to smooth out the attack. Also, RMS wouldn't prevent clipping in full-amplitude signals.

I was wondering, is there a name for a lowpass which simply processes the absolute value of the input? I sometimes see that one named "amp follower" and the zero-delay attack with exp. decay "peak envelope", but I guess it might change from author to author.

Cheers, Dario

On Wed, 17 Jul 2019 at 01:48, Julius Smith < jos@ccrma.stanford.edu> wrote:

To get around the delay problem, you could consider an.amp_follower(). It is based on the typical amplitude envelope follower used in analog (zero delay rise to peaks, exponential decay after each local peak)

On Tue, Jul 16, 2019 at 2:07 PM Bart Brouns < bart@magnetophon.nl> wrote:

Hi Benoit,

Sorry for the late reply.

I originally wrote slidingRMSn for usage in compressors, which is in essence what you are doing, so this is certainly an option.

The downsides of using it here are:

You have to wait a bit for an estimate of the loudness, so it's always late. With smaller values of N you get faster reaction, but also more distortion.

If you can find a way to predict the level of your synth before you make the sound, it will sound better, cause you then could avoid these problems.

If you want to use slidingRMSn, I suggest you look at

https://github.com/magnetophon/faustCompressors and in particular

https://github.com/magnetophon/faustCompressors/blob/master/RMS_FBFFcompressor_mono.dsp

Note: they where written before slidingReduce was merged upstream and I haven't adopted them yet to the new libs, cause I wasn't able to package the new faust release for my distro yet.

As to your other questions:

maxN is a necessary implementation detail: faust needs to know the maximum length of a delayline before it can create it. N can be the same as maxN if you want. It's just that maxN needs to be known at compile-time, and N can vary continuously during use if you want. Choosing N is the hard part. It makes sense to have it related to your lowest freq, but the best value you'll have to determine by ear, afaik. In other synths I've gotten good results by setting the decay-time of the built-in limiter per note.

Hope that helps, let me know if you have any other questions!

Cheers, Bart.

Benoit Delemps < benoitdelemps.add@gmail.com> writes:

Hello everyone,

i am trying to build the additive synthesis module like illustrated in this example.

https://faust.grame.fr/doc/tutorials/#additive-synthesis

The thing is that the normalization applied at the end of the signal (dividing by the number of harmonics) prevents overloading but in the same time reduces drastically the level output if the energy in the spectrum is low.

So instead of dividing by number of harmonics, i choose to divide by ba.slidingRMSn to prevent overloading and maintain the level ouput.

And here are my questions.

  • using slidingRMSn, is this the "good" way to normalize ouput knowing i want to maintain the level output even if i drop some harmonic's energy?

in the documentation, we got: usage

: slidingRMSn(N,maxN) :

  • What is the purpose of maxN ?
  • N has to be different of maxN ?
  • And last question, how i choose N ?

I tought i should do that: nextpowerof2(Fs / 2*lowest frequency) but that doesn't work well at low frequency. So i did that instead: nextpowerof2(Fs / lowest frequency) works fine but don't know really why

here is a sample of my code:

additiveSynth = freq <: par(i,nHarmonics,oscilator(i)):><:,( : ba.slidingRMSn(512,512)) : / :> *gain : envelope with{ freq =

vgroup("[0]control",hgroup("params",hslider("fundamental[style:knob]",440,125,3000,0.01)));

gain =

vgroup("[0]control",hgroup("params",hslider("gain[style:knob]",-10,0,-100,0.01):

ba.db2linear())); gate = vgroup("[1]control",button("gate")); envelope = *en.asr(0.35,1,0.35,gate); nHarmonics = 10; };

I thank you for you help

bests

Benoit _ Faudiostream-users mailing list

Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users


Faudiostream-users mailing list

Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III < jos@ccrma.stanford.edu> Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/


Faudiostream-users mailing list

Faudiostream-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/faudiostream-users

--

Julius O. Smith III < jos@ccrma.stanford.edu

Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III < jos@ccrma.stanford.edu> Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

--

Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

On Mon, Apr 27, 2020 at 5:57 AM Dario Sanfilippo < notifications@github.com

wrote:

I vaguely remember discussing this with Julius but I can't find the conversation in my inbox.

I am used to seeing the function "(an.)amp_follower" being called "peak envelope."

On the other hand, amplitude tracking implemented as rectified and low-passed signals, RMS, or instantaneous amplitude are sometimes called "balancing function" (Dodge and Jerse) or "envelope detector" (Wikipedia).

Do you have any information on these naming conventions?

A different but related matter: if doing so wouldn't break any other piece of code, shouldn't the RMS functions be moved in the analyzers library?

Cheers

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33 , or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFIEFSJZN4M5RS6NBMTROV6M3ANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620025663

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2COFXRONJ6BNPMSFELROWJUVANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620126241

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2FVXVXAC32SIBPYKA3ROW6L3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620142505

,

or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFJXJLDZC642OQFRXOLROXCFHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620918415

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2DSBIPTCCHSNS7KDITRO5WEZANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-620937641

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFLHECIPRNYGZVKXZATRO56GHANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621207160

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AHG3I2AKB2N6YKA663I3QTDRPATWHANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub <

https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621255818

, or unsubscribe <

https://github.com/notifications/unsubscribe-auth/AAQZKFPXUKHGNR6ADQF2CCLRPA4CXANCNFSM4MR4YWGQ

.

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub < https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621312763 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/AHG3I2H7A5S672DCSVSLB63RPBGZ3ANCNFSM4MR4YWGQ

.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/grame-cncm/faustlibraries/issues/33#issuecomment-621349762, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQZKFIIL4SSRSTIV75KKDTRPBOWBANCNFSM4MR4YWGQ .

-- Julius O. Smith III jos@ccrma.stanford.edu Professor of Music and, by courtesy, Electrical Engineering CCRMA, Stanford University http://ccrma.stanford.edu/~jos/