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

Loudness Nomalization seems to be clipping even when using F32 format #1320

Closed
v-fox opened this issue Nov 20, 2023 · 19 comments
Closed

Loudness Nomalization seems to be clipping even when using F32 format #1320

v-fox opened this issue Nov 20, 2023 · 19 comments
Assignees

Comments

@v-fox
Copy link

v-fox commented Nov 20, 2023

  • [X ] I have checked the FAQ for answers.
  • [X ] I have checked the Changelog that the issue is not already fixed.
  • [X ] I believe this issue is a bug, and not a general technical issue, question or feature requests that can be discussed on the forum.

Describe the bug
"EBU R 128 Loudness Nomalization" seems to produce muffled output when peeking with "unsafe" values such as "-6" regardless if output format allows non-clipped overload or not.

To Reproduce

  • Set up pipewire to use F32 in software part (should be default already) and S32 (shouldn't matter) in hardware.
  • Set up easyeffects with limiter at the end then use "pulse" output in Strawberry but "openal" should also work.
  • Try comparing sound during "overload" (near-0 peaks in EE's spectrogram) between being maxed using limiter's boost feature (using "input gain" or "threshold", doesn't matter) and "unsafe" values in LN such as "-6" and above.

As a result, if LN is "safely" below 0 but limiter boosted to peak sound is smooth
but if reversed, LN peaks to 0 but limiter has no boost, sound seems distorted.

Expected behavior
Output should be the same because with F32 clipping should always happen in limiter.

Screenshots:
screenshot_strawberry
Clipping during big cymbal smash in the song.

used EE profile:
{
    "output": {
        "bass_enhancer#0": {
            "amount": 0.0,
            "blend": 0.0,
            "bypass": false,
            "floor": 30.0,
            "floor-active": true,
            "harmonics": 6.000000000000009,
            "input-gain": 0.0,
            "output-gain": 0.0,
            "scope": 115.0
        },
        "blocklist": [],
        "equalizer#0": {
            "balance": 0.0,
            "bypass": false,
            "input-gain": 0.0,
            "left": {
                "band0": {
                    "frequency": 16.0,
                    "gain": 0.0,
                    "mode": "RLC (BT)",
                    "mute": false,
                    "q": 0.5,
                    "slope": "x2",
                    "solo": false,
                    "type": "Hi-pass",
                    "width": 4.0
                },
                "band1": {
                    "frequency": 30.0,
                    "gain": -9.000001907348633,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 0.0,
                    "slope": "x1",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band2": {
                    "frequency": 100.0,
                    "gain": -1.0000003576278687,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 0.0,
                    "slope": "x1",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band3": {
                    "frequency": 3000.0,
                    "gain": -8.0,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 1.0,
                    "slope": "x1",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band4": {
                    "frequency": 6000.0,
                    "gain": -2.000000238418579,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 4.0,
                    "slope": "x2",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band5": {
                    "frequency": 12500.0,
                    "gain": 4.000000476837158,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 3.0,
                    "slope": "x1",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band6": {
                    "frequency": 16000.0,
                    "gain": -5.999999523162842,
                    "mode": "RLC (BT)",
                    "mute": false,
                    "q": 3.0,
                    "slope": "x2",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band7": {
                    "frequency": 22000.0,
                    "gain": 0.0,
                    "mode": "RLC (BT)",
                    "mute": false,
                    "q": 0.75,
                    "slope": "x1",
                    "solo": false,
                    "type": "Off",
                    "width": 4.0
                }
            },
            "mode": "IIR",
            "num-bands": 8,
            "output-gain": 0.0,
            "pitch-left": 0.0,
            "pitch-right": 0.0,
            "right": {
                "band0": {
                    "frequency": 16.0,
                    "gain": 0.0,
                    "mode": "RLC (BT)",
                    "mute": false,
                    "q": 0.5,
                    "slope": "x2",
                    "solo": false,
                    "type": "Hi-pass",
                    "width": 4.0
                },
                "band1": {
                    "frequency": 30.0,
                    "gain": -9.000001907348633,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 0.0,
                    "slope": "x1",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band2": {
                    "frequency": 100.0,
                    "gain": -1.0000003576278687,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 0.0,
                    "slope": "x1",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band3": {
                    "frequency": 3000.0,
                    "gain": -8.0,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 1.0,
                    "slope": "x1",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band4": {
                    "frequency": 6000.0,
                    "gain": -2.000000238418579,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 4.0,
                    "slope": "x2",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band5": {
                    "frequency": 12500.0,
                    "gain": 4.000000476837158,
                    "mode": "RLC (MT)",
                    "mute": false,
                    "q": 3.0,
                    "slope": "x1",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band6": {
                    "frequency": 16000.0,
                    "gain": -5.999999523162842,
                    "mode": "RLC (BT)",
                    "mute": false,
                    "q": 3.0,
                    "slope": "x2",
                    "solo": false,
                    "type": "Bell",
                    "width": 4.0
                },
                "band7": {
                    "frequency": 22000.0,
                    "gain": 0.0,
                    "mode": "RLC (BT)",
                    "mute": false,
                    "q": 0.75,
                    "slope": "x1",
                    "solo": false,
                    "type": "Off",
                    "width": 4.0
                }
            },
            "split-channels": false
        },
        "exciter#0": {
            "amount": 0.0,
            "blend": 0.0,
            "bypass": false,
            "ceil": 16000.0,
            "ceil-active": true,
            "harmonics": 3.0,
            "input-gain": 0.0,
            "output-gain": 0.0,
            "scope": 8870.0
        },
        "limiter#0": {
            "alr": true,
            "alr-attack": 4.0,
            "alr-knee": 3.0,
            "alr-release": 768.0,
            "attack": 8.0,
            "bypass": false,
            "dithering": "24bit",
            "external-sidechain": false,
            "gain-boost": true,
            "input-gain": 6.0,
            "lookahead": 8.0,
            "mode": "Herm Thin",
            "output-gain": 0.0,
            "oversampling": "Full x4(3L)",
            "release": 8.0,
            "sidechain-preamp": 0.0,
            "stereo-link": 100.0,
            "threshold": 0.0
        },
        "plugins_order": [
            "stereo_tools#0",
            "bass_enhancer#0",
            "exciter#0",
            "equalizer#0",
            "limiter#0"
        ],
        "stereo_tools#0": {
            "balance-in": 0.0,
            "balance-out": 0.0,
            "bypass": false,
            "delay": 0.0,
            "input-gain": -3.0,
            "middle-level": 0.0,
            "middle-panorama": 0.0,
            "mode": "LR > LR (Stereo Default)",
            "mutel": false,
            "muter": false,
            "output-gain": 0.0,
            "phasel": false,
            "phaser": false,
            "sc-level": 1.0,
            "side-balance": 0.0,
            "side-level": 0.0,
            "softclip": false,
            "stereo-base": 0.0,
            "stereo-phase": 0.0
        }
    }
}

In this example the EE profile is set up to do "-3" at input stage and "+6" before input of the LSP limiter (that is the last pre-hardware stage, not counting PW's internal format conversions), LN in Strawberry is set to "-9". This seems stable but using "+3" in limiter and "-6" in Strawberry seems to clip on peaks.
The hardware output of AK4490/LM4562|LME49{72,86}X-based DAC for planar headphones is set to "-12" or "-10" dB (they need more power than normal headphones, despite being mere ~16 Ohm).

System Information:

  • Operating system: openSUSE Tumbleweed
  • Strawberry Version: 1.0.21
  • EasyEffects Version: 7.1.3+30~git20231112.45d08f844
  • PipeWire Version: 0.3.85+1~git20231117.44bfeaac6
  • Linux Studio Plugins version: 1.2.13

Additional context
Loudness Normalization is an incredible feature. No matter how much I fiddled about with "Replay Gain", it never worked. But this one does handle badly normalized files (in both ways, too loud and too quiet). It would be perfect if not for perceived clipping.

However, I might have hallucinated the whole thing since there is no logs for clipping/xruns anywhere, other than peaking in EE. But with limiter is should be smooth even with crazy +50 dB overload.

@jonaski
Copy link
Member

jonaski commented Nov 26, 2023

@LebedevRI Can you look into this?

@LebedevRI
Copy link
Contributor

@v-fox are you able to reliably reproduce the issue?

@LebedevRI
Copy link
Contributor

Also, can you please show a screenshot of Settings -> Backend?
My only guess here is that somehow the strawberry's own gstreamer pipeline
somehow ends up needing to convert from floating-point in the middle of the process...

@v-fox
Copy link
Author

v-fox commented Nov 27, 2023

are you able to reliably reproduce the issue?

Yes, in fact, it's more aggressive than I thought. It triggers more often with less loud tracks, so I had to decrease target further to -16 dB (after initial -6 to -9 to -12) while increasing limiter's boost. It was really bad with a quiet piano track.
Don't remember which one was it (maybe "Piano Collections NieR Gestalt & Replicant - Kainé" or "Hills of Radiant Wind") but it had a low "Integrated Loudness" of like -12 to -24.

Also, can you please show a screenshot of Settings -> Backend?

Sure but whole thing is not getting on screen.
screenshot_str_b1
screenshot_str_b2

@LebedevRI
Copy link
Contributor

LebedevRI commented Nov 27, 2023

Could you please try narrowing it a bit, namely, try disabling all of the:

  • Enable volume control
  • Improve headphone listening <...> (bs2b)
  • All of fading

Does it still reproduce with all of them disabled?
(Do fully restart the strawberry after changing settings before trying to reproduce!)

If not, does it reproduce with one specific setting enabled?
Or perhaps a combination of settings?

@v-fox
Copy link
Author

v-fox commented Nov 27, 2023

Could you please try narrowing it a bit, namely, try disabling all of the:

I've set target to LN -6 and limiter to -4 (more like -1, considering -3 on input). The distortion became immediately apparent on "Kainé" piano track (IL=-15.85 LUFS and LR=10.67 LU; input spectrum smashes 0 dB in limiter). And you were right, disabling bs2b and just restarting playback made it stop sounding like as if headphone wires are about to fall off.

And I would have bet on fading effects instead, since they make slight "crunching" glitch under pipewire, at least when manually pausing. But this seems to be unrelated.

@LebedevRI
Copy link
Contributor

Aha.
I think this is working as intended:
https://salsa.debian.org/debian/libbs2b/-/blob/2cd2edd45aa0736642c9b3181731ab0d1548de0a/src/bs2b.c#L504-508
Smart, i know, right?

I would certainly suggest that you ask the upstream to stop doing that.

LebedevRI referenced this issue in alexmarsev/libbs2b Nov 27, 2023
@LebedevRI
Copy link
Contributor

LebedevRI commented Nov 27, 2023

@jonaski i'm not really sure how this can be addressed on strawberry's side.
gstreamer lists bs2b in "bad" category, and original upstream is dead.

(I could supply a patch to remove bs2b from strawberry, if that's what is preferred :) )

@LebedevRI
Copy link
Contributor

@v-fox thank you for the report! This is indeed a very not-nice issue.

@v-fox
Copy link
Author

v-fox commented Nov 27, 2023

@v-fox thank you for the report! This is indeed a very not-nice issue.

@LebedevRI Thanks for pointing me to the right direction.
Could simply patching out the offending code do the trick or the whole logic for bs2b is hardcoded for integers?

@jonaski
Copy link
Member

jonaski commented Nov 27, 2023

Thanks @LebedevRI
I don't want to remove bs2b, I use it at work to play music through headphones.
So there are two alternatives as far as I can see, either disable loudness normalization when bs2b is checked, or submit the patch fixing bs2b to upstream and different distros.
If alexmarsev/libbs2b@5ca2d59 is the correct way of fixing it, I suggest we patch bs2b, I can submit the patch to Fedora and openSUSE and ask Arch and Debian if they can add it.
The official repository is here: https://sourceforge.net/p/bs2b/code/HEAD/tree/trunk/libbs2b/ and the last time there was any real activity was in 2009, so not much chance a new version will be released.

@LebedevRI
Copy link
Contributor

@v-fox thank you for the report! This is indeed a very not-nice issue.

@LebedevRI Thanks for pointing me to the right direction. Could simply patching out the offending code do the trick or the whole logic for bs2b is hardcoded for integers?

I think, simply patching out the offending code (i.e. clamping) is enough,
and the actual processing is done on double's. That being said,
theoretically such clamping might be required, but that is not likely.

Thanks @LebedevRI
I don't want to remove bs2b, I use it at work to play music through headphones.
So there are two alternatives as far as I can see, either disable loudness normalization when bs2b is checked, or submit the patch fixing bs2b to upstream and different distros.

Just to spell it out explicitly: the fact that Loudness Normalization can result in values > 1.0 (> +0 dB / > +0 dBFS)
is NOT a bug, is very intentional, and the fact that there is no limiter / clamping
after Loudness Normalization is NOT a bug. The whole pipeline should never internally limit.

If alexmarsev/libbs2b@5ca2d59 is the correct way of fixing it, I suggest we patch bs2b, I can submit the patch to Fedora and openSUSE and ask Arch and Debian if they can add it.

I think that could be the best way forward,
but there's a lot of distros/packages of bs2b :)

The official repository is here: https://sourceforge.net/p/bs2b/code/HEAD/tree/trunk/libbs2b/ and the last time there was any real activity was in 2009, so not much chance a new version will be released.

Yup. It kind-of sounds like it's time for an official fork for the project.

@diizzyy
Copy link

diizzyy commented Dec 14, 2023

fwiw, already submitted to FreeBSD
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=275403
This will likely be committed during the weekend due to maintainer timeout (port/package policies)

vishwin pushed a commit to vishwin/freebsd-ports that referenced this issue Dec 17, 2023
Disable clamping as it causes incorrect behaviour
While at it return port to pool as maintainer hasn't responded on
multiple bug reports.

Reference:
strawberrymusicplayer/strawberry#1320

Source:
alexmarsev/libbs2b@5ca2d59

PR:		275403
Approved by:	portmgr (maintainer timeout, 2+ weeks)
jonaski added a commit to strawberrymusicplayer/strawberry-macos-dependencies that referenced this issue Jan 8, 2024
jonaski added a commit to strawberrymusicplayer/strawberry-msvc-dependencies that referenced this issue Jan 8, 2024
jonaski added a commit to strawberrymusicplayer/strawberry-mxe that referenced this issue Jan 8, 2024
strawbsbot pushed a commit to strawberrymusicplayer/strawberry-msvc-dependencies that referenced this issue Jan 8, 2024
strawbsbot pushed a commit to strawberrymusicplayer/strawberry-macos-dependencies that referenced this issue Jan 9, 2024
jonaski added a commit to strawberrymusicplayer/strawberry-mxe that referenced this issue Jan 11, 2024
@jonaski jonaski self-assigned this Jan 30, 2024
@jonaski
Copy link
Member

jonaski commented Jan 30, 2024

openSUSE: https://build.opensuse.org/request/show/1142856
Fedora: https://bugzilla.redhat.com/show_bug.cgi?id=2261991

@jonaski
Copy link
Member

jonaski commented Jan 30, 2024

Submitting to Debian is a bit tedious, you have to do it through the mailing-list, so I'll leave that to someone else already in the Debian system.
And I could not register an account in Arch, they have closed the registration because of spam, also better someone already in the Arch system does this.
Patch is added to macOS and Windows builds.

@jonaski jonaski closed this as completed Jan 30, 2024
@LebedevRI
Copy link
Contributor

https://salsa.debian.org/debian/libbs2b/-/merge_requests/2

@jonaski
Copy link
Member

jonaski commented Jan 30, 2024

Thanks @LebedevRI

@hosiet
Copy link

hosiet commented Mar 8, 2024

I merged the libbs2b changes in Debian. Note that I am not familiar with related audio libraries, and I count on you to ensure the patch correctness. If the patch on libbs2b would introduce side effects, please do let people know.

@LebedevRI
Copy link
Contributor

@hosiet thank you! We are reasonably sure that the patch is correct, yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants