Output 32-bit float samples to preserve dynamic range and prevent clipping#59
Output 32-bit float samples to preserve dynamic range and prevent clipping#59Falcosoft wants to merge 4 commits intonukeykt:masterfrom
Conversation
…pping Added '-af' option to output 32-bit float samples in order to preserve dynamic range and prevent clipping at the same time.
| else if (sample_buffer_float) | ||
| { | ||
| const float divRec = 1 / 32768.0f; | ||
| sample[0] >>= 14; |
There was a problem hiding this comment.
There should be no need for bit shift if you divide for 2147483648.0 instead, and you could also keep more precision
There was a problem hiding this comment.
HI,
If you inspect sample[0] and sample[1] at that place you will notice that if you right shift with 13 you will get samples that has a granularity of 2 if you right shift with 12 you will get a granularity of 4 and so on. So currently with right shift 14 you get the maximum resolution. So you will not get more resolution with fewer right shifts.
Moreover the float resolution is not infinite. By dividing with 2^31 you will get less precise results than with exact right shifts and then dividing with 2^15 since 1 / 2^15 and its multiplicands can be exactly represented in 32-bit float.
There was a problem hiding this comment.
makes sense, thanks for the explanation!
There was a problem hiding this comment.
Hi,
Actually you were right in the sense that the 2 shifts can be skipped and the result is the same. So no more precision, but somewhat better performance. You do not have to divide by 2147483648.0 but only 536870912.0.
So overall this produces the same numbers as the current code:
const float divRec = 1 / 536870912.0f;
sample_buffer[sample_write_ptr + 0] = sample[0] * divRec;
sample_buffer[sample_write_ptr + 1] = sample[1] * divRec;
sample_write_ptr = (sample_write_ptr + 2) % audio_buffer_size;
| } | ||
|
|
||
| if (audioFormat == AudioFormat::FLOAT32 && !isBufferSet) | ||
| { |
There was a problem hiding this comment.
Maybe this flag would be not needed if you move the pageSize,pageNum set to inside the else if (!strcmp(argv[i], "-af")) if case?
There was a problem hiding this comment.
In that case the argument order would be mandatory otherwise at
(!strcmp(argv[i], "-af")) you cannot know if -ab is set before, not set at all or only will be set after -af.
The if (audioFormat == AudioFormat::FLOAT32 && !isBufferSet) check is added to make sure that only change the dafault if -ab is not set manually.
But correct me if I'm wrong, maybe I overlook something.
It significantly improves the consistency of audio output (less pauses, crackles) when the emulator is used together with other programs. Tested with Win10 x64, Win7 x64, WinXP x86.
Sample conversion implementation by @Falcosoft Upstream PR: nukeykt#59
Sample conversion implementation by @Falcosoft Upstream PR: nukeykt#59
Sample conversion implementation by @Falcosoft Upstream PR: nukeykt#59
Sample conversion implementation by @Falcosoft Upstream PR: nukeykt#59
Added '-af' option to output 32-bit float samples in order to preserve dynamic range and prevent clipping at the same time.