How would YOU refactor this code with ES6/best practices


#1

I’m just curious about how others might write this piece of code with ES6. You can test your code for this at http://mmckegg.github.io/web-audio-school/ (click on 16. Better Overdrive).

var audioContext = new AudioContext();
var startTime = audioContext.currentTime + 0.2;

var shaper = audioContext.createWaveShaper();
shaper.curve = generateCurve(22050); // half of 44100 (sample rate)

var bandpass = audioContext.createBiquadFilter();
bandpass.type = 'bandpass';
bandpass.frequency.value = 1000;
bandpass.connect(shaper);

function generateCurve (steps) {
  var curve = new Float32Array(steps);
  var deg = Math.PI / 180;

  for (var i = 0;i < steps;i++) {
    var x = i * 2 / steps - 1;
    curve[i] = (3 + 10) * x * 20 * deg / (Math.PI + 10 * Math.abs(x));
  }

  return curve;
}

var amp = audioContext.createGain();
amp.gain.value = 20;
amp.connect(bandpass);
shaper.connect(audioContext.destination);

getSample('guitar.wav', function play (buffer) {
  var player = audioContext.createBufferSource();
  player.buffer = buffer;
  player.connect(amp);
  player.start(startTime);
})

function getSample (url, cb) {
  var request = new XMLHttpRequest();
  request.open('GET', url);
  request.responseType = 'arraybuffer';
  request.onload = function () {
    audioContext.decodeAudioData(request.response, cb);
  }
  request.send();
}

#2

There’s not much to do. It looks like all of the var keywords can be safely changed to const and all function expressions can be rewritten as arrow functions.


#3

Everything @PortableStick said, plus maybe changing the generateCurve function to:

function generateCurve (steps) {
  const deg = Math.PI / 180;
  return new Float32Array(steps).map((val,idx) => {
    const x = idx * 2 / steps - 1;
    return (3 + 10) * x * 20 * deg / (Math.PI + 10 * Math.abs(x));
  });
}

#4

I’ve made a Sample class for the client code of the GainNode - I use fetch and promises instead of xhr - the typed array in generateCurve is filled in a map callback of Float32Array.from - I’ve used arrow functions - I’ve replaced var with let and const quite arbitrarily

class Sample {
  constructor(node) {
    this.node=node
  }

  play(url, start) {
    let rq = new Request(url)
    fetch(rq)
    .then(rsp => rsp.arrayBuffer())
    .then(buf => {
      this.node.context.decodeAudioData(buf, decoded => {
        let player = this.node.context.createBufferSource()
        player.buffer = decoded
        player.connect(this.node)
        player.start(start)
      })
    })
  }
}
function generateCurve(steps) {
  const deg = Math.PI / 180
  return Float32Array.from({length: steps}, (a, i) => {
    const x = i * 2 / steps - 1
    return (3 + 10) * x * 20 * deg / (Math.PI + 10 * Math.abs(x))
  })
}
let audioContext = new AudioContext()
const startTime = audioContext.currentTime + 0.2

let shaper = audioContext.createWaveShaper()
shaper.curve = generateCurve(22050) // half of 44100 (sample rate)

let bandpass = audioContext.createBiquadFilter()
bandpass.type = "bandpass"
bandpass.frequency.value = 1000
bandpass.connect(shaper)

let amp = audioContext.createGain()
amp.gain.value = 20
amp.connect(bandpass)
shaper.connect(audioContext.destination)
const wav="guitar.wav"
let sample=new Sample(amp)
sample.play(wav, startTime)

#5

Good stuff!

Just one minor thing. Instead of

shaper.curve = generateCurve(22050) // half of 44100 (sample rate)

say

const DEFAULT_SAMPLE_RATE = 44100; 

and

shaper.curve = generateCurve(DEFAULT_SAMPLE_RATE/2.0);

or

shaper.curve = generateCurve(DEFAULT_SAMPLE_RATE*0.5);

We all agree? Excellent. Thank you.