Skip to main content
Topic: New simple, good sounding multiband compressor available. (Read 899 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

New simple, good sounding multiband compressor available.

This compressor is fully THATcorp/dbx style RMS, and has 3 bands:  20-160, 160-2600, 2600-20k.
Sounds much better when there is lots of bass, etc.

It does any compression ratio between 1:1 to inf:1.  The command line args are:

Real compression ratio is 1/(1-cratio), where if cratio = 0.90, then the real compression ratio is 10:1

Pivot location -- 9dB is a good value.

--ingain=xxx, --outgain=xxx
input/output gains in dB

Lots of things can change if you modify the source -- all of it is in there.

Repo will contain examples in a while, and will have 'MB' in the name for 'multiband'.

Re: New simple, good sounding multiband compressor available.

Reply #1
Since there have been some downloads -- I will be posting some changes/updates to tweak the performance. As it is -- it is a bit 'fast'.   I have really offered this for people who want to work on the source and change its behavior -- but I'll be tweaking it over time.

THIS IS BRAND NEW CODE -- in the sense that the compressor has only existed for a few hours of working on it.  I have a few good updates coming.  Also -- I'll post the source changes so you can see the progress.

right now, it is happiest runnjing at 1.5:1 or lower, but can sometimes do well at higher ratios.  So, it means use a cratio=0.33 or less for now.

At this moment, I am listening to a major improvement, but need to test more.  This was originally single band, so it has come a long way already :-).


Re: New simple, good sounding multiband compressor available.

Reply #2
Good news -- added a few fixes, and now sounds better at higher compression ratios.  It did really well as a single band, but there were a few nits as multi band.  It still has a bit too much response skew between channels, but now is MUCH MUCH more robust.

Sorry for the 'too early' release.  I do that sometimes.  This version 'C' is much nicer.  Still not perfect, it is meant for a devloper to grab it and add it to something useful!!!

Current criticism -- attack time a bit too fast for HF.  The decay time is much better.  MUCH MUCH less pumping, a correction in the front end filters.


Uploaded a multiband compression example at 2:1 compression -- not too bad.

Reply #3
2:1 compression is actually pretty severe, and it is still okay sounding.  It is 'fernando' from abba.  The uncompressed version is also  online:

abbaMB-1.5.mp3  -- Chiququita  at 1.5:1 with the multiband compressor
abbaMB-2.0.mp3 -- Chiquaquita at 2:1 with the multiband compressor
abba-1.0.mp3 -- Ciququita uncompressed.

Note that the compression done by the RMS style compressor is very smooth, and can be very fast and still listenable.  So, don't think that 2:1 isn't much compresison.  It is VERY FAST compression, with minimal distortion.  I screwed up the previous versions of the compressor (I am really good at making something work, then screw it up at the last minute.)  This one 'C' is fixed.

here is the repo location with the examples -- this is using the 'C' version:

A more mellow example -- 'higher fidelity' that ABBA :-).

Reply #4
I added a Dionne Warwick example -- I also retuned the compressor to be more automatic (remember -- the compressor is a platform to start from.)   After the RMS detector algorithms and the input filters -- I'll probably have to explain how to adjust the design (it is pretty much all parameters in the class initialization for the RMS filters.)

I created a more dynamic attack/release scheme, where there is the inter syllable and intra syllable compression.  The intra-syllable compression is fast, and the inter syllable compression 'moderates' the behavior of the intra-syllable compression.  Basically it helps to mitigate pumping and the over compressed sound.  In the source code, there are several gain control filters, one is rfilt1 -- that is the inter syllable compression.  The intra-syllable compression is rfilt3 -- and probably doesn't need much tuning.

If someone is REALLY interested, I'd be willing to document the scheme -- but it does approach as good as it can be.

I didn't spend a lot of time on this specific example -- but I already know how to tune the attack/decay learning biases -- and they are definitely tuned JUST FOR THE GENERAL CASE.  The attack/decay control is much more capable than a normal/simple nonlinear capacitor scheme or a simple dual time constant scheme.  This is almost a learning scheme.

For some proof, listen to the 'dionneMB-2.0.mp3' example -- that is 2:1 compression, while the original is dionneMB-1.0.mp3. The amount of compression is excessive for the material, but I wanted to show how robust the compression scheme can be.  After these settings are chosen -- they don't need to be touched again no matter the kind of music.

There might be some desire to change some of compression characteristics, and the facility is in the code to change the compression timing/behavior and learning in almost any useful way.  The goal might be to have some fun with this thing!!!

Again -- look for the 'dionne' filenames, and 1.0 is no compression, and 2.0 is 2:1.



Version with vastly improved long term stats

Reply #5
The longer term behavior is improved on this version.  Also, the repository contains an example compressed with this version (dionneMB-2.0.mp3), previous versions have been supersceded.  It is even better now at 2:1 compression.

If you look at he progression of changes, you'll notice few changes -- the parameters and slight coding changes are all that is needed to make the significant improvements.


New compressor is attached also.

NOW works -I am so sorry -- had cygwin library problem, problem fixed/works nice

Reply #6
There will sometimes be problems when running the compressor.  I just got caught by it, and only just now noticed it.  There were .dll/shared lib problems -- and sometimes the compressor would 'run' but be very stupid.
This was an embarassing surprise, because even though I wasn't completely testing it on windows, I was verifying it, and it was working correctly on my environment!!!

This version has major cleaned up source code, and also will actually work on non-cygwin envrionements now!!!  Sorry about this trouble -- very frustrating.  This also screwed up my DolbyA compatible DHDA decoder distribution.  Somehow, some new libraries slipped in without me catching it.

REALLY APOLOGIZE.  The compressor really does sound nice...  REALLY DOES!!!
Everytime I try to do something nice for someone, I screw up terribly -- I can't do anything right sometimes.


New switch for the compressor -- important.

Reply #7
There are several important switches, a new one has been added -- '--maxgain'.  It is already in the code.

So, the actual depth of compression is manipulated by the three switches (along with the signal itself):

Sorry for the confused nature of the switch values -- I really am not focusing on this very much -- just a distraction...

--thresh=xxx   it is the pivot level.  It is actually the negative of the number of dB where the gain pivot is.  Values
between approx 3dB (for -3dB) through 10dB (for -10dB) are probably most useful for normal level signals.

--cratio=xxx is a REPRESENTATION of the compression ratio.  The real compression ratio is 1.0 / (1 - cratiovalue).  So, a --cratio=0.50 means 2:1 compression, --cratio=0.33 is 1.5:1, --cratio=1.0 is inf:1.

--maxgain=xxx is the maximum gain produced by the compressor.  Previously, the default maximum gain was 9dB, now it is variable.

A useful mode to run the compressor is where --maxgain and --thresh have the same value.  It will act more like a soft limiter (very soft) than a full dynamic range compressor.

--info gives a running log of the gains & input/output  levels -- very useful!!!

Again, have fun -- and the --maxgain is VERY helpful.


Added peak limiter to 'simplecomp', new version w/limiter

Reply #8
I noticed that peak excursions are happening because of the slow 'RMS' style attack in the gain control.  So, I added a simple two stage peak limiter, and an additional switch: --maxlevel.   The default value for '--maxlevel' is '-0.5', so the default state is as if the user types '--maxlevel=-0.5' in the command line.   That is a good limiting level that avoids most peak excursions.

I didn't write the peak limiter to be infinitely fast (I didn't want to add an additional delay -- I guess I could have -- no biggie, it is done A LOT in the DolbyA compatible decoder.)  Anyway, the fastest attack time of the 'limiter' is about 250usec, which should be fast enough for most cases, esp since there is a 0.5 dB slop room.  Note that the peak limiter is on a channel by channel basis instead of a total of both channels, so some programs like sox will still complain, but by far MOST of the time, there won't be an excursion much beyond the highest representable level.  I also normally use --outgain=-3 just in case (which keep clipping from happening very often also.)

The peak limiter is NOT meant to sound pretty and can uglify the sound very quickly.  SO, I suggest using it only for the peak excursions.  I did not bandwidth limit the output nor did I shape the attack curve -- so it is a fairly raw limiter.  Not as bad as a clipper, and that is the ONLY positive thing that I can say about the built-in limiter.  To disable the limiter entirely, just set the '--maxlevel' to a high level, like +10dB.

Here is the next version of the 'compressor'.  I'll probably be laying off of it now, but I'll be glad to look-at and fix bugs as they come around.


New compressor -- much better control of peaks.

Reply #9
After running lots of tests -- I still didn't like the number of peaks in the output signal.  I did something fairly aggressive and added in some faster 'RMS-style' compression at lower compression ratio to bring the peaks a little better under control.

This 'better' peak control along with the limiter should produce 'safer' output.   The result does sound a little more compressed, but the output signal is also more useful.

You can have both versions (version F and versionG), and have the source code for both (do a diff between the different versions of the file 'audioproc.cpp'.)  Which is better for you?  More peaks -- maybe a LITTLE more natural sounding, vs better peak control?

I might someday add a swtich to allow some customization of the result.  Both versions of the compressor sound 'okay', but it is all a matter of preference and taste anyway.

I am attaching the new version of the compressor (of coruse, with source also.)
Hopefully, this might be a learning exercise for some -- others might find my attack/decay classes (I only included a few of them) to be very useful at times.


Re: New simple, good sounding multiband compressor available.

Reply #10
What you use to split audio into several bands?

Re: New simple, good sounding multiband compressor available.

Reply #11
What you use to split audio into several bands?
I used a general purpose IIR filter generator subroutine -- produces the z transform for a 2nd order 's' domain filter specification.   The subroutine builds the IIR filter coefficients based upon the sample rate, and the filter function f(s)=(a0*s^2 + a1 *s + a2)/(b0 * s^2 + b1 * s + b2) is the filter specification.  Most of my filters are HPF, and since it doesn't need anything special, I do a group of subtractions with several filters to get the bands.  The source code for the IIR filter code itself starts at line 803 in agcfilters.h.  The magic subroutine that does the bilinear transform is called calcbilinear2 (actually a function template), resides earlier in the agcfilters.h file, and it does most of the hard work.  The filter spec is essentially the s transform stuff plus the typical hint for the 'match' frequency between analog and digital filter characteristics.  I use a varation of this scheme for my DolbyA decoder input filters (but the input filters are more dynamic and are recalculated on the fly.)
The filter scheme works great, and I suspect that the bands could be optimized for minimal artifacts.  I don't believe in the 80Hz base frequency for the LF on DolbyA (for a compressor), so I chose 160Hz.  Frankly, 240Hz might be a little better.

(Some hints on creating an HPF/LPF filter):
For an HPF filter, the specification looks like this:  f(z) = s^2/(s^2 + s * 2*pi*fc/q + (2*pi*fc)^2);.  The various parameters are obvious -- pi is 3.14159265..., fc is the HPF cutoff, q is the filter q.
For an LPF filter, the specification looks like this:  f(z) = (2*pi*fc)^2/(s^2 + s * 2*pi*fc/q + (2*pi*fc)^2);

I might have remembered these incorrectly -- so look them up under 'second order filter', and a wiki lookup is likly much more reliable than my memory :-).

I was VERY careful to make sure that the HF band fell fairly deep into the middle frequency range (2.6kHz) so that the levels for each band will be better balanced.  Don't want to use too high a frequency cutoff for the highest frequency band -- it needs some MF energy to make sure that it doesn't gain-up too often.

If you have any more questions -- just let me know.  I do have further improved versions of the compressor that have slightly better peak level vs. RMS behavior balance.

I can certainly help with simple DSP matters -- I know a lot about certain things, but very little about others.  I have some pretty good references available online and I can send them to you legally -- might help with audio DSP matters.



Previous response incomplete about how the fiilters were done.

Reply #12
I spent lots of the previous post on how to calculate the filters, but I didn't talk much about how to do the filtering.  I have a C++ class called dfIIRHPF (HPF in the name is actually legacy and misnomer, it will work for any kind of standard 2nd order filter -- I just cobbled it from my DHDA code, and stripped out the proprietary secret sauce that is part of the magic in the DHDA code.)

So, an example of using the whole mix of filters is based on this idea:  A filter interpreter class (which does the filtering at very high speed), and the filter generator subroutine, the filter specification array, and then the owner of the filters (where the classes are instantiated.)

The filter interpreter is overly complicated for what is needed -- but you can grab that and convert it to any language.  But in C++, declares the filter interpreter (which calls the filter calculator subroutine 'calcbilinear2' when needed), and when it is instantiated as a class, the arguement is the filter specification array.  There are some examples (for exactly the compressor) close to the line 802 area of agcfilters.h.   I didn't just use magic numbers in the filter specs, so you can see pretty easily how to tune them as you desire.


New release, fixed some bugs, limits peaks better.

Reply #13
Fixed some serious bugs, limits peaks much, much better. Compression a little looser, but the limiting is more absolute (and fewer errors.)

Will still sometimes go overlimit, but not often.  I decided not to add a delay yet, but will probably do so for the next release.


New version of the compressor -- better all around.

Reply #14
This version has better text RT display along with much better sound, along with much better peak limiting.
It now has a real version number -- I am comfortable with the general quality now.
You still get the source for future hacking on the code, etc.
For the nice RT text display, add the --info=10 switch -- it also gives peak limiter information -- example:

S:         16, INPUT(RMS:-22.83dB, -3.65dB), OUTPUT(RMS:-18.65dB, -1.21dB):
    CP LL( -2.07/ +2.58/ +4.90), M( +0.85/ +3.30/ +4.18), H( +1.35/ +3.87/ +4.78), PK( -1.95/ -0.00/ -0.00)
    CP RL( -2.23/ +2.58/ +4.90), M( -0.91/ +3.30/ +4.18), H( -0.41/ +3.86/ +4.78), PK( -3.70/ -0.01/ -0.00)

Here is the (long) BASH command line that also uses my DHDA DolbyA compatible decoder as input (this happens to be ABBA SuperTrouper DolbyA compatible decode, and then compression):

sox -v 0.50 "/music/agflac/raw1/ABBA*06*" --type=wav --encoding=floating-point - rate -v 96k | ~jdyson/ap/damulti/da-avx  --affinity  --ingain=6 --outgain=0.0 --tone=-22.67 --allow=no --info=0 --xfinalize --clarify| ~jdyson/ap/comp/comp-win --cratio=0.67 --thresh=3 --maxgain=6 --outgain=0.0 --info=10 | play -q -

Even though the compressor R+L channels have same gain, the peak limiter is per channel, and the limiter
information is applied to the total gain numbers.
First is the input/output levels.
Next is the Left channel info (LF, MF, HF, and then PEAK limiter) gains.
Next is the Right channel info (LF, MF, HF and then PEAK limiter) gains.
Each triplet for each band is (mingain, avgain, maxgain) over the 1second sample interval.

For sound quality -- the compressor is much better balanced, and has better short term/long term stats.
The peak limiters have been corrected, and is now three stage.  The goal is to first do a normal gain control
limiter, then subsequently faster and faster gain control that ends up being soft clipping at the end.   The peak limiters are essentially inaudible in most cases.

Remember the supported switches:
--cratio=xx, where the real compression ratio is CR=1/(1-cratio).  I know -- I should have fixed this.  So, for a true CR=2:1, then the cratio needs to be 0.5.  For a true CR=inf:1, then the cratio needs to be 1.0.  For a true CR=1.5:1, then the cratio needs to be 0.33.
--thresh=xx, the pivot point for the gain -- but negate the dB (I should have fixed this also.)  A typically good number is 6 (means -6dB), or 9 (means -9dB)
--maxgain=xx, the maximum gain-up for the compressor.
--maxlevel=xx, then maximum output level -- is the setting for the peak limiter.
--ingain=xx, the input gain
--outgain=xx, the output gain.
I have no external control for the attack/decay speeds or for the band frequencies.  If you want to play with those -- you have the source :-).

If you have any usage questions or want to discuss the source code -- just contact me through this group...

Note about the most recent download V1.0A

Reply #15
Just wanted to warn -- the limiter is still a little too intrusive.  The limiter certainly helps, but sometimes will become obvious well before I think that it should.

There is a new version coming soon, with a better limiter (design is mostly the same, minor changes and new parameters.)  The new prototype is more hidden from hearing.

The compressor itself is pretty good as-is.  If I have time, I might make the compressor slightly tunable, but it is already set-up to be close-to-optimal for hiding itself.   I'll try to make an option that gives different sound qualities.  Don't expect a new compressor before 8 Oct2018 (2 days.)    If you want to experiment with the compressor this weekend, the most recent download will be your best bet.

For compiling the compressor, clang++/llvm will be your best bet, and the source is optimized to get the best performance when using clang++/llvm.  I haven't compiled with g++ in a month or so -- there might be some changes needed again in the vector code -- but shouldn't be very bad.  Originally, the C++ headers/libraries used on the compressor were written to work best using g++, but I found that clang++/llvm is a little smarter in manipulating certain kinds of vectors, so that is why I am using clang++/llvm.   At one time, I did use the Intel C++ to compile with the C++ headers, but for my specific situation, ICC++ was no better than any other compiler.

If you have questions or problems using or compiling the compressor, just let me know -- and I will really try to help.


SimplePortal 1.0.0 RC1 © 2008-2018