Source: common/operator/Magnitude.js

import BaseLfo from '../../core/BaseLfo';

const sqrt = Math.sqrt;

const definitions = {
  normalize: {
    type: 'boolean',
    default: true,
    metas: { kind: 'dynamic' },
  },
  power: {
    type: 'boolean',
    default: false,
    metas: { kind: 'dynamic' },
  }
}

/**
 * Compute the magnitude of a `vector` input.
 *
 * _support `standalone` usage_
 *
 * @param {Object} options - Override default parameters.
 * @param {Boolean} [options.normalize=true] - Normalize output according to
 *  the vector size.
 * @param {Boolean} [options.power=false] - If true, returns the squared
 *  magnitude (power).
 *
 * @memberof module:common.operator
 *
 * @example
 * import * as lfo from 'waves-lfo/common';
 *
 * const eventIn = new lfo.source.EventIn({ frameSize: 2, frameType: 'vector' });
 * const magnitude = new lfo.operator.Magnitude();
 * const logger = new lfo.sink.Logger({ outFrame: true });
 *
 * eventIn.connect(magnitude);
 * magnitude.connect(logger);
 * eventIn.start();
 *
 * eventIn.process(null, [1, 1]);
 * > [1]
 * eventIn.process(null, [2, 2]);
 * > [2.82842712475]
 * eventIn.process(null, [3, 3]);
 * > [4.24264068712]
 */
class Magnitude extends BaseLfo {
  constructor(options = {}) {
    super(definitions, options);

    this._normalize = this.params.get('normalize');
    this._power = this.params.get('power');
  }

  /** @private */
  onParamUpdate(name, value, metas) {
    super.onParamUpdate(name, value, metas);

    switch (name) {
      case 'normalize':
        this._normalize = value;
        break;
      case 'power':
        this._power = value;
        break;
    }
  }

  /** @private */
  processStreamParams(prevStreamParams) {
    this.prepareStreamParams(prevStreamParams);
    this.streamParams.frameSize = 1;
    this.streamParams.frameType = 'scalar';
    this.streamParams.description = ['magnitude'];
    this.propagateStreamParams();
  }

  /**
   * Use the `Magnitude` operator in `standalone` mode (i.e. outside of a graph).
   *
   * @param {Array|Float32Array} values - Values to process.
   * @return {Number} - Magnitude value.
   *
   * @example
   * import * as lfo from 'waves-lfo/client';
   *
   * const magnitude = new lfo.operator.Magnitude({ power: true });
   * magnitude.initStream({ frameType: 'vector', frameSize: 3 });
   * magnitude.inputVector([3, 3]);
   * > 4.24264068712
   */
  inputVector(values) {
    const length = values.length;
    let sum = 0;

    for (let i = 0; i < length; i++)
      sum += (values[i] * values[i]);

    let mag = sum;

    if (this._normalize)
      mag /= length;

    if (!this._power)
      mag = sqrt(mag);

    return mag;
  }

  /** @private */
  processVector(frame) {
    this.frame.data[0] = this.inputVector(frame.data);
  }
}

export default Magnitude;