Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Compressor effect to LMMS #5458

Merged
merged 33 commits into from
Mar 11, 2021
Merged

Conversation

LostRobotMusic
Copy link
Contributor

@LostRobotMusic LostRobotMusic commented Apr 19, 2020

(Simple video demo: https://www.youtube.com/watch?v=j-i0gY_KmVk)

This took a few months to make, the visualizer in the back taking the bulk of the development time. I wanted to make this the best audio compressor in the world... and while it's entirely subjective which compressor is the best, I'm very satisfied with how this turned out.

This is a purely digital compressor, completely void of any coloring of any kind so you can focus on exactly what a compressor is meant for, being compression. Even with 2572985782 db of input gain, unless your parameter settings are asking for it, you'll hear absolutely no distortion whatsoever.

It comes with some fairly unique features, like the toggleable Feedback mode, the Hold control (which is usually only for Gates), the blending between stereo linking modes, the mid/side compression, and the 100% adjustable automatic compression and release, which is significantly more complex than automatic attack/release in most compressors.

The automatic attack/release in this compressor analyzes the crest factor (peak divided by RMS) and adjusts those parameters automatically depending on that value. The knobs control how much this has an impact on those parameters, giving you ultimate flexibility which I've never seen in any other compressor.

It also features fully-automatable lookahead, which applies a constant 20 ms of latency when enabled regardless of the lookahead time. Along with L/R or M/S balancing for either the sidechain input or the audio itself, a sidechain tilt filter which can transform into a highpass, lowpass, or a hybrid between the two, adjustable RMS sizes that can go all the way up to 21.5 ms, a Mix knob which takes lookahead delay into account, and an audition button that can be used to listen to the delta signal of the compressor to know exactly how the compressor is changing your sound, this is by far LMMS's most complex audio effect and I'm very proud to be the author of it.

And well, nobody likes a compressor without a fancy visualizer to assist you. Or maybe they do. But those people are weird. The visualizer has a flowing, moving graph showing the input volume, output volume, and gain reduction. It also contains a visualizer of the compressor's dynamics curve, so you can see exactly how your dynamics are being impacted at any time depending on your compressor settings.

The compressor window is fully resizeable. You can just drag the corner of the window, and the contents will scale to fit the new size. Also, the visualizer supports zooming in all the way to 3 db or all the way out to 96 db, so you can see what the compressor is doing to your audio with whatever amount of detail best suits your needs. All in all, a very cool plugin. :)

This'll definitely need a code/style review. I abandoned this project three times or so, so the code may be kind of a mess. I tried to clean it up the best I could.

(Special thank you to H4CKTON3 (aka RoxasKH on Github) for helping me immensely with the artwork!)

@LmmsBot
Copy link

LmmsBot commented Apr 19, 2020

🤖 Hey, I'm @LmmsBot from github.com/lmms/bot and I made downloads for this pull request, click me to make them magically appear! 🎩

Windows

Linux

🤖
{"platform_name_to_artifacts": {"Windows": [{"artifact": {"title": {"title": "32-bit", "platform_name": "Windows"}, "link": {"link": "https://12913-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.107%2Bg449528be8-mingw-win32.exe"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/12913?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}, {"artifact": {"title": {"title": "64-bit", "platform_name": "Windows"}, "link": {"link": "https://12915-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.107%2Bg449528be8-mingw-win64.exe"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/12915?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}, {"artifact": {"title": {"title": "32-bit", "platform_name": "Windows"}, "link": {"link": "https://ci.appveyor.com/api/buildjobs/oxnom44236p0qg1k/artifacts/build/lmms-1.3.0-alpha-msvc2017-win32.exe"}}, "build_link": "https://ci.appveyor.com/project/Lukas-W/lmms/builds/38162586"}, {"artifact": {"title": {"title": "64-bit", "platform_name": "Windows"}, "link": {"link": "https://ci.appveyor.com/api/buildjobs/9no642di5thvhpx1/artifacts/build/lmms-1.3.0-alpha-msvc2017-win64.exe"}}, "build_link": "https://ci.appveyor.com/project/Lukas-W/lmms/builds/38162586"}], "Linux": [{"artifact": {"title": {"title": "(AppImage)", "platform_name": "Linux"}, "link": {"link": "https://12912-15778896-gh.circle-artifacts.com/0/lmms-1.3.0-alpha.1.107%2Bg449528b-linux-x86_64.AppImage"}}, "build_link": "https://circleci.com/gh/LMMS/lmms/12912?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link"}]}, "commit_sha": "b78ddbcee1cf2f278603f553ef83286961b4fbcd"}

@qnebra
Copy link

qnebra commented Apr 20, 2020

At this moment compressor work really nice. No crashes, no bugs at this moment.

@PhysSong PhysSong added needs code review A functional code review is currently required for this PR needs style review A style review is currently required for this PR needs testing This pull request needs more testing labels Apr 25, 2020
@PhysSong
Copy link
Member

Why is the unit of RMS size 1/44100 second? Isn't it more natural to use something like milliseconds?

plugins/Compressor/CompressorControlDialog.h Outdated Show resolved Hide resolved
plugins/Compressor/Compressor.cpp Outdated Show resolved Hide resolved
plugins/Compressor/Compressor.cpp Outdated Show resolved Hide resolved
Comment on lines +362 to +367
m_maxLookaheadTimer[i] = std::distance(std::begin(m_lookaheadBuf[i]),
std::max_element(std::begin(m_lookaheadBuf[i]), std::begin(m_lookaheadBuf[i]) + m_lookaheadLength));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, it's possible to optimize finding the maximum value in a ring buffer using a double-ended queue. I can provide the detail if you want.
BTW, why do you want to use the maximum value in the lookahead buffer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this doesn't consume CPU much, so I think the existing comment is enough which says about the possibility of further optimization.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, it's possible to optimize finding the maximum value in a ring buffer using a double-ended queue. I can provide the detail if you want.

Would that be faster than O(n)? 😮

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's amortized O(1) for fixed lookahead value, and additional O(log(n)) if it's automated.

plugins/Compressor/Compressor.cpp Outdated Show resolved Hide resolved
@LostRobotMusic
Copy link
Contributor Author

LostRobotMusic commented Jul 9, 2020

Rather than using true RMS, I'm now instead using a buffer-free approximation which sounds better in a compression context. I also made it so RMS is in units of milliseconds rather than samples.

On top of that, I fixed a bug with auto gain which made it act... incorrectly... as well as a bug making it so the input fader displayed the output volume.

I was also notified of some bug involving a crash every time the lookahead knob was moved up all the way. I never experienced this bug on my system, but their error message suggested an out-of-range index, so I bumped up the lookahead buffer size to 21 milliseconds rather than 20. That'll probably fix the issue. The bug has been found and this "fix" has been reverted.

@LostRobotMusic
Copy link
Contributor Author

Everything is ready now as far as I know. Probably needs some more testing though, to be sure.

@firewall1110
Copy link
Contributor

I tested this branch by compiling from source in Debian Buster using clang compiler.

It seems all work fine.

P.S.

Nice interface, but I would like some check box to hide controls |& background.

[I am new in testing ...]

@LostRobotMusic
Copy link
Contributor Author

The only thing I found that I don't know if it's correct or not, is that when having the mix knob on (over 0%) the input slider works weird to me: the higher the input the lower the volumen produced. It's that correct?

Oh gosh. I guess I was so focused on fixing input gain bugs for the Autogain and Lookahead and such that I didn't realize I broke it for literally everything else. Fixed in the latest commit, it should work properly now.

Though it's somehow transparent, I think the knob's section hide a lot of information (only the last 15db are clearly visible). I'd be great to have the possibility to hide that section or have a slide to make it more transparent.

If you scroll on the background, it will change its scale so you can see more. Also, I made the Compressor fully resizable, so you can resize the Compressor window to open up more room for you to see the visualizer.

A request: having a SideChain option like the Calf SideChain CompressorLDSPA, if it's not very complicated to implement. Having the visual aid to set the sidechain effect would be great ;-)

I agree that that would be a great feature to have, but I am waiting for LMMS to support multiple audio inputs to effects so that I can allow the user to directly send their audio into the compressor's sidechain signal, rather than using a knob and peak controller as messy workaround that we'll have to worry about backwards compatibility for later.

I think users would need a manual to understand the possibilites of the pluggin, otherwise it's use seem overwhelming.

I put a lot of information in the knob tooltips that you can check out, but yes, maybe an in-plugin manual is called for here since many of the features may seem a bit hidden (e.g. scrolling to resize the visualizer)...

@superpaik
Copy link
Contributor

Great! It work ok now!
Sorry, I didn't get the scroll on the background. It's very good!
I think it's a great stock pluggin!

plugins/Compressor/Compressor.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.h Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.h Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
@RoxasKH
Copy link
Contributor

RoxasKH commented Feb 19, 2021

Ok, so, i don't wanna be the stop-merging guy, but here's what i think about it.

The default size of the plugin is a bit big for HD screens, but the plugin is resizable, so this is not a big problem.

Now let's talk about what i still think it's the real issue in this plugin. The autogain feature.
I'm not an expert in dsp, neither i have still taken a glance at LMMS code. But as a user of LMMS and as i produce music, i feel like it's not functional at all.

For how it works at the moment it makes the sound incredibly clips, and this obviously forces you to do a manual decrease in volume after activating it. But this feels nosense. What's the point in having an autogain button that forces you to do a manual adjusting in gain after? You could just do a manual increase in gain from the start, in 1 move instead of 2. And this is actually how most compressor works out there, they just have a postgain knob, just to make an example i could mention the LADSPA version of Calf Compressor which is native in LMMS. It's way more rare to find compressor with an auto gain function, because it's probably difficult to code i guess.

But according to my experience, the autogain button should do something like detecting the peak of the sound after the compression and bring it up to 0db. To make an example, i had my hands on the WA Production SphereComp as i bought the whole Sphere bundle on sale. This compressor has an autogain function, which isn't always able to bringup the sound to 0db, but for sure doesn't make the sound clip so much, if most of the times not at all.

To mention another plugin, the MCompressor by Melda Production have an autogain function even if it's not called this way, "Maximize to 0db"; the name itself it's pretty explicit, even if haven't tried the vst myself.

I feel like bringing this up because if it won't be fixed now, in my opinion it will come up multiple times as an issue in the future, too. With the little differences that it won't be fixable without breaking retrocompatibility.

The plugin is great, LMMS needs it, and every other feature seems fine to me, but i'd rather have a working auto gain button.
I don't know if this is fixable (maybe considering it brings up the sound the the limit, an auto decrease after the increase could be programmed), but if there's any possibility to make it works i'd say properly, it'd be better to do it, in my opinion.

As i said i'm not a coder, neither a dsp expert, but this is what i feel from my user experience.

@LostRobotMusic
Copy link
Contributor Author

I think your concerns are due to confusion around what the auto gain function is actually for.

The auto gain function is not meant to choose a decent output volume for you; that depends on the context and is up to the musician. The auto gain function is used to maximize the compression shape to 0 dbFs, so a 0 dbFs input will result in a 0 dbFs target output. This allows the musician to change the compression amount with minimal loudness change, so they can better hear what the compression is doing to the sound.

The clipping you're encountering is not an inherent issue. Again, this function is not intended to choose an output volume for you (and isn't a mastering tool either), so you should fix the clipping that results due to your settings by adjusting the output gain.

But according to my experience, the autogain button should do something like detecting the peak of the sound after the compression and bring it up to 0db.

This isn't possible with realtime audio. And if we were to make use of the lookahead to try to make it possible, it would result in unwanted upward compression when the Auto Gain isn't supposed to change over time at all.

To mention another plugin, the MCompressor by Melda Production have an autogain function even if it's not called this way, "Maximize to 0db"; the name itself it's pretty explicit, even if haven't tried the vst myself.

You mentioned the "Maximize to 0 db" function in Melda Audio's MCompressor. The Auto Gain button in this compressor is actually identical to that, they do exactly the same thing. In fact, Fabfilter's Pro-C 2 also does the same thing (except they also lower the volume depending on the attack time, which I decided to not bother with). The feature is working exactly as intended.

@RoxasKH
Copy link
Contributor

RoxasKH commented Feb 19, 2021

I think your concerns are due to confusion around what the auto gain function is actually for.

The auto gain function is not meant to choose a decent output volume for you; that depends on the context and is up to the musician. The auto gain function is used to maximize the compression shape to 0 dbFs, so a 0 dbFs input will result in a 0 dbFs target output. This allows the musician to change the compression amount with minimal loudness change, so they can better hear what the compression is doing to the sound.

The clipping you're encountering is not an inherent issue. Again, this function is not intended to choose an output volume for you (and isn't a mastering tool either), so you should fix the clipping that results due to your settings by adjusting the output gain.

But according to my experience, the autogain button should do something like detecting the peak of the sound after the compression and bring it up to 0db.

This isn't possible with realtime audio. And if we were to make use of the lookahead to try to make it possible, it would result in unwanted upward compression when the Auto Gain isn't supposed to change over time at all.

To mention another plugin, the MCompressor by Melda Production have an autogain function even if it's not called this way, "Maximize to 0db"; the name itself it's pretty explicit, even if haven't tried the vst myself.

You mentioned the "Maximize to 0 db" function in Melda Audio's MCompressor. The Auto Gain button in this compressor is actually identical to that, they do exactly the same thing. In fact, Fabfilter's Pro-C 2 also does the same thing (except they also lower the volume depending on the attack time, which I decided to not bother with). The feature is working exactly as intended.

Ok, thanks again for the clarifying, i was misunderstanding something.
As i said i hadn't tried MCompressor myself, so i wasn't aware of the real job of the feature.
Just to talk about the fabfilter addition, i don't even get why the decreasing should be done basing on the attack time (unless it's not talking about the attack time of the compressor but of some other attack time).

@LostRobotMusic
Copy link
Contributor Author

Fabfilter Pro-C 2 does that because increasing the attack time results in an overall increase in volume (and therefore perceived loudness as well), but when I analyzed the scale at which attack time became auto gain volume reduction... it was really added in a fairly lazy way from what I could see, basically just turning the attack knob into a linear volume knob without really taking the scale of the attack time into account (...from what I can remember from over a year ago when I tested this). I decided to not bother with that aspect, it seemed rather unnecessary anyway.

@RoxasKH
Copy link
Contributor

RoxasKH commented Feb 19, 2021

Fabfilter Pro-C 2 does that because increasing the attack time results in an overall increase in volume (and therefore perceived loudness as well), but when I analyzed the scale at which attack time became auto gain volume reduction... it was really added in a fairly lazy way from what I could see, basically just turning the attack knob into a linear volume knob without really taking the scale of the attack time into account (...from what I can remember from over a year ago when I tested this). I decided to not bother with that aspect, it seemed rather unnecessary anyway.

Oh got it, well the volume increase would be only at the start of the sound tho, so

@LostRobotMusic
Copy link
Contributor Author

No, it's for the attack time, as in the value that the attack knob is set to.
Automatic gain compensation will never change over time. It'll only change when a knob's value is changed (in this case, either the threshold, the knee, or the ratio). Otherwise, it would change the dynamics of the sound in its own ways, which would obviously not fall in line with what we want the effect to do...

@RoxasKH
Copy link
Contributor

RoxasKH commented Feb 19, 2021

No, it's for the attack time, as in the value that the attack knob is set to.
Automatic gain compensation will never change over time. It'll only change when a knob's value is changed (in this case, either the threshold, the knee, or the ratio). Otherwise, it would change the dynamics of the sound in its own ways, which would obviously not fall in line with what we want the effect to do...

Nono, i was just saying that increase the value of the attack knob increase the volume only of the start of the sound, as the compressor follows it to compress the sound. Just stating that the increase wouldn't be on the whole sound, nothing more.

@LostRobotMusic
Copy link
Contributor Author

LostRobotMusic commented Feb 19, 2021

The volume change would be on the entire sound though.
(We should probably take this to Discord or something, we're likely misunderstanding each other.)

plugins/Compressor/Compressor.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
@RoxasKH
Copy link
Contributor

RoxasKH commented Feb 25, 2021

Just wanna state that any misunderstanding has been cleared here and on discord.

@LostRobotMusic
Copy link
Contributor Author

Everything's finished here for now. Ready for merge as long as there aren't other issues with it.

Copy link
Member

@DomClark DomClark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a comprehensive review by any means, but I saw you intended to merge soon, so I wrote up some notes I made when I started looking at this a while ago.

plugins/Compressor/Compressor.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.cpp Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControlDialog.h Outdated Show resolved Hide resolved
plugins/Compressor/CompressorControls.cpp Outdated Show resolved Hide resolved
plugins/Compressor/Compressor.cpp Outdated Show resolved Hide resolved
@LostRobotMusic LostRobotMusic merged commit 459948f into LMMS:master Mar 11, 2021
@LostRobotMusic
Copy link
Contributor Author

Merged. Here's a demo video I made:
https://www.youtube.com/watch?v=4uaCVkrF2u4

IanCaio pushed a commit to IanCaio/lmms that referenced this pull request Mar 28, 2021
devnexen pushed a commit to devnexen/lmms that referenced this pull request Apr 10, 2021
sdasda7777 pushed a commit to sdasda7777/lmms that referenced this pull request Jun 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs code review A functional code review is currently required for this PR needs style review A style review is currently required for this PR needs testing This pull request needs more testing
Projects
None yet
Development

Successfully merging this pull request may close these issues.