Source: components/FrequencyBars.js

import VisuComponentMono from '../utils/VisuComponentMono.js';
import CanvasUtils from '../utils/CanvasUtils.js';
import ColorUtils from '../utils/ColorUtils.js';


class FrequencyBars extends VisuComponentMono {


  /** @summary FrequencyBars displays the audio spectrum as frequency bars in real time.
   * @author Arthur Beaulieu
   * @since 2020
   * @augments VisuComponentMono
   * @description <blockquote>This will display a single canvas with frequency from left to right be bass to high. The bar
   * height depends on audio bin intensity. The audio graph is then draw with a gradient from bottom to top that is from
   * green to red. Those color can be custom ones (see constructor options).</blockquote>
   * @param {object} options - The frequency bars options
   * @param {string} options.type - The component type as string
   * @param {object} options.player - The player to take as processing input (if inputNode is given, player source will be ignored)
   * @param {object} options.renderTo - The DOM element to render canvas in
   * @param {number} options.fftSize - The FFT size for analysis. Must be a power of 2. High values may lead to heavy CPU cost
   * @param {object} [options.audioContext=null] - The audio context to base analysis from
   * @param {object} [options.inputNode=null] - The audio node to take source instead of player's one
   * @param {object[]} [options.colors] - The peak meter gradient colors, must be objects with color (in Hex/RGB/HSL) and index (in Float[0,1]) properties **/
  constructor(options) {
    super(options);
    // Peak gradient
    if (!options.colors || !options.colors.gradient) {
      this._barGradient = ColorUtils.defaultAudioGradient;
    } else {
      this._barGradient = options.colors.gradient;
    }
    // Update canvas CSS background color
    this._canvas.style.backgroundColor = options.colors ? options.colors.background || ColorUtils.defaultBackgroundColor : ColorUtils.defaultBackgroundColor;
  }


  /*  --------------------------------------------------------------------------------------------------------------- */
  /*  --------------------------------------  VISUCOMPONENTMONO OVERRIDES  -----------------------------------------  */
  /*  --------------------------------------------------------------------------------------------------------------- */


  /** @method
   * @name _processAudioBin
   * @private
   * @override
   * @memberof FrequencyBars
   * @author Arthur Beaulieu
   * @since 2020
   * @description <blockquote>Real time method called by WebAudioAPI to process PCM data. Here we make a 8 bit frequency
   * analysis. Then we use utils method to draw bar for each audio bin in studied audio spectrum.</blockquote> **/
  _processAudioBin() {
    // Only fill again the canvas if player is playing
    if (this._isPlaying === true) {
      this._clearCanvas();
      // Get frequency data for current bin in node analyser
      const frequencyData = new Uint8Array(this._nodes.analyser.frequencyBinCount);
      this._nodes.analyser.getByteFrequencyData(frequencyData);
      // Compute single frequency width according to analyser node
      const frequencyWidth = (this._canvas.width / this._nodes.analyser.frequencyBinCount);
      // Iterate over data to build each bar
      let cursorX = 0; // X origin for items in loop
      for (let i = 0; i < this._nodes.analyser.frequencyBinCount; ++i) {
        // Compute frequency height in px, relative to the canvas height
        let frequencyHeight = (frequencyData[i] / 255) * (this._canvas.height);
        CanvasUtils.drawVerticalBar(this._canvas, {
          height: frequencyHeight,
          width: frequencyWidth,
          colors: this._barGradient,
          originX: cursorX
        });
        // Update cursor position
        cursorX += frequencyWidth;
      }
      // Draw next frame
      requestAnimationFrame(this._processAudioBin);
    }
  }


}


export default FrequencyBars;