Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WaveShaper node in WebAudio - how to emulate distortion?

working with WebAudio API and trying to get distortion going! Issue is, I'm not sure how to get into the "curve" param of WaveShaper.

Simply put, 'oscidis' is a WaveShaper node created earlier in the program. Oscidisv is a value I have set to 0 statically, for now.:

const wsCurve = new Float32Array();

if (oscidisv >= -1 && oscidisv < 1) {
  const k = (2 * oscidisv) / (1 - oscidisv);
  for (let i = 0; i < 16; i += 1) {
    // LINEAR INTERPOLATION:
    // x = (c - a) * (z - y) / (b - a) + y
    // given
    // a = 0, b = 2048, z = 1, y = -1, c = i
    const x = ((i - 0) * (1 - -1)) / (16 - 0) + -1;
    wsCurve[i] = ((1 + k) * x) / (1 + k * Math.abs(x));
  }
}

oscidis.curve.value = wsCurve;

The issue - I'm not hearing any difference in sound regardless of what I put here )-=. I don't notice any real distortion even with the distortion at max (1). Do you guys know anything about a more noticeable distortion waveshaping function? Or if I'm doing this right at all in the WebAudio API?

like image 331
PinkElephantsOnParade Avatar asked Mar 10 '14 22:03

PinkElephantsOnParade


2 Answers

Here's one I've used that's based on a few different functions I've found in white papers and things like that:

const DEG = Math.PI / 180;

function makeDistortionCurve(k = 50) {
  const n_samples = 44100;
  const curve = new Float32Array(n_samples);
  curve.forEach((_, i) => {
    const x = (i * 2) / n_samples - 1;
    curve[i] = ((3 + k) * x * 20 * DEG) / (Math.PI + k * Math.abs(x));
  });
  return curve;
}

I'd be lying if I told you I knew where the 3 + k or 20 come from — but it works.

The value of amount can basically be any positive number, but I've found that 0 - 100 is a pretty good range depending on how much distortion you need.

If you have any interest in seeing what these functions look like, I built a little tool to help me visualize them here: http://kevincennis.github.io/transfergraph/

like image 158
Kevin Ennis Avatar answered Nov 14 '22 07:11

Kevin Ennis


I took some of the suggestions above and re-factored the function. I also cut down the number of samples in the typed array from 44K to 256, it makes the browser happier :-()

let distortionFilter = audioCtx.createWaveShaper();
distortionFilter.curve = makeDistortionCurve();

function makeDistortionCurve(amount=20) {
    let n_samples = 256, curve = new Float32Array(n_samples);
    for (let i = 0 ; i < n_samples; ++i ) {
        let x = i * 2 / n_samples - 1;
        curve[i] = (Math.PI + amount) * x / (Math.PI + amount * Math.abs(x));
    }
    return curve;
} 
like image 36
tonethar Avatar answered Nov 14 '22 08:11

tonethar