Author Topic: BASSloud (loudness measurement)  (Read 4035 times)

Ian @ un4seen

  • Administrator
  • Posts: 26108
BASSloud (loudness measurement)
« on: 17 May '23 - 14:43 »

Now available on the BASS page.


Here is a new add-on for loudness measurement. Windows/Linux/macOS versions are included along with C/Delphi/VB APIs and documentation. An example loudness scanner (LOUDSCAN.C) is also included to demonstrate things, and here's some stripped-down code for getting the loudness of a file:

Code: [Select]
// create file decoder
HSTREAM decoder = BASS_StreamCreateFile(false, filename, 0, 0, BASS_STREAM_DECODE | BASS_SAMPLE_FLOAT);
// start loudness measurement on it
HLOUDNESS loudness = BASS_Loadness_Start(decoder, BASS_LOUDNESS_INTEGRATED | BASS_LOUDNESS_AUTOFREE, 0);
// process the entire file
while (1) {
char buffer[20000];
int c = BASS_ChannelGetData(decoder, buffer, sizeof(buffer));
if (c < 0) break;
}
// get the loudness level
float level;
BASS_Loadness_GetLevel(loudness, BASS_LOUDNESS_INTEGRATED, &level);
// free the decoder and loudness measurement (due to AUTOFREE)
BASS_StreamFree(decoder);

The measurement could then be used to normalize the loudness during playback of the file, like this:

Code: [Select]
BASS_ChannelSetAttribute(channel, BASS_ATTRIB_VOL, pow(10, (target - level) / 20));

Where "target" is the level that you want, eg. -23 for EBU R-128.

This is not a final release, so things may change. Feel free to make suggestions for changes/improvements/etc. Please also report any problems that you encounter.
« Last Edit: 7 Mar '24 - 12:46 by Ian @ un4seen »

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: BASSloud (loudness measurement)
« Reply #1 on: 1 Jun '23 - 16:53 »
An update is up in the first post. The BASS_LOUDNESS_MOMENTARY and BASS_LOUDNESS_SHORTTERM options have been replaced by a new more flexible BASS_LOUDNESS_CURRENT option, which allows a custom window/duration (not only 400ms or 3s) to be used in the loudness measurement. Note the values of the other flags have also changed (see updated headers).

mrRdo

  • Posts: 25
Re: BASSloud (loudness measurement)
« Reply #2 on: 5 Jun '23 - 23:00 »
Hi Ian,

Could this module be used to create a DAMP like effect, only acting on perceived loudness rather than peak values?

Peak values are great in things like broadcast, but for other applications it would be really helpful to have a 'loudness' auto gain controller.

Thank

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: BASSloud (loudness measurement)
« Reply #3 on: 6 Jun '23 - 14:45 »
Yes, I think something like that should be possible. You could periodically (eg. in a timer) check the loudness and apply a gain adjustment via the BASS_ATTRIB_VOL setting. If it's for a single file then you could use the BASS_LOUDNESS_INTEGRATED value, which is the average loudness since measurement started. If it's for multiple (or live) sources then you might use the BASS_LOUDNESS_CURRENT value instead and apply your own averaging. Note BASS_LOUDNESS_INTEGRATED is gated so that much quieter parts are ignored, but BASS_LOUDNESS_CURRENT isn't, so you would need to apply your own gating then, ie. ignore the BASS_LOUDNESS_CURRENT value when it's below some threshold.

rv

  • Posts: 387
Re: BASSloud (loudness measurement)
« Reply #4 on: 6 Jun '23 - 15:02 »
I am trying years ago to cut a drum beat into slices.
I think this is called onset detector
Can this loudness add-on can help in this task?
What is the model used to calculate the loudness?
What do you have in mind while creating this add-on, an auto gain feature?

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: BASSloud (loudness measurement)
« Reply #5 on: 6 Jun '23 - 16:50 »
I am trying years ago to cut a drum beat into slices.
I think this is called onset detector
Can this loudness add-on can help in this task?

I don't think it would help with that.

What is the model used to calculate the loudness?

The add-on is based on the libebur128 library:

   https://github.com/jiixyj/libebur128

Its loudness (and true-peak) measurements are based on ITU-R BS.1770-4:

   https://www.itu.int/dms_pubrec/itu-r/rec/bs/R-REC-BS.1770-4-201510-I!!PDF-E.pdf

What do you have in mind while creating this add-on, an auto gain feature?

It's main purpose is to measure the loudness of entire files (using the BASS_LOUDNESS_INTEGRATED option), which can then be used to normalize the loudness of them. As in ReplayGain, or EBU R128:

   https://tech.ebu.ch/docs/tech/tech3343.pdf

But it can also be used for live/windowed loudness measurements (the BASS_LOUDNESS_CURRENT option), which could be the basis of an auto-gain feature.

rv

  • Posts: 387
Re: BASSloud (loudness measurement)
« Reply #6 on: 8 Jun '23 - 15:17 »
Thank you, I understand better
But maybe the BASS_LOUDNESS_CURRENT will help to detect when loudness is changing in a drum beat , and will help instead of dealing with sample points directly

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: BASSloud (loudness measurement)
« Reply #7 on: 8 Jun '23 - 16:48 »
I guess you want the exact position of a beat? Unfortunately, I don't think loudness measurement can give you that, as it processes blocks of data (400ms default) as a whole.

Have you already tried the BASS_FX add-on's beat detection?

rv

  • Posts: 387
Re: BASSloud (loudness measurement)
« Reply #8 on: 13 Jun '23 - 01:27 »
Bass_fx detects the beat positions and tries to avoid half beats etc... (I think)
The onset is before the beat, when the beat starts, and also every transient should be detected
https://en.wikipedia.org/wiki/Onset_(audio)

RisingMoon

  • Posts: 11
Re: BASSloud (loudness measurement)
« Reply #9 on: 11 Nov '23 - 09:31 »
Hello Ian,

thanks for this addon !

Tested on Win / Delphi 10.1, seems to work OK.

 

Remy

RisingMoon

  • Posts: 11
Re: BASSloud (loudness measurement)
« Reply #10 on: 27 Nov '23 - 09:32 »
Hi Ian,

After successfully got LRA, TP and others LU values from a full stream/file, I try to get I, M and S values in realtime, during playback.
What I see is that LU-I, Lu-S and Lu-M values are "refreshed" before peak values.


(last values at right, older at left)

Do I have to play with any buffer or do I have to delay "previous" (LU) values to sync with "later" (Peak) values ?

Edit : all values are read "at the same time" in the same proc (timer).

Thanks for your help.

Remy

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: BASSloud (loudness measurement)
« Reply #11 on: 27 Nov '23 - 15:58 »
I guess the peak and RMS values in your graph are from BASS_ChannelGetLevelEx? If so, are you getting them during playback? BASSloud and BASS_ChannelGetLevelEx measurements would indeed be out of sync then because they see the data at different stages. BASSloud measures the data in the DSP/FX stage, while BASS_ChannelGetLevelEx measures it later in the playback buffer (so that it's in sync with what's currently being heard). If you do the measurements on a decoding channel (BASS_STREAM_DECODE), which doesn't have a playback buffer, then they should be in sync.

If you need to get the levels in sync during playback then you can move BASS_ChannelGetLevelEx calls to the DSP/FX stage via a DSP function and "push" stream. Something like this:

Code: [Select]
BASS_CHANNELINFO info;
BASS_ChannelGetInfo(stream, &info); // get stream format info
levelstream = BASS_StreamCreate(info.freq, info.chans, (info.flags & (BASS_SAMPLE_FLOAT | BASS_SAMPLE_8BITS)) | BASS_STREAM_DECODE, STREAMPROC_PUSH, 0); // create push stream with same format
BASS_ChannelSetDSP(stream, LevelDSP, (void*)levelstream, 0); // set DSP function on stream

...

void CALLBACK LevelDSP(HDSP handle, DWORD channel, void *buffer, DWORD length, void *user)
{
DWORD levelstream = (DWORD)user;
float peak;
BASS_StreamPutData(levelstream, buffer, length); // pass data to push stream
BASS_ChannelGetLevelEx(levelstream, &peak, 1, BASS_LEVEL_MONO); // get back peak level
...

Please see the documentation for details on the mentioned functions.

RisingMoon

  • Posts: 11
Re: BASSloud (loudness measurement)
« Reply #12 on: 27 Nov '23 - 17:56 »
Hi Ian,

thanks for your answer.

Quote
I guess the peak and RMS values in your graph are from BASS_ChannelGetLevelEx?
I used BASS_ChannelGetLevel() for peak values and BASS_ChannelGetLevelEx() for RMS values.

Code: [Select]
  iLevelLR := BASS_ChannelGetLevel(chan);
  BASS_ChannelGetLevelEx(chan, @ArrLevelLR, 0.3, BASS_LEVEL_RMS);
  BASS_Loudness_GetLevel(RTLoudness, BASS_LOUDNESS_INTEGRATED, &LuLevel);

Will try your code and do feedback.

Remy

RisingMoon

  • Posts: 11
Re: BASSloud (loudness measurement)
« Reply #13 on: 27 Nov '23 - 23:10 »
Didn't got it working with this code.
Finally managed sync by adding "auto-adjust delays" (~100ms) to RMS and LU.
Thanks again.

Edit : to be more precise about my previous message, I can get values with suggested code, but it's more "slowly" and less in sync with main peak indicator.
« Last Edit: 28 Nov '23 - 09:37 by RisingMoon »

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: BASSloud (loudness measurement)
« Reply #14 on: 28 Nov '23 - 12:55 »
The peak/RMS levels were even later when using the DSP callback? That would be strange because the measurements are all taken in the DSP/FX stage then.

One thing I didn't mention is that you would need to call BASS_StreamPutData once for the peak level and again for the RMS level. Note you should use BASS_ChannelGetLevelEx in both cases (not BASS_ChannelGetLevel) to ensure that the pushed data is all used up in each call, avoiding a backlog of data in the push stream.

Code: [Select]
BASS_StreamPutData(levelstream, buffer, length); // pass data to push stream
BASS_ChannelGetLevelEx(levelstream, &peak, 1, BASS_LEVEL_MONO); // get back peak level
BASS_StreamPutData(levelstream, buffer, length); // pass data to push stream
BASS_ChannelGetLevelEx(levelstream, &rms, 1, BASS_LEVEL_RMS | BASS_LEVEL_MONO); // get back RMS level

RisingMoon

  • Posts: 11
Re: BASSloud (loudness measurement)
« Reply #15 on: 28 Nov '23 - 13:31 »
Hi Ian,

I effectively called BASS_StreamPutData only one time in the DSPproc, and used BASS_ChannelGetLevelEx().
I'll try your last suggestions.

Thanks !

RisingMoon

  • Posts: 11
Re: BASSloud (loudness measurement)
« Reply #16 on: 29 Nov '23 - 06:10 »
Effectively better when calling BASS_StreamPutData before each new call to BASS_ChannelGetLevelEx.
Thanks again.

thr

  • Posts: 18
Re: BASSloud (loudness measurement)
« Reply #17 on: 23 Jan '24 - 12:57 »
Hi, interesting Thread.
Are the measurements with playing data the same as looping through the data without playing?

Ian @ un4seen

  • Administrator
  • Posts: 26108
Re: BASSloud (loudness measurement)
« Reply #18 on: 23 Jan '24 - 15:30 »
Yes, the data used in the measurements would be the same in both cases.

RisingMoon

  • Posts: 11
Re: BASSloud (loudness measurement)
« Reply #19 on: 23 Jan '24 - 20:16 »
Hi Thr,

I confirm (see values at bottom of following screenshot) ;)



Remy

thr

  • Posts: 18
Re: BASSloud (loudness measurement)
« Reply #20 on: 30 Jan '24 - 12:03 »
awesome job.

i'm busy working on some loudness matching, but didn't manage to get it working yet without songs "sucking" due to volume changes

Re: BASSloud (loudness measurement)
« Reply #21 on: 5 Feb '24 - 11:24 »
Is there any timeframe for when this may be implemented into the Bass.Net wrapper?

sveakul

  • Posts: 157
Re: BASSloud (loudness measurement)
« Reply #22 on: 18 Feb '24 - 07:28 »
@RisingMoon -- the Loudness Test GUI's you made for bassloud that appear in your posts are impressive!  Is there any way of downloading these apps (Windows)?

RisingMoon

  • Posts: 11
Re: BASSloud (loudness measurement)
« Reply #23 on: 21 Feb '24 - 11:53 »
@sveakul
this version is not available in public domain, but I can send it to you under some conditions.
PM me for details.
Remy

Sakawish

  • Guest
Re: BASSloud (loudness measurement)
« Reply #24 on: 7 Mar '24 - 07:23 »
Hi, I use BASSLoud in Android. The funcation:
Code: [Select]
public static native boolean BASS_Loudness_GetLevel(int handle, int mode, Float level);error, bacause:
JNI DETECTED ERROR IN APPLICATION: JNI SetFloatField called with pending exception java.lang.NoSuchFieldError: no "F" field "value" in class "Ljava/lang/Float;" or its superclasses
  at boolean com.un4seen.bass.BASSloud.BASS_Loudness_GetLevel(int, int, java.lang.Float) (BASSloud.java:-2)

I saw FloatValue class in BASS, how should I solve it? Thanks a lot.