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

New dynamic limiter for very wide dynamic ranges #935

Merged
merged 4 commits into from
Jan 14, 2022

Conversation

roderickvd
Copy link
Member

Well that was a fun exercise! This time I actually think I know what I'm doing.

The current dynamic limiter was an amateur attempt that worked within a limited range and first Rust code I ever wrote. This time I took a article from the Journal of the Audio Engineering Society [1] and wrote a fresh implementation of the most recommended variant (feed-forward in the log domain with a smooth, decoupled peak detector).

So far it seems to work beautifully, including the tracks with wide dynamic range in the linked issue. Would be nice if some of you could give this a spin on various genres and let me know how it goes.

I purposely changed the field names to signal developers downstream that some of these fields now hold values in a different unit. Before in 0.2.0 this caused distorted audio for some other applications and I'd like to prevent that this time.

Closes: #934

[1] Giannoulis, D., Massberg, M., & Reiss, J.D. (2012). Digital Dynamic Range Compressor Design—A Tutorial and Analysis. Journal of The Audio Engineering Society, 60, 399-408

@roderickvd roderickvd self-assigned this Jan 12, 2022
@acid-sun
Copy link

acid-sun commented Jan 12, 2022

I found another track.

[2022-01-12T13:50:58Z INFO  librespot_playback::player] <Danse Macabre, Op. 40,R.171> (442693 ms) loaded
[2022-01-12T13:50:58Z WARN  librespot_playback::player] This track will at its peak be subject to 7.44 dB of dynamic limiting.
[2022-01-12T13:50:58Z WARN  librespot_playback::player] Please lower pregain toavoid.
[2022-01-12T13:50:58Z DEBUG librespot_playback::player] Normalisation Data: NormalisationData { track_gain_db: 5.923416, track_peak: 0.94552505, album_gain_db:1.1973114, album_peak: 0.9883812 }
[2022-01-12T13:50:58Z DEBUG librespot_playback::player] Calculated Normalisation Factor for Track: 197.77%

All sounds good. I like it. Thank you.

@roderickvd
Copy link
Member Author

Great to hear. One more report would be great for me to merge this with confidence.

@JasonLG1979
Copy link
Contributor

I will give it a test. There are a couple tracks that I know of that distort.

@JasonLG1979
Copy link
Contributor

So far so good. The entire Bush, Sixteen Stones album was pretty bad with the old limiter
( https://open.spotify.com/album/5IJm0boSQuEBLiYNZJKV2Y?si=5q4kkdqFRWOFdQatWWUVdQ ) It's honestly not much better with the new limiter but it's at least somewhat tolerable. Even without a limiter it's really bad. It's a fuzzy, squished hot mess full of inter-sample peaks I'd guess. A victim of the loudness wars and "more me" mixing.

@JasonLG1979
Copy link
Contributor

I do notice that it uses a little bit more CPU though. Maybe 2%-ish more on my Raspberry Pi 4. That should still be fine on a Pi Zero I would think though. It should still be under 30%.

@roderickvd
Copy link
Member Author

So far so good. The entire Bush, Sixteen Stones album was pretty bad with the old limiter
( https://open.spotify.com/album/5IJm0boSQuEBLiYNZJKV2Y?si=5q4kkdqFRWOFdQatWWUVdQ ) It's honestly not much better with the new limiter but it's at least somewhat tolerable. Even without a limiter it's really bad. It's a fuzzy, squished hot mess full of inter-sample peaks I'd guess. A victim of the loudness wars and "more me" mixing.

Oh man that's definitely a throwback! Can't remember much often I played that album back in the days. A lot.

However with the default pregain of 0.0 I don't think the dynamic limiter kicks in at all? The tracks indeed suffer from very low dynamic range. The average ReplayGain for these tracks is around -10 dB. The peaks then all stay under threshold.

I do notice that it uses a little bit more CPU though. Maybe 2%-ish more on my Raspberry Pi 4. That should still be fine on a Pi Zero I would think though. It should still be under 30%.

Yeah, that's quite possible. Though the code is short and sweet, there are more things going on now that the CPU has no intrinsics for. Like linear <> logarithmic conversions, twice for every sample.

@roderickvd
Copy link
Member Author

Now that you mentioned it I do have some ideas to optimize this when we aren’t attacking or releasing a peak.

@roderickvd
Copy link
Member Author

dce7944 is a little more efficient and hasn't broken anything right?

@JasonLG1979
Copy link
Contributor

The tracks indeed suffer from very low dynamic range. The average ReplayGain for these tracks is around -10 dB.

I didn't read the logs but I want to say that Glycerine in track mode distorts?

dce7944 is a little more efficient and hasn't broken anything right?

I will give it a go and report back.

@JasonLG1979
Copy link
Contributor

Yep, that cut it from about 2% to about 1%,lol!!!

LGTM

After you merge this and your --device fix I'll release a new version of Raspotify. I'm sure if there's any bugs they'll show themselves.

@roderickvd
Copy link
Member Author

The tracks indeed suffer from very low dynamic range. The average ReplayGain for these tracks is around -10 dB.

I didn't read the logs but I want to say that Glycerine in track mode distorts?

I don't think so -- it's down -5.6 dB. If you mean that guitar, I do think that it clips but already in the recording and possibly even on the guitar amp. This is "Glycerine - Remastered" on "Sixsteen Stone (Remastered)": https://open.spotify.com/track/5buITai6eMzU8rJonMEI6e?si=962443be52484f34

dce7944 is a little more efficient and hasn't broken anything right?

Yep, that cut it from about 2% to about 1%,lol!!!

Well, like it said on the tin 😆 I'll take it.

After you merge this and your --device fix I'll release a new version of Raspotify. I'm sure if there's any bugs they'll show themselves.

For a final check maybe you can compare what Glycerine sounds like in an official Spotify client. On macOS, the official app sounds a little lower in volume, but the guitar no better.

After you merge this and your --device fix I'll release a new version of Raspotify. I'm sure if there's any bugs they'll show themselves.

👍

@roderickvd roderickvd merged commit 72af0d2 into librespot-org:dev Jan 14, 2022
@JasonLG1979
Copy link
Contributor

Testing on my Pi Zero shows CPU usage in the high teens to low 20's. So it's about what I expected. 1% increase on the Pi 4 and 5-10% on the Pi Zero. Not great but not a deal breaker. Still plenty of headroom. When the new API work becomes more complete I will test that on the Zero.

@ghost
Copy link

ghost commented Jan 16, 2022

Wow! Thank you for this! I could never use the old dynamic limiter, because this song was always crackling:

[2022-01-16T16:19:01Z INFO  librespot_playback::player] Loading <Feel Like Going Home> with Spotify URI <spotify:track:0qMPttvKZkUXyDgNmZhKsY>
[2022-01-16T16:19:01Z DEBUG librespot_audio::fetch] File 8663bb953f40917e6c295a7e4ac96d06d0074ad2 already in cache
[2022-01-16T16:19:01Z DEBUG librespot_core::audio_key] new AudioKeyManager
[2022-01-16T16:19:01Z INFO  librespot_playback::player] <Feel Like Going Home> (292773 ms) loaded
[2022-01-16T16:19:01Z WARN  librespot_playback::player] This track will at its peak be subject to 7.47 dB of dynamic limiting.
[2022-01-16T16:19:01Z WARN  librespot_playback::player] Please lower pregain to avoid.
[2022-01-16T16:19:01Z DEBUG librespot_playback::player] Normalisation Data: NormalisationData { track_gain_db: 1.2700005, track_peak: 0.81324977, album_gain_db: 0.3600006, album_peak: 1.0166621 }
[2022-01-16T16:19:01Z DEBUG librespot_playback::player] Calculated Normalisation Factor for Track: 230.94%

Now the limiter is finally useful!

@roderickvd
Copy link
Member Author

Glad to hear it’s appreciated ❤️

@roderickvd roderickvd added the breaking includes a breaking change label Jan 22, 2022
michaelherger added a commit to michaelherger/librespot that referenced this pull request Feb 17, 2022
* spotty-dev: (76 commits)
  Quantum-realm level normalisation optimization (librespot-org#965)
  Only log runtime argument if it starts with a dash "-"
  Improved error handling when fetching tokens or track data.
  update changelog
  Prevent shuffle crash
  Remove basic normalisation deprecation warning
  Fix Alsa softvol linear mapping (librespot-org#950)
  simplify get_factor (librespot-org#942)
  Update LMS integration to
  Remove unsafe code (librespot-org#940)
  Save some more CPU cycles in the limiter (librespot-org#939)
  New dynamic limiter for very wide dynamic ranges (librespot-org#935)
  Fix `--device` argument to various backends (librespot-org#938)
  examples/playlist_tracks: Use normal URI parser
  Fix clippy lint warning
  Clean up list_compatible_devices
  Sink: pass ownership of the packet on write()
  Restore giving feedback about auth success. The plugin is checking for this.
  Remove that last couple unwraps from main
  Fix auto fallback for --alsa-mixer-device and --alsa-mixer-index
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
audio breaking includes a breaking change enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Clipping with dynamic volume normalisation
3 participants