Guest

— Forum Scope —

— Match —

— Forum Options —

Minimum search word length is 3 characters - maximum search word length is 84 characters

S-shaped attack/release curves
November 19, 2014
9:53 pm
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

Hi Will, how are you?

I’m slowly starting to get the hang of it, and I’m trying to modify my compressor again in a subtle way. What I want to do is modify the attack/release curves in a way so that they don’t have a linear or exponential (gain reduction) curve, but an S-curve (sigmoid). I realize this might seem like a subtle modification, but I did some tests and I’m quite certain that it makes some of the compression techniques I use during my mastering sessions a bit smoother. So I’m curious if something like this is possible without being super heavy on the cpu.

I figured out two ways of implementing this modification. By actually changing the envelope detector, or by scaling the release and attack times before they get to the detector. I am working on a very flexible formula where I can shape the sigmoid curve as I wish, giving me a lot of options, but for now I’m doing some tests with a simple sine function that changes a linear value between 0 and 1 to a sigmoid value between 0 and 1. Here it is: Y(x) = 0.5(sin(x*pi-pi/2)+1)

At this point I’m just curious if it can be done, or if it would require an envelope detector that works fundamentally different. Do you have any thoughts on this?

All the best,

JD

November 20, 2014
5:29 am
W Pirkle
Forum Posts: 206
Member Since:
January 29, 2017
Offline

Hi JD, all good.

You can just apply the waveshaper to the output of the detector. There are a bunch of sigmoid waveshapers out there; I list several in the synth book, but a google of "sigmoid functions" should get you plenty more.

- Will

November 20, 2014
6:14 am
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

Mmm, didn’t expect it to be that simple But I think I get it. Maybe it’s time to learn some more about envelope detectors in general… Still some difficulties to wrap my head around it. Anyway, thanks very much for the fast reply, Will! Back to work

November 20, 2014
5:26 pm
W Pirkle
Forum Posts: 206
Member Since:
January 29, 2017
Offline

Just remember that these envelope detectors do not output a linear shape (like the ADSR figures you sometimes see, which almost always are not linear either). These detectors mimic the exponential charge and discharge of a capacitor, so you are really waveshaping *those* curves.

- WP

November 20, 2014
6:24 pm
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

Ah thanks:) I was just re-reading a part of the book and trying to figure that out! I'll get to that as soon as possible, but I'm still struggling with one other thing. I don’t want to take up too much of your time, but it would be great if you had time for some last advise!

It seems that if I want to use the same S-curve for the attack and release, I can just end EnvelopeDetector::detect(float fInput) with the following, temporarily using my test sine function (like you explained in your last message):

m_fEnvelope = 0.5*(sin(m_fEnvelope*pi-pi/2)+1);
return m_fEnvelope;

But what if I would like to have a different curve for the attack and release. Then I would have to branch the function into an attack and a release part. I came up with this, but I might have missed something.

if(fInput> m_fEnvelope)
{
m_fEnvelope = m_fAttackTime * (m_fEnvelope - fInput) + fInput;
if(m_fEnvelope > 0.0 && m_fEnvelope < FLT_MIN_PLUS) m_fEnvelope = 0;
if(m_fEnvelope FLT_MIN_MINUS) m_fEnvelope = 0;

// bound them; can happen when using pre-detector gains of more than 1.0
m_fEnvelope = min(m_fEnvelope, 1.0);
m_fEnvelope = max(m_fEnvelope, 0.0);

//16-bit scaling!
if(m_bLogDetector)
{
if(m_fEnvelope 0.0 && m_fEnvelope < FLT_MIN_PLUS) m_fEnvelope = 0;
if(m_fEnvelope FLT_MIN_MINUS) m_fEnvelope = 0;

// bound them; can happen when using pre-detector gains of more than 1.0
m_fEnvelope = min(m_fEnvelope, 1.0);
m_fEnvelope = max(m_fEnvelope, 0.0);

//16-bit scaling!
if(m_bLogDetector)
{
if(m_fEnvelope <= 0)
return -96.0; // 16 bit noise floor

return 20*log10(m_fEnvelope);
}

m_fEnvelope = 0.5*(sin(m_fEnvelope*pi-pi/2)+1); // S-curve for release
return m_fEnvelope;
}

(hope the code won’t get truncated after posting)

November 20, 2014
6:27 pm
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

November 21, 2014
6:41 pm
W Pirkle
Forum Posts: 206
Member Since:
January 29, 2017
Offline

Hmmm. Well, yeah that's going to be a problem. The main issue is that unlike a synth EG, the envelope detector is "attacking" when it is increasing and "releasing" when it is decreasing, one after the other, after the other... forever. So you will need to detect the current direction to know which curve to apply. Within that is the direction issue itself; how do you decide that the direction has flipped? One sample or two samples or... 100 samples all going in the same direction, increasing or decreasing? That implies that the detector needs memory but you already have with your window-of-samples so you could start there.

What you are doing is interesting - nonlinear or "distorted detection" and I'd be curious to hear comparisons with the normal detector.

WP

November 21, 2014
7:06 pm
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

Thanks for the advice Will! I'll look into it If I succeed, I'll let you know.

All the best,

JD

November 24, 2014
3:22 pm
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

HI Will:)

It seems to me that making the envelope detection linear first, is key for accurate waveshaping. So I’m just thinking, in your envelope follower you do the following calculation:
m_fAttackTime = exp(DIGITAL_TC/( attack_in_ms * m_fSampleRate * 0.001));

Would it be linear if I changed it to this?

m_fAttackTime = 1/(1+(1/( attack_in_ms * m_fSampleRate * 0.001)));

All the best,

JD

November 25, 2014
4:22 am
W Pirkle
Forum Posts: 206
Member Since:
January 29, 2017
Offline

Yes, that's correct regarding "start with linear" and then waveshape (I'm doing a similar thing with the sawtooth oscillator in my synth book). I'm not sure about your equation without simulating it for sure, but it is a linear mapping. We are on holiday here so my time is pretty limited.

- Will

November 25, 2014
1:46 pm
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

December 3, 2014
11:40 pm
W Pirkle
Forum Posts: 206
Member Since:
January 29, 2017
Offline

Hi JD

just checking to see if you made any progress on your interesting Detector algorithm?

WP

December 5, 2014
5:15 pm
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

Hi Will,

Thanks for your message! Getting the detector to act linear seems to have worked out, but it sounds a bit grainy, even with some S-shaped curves. I’m not sure if it’s the ‘cheaper’ linear sound, or I messed up the formula, but it has been very insightful anyway.

But I must admit – after going through the envelope follower code many times – that I still don’t get it a 100%. The code I get, but the inner workings still seem a bit vague to me (for compressors in general). So I’m reading everything I can about the subject at the moment. I also ordered the new Joshua D. Reiss book you mentioned; looking forward to reading that as well:) I guess to me it’s important to be able to visualize these concepts in order to make the right calls implementing them. But I’m still having a lot of fun exploring these subjects!

It comes down to making this linear:

exp(ANALOG_TC/( attack_in_ms * m_fSampleRate * 0.001));

And understanding this piece, which seems to take in account the angle of the wave as well:

if(fInput> m_fEnvelope)
m_fEnvelope = m_fAttackTime * (m_fEnvelope - fInput) + fInput;
else
m_fEnvelope = m_fReleaseTime * (m_fEnvelope - fInput) + fInput;

I’ll give it another go as soon as possible

All the best,

JD

December 11, 2014
9:39 pm
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

Hi Will, how are you?

I think I’ve got my detector working the way I want. I branched out the attack and release part (without the need of a memory aliment so far) and tried a different approach on the linear formula calculating m_fAttackTime and m_fReleaseTime. In graph form it seems to be exactly the same, but without the danger of dividing by zero: 1-(1/(S+1)). (with ‘S’ being the attack or release in samples). I was wondering why there are no ‘divided by zero’ issues in your algorithm, with the attack or release set to zero? I’m fiddling around with some S-curves now and it does sound quite nice.

I’m trying to make a brickwall limiting version as well. I’ve coded it to limit like in your book and implemented a look-ahead into the algorithm. Now I’m trying to find a way to link it to the attack control in a way to catch every peak in time while having a nice controllable ‘pre’-attack. I had hoped because of the now linear detector this would be as easy as setting the attack an look-ahead to the same value, but this doesn’t work. I’m thinking of hard-coding a static attack curve in the algorithm, while setting the detectors attack to zero. But maybe you have a trick up your sleeve you want to share?

All the best,

JD

December 16, 2014
6:35 pm
W Pirkle
Forum Posts: 206
Member Since:
January 29, 2017
Offline

Hmmm. Not sure how the hardcoded attack would work there, but I am very interested in hearing your compressor. Did you notice the thread on this forum

http://www.willpirkle.com/foru.....uency-cut/

Alex found a very old typo in the code/FX book that resulted in the wrong analog and digital TCs. Ironically, if I had left the older (less efficient) code in place, the error would not be there. This small change does make quite an audible difference in the brief tests I have run.

- Will

December 17, 2014
12:56 am
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

Thanks for the link! I will try the new time constants tomorrow. Very curious:) About the hard coded attack - maybe I’m not using the right terminology. I was just wondering how to implement a sort of pre-attack in the brickwall limiting version I’ve build now. Because just linking the look ahead and attack doesn’t work, I was thinking about another circular buffer to ‘fade in’ the gain reduction that is needed. Is this a good idea?

December 17, 2014
3:02 am
W Pirkle
Forum Posts: 206
Member Since:
January 29, 2017
Offline

Well, the gain reduction fade-in I get in the brickwall case. I think a table (or buffer) with a preset attack curve would work, the main thing is getting the trigger to work correctly. But, you have to be careful when you keep adding more bandages to the plugin - maybe there is a more elegant solution.

- Will

December 17, 2014
3:10 am
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

Thanks! I’ll give it a go and try to keep it simple

December 17, 2014
5:31 pm
JD Young
Leiden, The Netherlands
Forum Posts: 80
Member Since:
November 5, 2014
Offline

Hi Will,

The new time constants work fine! Especially the ANALOG_TC sounds very smooth. And the DIGITAL_TC, yeah, sounds digital

JD

Forum Timezone: America/New_York

Most Users Ever Online: 36

Currently Online:
4 Guest(s)

1 Guest(s)

Top Posters:

Skyler: 48

Derek: 44

Peter: 41

Frodson: 40

clau_ste: 39

Gwen: 32

JimmyM: 29

EZB: 24

lppier: 23

Msaldaña: 18

Member Stats:

Guest Posters: 1

Members: 506

Moderators: 1

Forum Stats:

Groups: 11

Forums: 31

Topics: 524

Posts: 2022