Kilohearts Plug-ins (My Misunderstanding)

VST, AU, AAX, CLAP, etc. Plugin Virtual Instruments Discussion
Post Reply New Topic
RELATED
PRODUCTS

Post

In case anybody wants to do some experiments, here's some code:

Code: Select all

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
	// Set precision to std::cout's output
	std::cout << std::setprecision (8);
	
	float minus6dbFS = -6.0205999f;
	float a = powf(10.f, minus6dbFS / 20.f);
	std::cout << minus6dbFS << " dbFS is represented as a factor of " << a << std::endl;
	
	float plus6dbFS = 6.0205999f;
	float b = powf(10.f,  plus6dbFS / 20.f);
	std::cout << plus6dbFS << " dbFS is represented as a factor of " << b << std::endl;
	
	float assumedUnity = a * b;
	std::cout << "Multiplying both yields " << assumedUnity << std::endl;
	
	float assumedUnityAsDbFS = 20.f * log10(assumedUnity);
	std::cout << "This is " << assumedUnityAsDbFS << " dbFS shy of the expected 1.0f" << std::endl;
}
The output is:

Code: Select all

-6.0205998 dbFS is represented as a factor of 0.5
6.0205998 dbFS is represented as a factor of 1.9999999
Multiplying both yields 0.99999994
This is -5.177194e-07 dbFS shy of the expected 1.0f
This pretty much shows what others have mentioned in this thread. Even if you enter numbers that look the same just with different signs the conversion to the amplification factors will not yield what you'd expect.
Passed 303 posts. Next stop: 808.

Post

BlitBit wrote: Fri Jul 19, 2024 9:18 pm In case anybody wants to do some experiments, here's some code:

Code: Select all

#include <iostream>
#include <iomanip>
#include <cmath>

int main()
{
	// Set precision to std::cout's output
	std::cout << std::setprecision (8);
	
	float minus6dbFS = -6.0205999f;
	float a = powf(10.f, minus6dbFS / 20.f);
	std::cout << minus6dbFS << " dbFS is represented as a factor of " << a << std::endl;
	
	float plus6dbFS = 6.0205999f;
	float b = powf(10.f,  plus6dbFS / 20.f);
	std::cout << plus6dbFS << " dbFS is represented as a factor of " << b << std::endl;
	
	float assumedUnity = a * b;
	std::cout << "Multiplying both yields " << assumedUnity << std::endl;
	
	float assumedUnityAsDbFS = 20.f * log10(assumedUnity);
	std::cout << "This is " << assumedUnityAsDbFS << " dbFS shy of the expected 1.0f" << std::endl;
}
The output is:

Code: Select all

-6.0205998 dbFS is represented as a factor of 0.5
6.0205998 dbFS is represented as a factor of 1.9999999
Multiplying both yields 0.99999994
This is -5.177194e-07 dbFS shy of the expected 1.0f
This pretty much shows what others have mentioned in this thread. Even if you enter numbers that look the same just with different signs the conversion to the amplification factors will not yield what you'd expect.
Thank you for this.

Post

So at this point my conclusion is as follows:

• All plug-in developers should be transparent about the precision at which their plug-ins work internally and the input/output precision of said plug-ins.
• It would be great if plug-in developers gave us the option to choose the plug-in's input/output precision (and possibly even its internal precision) according to our session's precision - just like how you can change Nuendo/Cubase/REAPER's precision.

The goal, or should I say *my* goal at this moment is, to have only one precision (whether it's 32-Bit FP or 64-Bit FP) throughout the whole session for all the plug-ins involved in the session. From start to finish.

So if all the plug-ins that I'm planning to use in a session have 32-Bit FP precision, I'll switch the DAW's precision to 32-Bit FP, and vice versa, and not mix and match 32-Bit FP and 64-Bit FP plug-ins.

I think converting between the two precision nonchalantly hundreds of times throughout a session is detrimental.

Post

I think I did a JSFX to apply thousands of gains to a signal somewhere when discussing why airwindows bitshiftgain and such is audiophile-level stuff, and which BTW doesn't need bitshifts because floating point multiplication (gain) by any power of two (or inverse) leaves the mantissa untouched. Let me dig and see if my memory doesn't fail because JSFX uses double only.

Post

Found it. First post: viewtopic.php?p=8678417#top

Post

limitlesssss wrote: Fri Jul 19, 2024 10:02 pm I think converting between the two precision nonchalantly hundreds of times throughout a session is detrimental.
You think that, now you have to prove it. Aka do A/B tests.

If you are wrong you are imposing yourself artificial restrictions that will hinder your workload and somehow hurt your creativity. You will be spending time searching for bit-depths of plugins when you should be having fun.

Take this hint, plugin developers normally have expertise (there are shills too) and do a balancing act between samplerates, bit depths, sound quality and cpu usage.

Another hint. Are you going to apply thousands of linear processes to a single track in any realistic situation?

Another hint. Any audiophile-level headphones or speakers are going to cause signal distortions many orders of magnitude bigger than 32vs64 bit float.

Post

The only way that comes to my mind that I can prove/disprove that, is using two different linear processes like gain, one of which is at 32-Bit FP precision internally and also its input/output stages, and the other is at 64-Bit FP.

I used BitShiftGain at 1-Bit boost, followed by Kilohearts Gain at exactly −6.0206dB cut, and they nulled to negative infinity, no matter what precision I used in REAPER.

The opposite did not happen, meaning 1-Bit cut using BitShiftGain, followed by exactly 6.0206dB boost using Kilohearts Gain. Which proves rounding errors happen.

I would very much like to test this in Cubase/Nuendo but I wasn't able to install their demo.

Post

BitShiftGain and co. are snake-oil. Audiophile stuff for "pros". Very harmful for the audio community.

It's not about if they null or not, it's about if one can create a test case where doing a blind test using his ears notices something reliably.

No one is saying that there is no effect happening, the point is that it's so many orders of magnitude under human perception (and speaker/headphone capabilities) that it can be safely discarded.

What does happen in the most high-end analog console if one applies a 6dB gain followed by a 6dB cut? I'm sure it would measure much worse when trying to null, this assuming one has equipment that precise able to measure reliably into the -150dBFs range, yet they are still perfectly "pro" and fit for purpose, history proves it.

Me personally I prefer my plugins to be 32-bit float if a good DSP engineer decided that. Especially if they touch a lot of memory, as the achiles-heel of computers today when number crunching is memory/cache access. Still splitting hairs and probably neglibible both on CPU and audio quality if e.g. we are talking about an EQ/gain plugin.

What I want you to realize is that you are "nerding" about technology, probably without the required training/knowledge, and that you are fighting against a nonproblem. I don't know if I suceeded. I concede that you might learn something in the process and that sometimes one needs to walk that path on its own. At least you have the correct information available.
Last edited by rafa1981 on Sat Jul 20, 2024 11:12 am, edited 1 time in total.

Post

limitlesssss wrote: Sat Jul 20, 2024 7:02 am The only way that comes to my mind that I can prove/disprove that, is using two different linear processes like gain, one of which is at 32-Bit FP precision internally and also its input/output stages, and the other is at 64-Bit FP.

I used BitShiftGain at 1-Bit boost, followed by Kilohearts Gain at exactly −6.0206dB cut, and they nulled to negative infinity, no matter what precision I used in REAPER.

The opposite did not happen, meaning 1-Bit cut using BitShiftGain, followed by exactly 6.0206dB boost using Kilohearts Gain. Which proves rounding errors happen.

I would very much like to test this in Cubase/Nuendo but I wasn't able to install their demo.
I think everybody has its own focus and point of attention but I have a tendency to agree with what was said that paying attention to this very very tiny detail that will very very probably never impact you practicly in real life may hinder your creativity (except that I am not sure than restriction can't in fact sometime boost creativity).

We have all our own "OCD"-ness. But I must agree on that fact that while I was secretly thinking that I was one of the neirdier/geekier in this forum, you totally humbled me :-).

Post

limitlesssss wrote: Sat Jul 20, 2024 7:02 am The only way that comes to my mind that I can prove/disprove that, is using two different linear processes like gain, one of which is at 32-Bit FP precision internally and also its input/output stages, and the other is at 64-Bit FP.
This may be the heart of the issue. If you cannot "prove" that audio is being negatively effected by a plugin simply via hearing this negative impact, the issue isn't worth worrying about.

Post

To be fair though... is there any proof that BitShiftGain, or using double instead of float internally, makes any performance difference or consumes a meaningful anount of memory, either? We're talking about small buffers here.

I expect both the positive and negative impacts are far too small to notice in practice.

Post

limitlesssss wrote: Sat Jul 20, 2024 7:02 am The only way that comes to my mind that I can prove/disprove that, is using two different linear processes like gain, one of which is at 32-Bit FP precision internally and also its input/output stages, and the other is at 64-Bit FP.
I think this can be done with Reaktor.

Post

foosnark wrote: Sat Jul 20, 2024 11:14 am To be fair though... is there any proof that BitShiftGain, or using double instead of float internally, makes any performance difference or consumes a meaningful anount of memory, either?
Using doubles instead of floats requires twice as much memory for all the variables included in all the calculations of the plugin. That's about it.

To the OP: it is not trivial to make every plugin support both 32-bit and 64-bit FP processing. Because this is, on plugin SDK level, done in two completely separate process calls: processReplacing() and processDoubleReplacing(). This is the extra work that FabFilter post was talking about. It is not an insignificant change to the plugin development pipeline.

From my perspective, if your daily driver is REAPER, just set the summing precision to 32-bit FP and this should work perfectly fine for your original test case.

Post

EvilDragon wrote: Sat Jul 20, 2024 12:11 pm
foosnark wrote: Sat Jul 20, 2024 11:14 am To be fair though... is there any proof that BitShiftGain, or using double instead of float internally, makes any performance difference or consumes a meaningful anount of memory, either?
Using doubles instead of floats requires twice as much memory for all the variables included in all the calculations of the plugin. That's about it.

To the OP: it is not trivial to make every plugin support both 32-bit and 64-bit FP processing. Because this is, on plugin SDK level, done in two completely separate process calls: processReplacing() and processDoubleReplacing(). This is the extra work that FabFilter post was talking about. It is not an insignificant change to the plugin development pipeline.

From my perspective, if your daily driver is REAPER, just set the summing precision to 32-bit FP and this should work perfectly fine for your original test case.
Yeah, your last remark is my conclusion as well. To have everything in either 32-Bit FP only, or 64-Bit FP only, and not mix and match the two precisions.

Post

foosnark wrote: Sat Jul 20, 2024 11:14 am To be fair though... is there any proof that BitShiftGain, or using double instead of float internally, makes any performance difference or consumes a meaningful anount of memory, either? We're talking about small buffers here.

I expect both the positive and negative impacts are far too small to notice in practice.
Bitshitgain is doing some additional algorithm to multiply by integer powers of two that could be implemented by just multiplying the float directly, as multiplying any floating point value by a power of two is already lossless without any additional ceremony.

So bitshiftgain can be implemented as "float × 2power and that's it.

Also in the thread he proposed e.g. that in order to get a gain of 3 to multiply by two with bitshiftgain and then sum the original signal, but summing itself is not lossless so it completely defeats the purpose of all that purity "dance".
Last edited by rafa1981 on Sun Jul 21, 2024 9:40 am, edited 5 times in total.

Post Reply

Return to “Instruments”