Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Output 32-bit float samples to preserve dynamic range and prevent clipping #59

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

Falcosoft
Copy link
Contributor

Added '-af' option to output 32-bit float samples in order to preserve dynamic range and prevent clipping at the same time.

…pping

Added '-af' option to output 32-bit float samples in order to preserve dynamic range and prevent clipping at the same time.
src/mcu.cpp Outdated
else if (sample_buffer_float)
{
const float divRec = 1 / 32768.0f;
sample[0] >>= 14;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no need for bit shift if you divide for 2147483648.0 instead, and you could also keep more precision

Copy link
Contributor Author

@Falcosoft Falcosoft Apr 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, thanks for the explanation!

Copy link
Contributor Author

@Falcosoft Falcosoft Apr 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

@Falcosoft Falcosoft Apr 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@jcmoyer jcmoyer mentioned this pull request May 2, 2024
jcmoyer added a commit to jcmoyer/Nuked-SC55 that referenced this pull request May 9, 2024
Sample conversion implementation by @Falcosoft

Upstream PR: nukeykt#59
jcmoyer added a commit to jcmoyer/Nuked-SC55 that referenced this pull request May 13, 2024
Sample conversion implementation by @Falcosoft

Upstream PR: nukeykt#59
jcmoyer added a commit to jcmoyer/Nuked-SC55 that referenced this pull request May 24, 2024
Sample conversion implementation by @Falcosoft

Upstream PR: nukeykt#59
jcmoyer added a commit to jcmoyer/Nuked-SC55 that referenced this pull request May 25, 2024
Sample conversion implementation by @Falcosoft

Upstream PR: nukeykt#59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants