Source: operator/Intensity.js

import * as lfo from 'waves-lfo/common';

const BaseLfo = lfo.core.BaseLfo;
const Delta = lfo.operator.Delta;

const definitions = {
  feedback: {
    type: 'float',
    default: 0.7,
    min: 0,
    max: 1,
  },
  gain: {
    type: 'float',
    default: 0.07,
    min: 0,
  },
};

const inverseGravity = 1 / 9.81;
const abs = Math.abs;
const min = Math.min;
const max = Math.max;
const pow = Math.pow;

/**
 * Compute the intensity of the accelerometers.
 *
 * input: an array of numbers of size 1 to 3 (`[x]`, `[x, y]` or `[x, y, z]`).
 * output: `[normIntensity, xIntensity, yIntensity, zIntensity]`
 *
 * @memberof operator
 *
 * @param {Object} [options] - Override default options.
 * @param {Number} [options.feedback=0.7] - Feedback coefficient.
 * @param {Number} [options.gain=0.07] - Post gain coefficient.
 */
class Intensity extends BaseLfo {
  constructor(options = {}) {
    super(definitions, options);

    this.memory = null;
    this.normAcc = null;
    this.delta = new Delta({ size: 3, useFrameRate: 1 });
  }

  /** @private */
  processStreamParams(prevStreamParams = {}) {
    this.prepareStreamParams(prevStreamParams);

    this.streamParams.frameSize = 4;
    this.streamParams.description = [
      'norm',
      'x',
      'y',
      'z',
    ];

    this.delta.processStreamParams({
      frameSize: 3,
      frameRate: this.streamParams.frameRate,
    });

    this.memory = new Float32Array(3);
    this.normAcc = new Float32Array(3);

    this.propagateStreamParams();
  }

  resetStream() {
    super.resetStream();

    this.delta.resetStream();

    for (let i = 0; i < 3; i++)
      this.memory[i] = 0;
  }

  inputVector(data) {
    const outData = this.frame.data;
    const buffer = this.buffer;
    const memory = this.memory;
    const normAcc = this.normAcc;
    const feedback = this.params.get('feedback');
    const gain = this.params.get('gain');
    let norm = 0;

    // normalize accelerometers
    for (let i = 0; i < this.streamParams.frameSize; i++)
      normAcc[i] = (data[i] || 0) * inverseGravity;

    const deltas = this.delta.inputVector(normAcc);

    for (let i = 0; i < 3; i++) {
      let value = abs(deltas[i]);
      value = value + feedback * memory[i];

      // store value for next pass
      memory[i] = value;

      value = value * gain;
      value = value * value;

      norm += value;
      outData[i + 1] = value;
    }

    outData[0] = norm;

    return outData;
  }

  processVector(frame) {
    this.frame.data = this.inputVector(frame.data);
  }
}

export default Intensity;