Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Dynamic Loudness Control (Read 13834 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Dynamic Loudness Control

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.

Re: Dynamic Loudness Control

Reply #1
No.
But it is possible to create script to automatically switch DSP presets depending on current volume level.

Re: Dynamic Loudness Control

Reply #2
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.

Re: Dynamic Loudness Control

Reply #3
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

Re: Dynamic Loudness Control

Reply #4
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.

Re: Dynamic Loudness Control

Reply #5
Достал уже всех со своей тонокомпенсацией ))

Re: Dynamic Loudness Control

Reply #6
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.

Re: Dynamic Loudness Control

Reply #7
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.

Re: Dynamic Loudness Control

Reply #8
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.

Re: Dynamic Loudness Control

Reply #9
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.


Re: Dynamic Loudness Control

Reply #11
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

Re: Dynamic Loudness Control

Reply #12
@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.

Re: Dynamic Loudness Control

Reply #13
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.

 

Re: Dynamic Loudness Control

Reply #14
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?

Re: Dynamic Loudness Control

Reply #15
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.

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.

Re: Dynamic Loudness Control

Reply #16
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.

Re: Dynamic Loudness Control

Reply #17
Demonstration that it works (with JScript Panel). Look at Spectrum and console.
https://youtu.be/Fv-iZcGl850

Re: Dynamic Loudness Control

Reply #18
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...

Re: Dynamic Loudness Control

Reply #19
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

Re: Dynamic Loudness Control

Reply #20
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);
};

Re: Dynamic Loudness Control

Reply #21
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").

Re: Dynamic Loudness Control

Reply #22
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.

Re: Dynamic Loudness Control

Reply #23
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.  ;)

Re: Dynamic Loudness Control

Reply #24
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