Hydrogenaudio Forums

Hosted Forums => foobar2000 => General - (fb2k) => Topic started by: wcs13 on 2020-08-18 18:24:17

Title: Dynamic Loudness Control
Post by: wcs13 on 2020-08-18 18:24:17
Hi guys,

Does foobar (or one of its 3rd-party components) provide Dynamic Loudness Control according to the Fletcher-Munson curves, like the one that can be found in JRiver ? https://yabb.jriver.com/interact/index.php?topic=76608.0

Thanks.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-19 06:39:09
No.
But it is possible to create script to automatically switch DSP presets depending on current volume level.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-19 15:21:51
Thanks Rollin. If somebody has already done this, I'd be interested in the script and relevant DSP presets.
With that said, it could also be a nice feature request. After all, JRiver are doing it already and people seem to like it.
Title: Re: Dynamic Loudness Control
Post by: Priest_1 on 2020-08-19 15:28:14
Hi guys,

Does foobar (or one of its 3rd-party components) provide Dynamic Loudness Control according to the Fletcher-Munson curves, like the one that can be found in JRiver ? https://yabb.jriver.com/interact/index.php?topic=76608.0

Thanks.

I use WOK vst loudness plugin - http://wokwave.com/old-plugins/html/wok_loudness_free_vst_plugin.html
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-19 15:42:18
If somebody has already done this, I'd be interested in the script and relevant DSP presets.
Yes. Somebody has done this already. Here is script for JScript Panel - https://translate.google.ru/translate?sl=ru&tl=en&u=https%3A%2F%2Ffoobar2000.ru%2Fforum%2Fviewtopic.php%3Fp%3D77623%23p77623 It switch DSP preset for every 5 dB step in volume and can use up to 20 presets. It can be modified  to change step, use more or less presets, use other presets names. But you should create DSP presets yourself.
Code: [Select]
var dsp_active_name = "";
var dsp_str = fb.GetDSPPresets();
var dsp_arr = JSON.parse(dsp_str);
var dsp_count = dsp_arr.length;

function get_dsp() {
   dsp_active_name = "";
   dsp_str = fb.GetDSPPresets();
   dsp_arr = JSON.parse(dsp_str);
   dsp_count = dsp_arr.length;
   for (var i = 0; i < dsp_arr.length; i++) {

      //tt(">>> dsp presets name # " + i + ": " + dsp_arr[i].name);

      if (dsp_arr[i].active) {
         dsp_active_name = dsp_arr[i].name;
      }

   }
   tt('>>> dsp presets count = ' + dsp_count);
   tt(">>> dsp active name = " + dsp_active_name);
};
//get_dsp();

function get_dsp_idx(dsp_name) {

   for (var i = 0; i < dsp_arr.length; i++) {

      if (dsp_arr[i].name == dsp_name) {

         return i
      }

   }

};

function on_dsp_preset_changed() {
   get_dsp();
};

var vol_lvl = Math.ceil(fb.Volume);
function on_volume_change(val) {
   //---
   // 0 is max
   // -100 is min

   vol_lvl = Math.ceil(val);
   if (isNaN(vol_lvl))
      vol_lvl = Math.ceil(fb.Volume);

   if (vol_lvl == 0) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -5) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -5")); // set dsp preset -5
   };
   if (vol_lvl == -10) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -10")); // set dsp preset -10
   };
   if (vol_lvl == -15) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -15")); // set dsp preset -15
   };
   if (vol_lvl == -20) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -20")); // set dsp preset -20
   };
   if (vol_lvl == -25) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -25")); // set dsp preset -25
   };
   if (vol_lvl == -30) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -30")); // set dsp preset -30
   };
   if (vol_lvl == -35) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -35")); // set dsp preset -35
   };
   if (vol_lvl == -40) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -40")); // set dsp preset -40
   };
   if (vol_lvl == -45) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -45")); // set dsp preset -45
   };
   if (vol_lvl == -50) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -50")); // set dsp preset -50
   };
   if (vol_lvl == -55) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -55")); // set dsp preset -55
   };
   if (vol_lvl == -60) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -60")); // set dsp preset -60
   };
   if (vol_lvl == -65) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -65")); // set dsp preset -65
   };
   if (vol_lvl == -70) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -70")); // set dsp preset -70
   };
   if (vol_lvl == -75) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -75")); // set dsp preset -75
   };
   if (vol_lvl == -80) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -80")); // set dsp preset -80
   };
   if (vol_lvl == -85) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -85")); // set dsp preset -85
   };
   if (vol_lvl == -90) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -90")); // set dsp preset -90
   };
   if (vol_lvl == -95) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -95")); // set dsp preset -95
   };
   if (vol_lvl == -100) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -100")); // set dsp preset -100
   };

};
on_volume_change();

function tt(t) {
   console.log(t);
};

I use WOK vst loudness plugin - http://wokwave.com/old-plugins/html/wok_loudness_free_vst_plugin.html
For it to work correctly with fb2k, volume should be changed before this VST. But volume bar changes volume after DSP. So it is needed to add to DSP chain some plugin that can change volume and use it instead of volume bar. Otherwise, correction level will be fixed regardless of volume.
Title: Re: Dynamic Loudness Control
Post by: VlaKor on 2020-08-19 17:49:43
Достал уже всех со своей тонокомпенсацией ))
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-19 18:14:50
Thanks both of you.

Rollin has made a very interesting remark about how the WOK loudness plugin can't work unless another plugin is added to the DSP chain. @Priest_1 have you found such plugin ?

@Rollin so I guess the relevant approach would be :
- Play some music with foobar volume @ 0 dB
- Measure the dB with a dBmeter (ex : 90dB)
- Check the corresponding Fletcher-Munson curve, and enter it in a DSP preset naming it "dsp 0"
- Continue from there (85dB curve = "dsp -5", 80dB curve = "dsp -10", and so on
Am I right ?

Of course with this meahod we should only use foobar's volume control once and for all. If we have an external amp and we turn the knob, the dB intensity will be changed and all the DSP presets will become invalid.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-19 18:43:00
I don't know if Priest_1 found DSP to change volume, but i can recommend foo_dsp_amp - https://foobar.hyv.fi/?view=foo_dsp_amp

so I guess the relevant approach would be :
- Play some music with foobar volume @ 0 dB
- Measure the dB with a dBmeter (ex : 90dB)
- Check the corresponding Fletcher-Munson curve, and enter it in a DSP preset naming it "dsp 0"
- Continue from there (85dB curve = "dsp -5", 80dB curve = "dsp -10", and so on
Am I right ?
Yes.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-19 20:32:36
Sounds great. This is being really helpful.
Can foo_dsp_amp be linked to a couple of keyboard shortcuts ? (vol. up / down)
If I could replace the shortcuts that I currently use for foobar volume bar, everything would be perfect.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-20 02:25:44
Another thing : all this process implies that some volume normalization algorithm is activated, such as ReplayGain.
Otherwise two different songs could have very different output volumes while foobar volume remains @ 0 dB, which means that the DSP presets wouldn't make any sense.
Title: Re: Dynamic Loudness Control
Post by: Priest_1 on 2020-08-21 00:00:34
LOUDNESS VST BY WOK.
You also need Foobar2000 VST 2.4 adapter - https://hydrogenaud.io/index.php?topic=84947.0
Title: Re: Dynamic Loudness Control
Post by: Priest_1 on 2020-08-21 07:57:31
LOUDNESS VST BY WOK.

LOUDNESS simulates the loudness button on old HiFi amps, which alters the frequency response curve to correspond roughly with the equal loudness characteristic of the ear at lower volumes.

The level of high and low frequencies is increased at low listening levels, to compensate for the fact that as the volume of audio decreases, the ears lower sensitivity to extreme high and low frequencies may cause these signals to fall below threshold. As a result audio material may seem to become ‘thin’ sounding at low volumes, losing bass and treble, the ‘Loudness compensation’ button (often just labelled ‘Loudness’ or ‘Loud’) is intended to rectify this situation.


6 VST plugins that will make your tracks sound louder without destroying punch - https://www.musicradar.com/how-to/vst-plugins-for-loudness-and-punch
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-24 02:12:35
@Rollin , silly question maybe, but with the JScript Panel script and manual DSP presets (which would be my preferred solution because I could enter the Fletcher-Munson curves accurately one by one), foo_dsp_amp wouldn't be needed, right? Or would it?

Also, is there a more precise DSP EQ that the standard one? The standard one has 18 pre-defined bands, from 55 Hz up, and we can only go in +/-1 dB increments. Ideally I'd like to define my own band frequencies (27 of them), and +/-0.5 dB increments.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-24 17:01:43
with the JScript Panel script and manual DSP presets (which would be my preferred solution because I could enter the Fletcher-Munson curves accurately one by one), foo_dsp_amp wouldn't be needed, right? Or would it?
foo_dsp_amp is not needed.  Just use volume bar as usually. Create some dummy DSP presets and try it yourself. It even reports in console when presets are switched.
Also, is there a more precise DSP EQ that the standard one?
http://www.foobar2000.org/components/view/foo_dsp_xgeq
Also there is parametric EQ in http://www.foobar2000.org/components/view/foo_dsp_effect It is single-banded, but many instances with different settings can be used in a row in one preset.
Also there is convolver https://hydrogenaud.io/index.php?topic=85107.0
Or you can use some VST equalizer wih foo_vst

so I guess the relevant approach would be :
- Play some music with foobar volume @ 0 dB
- Measure the dB with a dBmeter (ex : 90dB)
- Check the corresponding Fletcher-Munson curve, and enter it in a DSP preset naming it "dsp 0"
- Continue from there (85dB curve = "dsp -5", 80dB curve = "dsp -10", and so on
Am I right ?
After some thoughts, i guess that maybe -5 dB in foobar will not lead to -5 actual physical dB. So, probably, you will need to change presets names for convenience and edit script accordingly.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-25 00:53:45
Thank you so much @Rollin  , you are being extremely helpful here!
I understand your final thoughts, they will require some testing.

I'll try using the script + foo_dsp_xgeq, see what happens and report the results.
I'm using SMP instead of the older JSP, but I hope the script will work.

I have installed foo_dsp_xgeq, and exported a first test preset named "dsp 0.xgeq".
My question is: where should I put it so the SMP script can find it?

Another question, not being able to understand how the script works: let's say that foobar volume = 0 dB. So the "dsp 0" script is active.
What if I lower the volume to, say, -2 dB? Will the "dsp 0" preset remain active until we reach -5 dB?
Same thing backwards: let's say that foobar volume = -5 dB. So the "dsp -5" preset is active.
What if I set the volume to -2 dB? Will the "dsp 0" preset kick in?
I guess ideally the "dsp 0" script should be active between 0 and -4 dB, the "dsp -5" preset between -5 and -9 dB, and so on. Is that how the script works?
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-25 15:28:04
I dont't know if this script is compatible with SMP. I tested it with JSP only.
I have installed foo_dsp_xgeq, and exported a first test preset named "dsp 0.xgeq".
My question is: where should I put it so the SMP script can find it?
No need to export *.xgeq presets. You need to create DSP chain presets.
(https://i.imgur.com/aAUQGob.png)
I guess ideally the "dsp 0" script should be active between 0 and -4 dB, the "dsp -5" preset between -5 and -9 dB, and so on. Is that how the script works?
Yes. It works this way.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-25 17:41:09
Oh I see! Sorry about that.
The script seems compatible with SMP, at least it shows no errors.

I have created 2 completely different DSP chain presets named "dsp 0" and "dsp -5", to effectively hear a difference when I lower the volume. If I load them manually I hear the difference. But when I lower the volume I hear nothing. It's like the script doesn't kick in. I have checked it and it seems active.

If somebody has managed to make this work, please give me a sign before I run out of hair to pull. Thank you.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-25 18:01:45
Demonstration that it works (with JScript Panel). Look at Spectrum and console.
https://youtu.be/Fv-iZcGl850
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-26 00:26:58
Thank you, that's very clear indeed ! So it must be because of SMP then. I'll have to install JSP (or find a Javascript dev to modify the script - there's probably only a couple lines to adapt, if somebody's listening...).

One last thing : the standard EQ goes from -20 to +20 and has 18 bands. The XGEQ  goes from -12 to +12 and has 31 bands. To accurately reproduce the Fletcher-Munson curves I need an EQ that goes approximately from +39 to -8 and has 27 bands...
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-26 02:16:25
For the record, I have installed JSP. The script works now... but not as it should. This can be reproduced 100%.
0 db : dsp 0 is active
-1 db : dsp 0
-2 db : dsp 0
-3 db : dsp 0
-4 db : dsp 0
-5 db : dsp -5 kicks in
-4 db : dsp -5 remains, THIS is not normal
-3 db : dsp -5
-2 db : dsp -5
-1 db : dsp -5
0 db : dsp 0 kicks in again
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-26 15:37:14
To accurately reproduce the Fletcher-Munson curves I need an EQ that goes approximately from +39 to -8 and has 27 bands
As already been said, you can use multiple instances of the same DSP in a row in one DSP preset. Or you can use convolver instead of EQ. Or VST plugins. Or combine them all.

-4 db : dsp -5 remains, THIS is not normal
Here is modified script for dsp 0 to kick in right time. You can get the idea and modify it for other presets yourself - this is mostly copy-paste.
Code: [Select]
var dsp_active_name = "";
var dsp_str = fb.GetDSPPresets();
var dsp_arr = JSON.parse(dsp_str);
var dsp_count = dsp_arr.length;

function get_dsp() {
   dsp_active_name = "";
   dsp_str = fb.GetDSPPresets();
   dsp_arr = JSON.parse(dsp_str);
   dsp_count = dsp_arr.length;
   for (var i = 0; i < dsp_arr.length; i++) {

      //tt(">>> dsp presets name # " + i + ": " + dsp_arr[i].name);

      if (dsp_arr[i].active) {
         dsp_active_name = dsp_arr[i].name;
      }

   }
   tt('>>> dsp presets count = ' + dsp_count);
   tt(">>> dsp active name = " + dsp_active_name);
};
//get_dsp();

function get_dsp_idx(dsp_name) {

   for (var i = 0; i < dsp_arr.length; i++) {

      if (dsp_arr[i].name == dsp_name) {

         return i
      }

   }

};

function on_dsp_preset_changed() {
   get_dsp();
};

var vol_lvl = Math.ceil(fb.Volume);
function on_volume_change(val) {
   //---
   // 0 is max
   // -100 is min

   vol_lvl = Math.ceil(val);
   if (isNaN(vol_lvl))
      vol_lvl = Math.ceil(fb.Volume);

   if (vol_lvl == 0) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -1) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -2) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -3) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -4) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -5) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -5")); // set dsp preset -5
   };
   if (vol_lvl == -10) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -10")); // set dsp preset -10
   };
   if (vol_lvl == -15) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -15")); // set dsp preset -15
   };
   if (vol_lvl == -20) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -20")); // set dsp preset -20
   };
   if (vol_lvl == -25) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -25")); // set dsp preset -25
   };
   if (vol_lvl == -30) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -30")); // set dsp preset -30
   };
   if (vol_lvl == -35) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -35")); // set dsp preset -35
   };
   if (vol_lvl == -40) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -40")); // set dsp preset -40
   };
   if (vol_lvl == -45) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -45")); // set dsp preset -45
   };
   if (vol_lvl == -50) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -50")); // set dsp preset -50
   };
   if (vol_lvl == -55) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -55")); // set dsp preset -55
   };
   if (vol_lvl == -60) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -60")); // set dsp preset -60
   };
   if (vol_lvl == -65) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -65")); // set dsp preset -65
   };
   if (vol_lvl == -70) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -70")); // set dsp preset -70
   };
   if (vol_lvl == -75) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -75")); // set dsp preset -75
   };
   if (vol_lvl == -80) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -80")); // set dsp preset -80
   };
   if (vol_lvl == -85) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -85")); // set dsp preset -85
   };
   if (vol_lvl == -90) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -90")); // set dsp preset -90
   };
   if (vol_lvl == -95) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -95")); // set dsp preset -95
   };
   if (vol_lvl == -100) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -100")); // set dsp preset -100
   };

};
on_volume_change();

function tt(t) {
   console.log(t);
};
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-26 16:10:10
Thanks ! That was easier than I thought.  :) Here's the modified working script (I have done it between 0 and -60 dB which should be more than enough) :

Code: [Select]
var dsp_active_name = "";
var dsp_str = fb.GetDSPPresets();
var dsp_arr = JSON.parse(dsp_str);
var dsp_count = dsp_arr.length;

function get_dsp() {
   dsp_active_name = "";
   dsp_str = fb.GetDSPPresets();
   dsp_arr = JSON.parse(dsp_str);
   dsp_count = dsp_arr.length;
   for (var i = 0; i < dsp_arr.length; i++) {

      //tt(">>> dsp presets name # " + i + ": " + dsp_arr[i].name);

      if (dsp_arr[i].active) {
         dsp_active_name = dsp_arr[i].name;
      }

   }
   tt('>>> dsp presets count = ' + dsp_count);
   tt(">>> dsp active name = " + dsp_active_name);
};
//get_dsp();

function get_dsp_idx(dsp_name) {

   for (var i = 0; i < dsp_arr.length; i++) {

      if (dsp_arr[i].name == dsp_name) {

         return i
      }

   }

};

function on_dsp_preset_changed() {
   get_dsp();
};

var vol_lvl = Math.ceil(fb.Volume);
function on_volume_change(val) {
   //---
   // 0 is max
   // -60 is min

   vol_lvl = Math.ceil(val);
   if (isNaN(vol_lvl))
      vol_lvl = Math.ceil(fb.Volume);

   if (vol_lvl == 0) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -1) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -2) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -3) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -4) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp 0")); // set dsp preset 0
   };
   if (vol_lvl == -5) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -5")); // set dsp preset -5
   };
   if (vol_lvl == -6) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -5")); // set dsp preset -5
   };
   if (vol_lvl == -7) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -5")); // set dsp preset -5
   };
   if (vol_lvl == -8) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -5")); // set dsp preset -5
   };
   if (vol_lvl == -9) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -5")); // set dsp preset -5
   };
   if (vol_lvl == -10) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -10")); // set dsp preset -10
   };
   if (vol_lvl == -11) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -10")); // set dsp preset -10
   };
   if (vol_lvl == -12) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -10")); // set dsp preset -10
   };
   if (vol_lvl == -13) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -10")); // set dsp preset -10
   };
   if (vol_lvl == -14) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -10")); // set dsp preset -10
   };
   if (vol_lvl == -15) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -15")); // set dsp preset -15
   };
   if (vol_lvl == -16) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -15")); // set dsp preset -15
   };
   if (vol_lvl == -17) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -15")); // set dsp preset -15
   };
   if (vol_lvl == -18) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -15")); // set dsp preset -15
   };
   if (vol_lvl == -19) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -15")); // set dsp preset -15
   };
   if (vol_lvl == -20) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -20")); // set dsp preset -20
   };
   if (vol_lvl == -21) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -20")); // set dsp preset -20
   };
   if (vol_lvl == -22) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -20")); // set dsp preset -20
   };
   if (vol_lvl == -23) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -20")); // set dsp preset -20
   };
   if (vol_lvl == -24) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -20")); // set dsp preset -20
   };
   if (vol_lvl == -25) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -25")); // set dsp preset -25
   };
   if (vol_lvl == -26) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -25")); // set dsp preset -25
   };
   if (vol_lvl == -27) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -25")); // set dsp preset -25
   };
   if (vol_lvl == -28) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -25")); // set dsp preset -25
   };
   if (vol_lvl == -29) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -25")); // set dsp preset -25
   };
   if (vol_lvl == -30) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -30")); // set dsp preset -30
   };
   if (vol_lvl == -31) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -30")); // set dsp preset -30
   };
   if (vol_lvl == -32) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -30")); // set dsp preset -30
   };
   if (vol_lvl == -33) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -30")); // set dsp preset -30
   };
   if (vol_lvl == -34) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -30")); // set dsp preset -30
   };
   if (vol_lvl == -35) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -35")); // set dsp preset -35
   };
   if (vol_lvl == -36) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -35")); // set dsp preset -35
   };
   if (vol_lvl == -37) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -35")); // set dsp preset -35
   };
   if (vol_lvl == -38) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -35")); // set dsp preset -35
   };
   if (vol_lvl == -39) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -35")); // set dsp preset -35
   };
   if (vol_lvl == -40) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -40")); // set dsp preset -40
   };
   if (vol_lvl == -41) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -40")); // set dsp preset -40
   };
   if (vol_lvl == -42) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -40")); // set dsp preset -40
   };
   if (vol_lvl == -43) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -40")); // set dsp preset -40
   };
   if (vol_lvl == -44) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -40")); // set dsp preset -40
   };
   if (vol_lvl == -45) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -45")); // set dsp preset -45
   };
   if (vol_lvl == -46) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -45")); // set dsp preset -45
   };
   if (vol_lvl == -47) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -45")); // set dsp preset -45
   };
   if (vol_lvl == -48) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -45")); // set dsp preset -45
   };
   if (vol_lvl == -49) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -45")); // set dsp preset -45
   };
   if (vol_lvl == -50) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -50")); // set dsp preset -50
   };
   if (vol_lvl == -51) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -50")); // set dsp preset -50
   };
   if (vol_lvl == -52) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -50")); // set dsp preset -50
   };
   if (vol_lvl == -53) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -50")); // set dsp preset -50
   };
   if (vol_lvl == -54) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -50")); // set dsp preset -50
   };
   if (vol_lvl == -55) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -55")); // set dsp preset -55
   };
   if (vol_lvl == -56) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -55")); // set dsp preset -55
   };
   if (vol_lvl == -57) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -55")); // set dsp preset -55
   };
   if (vol_lvl == -58) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -55")); // set dsp preset -55
   };
   if (vol_lvl == -59) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -55")); // set dsp preset -55
   };
   if (vol_lvl == -60) {
      tt(">>> vol = " + vol_lvl);
      fb.SetDSPPreset(get_dsp_idx("dsp -60")); // set dsp preset -60
   };

};
on_volume_change();

function tt(t) {
   console.log(t);
};

As for the EQ part, sorry about that, but please note that I'm not an expert in such things. I'd just like the solution that will cause the less possible degradation to the signal, as all this is supposed to be for a Hi-Fi application. So what would you do if you were in my position and had to accurately reproduce those curves ?

I love foobar and I'd never want to change it, but it's a pity that we have to do this by hand, when JRiver users can do it with the press of a button. I hope this can make a useful feature request ("dynamic loudness").
Title: Re: Dynamic Loudness Control
Post by: Case on 2020-08-26 18:43:10
JRiver is a paid product and they have to keep their customers happy no matter how nonsensical requests they make. Your ears will get used to any audio output but if you really want to tinker with EQ just make presets for the actual playback levels you use. I'd estimate two would be enough.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-27 23:29:53
You are absolutely right about JRiver, and indeed nobody is forced to do anything about foobar, especially since it already works great. So... let's all stop improving foobar and let's all go home, right?   :D

I just say there's always room for improvement, and that if foobar had a Dynamic Loudness feature (not just a static loudness of course) that we could activate via the Prefs, it would be a step in the right direction. And then just let everybody decide if they activate it or not.

Currently very few people are doing the Fletcher-Munson thing, for one good reason: because it's TEDIOUS and not for the average user, as we can all see from this topic. However if it was more user-friendly, I can safely bet that much more people would use it. After all, a lot of people did use those "loudness" buttons in old Hi-Fi gear.

And I guess that should be exactly the purpose of a developer : turning something tedious into something user-friendly.  ;)
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-28 15:53:56
I'd just like the solution that will cause the less possible degradation to the signal, as all this is supposed to be for a Hi-Fi application.
There will be no real degradation of signal unless you run into clipping.

So what would you do if you were in my position and had to accurately reproduce those curves ?
Parametric EQ VST or convolver. Since foo_vst is unstable and buggy, convolver is preferred.
Here is ultra-quick lesson (video-only, no comments) how to use convolver. Notice very important thing: impulse must be of the same samplerate and channels count as signal that is processed, so it is a good idea to have resampler in DSP chain before convolver. In this "lesson" i used Audacity with built-in EQ. You can use any sound editor (that supports 32 bit floating point) with any EQ.
https://youtu.be/zmYcSMkeT7Q
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-29 00:02:32
@Rollin , man, you're awesome. Huge thanks for your help and advice.
I have followed your instructions from A to Z and everything seems to work perfectly ! :D
I am familiar with Audacity so the whole operation was easy.
Now I only need to repeat the EQ operation with the same "Unitpulse2K.wav" start impulse file for every Fletcher-Munson curve.
I am very grateful. In this topic I have learned how to achieve Dynamic Loudness, but also how to use a resampler and a convolver ! :D

BTW you said that the impulse must be of the same sample rate and channel count as the signal that is processed. A majority of my files are of course 16/44.1 (mostly EAC-ripped CDs), but I have other sample rates up to 24/192. Which raises two questions :
1. Should I create a single set of impulse files in the highest possible sample rate rather than in 44.1 ? Or should I create several sets of impulse files ? (44.1, 48, 88.2, 96, 176.2, 192)
2. The resamplers (dbpoweramp/SSRC and PPHS) seem to go "only" to 96 KHz. How could I handle 192 KHz data ?

If it's of any help, my foobar outputs to a USB DAC (Topping E30) that can theoretically go up to 768 KHz (even if absolutely nobody can hear the difference, lol).
Title: Re: Dynamic Loudness Control
Post by: sveakul on 2020-08-29 04:09:06
2. The resamplers (dbpoweramp/SSRC and PPHS) seem to go "only" to 96 KHz. How could I handle 192 KHz data ?

Ivcql's SoX resampler (foo_dsp_resampler) will handle 192kHz:  https://hydrogenaud.io/index.php?topic=67376.0 (https://hydrogenaud.io/index.php?topic=67376.0)

Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-29 04:36:14
1. Should I create a single set of impulse files in the highest possible sample rate rather than in 44.1 ? Or should I create several sets of impulse files ? (44.1, 48, 88.2, 96, 176.2, 192)
To simplify, i would just use resampler before convolver and resample everything to 44.1. There will be no audible differences.
If you are going to create impulses for all samplerates, you can use foo_dynamicdsp to automate switching. https://hydrogenaud.io/index.php?topic=96094.0 https://hydrogenaud.io/index.php?topic=96094.msg956094#msg956094

2. The resamplers (dbpoweramp/SSRC and PPHS) seem to go "only" to 96 KHz. How could I handle 192 KHz data ?
Use keybooard and enter any samplerate manually.
But i would use SoX resampler because it is fastest.

BTW, you can also try to draw curves in MathAudio Room EQ - https://mathaudio.com/room-eq.htm
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-29 12:34:25
Maybe I'm getting lost here. Why should I resample after all ?  O:)  Maybe I should just make sure to get all the necessary impulse files, in all sample rates and channels, and never have to resample. It would be a bit of work, but then I wouldn't have to resample at all. Wouldn't that be better ?

If I created impulses for all samplerates (I know, no audible difference but at least it could be intellectually satisfying to have everything work), should I always use the same "Unitpulse2K.wav" source file? Isn't it only 44.1 KHz? Aren't there other impulses for higher frequencies?

BTW if I absolutely had to resample, my concern wouldn't be about a fast resampler, since my PC is recent and has a lot of computing power.
My concern would be about (1) best audio quality, (2) no audible glitches between songs, (3) easy to set up, and (4) 192 KHz compatibility.
Which resampler should I use then ? dbpoweramp/SSRC ? Ivcql's SoX ? Or the more recent Case's SRC ?

Thanks for the DRC part, that will be useful in a few months when I get my new active monitors.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-30 20:33:42
Of course you can create impulses for all samplerates.

You can resample this impulse to needed samplerate and use it. Or, if you want absolutely perfect impulses for all samplerates, you can create them in Audacity.

BTW if I absolutely had to resample, my concern wouldn't be about a fast resampler, since my PC is recent and has a lot of computing power.
My concern would be about (1) best audio quality, (2) no audible glitches between songs, (3) easy to set up, and (4) 192 KHz compatibility.
Which resampler should I use then ? dbpoweramp/SSRC ? Ivcql's SoX ? Or the more recent Case's SRC ?
1) No audible differences between all these resamplers. 2)No audible glitches on playback with all these resamplers (although glitches on tracks transition are possible on conversion (when using Converter) with dbpoweramp/SSRC) 3) All three are easy to set up 4) All are 192 kHz compatible. So why not use fastest? And SoX can have higher bandwidth than SRC (with 99% it is almost as high as dbpoweramp/SSRC) and at the same time it has less ringing than dbpoweramp/SSRC.

Thanks for the DRC part, that will be useful in a few months when I get my new active monitors.
Did you actually read description of foo_dynamicdsp? It has nothing to do with DRC. It is to automate switching of DSP depending on properties of playing file.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-31 10:52:14
Did you actually read description of foo_dynamicdsp? It has nothing to do with DRC. It is to automate switching of DSP depending on properties of playing file.
Haha, I was only talking about https://mathaudio.com/room-eq.htm which is the other link you provided. I didn't say anything about foo_dynamicdsp, and it will indeed be very helpful to automate switching.  ;)
BTW, the original foo_dynamicdsp by popatr doesn't seem to be available anymore, but there's a v2 fork by Mario66 that can be found here : https://hydrogenaud.io/index.php?topic=108904.0

So why not use fastest? And SoX can have higher bandwidth than SRC (with 99% it is almost as high as dbpoweramp/SSRC) and at the same time it has less ringing than dbpoweramp/SSRC.
I can use SoX, no problem :) I was just wondering : what's the use of Case's SRC then ? He developed it more recently than SoX, so if it's slower than SoX and with less performance, I don't understand...

About impulses for all sample rates, I can create them in Audacity (and then avoiding all resampling). I just have a question about the number of samples. For "Unitpulse2K.wav", there are 4096 samples and the impulse is of course in the middle (sample #2048). But why 4096 ? And is that number related to the sample rate ? Should I double it if I double the sample rate ? I'm sorry, I'm new to convolver and I haven't found any info on that.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-31 15:58:35
I guess that for simple EQ 4096 samples is enough for any samplerate. If you will multiply quantity of samples, there will be no negative effects for sure. But, probably, no positive effects too.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-31 16:16:39
OK, so in that case I just have to open "Unitpulse2K.wav" in Audacity, change the sample rate, and export as wav32. Seems easy. :)
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-31 16:49:19
so in that case I just have to open "Unitpulse2K.wav" in Audacity, change the sample rate, and export as wav32.
This way you just resample impulse. So don't forget to set Audacity Sample Rate Converter to Best Quality
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-31 17:13:35
Oh, you're right ! That wasn't good at all !!  :o
I had the settings to Best Quality and No Dither, but still the results weren't accurate.
So I have redone all the pulses by hand, from scratch. These should really be accurate, feel free to check. :)
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-31 17:31:05
Looks OK.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-31 18:31:39
Great! So now the final step is that for every sample rate (44.1, 48, 88.2...), I have a set of DSP presets (for 0dB, -5dB, -10dB...), based on the relevant convolver EQ files corresponding to the equal loudness curves.
So e.g. if I have 6 frequencies and 9 volume steps, I will need 54 convolver EQ files. It's a lot, but I can do it.
So if I play a 48 KHz song @ -5 dB, foobar would switch automatically to the corresponding DSP preset (48 KHz and -5 dB), without resampling. The signal would then be output in WASAPI to USB, and the external DAC would take care of it.
I know, it may seem crazy, but it should work.

Now I just have to figure how to use Dynamic DSP and the JScript Panel script together. I still need them both, right ?
The JScript Panel script requires presets to be called "dsp 0", "dsp -5" and so on.
But I need a "dsp 0" for 44.1, plus another "dsp 0" for 48, and so on.
How can I achieve this ?

I know that with Dynamic DSP I can do something like this, but it's not enough :

Code: [Select]
$if2([%trackdsp%],$ifgreater(%sameplerate%,191999,'192 preset',$ifgreater(%sameplerate%,176399,'176 preset',$ifgreater(%sameplerate%,95999,'96 preset',$ifgreater(%sameplerate%,88199,'88 preset',$ifgreater(%sameplerate%,47999,'48 preset',$ifgreater(%sameplerate%,44099,'44 preset','Low preset')))))))
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-08-31 20:01:46
https://youtu.be/F9Ma9veA4jQ

And so on...

By the way, i found that version of Dynamic DSP by Mario66 is not compatible with fb2k 1.6, but original version by popatr is compatible.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-08-31 22:51:30
Amazing. Simpy amazing. Now I finally understand. Huge thanks!!! :D
You, my friend, have rightfully earned the "employee of the month" award for the "most helpful comments" in foobar's forum ! Bravo ! ;)

(https://media.giphy.com/media/tODygE8KCqBzy/source.gif)

BTW, what if a samplerate isn't in the list ? (e.g. some old 22050 Hz file that I just don't want to handle DSP-wise, but that I still want to play). Is there a code to say "if %samplerate% isn't in the list, then just play without any DSP stuff" ?
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-09-01 15:16:22
If samplerate is not in the list, then no DSP will be applied.
Title: Re: Dynamic Loudness Control
Post by: Priest_1 on 2020-09-01 15:52:21
https://youtu.be/F9Ma9veA4jQ

And so on...

By the way, i found that version of Dynamic DSP by Mario66 is not compatible with fb2k 1.6, but original version by popatr is compatible.
original version by popatr - https://hydrogenaud.io/index.php?topic=96094.msg987385#msg987385
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-09-01 22:40:25
Great ! Thanks to both of you :)

Now I'm only missing one thing : either a table with the numeric values of the Fletcher-Munson curves, or at least a hi-res Fletcher-Munson diagram.
I have found a lot of diagrams online, but they are all low-res, very pixelated, with non-parallel axes if we look accurately, and of course no numeric values.
I suppose the original Fletcher-Munson study has some numeric values, but I haven't been able to find it yet.
Is there some serious source for such material ?
Once I can get such material and create all the relevant EQ files, I'll be happy to share them here for future usage. ;)

PS : I have read about the ISO 226-2003 standard, but I'm not convinced at all (there's too much controversy around it), so I'd prefer to stick with good old Fletcher-Munson.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-09-02 18:44:25
At least for ISO curves you can find this (https://chart-studio.plotly.com/~mrlyule/16.embed)
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-09-02 20:36:56
Yes, I've had it already for a few days. It's really nice. Too bad it's only for the ISO curves, they could at least have compared ISO with Fletcher-Munson.
I'm really surprised that we can't find any hi-res info on Fletcher-Munson. There must be a way.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-10-12 01:33:11
For the record, it took me nearly a month but I finally found a way. With the help of some knowledgeable folks at ASR (credits to them) and some clever work, we came up with this (see attached Excel file).

FINALLY, some real accurate numerical data on Fletcher-Munson curves. It's a good start.

Problem solved !  :D
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-10-16 20:14:20
Here's a short addendum about Convolver.

@Rollin , you always suggested that I create basic pulses of for example 4096 samples, with the pulse in the middle (sample #2048).
However, I have been to the Inner Fidelity website, where the guy offers not only PEQ settings but also ready-to-use convolver wavs. I've looked at one of them with Audacity, and the pulse is situated right at the beginning !  :o  So I don't understand : who's right, who's wrong, and why ?

Here's an attached wav file from Inner Fidelity. Thanks.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-10-17 12:49:38
For such simple task as equalization, both kinds of impulses will work OK. For some complex effects (when you need to add some pre-echo, for example), impulses that start right at beginning will not be suitable.
Also, be careful, you don't know how precisely was these impulses created  - https://hydrogenaud.io/index.php?topic=119860.msg988070#msg988070 (i only compared impulses for m50, though. do you need picture for proof?)
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-10-17 13:22:21
Curve from Oratory. Red - iir filter from foo_dsp_effect, orange - ffmpeg parametric eq, yellow - QRange, green - impulse from https://github.com/jaakkopasanen/AutoEq/tree/master/results
(https://i.imgur.com/ECbaS8t.png)
Title: Re: Dynamic Loudness Control
Post by: sacduser on 2020-10-17 14:00:05
I have tried to check the frequency response of my elderly AKG550 using Esser Audio Test Tone Generator and my own ears. The corrective filters I have downloaded seem to be way off for my ears.
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-10-17 15:59:51
Also, be careful, you don't know how precisely was these impulses created
Yes, I remember your post. And don't worry, I won't use their wav files. I intend to create mine, as precisely as possible, following your instructions.  ;)

Curve from Oratory. Red - iir filter from foo_dsp_effect, orange - ffmpeg parametric eq, yellow - QRange, green - impulse from https://github.com/jaakkopasanen/AutoEq/tree/master/results
Wow. I see your curves, but I'm not sure I understand them well. You mean that red = the "theoretic ideal" curve ?
Do you mean that QRange is really bad then ? I'm very surprised !

So I still don't know what would be the best way to go. I was leaning towards foo_convolver, but I was using QRange to generate the impulse responses. So if QRange not good, then I'll have to use another PEQ (or not use foo_convolver at all).

There's another PEQ VST that I could try with Audacity. It's DDMF IIEQPro ( https://ddmf.eu/iieqpro-equalizer-plugin/ ).
I could also try Toneboosters Morphit ( https://www.toneboosters.com/tb_morphit_v1.html ), but it's not a VST but an app.

Would you like me to generate an impulse response with IIEQPro and send it to you, so you could check it against the "theoretic ideal" ? What would you do ?
As always, I will listen to your suggestions.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-10-17 16:53:02
I ddn't mean that red (iir PEQ from foo_dsp_effect) is ideal. It cannot be ideal, because granularity is settings is limited to whole dB, not fractions of dB. Also i didn't mean QRange is bad. I just meant that pre-made impulses from https://github.com/jaakkopasanen/AutoEq/tree/master/results are definitely off-pair with results from parametric EQs.
To me it seems visually that curve from ffmpeg is closest to reference curve that can bee seen in pdf from Oratory, so i would use ffmpeg. Also, there is PEQ in SoX, but i didn't try it yet.
Would you like me to generate an impulse response with IIEQPro and send it to you, so you could check it against the "theoretic ideal" ?
If you will do this for m50(x).
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-10-17 20:17:21
I misread your post !  :o

You wrote this :
Curve from Oratory.
Red - iir filter from foo_dsp_effect,
orange - ffmpeg parametric eq,
yellow - QRange,
green - impulse from https://github.com/jaakkopasanen/AutoEq/tree/master/results

But I understood this :
Curve from Oratory. Red
- iir filter from foo_dsp_effect, orange
- ffmpeg parametric eq, yellow
- QRange, green
- impulse from https://github.com/jaakkopasanen/AutoEq/tree/master/results

I know, it makes no sense, but that's what I understood. In my country, dashes are separators.  :D Now I see what you mean !
So ffmpeg and QRange are quite close and probably hard do distinguish by ear.

Here are 3 impulse responses for you. They are from Oratory's M50x preset (this one : https://www.dropbox.com/s/r7wa83eb53da6fh/Audio%20Technica%20ATH-M50x.pdf?dl=0 ).
All were made with a 4096 samples basic pulse @ sample #2048.

Let's see what your graph says !  ;)
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-10-18 18:01:05
Red - ffmpeg, orange - IIEQ Pro Ana Peaks, yellow -  QRange Good FR Insane (Linear Phase), green - QRange Low Distorsion Minimum Phase. As you can see there are no differences between yellow and green. But actually minimum phase is preferred, because with minimum phase there is no pre-echo and human hearing is more sensitive to pre-echo than post-echo.
(https://i.imgur.com/ZvgpE7I.png)
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-10-18 21:33:59
Thanks ! It's good to see that everything is really close until 7 KHz. Even beyond, they all stay within 1dB of each other. So differences will probably be hard to hear, unless there are phase shifts and other weird stuff.
In that context, I would hesitate between IIEQ Pro (orange) and QRange Minimum Phase (green). Here are the pro/cons :

IIEQ Pro :

QRange :

Maybe QRange (green) is the best choice since at least I can set phase to minimum (I'm just unsure about this setting : "Low Distortion", "Medium Distortion and OK Frequency Response" or "Good Frequency Response").
And maybe IIEQ Pro (orange) is the best choice, since it seems closer to ffmpeg and it prevents treble warping.

PS : in case it matters, both QRange and IIEQ Pro are IIR-based, not FIR.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-10-18 23:43:23
so how could I know what happens with the phase ?
By looking at spectrogram. IIEQ Pro with Ana Peaks has minimum phase.
(https://i.imgur.com/y66GDeZ.png)
Title: Re: Dynamic Loudness Control
Post by: wcs13 on 2020-10-19 06:04:31
Interesting, thank you :) Then IIEQ Pro is indeed the best choice : minimum phase + closest to ffmpeg over 7 KHz. I hope I'm not missing anything.
Title: Re: Dynamic Loudness Control
Post by: Rollin on 2020-10-31 14:17:47
Notice about preamp gain. In some extreme cases, like processing Merzbow's "music" for example, volume should be lowered much more than normally calculated gain. For example, Oratory states pre-amp gain for m50x as -2.9 dB, but when processing Ananga-Ranga from Merzbow's Venerology (https://merzbow.bandcamp.com/album/venereology) gain should be ~ -5.27 dB to avoid clipping (if ReplayGain is not used).
SimplePortal 1.0.0 RC1 © 2008-2020