Learn about our RFC process, Open RFC meetings & more.Join in the discussion! »

audiomotion-analyzer

2.3.0 • Public • Published

About

I originally wrote this as part of my audioMotion spectrum analyzer and music player.

This package provides only the graphic spectrum analyzer, as a standalone module, for you to use in your own JavaScript projects.

Online demos

demo-animation

?> https://audiomotion.dev/demo/

Features

  • High-resolution (retina / HiDPI ready) real-time audio spectrum analyzer with fullscreen support
  • Logarithmic frequency scale with customizable range
  • 10 visualization modes: choose between discrete frequencies or octave bands based on the equal tempered scale
  • Optional vintage LED effect and variable luminance bars for octave bands modes
  • Optional customizable reflection effect
  • Customizable Web Audio API parameters: FFT size, sensitivity and time-smoothing constant
  • Comes with 3 predefined color gradients - easily add your own!
  • No dependencies, less than 20kB minified

Usage

Install with npm:

$ npm install audiomotion-analyzer

ES6 import:

import AudioMotionAnalyzer from 'audiomotion-analyzer';

Minimal constructor:

const audioMotion = new AudioMotionAnalyzer(
    document.getElementById('container'),
    {
        source: document.getElementById('audio')
    }
);

This will insert the analyzer canvas inside the #container element and start the visualization of audio coming from the #audio element.

Constructor

new AudioMotionAnalyzer( [container], [{options}] )

Creates a new instance of audioMotion-analyzer.

The analyzer canvas will be created and appended to the HTML element referenced by container.

If container is undefined, the canvas will be appended to the document's body.

Options

Available options and default values:

options = {
  audioCtx: undefined,
  barSpace: 0.1,
  bgAlpha: 0.7,
  fftSize: 8192,
  fillAlpha: 1,
  gradient: 'classic',
  height: undefined,
  lineWidth: 0,
  loRes: false,
  lumiBars: false,
  maxDecibels: -25,
  maxFreq: 22000,
  minDecibels: -85,
  minFreq: 20,
  mode: 0,
  onCanvasDraw: undefined,
  onCanvasResize: undefined,
  overlay: false,
  reflexAlpha: 0.15,
  reflexBright: 1,
  reflexFit: true,
  reflexRatio: 0,
  showBgColor: true,
  showFPS: false,
  showLeds: false,
  showPeaks: true,
  showScale: true,
  smoothing: 0.5,
  source: undefined,
  start: true,
  width: undefined
}

source HTMLMediaElement object

If source is specified, the media element (<audio> or <video>) referenced by the object will be connected to the analyzer.

You can later disconnect it by referring to the audioSource object.

At least one audio source is required for the analyzer to work. You can also connect audio sources with the connectAudio() method.

Object reference: https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement

start boolean

If start: false is specified, the analyzer will be created stopped. You can then start it with the toggleAnalyzer() method.

Defaults to true, so the analyzer will start running right after initialization.

Interface objects

analyzer AnalyserNode object

Connect any additional audio sources to this object, so their output is displayed in the graphic analyzer.

Object reference: https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode

audioCtx AudioContext object

AudioContext used by audioMotion-analyzer. If not provided by the user in the constructor options, it will be created automatically.

Use this object to create additional audio sources to be connected to the analyzer, like oscillator nodes, gain nodes and media streams.

The code fragment below creates an oscillator and a gain node using audioMotion's audioContext, and then connects them to the analyzer:

const audioMotion = new AudioMotionAnalyzer( document.getElementById('container') ),
      audioCtx    = audioMotion.audioCtx,
      oscillator  = audioCtx.createOscillator(),
      gainNode    = audioCtx.createGain();
 
oscillator.frequency.setValueAtTime( 440, audioCtx.currentTime ); // play 440Hz tone
oscillator.connect( gainNode );
 
gainNode.gain.setValueAtTime( .5, audioCtx.currentTime );
gainNode.connect( audioMotion.analyzer );
 
oscillator.start();

Object reference: https://developer.mozilla.org/en-US/docs/Web/API/AudioContext

audioSource MediaElementAudioSourceNode object

Object representing the HTML media element connected using the source property in the constructor options.

See also the connectAudio() method.

Object reference: https://developer.mozilla.org/en-US/docs/Web/API/MediaElementAudioSourceNode

canvas HTMLCanvasElement object

Canvas element created by audioMotion.

Object reference: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement

canvasCtx CanvasRenderingContext2D object

2D rendering context for drawing in audioMotion's canvas.

Object reference: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D

Properties

barSpace number

Available since v2.0.0

Customize the spacing between bars in octave bands modes.

Use a value between 0 and 1 for spacing proportional to the bar width. Values >= 1 will be considered as a literal number of pixels.

For example, barSpace = 0.5 will use half of the bar width for spacing, while barSpace = 2 will set a fixed spacing of 2 pixels, independent of the width of bars. Prefer proportional spacing to obtain consistent results among different resolutions and screen sizes.

barSpace = 0 will effectively show contiguous bars, except when showLeds is true, in which case a minimum spacing is enforced.

Defaults to 0.1.

bgAlpha number

Available since v2.2.0

Controls the opacity of the background, when overlay and showBgColor are both set to true.

It must be a number between 0 (completely transparent) and 1 (completely opaque).

Defaults to 0.7.

dataArray UInt8Array array (Read only)

Data array updated by the analyzer's getByteFrequencyData() method on every animation frame (ideally 60 times per second).

Array size is defined by analyzer.frequencyBinCount (which should be half the current FFT size), with element values ranging from 0 to 255.

Each array element represents a discrete value in the frequency domain, such that: frequency = index * audioCtx.sampleRate / fftSize.

See also binToFreq() and freqToBin() methods.

fftSize number

Number of samples used for the FFT performed by the analyzer node. It must be a power of 2 between 32 and 32768, so valid values are: 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, and 32768.

Higher values provide more detail in the frequency domain, but less detail in the time domain (slower response), so you may need to adjust smoothing accordingly.

Defaults to 8192.

fillAlpha number

Available since v2.0.0

Opacity of the area fill in Line / Area graph visualization (mode 10).

It must be a number between 0 (completely transparent) and 1 (completely opaque).

Please note that this affects only the area fill. The line (when lineWidth > 0) is always drawn at full opacity.

Defaults to 1.

fps number (Read only)

Current frame rate.

fsHeight number (Read only)

fsWidth number (Read only)

Canvas dimensions used during fullscreen mode. These take the current pixel ratio into account and will change accordingly when low-resolution mode is set.

gradient string

Currently selected color gradient used for analyzer graphics.

It must be the name of a built-in or registered gradient. Built-in gradients are 'classic', 'prism' and 'rainbow'.

Defaults to 'classic'.

height number

width number

Nominal dimensions of the analyzer.

If one or both of these are undefined, the analyzer will try to adjust to the container's width and/or height. If the container's width and/or height are 0 (inline elements), a reference size of 640 x 270 pixels will be used to replace the missing dimension(s). This should be considered the minimum dimensions for proper visualization of all available modes with the LED effect on.

You can set both values at once using the setCanvasSize() method.

?> You can read the actual canvas dimensions at any time directly from the canvas object.

isFullscreen boolean (Read only)

true when the analyzer is being displayed in fullscreen, or false otherwise.

isOn boolean (Read only)

true if the analyzer canvas animation is running, or false if it's stopped.

lineWidth number

Available since v2.0.0

Line width for the Line / Area graph visualization (mode 10).

For the line to be distinguishable, set also fillAlpha < 1.

Defaults to 0.

loRes boolean

true for low resolution mode. Defaults to false.

Low resolution mode halves the effective pixel ratio, resulting in four times less pixels to render. This may improve performance significantly, especially in 4K+ monitors.

?> If you want to allow users to interactively toggle low resolution mode, you may need to set a fixed size for the canvas via CSS, like so:

#container canvas {
    width: 100%;
}

This will prevent the canvas size from changing, when switching the low resolution mode on and off.

lumiBars boolean

Available since v1.1.0

This is only effective for visualization modes 1 to 8 (octave bands).

When set to true all analyzer bars will be displayed at full height with varying luminance (opacity, actually) instead.

Defaults to false.

maxDecibels number

minDecibels number

Highest and lowest decibel values represented in the Y-axis of the analyzer. The loudest volume possible is 0.

maxDecibels defaults to -25 and minDecibels defaults to -85.

You can set both values at once using the setSensitivity() method.

For more info, see AnalyserNode.minDecibels.

maxFreq number

minFreq number

Highest and lowest frequencies represented in the X-axis of the analyzer. Values in Hertz. maxFreq defaults to 22000 and minFreq defaults to 20.

The minimum allowed value is 1. Trying to set a lower value will throw an ERR_FREQUENCY_TOO_LOW error.

The maximum practical value is half the sampling rate (audioCtx.sampleRate), although this is not enforced by audioMotion-analyzer.

It is preferable to use the setFreqRange() method and set both values at once, to prevent minFreq being higher than the current maxFreq or vice-versa at a given moment.

mode number

Current visualization mode.

  • Discrete frequencies mode provides the highest resolution, allowing you to visualize individual frequencies provided by the FFT;
  • Octave bands modes display wider vertical bars, each one representing the nth part of an octave, based on a 24-tone equal tempered scale;
  • Line / Area graph mode uses the discrete frequencies data to draw a filled shape and/or a continuous line (see fillAlpha and lineWidth properties).
Value Mode Available since
0 Discrete frequencies v1.0.0
1 1/24th octave bands v1.0.0
2 1/12th octave bands v1.0.0
3 1/8th octave bands v1.0.0
4 1/6th octave bands v1.0.0
5 1/4th octave bands v1.0.0
6 1/3rd octave bands v1.0.0
7 half octave bands v1.0.0
8 full octave bands v1.0.0
9 reserved (not valid) -
10 Line / Area graph v1.1.0

Defaults to 0.

overlay boolean

Available since v2.2.0

Allows the analyzer to be displayed over other content, by making the canvas background transparent, when set to true.

When showBgColor is also true, bgAlpha controls the background opacity.

Defaults to false.

pixelRatio number (Read only)

Current devicePixelRatio. This is usually 1 for standard displays and 2 for retina / Hi-DPI screens.

You can refer to this value to adjust any additional drawings done in the canvas (via callback function).

When loRes is true pixelRatio is halved, i.e. 0.5 for standard displays and 1 for retina / Hi-DPI.

reflexAlpha number

Available since v2.1.0

Reflection opacity (when reflexRatio > 0).

It must be a number between 0 (completely transparent) and 1 (completely opaque).

Defaults to 0.15.

reflexBright number

Available since v2.3.0

Reflection brightness (when reflexRatio > 0).

It must be a number. Values below 1 darken the reflection and above 1 make it brighter. A value of 0 will render the reflected image completely black, while a value of 1 will preserve the original brightness.

Please note that this feature relies on the filter property of Canvas API, which is currently not supported in some browsers (notably, Opera and Safari).

Defaults to 1.

reflexFit boolean

Available since v2.1.0

When true the reflection will be adjusted (stretched or shrinked) to fit the canvas. If set to false the reflected image may be cut at the bottom (when reflexRatio < 0.5) or not fill the entire canvas (when reflexRatio > 0.5).

Defaults to true.

reflexRatio number

Available since v2.1.0

Percentage of canvas height used for reflection. It must be a number greater than or equal to 0, and less than 1. Trying to set a value out of this range will throw an ERR_REFLEX_OUT_OF_RANGE error.

For a perfect mirrored effect, set reflexRatio to 0.5 and both reflexAlpha and reflexBright to 1.

This has no effect when lumiBars is true.

Defaults to 0 (no reflection).

showBgColor boolean

true to use the background color defined by the current gradient; false for black or transparent (when overlay is true) background.

Please note that when showLeds is true, setting showBgColor to true will show the "unlit" LEDs instead of changing the background.

Defaults to true.

showFPS boolean

true to display the current frame rate. Defaults to false.

showLeds boolean

true to activate LED display effect. Only effective for visualization modes 1 to 8 (octave bands). Defaults to false.

showPeaks boolean

true to show amplitude peaks for each frequency. Defaults to true.

showScale boolean

true to display frequency labels in the X axis. Defaults to true.

smoothing number

Sets the analyzer's smoothingTimeConstant.

It must be a number between 0 and 1. Lower values make the analyzer respond faster to changes.

Defaults to 0.5.

version string (Read only)

Available since v2.0.0

Returns the version of the audioMotion-analyzer package.

Callback functions

onCanvasDraw function

If defined, this function will be called after rendering each frame.

The audioMotion object will be passed as an argument to the callback function.

Usage example:

const audioMotion = new AudioMotionAnalyzer(
    document.getElementById('container'),
    {
        source: document.getElementById('audio'),
        onCanvasDraw: displayCanvasMsg
    }
);
 
function displayCanvasMsg( instance ) {
    let size = 20 * instance.pixelRatio;
    if ( instance.isFullscreen )
        size *= 2;
 
    // find the data array index for 140Hz
    const idx = instance.freqToBin(140);
 
    // use the 140Hz amplitude to increase the font size and make the logo pulse to the beat
    instance.canvasCtx.font = `${size + instance.dataArray[ idx ] / 16 * instance.pixelRatio}px Orbitron,sans-serif`;
 
    instance.canvasCtx.fillStyle = '#fff8';
    instance.canvasCtx.textAlign = 'center';
    instance.canvasCtx.fillText( 'audioMotion', instance.canvas.width - size * 8, size * 2 );
}

onCanvasResize function

If defined, this function will be called whenever the canvas is resized.

Two arguments are passed: a string with the reason why the function was called (see below) and the audioMotion object.

Reason Description
'create' canvas created by the class constructor
'fschange' analyzer entered or left fullscreen mode
'lores' low resolution mode toggled on or off
'resize' browser window resized (only when width and/or height are undefined)
'user' canvas dimensions changed by user script, via height and width properties, setCanvasSize() or setOptions() methods

Usage example:

const audioMotion = new AudioMotionAnalyzer(
    document.getElementById('container'),
    {
        source: document.getElementById('audio'),
        onCanvasResize: ( reason, instance ) => {
            console.log( `[${reason}] set: ${instance.width} x ${instance.height} | actual: ${instance.canvas.width} x ${instance.canvas.height}` );
        }
    }
);

Methods

binToFreq( bin )

Available since v2.3.0

Returns the frequency (in hertz) represented by a given FFT bin (a dataArray index).

bin must be a number equal or greater than 0 and less than analyzer.frequencyBinCount (the same as dataArray.length).

connectAudio( element )

Connects an HTMLMediaElement (<audio> or <video> HTML element) to the analyzer.

Returns a MediaElementAudioSourceNode which can be used for later disconnection.

For connecting other audio sources, like oscillators and streams, use the audioCtx and analyzer objects.

freqToBin( frequency, [rounding] )

Available since v2.3.0

Returns the dataArray index which more closely corresponds to a given frequency.

frequency must be a number equal or greater than zero, representing a frequency in hertz.

rounding is an optional string to select the Math method used for rounding the index value to an integer. Valid options are 'floor', 'round' (default) and 'ceil'.

Please note that the returned value will cap at the highest valid index (analyzer.frequencyBinCount - 1) for any frequency higher than half the current sampling rate (audioCtx.sampleRate).

See the onCanvasDraw usage example.

registerGradient( name, options )

Registers a custom color gradient.

name must be a non-empty string that will be used when setting the gradient property. options must be an object as shown below:

const options = {
    bgColor: '#011a35', // background color (optional) - defaults to '#111'
    dir: 'h',           // add this property to create a horizontal gradient (optional)
    colorStops: [       // list your gradient colors in this array (at least 2 entries are required)
        'red',                      // colors may be defined in any valid CSS format
        { pos: .6, color: '#ff0' }, // use an object to adjust the position (0 to 1) of a color
        'hsl( 120, 100%, 50% )'     // colors may be defined in any valid CSS format
    ]
}
 
audioMotion.registerGradient( 'my-grad', options );

Additional information about gradient color-stops.

setCanvasSize( width, height )

Sets the analyzer nominal dimensions in pixels. See height and width properties for details.

setFreqRange( minFreq, maxFreq )

Sets the desired frequency range. Values are expressed in Hz (Hertz).

setOptions( {options} )

Shorthand method for setting several options at once.

Refer to the class constructor for available options. audioCtx and source properties can only be set at initialization.

setSensitivity( minDecibels, maxDecibels )

Adjust the analyzer's sensitivity. See maxDecibels and minDecibels properties.

toggleAnalyzer( [boolean] )

Starts (true) or stops (false) the analyzer animation. If no argument provided, inverts the current status.

Returns the resulting status.

The analyzer is started by default after initialization, unless you specify start: false in the constructor options.

toggleFullscreen()

Toggles fullscreen mode on / off.

As per API specification, fullscreen requests must be triggered by user action, so you must call this function from within a mouse or keyboard event handler, otherwise the request will be denied.

Please note that if you're displaying the analyzer over other content, you'll probably want to handle fullscreen mode on the container element instead. See the overlay demo for an example.

Custom Errors

Available since v2.0.0

audioMotion-analyzer uses a custom error object to throw errors for some critical operations.

The code property is a string label that can be checked to identify the specific error in a reliable way.

code Error description
ERR_AUDIO_CONTEXT_FAIL Could not create audio context. The user agent may lack support for the Web Audio API.
ERR_INVALID_AUDIO_CONTEXT Audio context provided by user is not valid.
ERR_INVALID_MODE User tried to set the visualization mode to an invalid value.
ERR_FREQUENCY_TOO_LOW User tried to set the minFreq or maxFreq properties to a value lower than 1.
ERR_GRADIENT_INVALID_NAME The name parameter for registerGradient() must be a non-empty string.
ERR_GRADIENT_NOT_AN_OBJECT The options parameter for registerGradient() must be an object.
ERR_GRADIENT_MISSING_COLOR The options parameter for registerGradient() must define at least two color-stops.
ERR_REFLEX_OUT_OF_RANGE Tried to assign a value < 0 or >= 1 to reflexRatio property.
ERR_UNKNOWN_GRADIENT User tried to select a gradient not previously registered.

Acknowledgments

Changelog

See Changelog.md

Get in touch!

If you create something cool with this project, or simply think it's useful, I would like to know! Please drop me an e-mail at hvianna@gmail.com

If you have a feature request or code suggestion, please see CONTRIBUTING.md

And if you're feeling generous you can buy me a coffee on Ko-fi 😁☕️

ko-fi

License

audioMotion-analyzer copyright (c) 2018-2020 Henrique Avila Vianna
Licensed under the GNU Affero General Public License, version 3 or later.

Install

npm i audiomotion-analyzer

DownloadsWeekly Downloads

26

Version

2.3.0

License

AGPL-3.0-or-later

Unpacked Size

102 kB

Total Files

6

Last publish

Collaborators

  • avatar