Using Double instead of Float increase noise?

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

Nowhk wrote: what if CPU is running two process together and one require denormals and the other not?
Setting the control word is process-specific.
https://en.wikipedia.org/wiki/Process_control_block

Post

Chris-S wrote:
matt42 wrote:Maybe CPU flushing is the best. To manually kill denormals we could do something like

Code: Select all

value += 1e-18;
value -= 1e-18;
Code like this might be optimized away. ;)
Yes, it's possible, but Ive never seen that with VS C++ compiler.

Post

mystran wrote:You want to take the existing state in constructor and store it somewhere and then you restore whatever state existed before the object was constructed. Then if the host already disabled them, or if you nest those objects, or whatever, things will always stay correct.
But what if the host (or another plug-in) changes the state? I would guess you would have to set/restore the state at each process call...

Post

camsr wrote:Setting the control word is process-specific.
Since VST is loaded as DLL, probably the process "itself" is the one created by the DAW, and its unique for other VSTs/DLLs.

Theoretically, if DAW doesn't disable this by default, and I load my plugin that disable denormal numbers, it's possible that those numbers will be disabled also for the other VSTs that I'm running in that moment. What if one of them (for example) require denormal numbers?

Limit case... but it's computer science... nothing should be ignored :borg:

Post

What if one of them (for example) require denormal numbers?
That could get worse, have a look at http://softpixel.com/~cwright/programming/simd/mmx.php, MMX State Management. The conclusion is that every piece of code should be written accordingly, setting its own required state.
~stratum~

Post

Nowhk wrote: Theoretically, if DAW doesn't disable this by default, and I load my plugin that disable denormal numbers, it's possible that those numbers will be disabled also for the other VSTs that I'm running in that moment. What if one of them (for example) require denormal numbers?

Limit case... but it's computer science... nothing should be ignored :borg:
If a plugin requires denormal numbers to work correctly its developer absolutely deserves the flood of angry support tickets that will arise when another plugin or the DAW activates FTZ.

Post

hugoderwolf wrote:If a plugin requires denormal numbers to work correctly its developer absolutely deserves the flood of angry support tickets that will arise when another plugin or the DAW activates FTZ.
Not a whole plugin, maybe just a function in a included library (which can be any kind of stuff, such as graphic library, for example). The discussion here is that my plugin could disable "somethings" required to other plugins, that's all!
stratum wrote:The conclusion is that every piece of code should be written accordingly, setting its own required state.
This means (as Tale stated I think) that at every "process" call I should set the required flag, and later restore it, at the end of the calling.

Is this cheaper than denormal the number at each iteration?

Post

This means (as Tale stated I think) that at every "process" call I should set the required flag, and later restore it, at the end of the calling.

Is this cheaper than denormal the number at each iteration?
If denormals is a problem for a specific processor then definitely yes.

I am not sure what "process call" means in this context, if a compiler unnecessarily was setting flags at every function entry I'd say it's a bad idea, but here we have a plugin (someone elses code), I guess it should be an implicit assumption that we are supposed to deal with "alien code", accordingly.
~stratum~

Post

Nowhk wrote:This means (as Tale stated I think) that at every "process" call I should set the required flag, and later restore it, at the end of the calling.
And that's exactly what the compiler does for you! Whenever the program flows into an entry point of a dll or returns from it, lots of householding instructions like this are carried out.
We are the KVR collective. Resistance is futile. You will be assimilated. Image
My MusicCalc is served over https!!

Post

And that's exactly what the compiler does for you! Whenever the program flows into an entry point of a dll or returns from it, lots of householding instructions like this are carried out.
I'm not sure that would be happening when some function returns an address of a function from a dll and then later some other code calls it. In fact that may be the case for the VST api, I do not recall the details, though. To me it looks like such details belong to the applicaiton binary interface (ABI) for a particular platform and compilers should better generate compliant code.
~stratum~

Post

mystran's trick is for the process() call of he plugin, so there is no talk about the interaction with other plugins or the host. They will see the state of the FPU as it was before.
In ATK (develop branch), I put something that I think does the trick on all major platforms (for an unknown reasons, everything on FTZ online refers to OS X and not C in general...): https://github.com/mbrucher/AudioTK/blo ... ToZero.cpp

Post

Nowhk wrote:
JCJR wrote:Low level noise doesn't just happen when sample numbers are tiny. For instance if you happen to have steady broadband noise at -60 db peak then in silent parts of the track you would have random numbers in the samples ranging from about -0.001 up to about +0.001.

If a loud -6 dB peak sine wave kicks in, that random noise peaking between -0.001 and +0.001 gets added to the peak of the sine wave and it gets added to the mid-values of the sine wave. The noise is super-imposed over the entire waveform.
Yes. But if I have broadband noise at -60db (which is quite imperceptible), once I add to a sine, the difference between the "real" sine wave and the one with noise is noticeable? I don't think so. Maybe for a compressor that will "act" some 0.001 before... or what do you mean?
Hi Nowhk

The noise may or may not be noticeable to the ear in that simple case of -60 dB noise mixed with a fairly loud steady sine wave. If viewed with oscilloscope or in a wave editor window, the clean sine wave would be a skinny distinct sine-shaped line and the noisy sine wave would be a slightly fatter fuzzier sine-shaped line. Psychoacoustics is interesting, sometimes studying what the ear can notice. As usual I don't know much about it. Took some classes on the topic 50 years ago but experts have learned more about it nowadays.

Cassette recordings with no noise reduction maybe had about 50 dB signal-to-noise ratio. Sometimes a little better or worse. IMO Dolby noise reduction only modestly improved the perceived SNR. DBX or other compander noise reductions were somewhat more successful.

To my ear noise was rather easily noticeable on commercial or home-made cassette music recordings, except in some cases DBX encoded tapes. Cassettes typically had at least an extra percent or two of distortion plus other assorted defects. You might listen for the music and not notice the defects so much. On the other hand if you allowed the defects to get your attention-- The defects were quite easy to hear and obsess about. :)

8 bit audio has a theoretical SNR somewhere in the ballpark of 48 dB. Maybe depending on how you measure it. With careful dithering, a person might be able to make a "somewhat clean sounding" 8 bit music file, but it is pretty easy to hear noise in typical 8 bit music files.

The psychoacoustics term masking, used in several contexts-- Basically, if sound A keeps the ear/brain from noticing sound B then sound A is masking sound B.

In music with steady background noise, when the music is loud the noise tends to be masked by the music. Quiet sections of music do not as effectively mask the noise, so in quiet parts of the music, or in silent parts between songs, the noise is much more noticeable.

That's why I mentioned noise gates in an earlier message. It sounded like you wanted to kill noise in quiet parts of the music. Sometimes that works fabulous. It is basically attenuating the quiet parts, but it doesn't do it sample-by-sample. It uses a longer-term envelope to judge whether the music is loud or quiet. If the smoothed music envelope is quieter than your noise threshold, the noise gate attenuates the entire audio in a smooth fashion until the music envelope gets loud again, over-threshold. Then the noise gate smoothly (but quickly) raises gain again to let the music thru at normal volume.

Doing it smoothly would avoid the distortion caused by simply chopping low-level samples and also it would actually work to reduce noise at overall quiet levels.

On mixes a gate can be difficult to adjust so that it doesn't annoy the ear, except for basic gating in-between songs and such. But for instance if you have a vocal track where the singer is good and loud while he is singing, but his headphones are leaking into the mic rather loud in-between phrases when he is not singing. Such situations sometimes could be easier to adjust a gate to keep the headphone leakage out of the vocal track. In other words, the headphone leakage would be in there when the singer is singing, but in that case he is so much louder than the headphone leakage that it isn't noticeable. The loud vocal masks the leakage. But in-between vocal phrases the gate can remove the leakage.

You could add gate-like strategies to your reverb loops if you want to mute noise way into the tail of the reverb.

Post

Miles1981 wrote:mystran's trick is for the process() call of he plugin, so there is no talk about the interaction with other plugins or the host. They will see the state of the FPU as it was before.
Can you be sure of this?

Let say I've my ProcessDoubleReplacing on an instance of my plug A, which iterate over 256 samples it got from the DAW. I set this flag at the beginning of the function, and I restore it at end.

What if in the middle of the iteration of the samples, the control pass to another thread (which is on the same cpu core) and start to process the ProcessDoubleReplacing of another plug B? Plug B will execute with the flag setted by plug A. I'm in the same "Process" within the DAW (so control word are shared across plugins), since VSTs are DLL (but honestly this depends by the host DAW; some will use the same process task, some could fork it on every DLL, and so on).

I just guess :D

Post

What if in the middle of the iteration of the samples, the control pass to another thread (which is on the same cpu core) and start to process the ProcessDoubleReplacing of another plug B? Plug B will execute with the flag setted by plug A. I'm in the same "Process" within the DAW (so control word are shared across plugins), since VSTs are DLL (but honestly this depends by the host DAW; some will use the same process task, some could fork it on every DLL, and so on).
The OS handles this - without which multithreading wouldn't be possible. There is a large set of registers (and some other state) that needs to be stored and restored during thread context switches (it is called a context switch for a reason..)

For windows running on an intel processor, the context is apparently this : http://www.nirsoft.net/kernel_struct/vista/CONTEXT.html It is the job of OS to store this somewhere before assinging the cpu to some other thread and restore that other thread's context just before it starts executing.
~stratum~

Post

Nowhk wrote: What if in the middle of the iteration of the samples, the control pass to another thread (which is on the same cpu core) and start to process the ProcessDoubleReplacing of another plug B?
When the OS switches between threads, it saves all the registers of one thread and restores the registers of another thread. The SSE control word is just a register and it gets saved and restored as part of a thread switch just like any other register. The registers are part of thread (not process) and there is absolutely nothing "special" about this register compared to any other registers as far as thread-switching is concerned, it's just another register. If the thread gets moved to another core, then the registers (including the control word) move with the thread, so you really don't need to worry about it.

The only way you can influence the behaviour of other code is when you set the control word and then call (or return) into other code in the same thread without restoring it first.

edit: This is also why you MUST do the whole set/restore dance in your process-method (rather than some other place like initialisation), because there is no guarantee that the host will always call your process-method with a specific thread... but as long as a thread (any thread) is executing your code, you can do whatever you want with any of the registers (including the SSE control word) as long as you return things back to normal by the time your code is done.

Post Reply

Return to “DSP and Plugin Development”