Skip to content

Conversation

@anabolyc
Copy link
Contributor

@anabolyc anabolyc commented Jan 5, 2026

Fixes #136

Issue description:

When DSP settings are enabled with high gain values together with a large volume level, audio starts to fill up with cracking sounds.

This seems to be related to integer overflow when applying gain.

Proposed solution:

Simple integer clamping (to prevent overflow) will replace cracks with clipping, which is always a better choice in terms of resulting sound

@CarlosDerSeher
Copy link
Owner

Are there any alternatives? Scale input if overflow is detected? Not such an easy task I guess especially if volume is adjusted this would mean scale factor needs to be reset too. Some form of AGC? Probably overkill.

Maybe we could print a warning when clipping happens? We shouldn't spam the log with warnings though. If this happens frequently. Any ideas?

@anabolyc
Copy link
Contributor Author

anabolyc commented Jan 5, 2026

Are there any alternatives? Scale input if overflow is detected? Not such an easy task I guess especially if volume is adjusted this would mean scale factor needs to be reset too. Some form of AGC? Probably overkill.

Maybe we could print a warning when clipping happens? We shouldn't spam the log with warnings though. If this happens frequently. Any ideas?

Exactly, AGL is an alternative. The simpler one is soft-slipping, perhaps. When volume/gain conditions are met, it happens constantly, almost, really annoying.

I'd start with simple clipping and go from there. To be honest, I'd be careful on required CPU budget here. DSP-enabled DACs have deicated micro-cores for this job, ESP32 can only do this on the main cores, obviously :)

@CarlosDerSeher
Copy link
Owner

CarlosDerSeher commented Jan 5, 2026

I see. So I think we should make the user at least aware this is happening by printing a warning at least once per synced playback. Maybe reset this on hard resyncs? Not sure how much effort this would take implementation wise though. Just printing a warning every time would spam log I guess? Maybe just print every 100th?

@anabolyc
Copy link
Contributor Author

anabolyc commented Jan 6, 2026

I'll try this one, want to hear it out, compated to hard-clipping:
image

Tranfer function:
image

@luar123
Copy link
Contributor

luar123 commented Jan 6, 2026

I think you should adjust the hard clip values to 2/3 instead of 1.

@CarlosDerSeher
Copy link
Owner

@CarlosDerSeher
Copy link
Owner

But this can never reach max volume then?

@anabolyc
Copy link
Contributor Author

anabolyc commented Jan 6, 2026

But this can never reach max volume then?

I think it is fairly easy to normalize to [-1, 1] range.

/**
 * Clamp float to range [-1.0, 1.0] and convert to int16_t
 * Prevents overflow/clipping artifacts when gain is high
 */
static inline int16_t float_to_int16_clamped(float value) {
#ifdef CONFIG_USE_DSP_SOFT_CLIP
  // Cubic soft clipping: y = x - x^3/3 for |x| < 1, y = 2/3 for |x| >= 1
  // The output range is [-2/3, 2/3], so we normalize by 3/2 to get [-1, 1]
  float clipped;
  if (value > 1.0f) {
    clipped = 2.0f / 3.0f;
  } else if (value < -1.0f) {
    clipped = -2.0f / 3.0f;
  } else {
    // Apply cubic soft clip: y = x - x^3/3
    float x3 = value * value * value;
    clipped = value - (x3 / 3.0f);
  }
  // Normalize from [-2/3, 2/3] to [-1, 1]
  value = clipped * 1.5f;
#else
  // Hard clamp to ±1.0 range
  if (value > 1.0f) value = 1.0f;
  if (value < -1.0f) value = -1.0f;
#endif
  
  return (int16_t)(value * INT16_MAX);
}

@anabolyc
Copy link
Contributor Author

anabolyc commented Jan 6, 2026

Commited to the branch, if you curious to try it out. I'm testing on Bass boost, and it really sounds less distorted.
image

@CarlosDerSeher
Copy link
Owner

In comparison to hard clipping?

@anabolyc
Copy link
Contributor Author

anabolyc commented Jan 6, 2026

In comparison to hard clipping?

correct. Although both options are far better than cracking :)

@CarlosDerSeher
Copy link
Owner

I like it, but I'll try this myself before accepting.

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.

3 participants