Skip to content

Commit

Permalink
Version 3.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
hvianna committed May 29, 2021
2 parents 48bfbb3 + f29d400 commit 411d767
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 89 deletions.
14 changes: 14 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
Changelog
=========

## version 3.4.0 (2021-05-29)

### Added: {docsify-ignore}

+ [`fsElement`](README.md#fselement-htmlelement-object) constructor option, for easily handling fullscreen on any element.

### Fixed and improved: {docsify-ignore}

+ Fixed radial analyzer too wide in vertical containers;
+ Fixed out of bounds bar in mode 0 (discrete frequencies) with `mirror` set to -1;
+ Improved fullscreen rendering in portrait orientation displays;
+ Improved font size adjustment for scale labels and FPS display on vertical containers.


## version 3.3.0 (2021-05-03)

### Added: {docsify-ignore}
Expand Down
112 changes: 81 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@

## About

**audioMotion-analyzer** is a high-resolution real-time audio spectrum analyzer module built upon Web Audio and Canvas JavaScript APIs.
**audioMotion-analyzer** is a high-resolution real-time audio spectrum analyzer module built upon **Web Audio** and **Canvas** JavaScript APIs.

It's highly customizable, and optimized for high performance and a small file size.
It was originally conceived as part of a larger project: a full-featured music player called [**audioMotion**](https://audiomotion.me).
As it started getting some attention, I realized other developers might be interested in using the spectrum analyzer in their own projects,
so I decided to make it available as a self-contained module.

I originally wrote it as part of my [**audioMotion**](https://audiomotion.me) music player. Check it out too!
> **audioMotion-analyzer** is aimed to be the best looking, most customizable spectrum analyzer around, with high accuracy and performance, in a small footprint package!
## Features

Expand Down Expand Up @@ -46,7 +48,7 @@ Load from Skypack CDN:
</script>
```

Or download the [latest version](https://github.com/hvianna/audioMotion-analyzer/releases) and copy the `audioMotion-analyzer.js` file from the `src/` folder to your project folder.
Or download the [latest version](https://github.com/hvianna/audioMotion-analyzer/releases) and copy the `audioMotion-analyzer.js` file from the `src/` folder into your project folder.

### npm project

Expand Down Expand Up @@ -85,17 +87,20 @@ const audioMotion = new AudioMotionAnalyzer(

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

### Options
### Options object

Available options and default values:
Valid properties and default values are shown below.

Properties marked as *constructor only* can only be set by the constructor call, the others can also be set anytime via [`setOptions()`](#setoptions-options-) method.

options = {<br>
&emsp;&emsp;[audioCtx](#audioctx-audiocontext-object-read-only): *undefined*, // constructor only<br>
&emsp;&emsp;[audioCtx](#audioctx-audiocontext-object): *undefined*, // constructor only<br>
&emsp;&emsp;[barSpace](#barspace-number): **0.1**,<br>
&emsp;&emsp;[bgAlpha](#bgalpha-number): **0.7**,<br>
&emsp;&emsp;[connectSpeakers](#connectspeakers-boolean): **true**, // constructor only<br>
&emsp;&emsp;[fftSize](#fftsize-number): **8192**,<br>
&emsp;&emsp;[fillAlpha](#fillalpha-number): **1**,<br>
&emsp;&emsp;[fsElement](#fselement-htmlelement-object): *undefined*, // constructor only<br>
&emsp;&emsp;[gradient](#gradient-string): **'classic'**,<br>
&emsp;&emsp;[height](#height-number): *undefined*,<br>
&emsp;&emsp;[lineWidth](#linewidth-number): **0**,<br>
Expand Down Expand Up @@ -131,7 +136,22 @@ options = {<br>
&emsp;&emsp;[width](#width-number): *undefined*<br>
}

### `connectSpeakers` *boolean*
### Constructor-specific options

#### `audioCtx` *AudioContext object*

*Available since v2.0.0*

Allows you to provide an external [*AudioContext*](https://developer.mozilla.org/en-US/docs/Web/API/AudioContext)
for **audioMotion-analyzer**, for connection with other Web Audio nodes or sound-processing modules.

Since version 3.2.0, `audioCtx` will be automatically inferred from the [`source`](#source-htmlmediaelement-or-audionode-object) property if that's an *AudioNode*.

If none are defined, a new context will be created. After instantiation, [`audioCtx`](#audioctx-audiocontext-object-read-only) will be available as a read-only property.

See [this live code](https://codesandbox.io/s/9y6qb) and the [multi-instance demo](/demo/multi.html) for more usage examples.

#### `connectSpeakers` *boolean*

*Available since v3.2.0*

Expand All @@ -150,14 +170,27 @@ Defaults to **true**.

See also [`connectedTo`](#connectedto-array-read-only).

### `source` *HTMLMediaElement or AudioNode object*
#### `fsElement` *HTMLElement object*

*Available since v3.4.0*

HTML element affected by the [`toggleFullscreen()`](#togglefullscreen) method.

If not defined, defaults to the [`canvas`](#canvas-htmlcanvaselement-object-read-only).
**Set it to a container `<div>` to keep additional interface elements available in fullscreen mode.**

See the [overlay demo](/demo/overlay.html) or [this pen](https://codepen.io/hvianna/pen/LYREBYQ) for usage examples.

After instantiation, [`fsElement`](#fselement-htmlelement-object-read-only) is available as a read-only property.

#### `source` *HTMLMediaElement or AudioNode object*

If `source` is specified, connects an [*HTMLMediaElement*](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement) object (an `<audio>` or `<video>` HTML tag)
or any instance of [*AudioNode*](https://developer.mozilla.org/en-US/docs/Web/API/AudioNode) to the analyzer.

At least one audio source is required for the analyzer to work. You can also connect audio sources after instantiation, using the [`connectInput()`](#connectinput-source-) method.

### `start` *boolean*
#### `start` *boolean*

If `start: false` is specified, the analyzer will be created stopped. You can then start it with the [`toggleAnalyzer()`](#toggleanalyzer-boolean-) method.

Expand All @@ -168,8 +201,6 @@ Defaults to **true**, so the analyzer will start running right after initializat
### `audioCtx` *AudioContext object* *(Read only)*

[*AudioContext*](https://developer.mozilla.org/en-US/docs/Web/API/AudioContext) used by **audioMotion-analyzer**.
It can be provided in the [constructor](#constructor) options, explicitly via the `audioCtx` property, or implicitly (since v3.2.0) when the [`source`](#source-htmlmediaelement-or-audionode-object) property is an AudioNode.
Otherwise, a new context will be created upon instantiation.

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

Expand All @@ -190,6 +221,10 @@ audioMotion.connectInput( gainNode ); // connect gainNode -> audioMotion
oscillator.start(); // play tone
```

You can provide your own *AudioContext* via the [`audioCtx`](#audioctx-audiocontext-object) property in the [constructor](#constructor) options.

See also the [fluid demo](/demo/fluid.html) and the [multi-instance demo](/demo/multi.html) for more usage examples.

### `barSpace` *number*

*Available since v2.0.0*
Expand Down Expand Up @@ -241,9 +276,9 @@ By default, **audioMotion-analyzer** is connected to the *AudioContext* `destina

See also [`connectOutput()`](#connectoutput-node-).

### `energy` *number* *(Read only)*
### `energy` **(DEPRECATED)**

**DEPRECATED - will be removed in version 4.0.0**
**This property will be removed in version 4.0.0**

Use [`getEnergy()`](#getenergy-preset-startfreq-endfreq-) instead.

Expand Down Expand Up @@ -274,6 +309,14 @@ Defaults to **1**.

Current frame rate.

### `fsElement` *HTMLElement object* *(Read only)*

*Available since v3.4.0*

HTML element affected by the [`toggleFullscreen()`](#togglefullscreen) method.

See [`fsElement`](#fselement-htmlelement-object) in the constructor options context for more information.

### `fsHeight` *number* *(Read only)*
### `fsWidth` *number* *(Read only)*

Expand Down Expand Up @@ -439,9 +482,11 @@ When [`showBgColor`](#showbgcolor-boolean) is also *true*, [`bgAlpha`](#bgalpha-

Defaults to **false**.

### `peakEnergy` *number* *(Read only)*
?> In order to keep elements other than the canvas visible in fullscreen, you'll need to set the [`fsElement`](#fselement-htmlelement-object) property in the [constructor](#constructor) options.

**DEPRECATED - will be removed in version 4.0.0**
### `peakEnergy` **(DEPRECATED)**

**This property will be removed in version 4.0.0**

Use [`getEnergy('peak')`](#getenergy-preset-startfreq-endfreq-) instead.

Expand Down Expand Up @@ -522,11 +567,11 @@ Opacity can be adjusted via [`bgAlpha`](#bgalpha-number) property, when [`overla
If ***false***, the canvas background will be painted black when [`overlay`](#overlay-boolean) is ***false***,
or transparent when [`overlay`](#overlay-boolean) is ***true***.

?> Please note that when [`overlay`](#overlay-boolean) is ***false*** and [`showLeds`](#showleds-boolean) is ***true***, the background color will always be black
and setting `showBgColor` to ***true*** will make the "unlit" LEDs visible instead.

Defaults to **true**.

?> Please note that when [`overlay`](#overlay-boolean) is ***false*** and [`showLeds`](#showleds-boolean) is ***true***, the background color will always be black,
and setting `showBgColor` to ***true*** will make the "unlit" LEDs visible instead.

### `showFPS` *boolean*

*true* to display the current frame rate. Defaults to **false**.
Expand Down Expand Up @@ -681,7 +726,7 @@ Reason | Description
`'user'` | canvas dimensions changed by user script, via [`height`](#height-number) and [`width`](#width-number) properties, [`setCanvasSize()`](#setcanvassize-width-height-) or [`setOptions()`](#setoptions-options-) methods

?> As of [version 2.5.0](https://github.com/hvianna/audioMotion-analyzer/releases/tag/2.5.0), the `'resize'` reason is no longer sent on fullscreen changes and
a callback is triggered only when canvas dimensions *effectively* change from the previous state.
the callback is triggered only when canvas dimensions *effectively* change from the previous state.

Usage example:

Expand Down Expand Up @@ -717,35 +762,41 @@ See also [`disconnectInput()`](#disconnectinput-node-) and [`connectedSources`](

This method allows connecting the analyzer **output** to other audio processing modules that use the Web Audio API.

`node` must be an [*AudioNode*](https://developer.mozilla.org/en-US/docs/Web/API/AudioNode) instance; **if not specified, the analyzer output is connected to the speakers** (the *AudioContext* `destination` node).
`node` must be an [*AudioNode*](https://developer.mozilla.org/en-US/docs/Web/API/AudioNode) instance.

By default, the analyzer is connected to the speakers upon instantiation, unless you set [`connectSpeakers: false`](#connectspeakers-boolean) in the constructor options.

See also [`disconnectOutput()`](#disconnectoutput-node-) and [`connectedTo`](#connectedto-array-read-only).

?> If called with no argument, analyzer output is connected to the speakers (the *AudioContext* `destination` node).

### `disconnectInput( [node] )`

*Available since v3.0.0*

Disconnects audio source nodes previously connected to the analyzer.

`node` may be an *AudioNode* instance or an **array** of such objects; **if not specified, all connected nodes are disconnected.**
`node` may be an *AudioNode* instance or an **array** of such objects.

Please note that if you have connected an `<audio>` or `<video>` element, you should disconnect the respective [MediaElementAudioSourceNode](https://developer.mozilla.org/en-US/docs/Web/API/MediaElementAudioSourceNode)
created for it.

See also [`connectInput()`](#connectinput-source-).

?> If called with no argument, all connected sources are disconnected.

### `disconnectOutput( [node] )`

*Available since v3.0.0*

Disconnects the analyzer output from previously connected audio nodes.

`node` must be a connected *AudioNode*; **if not specified, the output is disconnected from all nodes, including the speakers!**
`node` must be a connected *AudioNode*.

See also [`connectOutput()`](#connectoutput-node-).

?> If called with no argument, analyzer output is disconnected from all nodes, **including the speakers!**

### `getEnergy( [preset | startFreq], [endFreq] )`

*Available since v3.2.0*
Expand Down Expand Up @@ -832,11 +883,11 @@ You can try different values in the [fluid demo](https://audiomotion.dev/demo/fl

### `setOptions( [options] )`

Shorthand method for setting several options at once.
Shorthand method for setting several analyzer [properties](#properties) at once.

[`options`](#options) should be an object as defined in the class constructor.
See **[Options object](#options-object)** for object structure and default values.

**If called with no argument (or `options` is *undefined*), resets all configuration options to their default values.**
?> If called with no argument (or `options` is *undefined*), resets all configuration options to their default values.

### `setSensitivity( minDecibels, maxDecibels )`

Expand All @@ -854,12 +905,11 @@ The analyzer is started by default after initialization, unless you specify [`st

Toggles fullscreen mode on / off.

Please note that fullscreen requests must be triggered by user action, like a key press or mouse click,
so you must call this method from within a user-generated event handler.
By default, only the canvas is sent to fullscreen.
You can set the [`fsElement`](#fselement-htmlelement-object) constructor option to a parent container, to keep desired interface elements visible during fullscreen.

?> Fullscreen requests must be triggered by user action, like a key press or mouse click, so you must call this method from within a user-generated event handler.

Also, if you're displaying the analyzer over other content in [overlay](#overlay-boolean) mode,
you'll probably want to handle fullscreen on the container element instead, using your own code.
See the [overlay demo](/demo/overlay.html) for an example.

## Custom Errors

Expand Down
15 changes: 11 additions & 4 deletions demo/fluid.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,18 @@ document.getElementById('version').innerText = AudioMotionAnalyzer.version;
const audioCtx = audioMotion.audioCtx,
oscillator = audioCtx.createOscillator(),
gainNode = audioCtx.createGain(),
panNode = audioCtx.createStereoPanner();
panNode = audioCtx.createStereoPanner ? audioCtx.createStereoPanner() : false; // Safari >= 14.1; iOS Safari >= 14.5

oscillator.frequency.setValueAtTime( 0, audioCtx.currentTime );
oscillator.start();

// Connect audio nodes: oscillator -> panNode -> gainNode
oscillator.connect( panNode );
panNode.connect( gainNode );
if ( panNode ) {
oscillator.connect( panNode );
panNode.connect( gainNode );
}
else
oscillator.connect( gainNode );

// Connect gainNode to audioMotion's input
audioMotion.connectInput( gainNode );
Expand Down Expand Up @@ -207,7 +211,10 @@ document.getElementById('btn_play').addEventListener( 'click', () => {
document.getElementById('btn_soundoff').addEventListener( 'click', () => gainNode.gain.setValueAtTime( 0, audioCtx.currentTime ) );

// Stereo pan for test tones
document.getElementById('pan').addEventListener( 'change', e => panNode.pan.setValueAtTime( e.target.value, audioCtx.currentTime ) );
document.getElementById('pan').addEventListener( 'change', e => {
if ( panNode )
panNode.pan.setValueAtTime( e.target.value, audioCtx.currentTime );
});

// File upload
document.getElementById('uploadFile').addEventListener( 'change', e => loadSong( e.target ) );
Expand Down
3 changes: 2 additions & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ <h2><a href="multi.html">▶ Multiple instances demo</a></h2>
<h2><a href="overlay.html">▶ Overlay demo</a></h2>

<ul>
<li>Displays the analyzer over a video element and illustrates how to handle fullscreen on the container element.</li>
<li><em>audioMotion-analyzer</em> is connected to a <code>&lt;video&gt;</code> element and displayed over it with semi-transparent background;
<li>Fullscreen is handled on the parent container element.</li>
</ul>

</body>
Expand Down
2 changes: 1 addition & 1 deletion demo/overlay.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ <h1><a href="https://audiomotion.dev" class="logo">audioMotion-analyzer</a> | ov

<p class="center">
<button data-prop="isOn" data-func="toggleAnalyzer">toggleAnalyzer()</button>
<button id="btn_fullscr">Fullscreen</button>
<button data-prop="isFullscreen" data-func="toggleFullscreen">Fullscreen</button>
</p>

<div class="analyzer-configuration">
Expand Down
21 changes: 4 additions & 17 deletions demo/overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,10 @@ const presets = [
// Create audioMotion-analyzer object

try {
var audioMotion = new AudioMotionAnalyzer( container, { source: videoEl } );
var audioMotion = new AudioMotionAnalyzer( container, {
source: videoEl,
fsElement: container
});
}
catch( err ) {
container.innerHTML = `<p>audioMotion-analyzer failed with error: <em>${err}</em></p>`;
Expand Down Expand Up @@ -121,22 +124,6 @@ presetSelection.addEventListener( 'change', () => {
// Display value of ranged input elements
document.querySelectorAll('input[type="range"]').forEach( el => el.addEventListener( 'change', () => updateRangeElement( el ) ) );

// Handle fullscreen mode for container element
document.getElementById('btn_fullscr').addEventListener( 'click', () => {
if ( document.fullscreenElement ) {
if ( document.exitFullscreen )
document.exitFullscreen();
else if ( document.webkitExitFullscreen )
document.webkitExitFullscreen();
}
else {
if ( container.requestFullscreen )
container.requestFullscreen();
else if ( container.webkitRequestFullscreen )
container.webkitRequestFullscreen();
}
});

// Populate the UI presets select element
presets.forEach( ( preset, index ) => {
const option = new Option( preset.name, index );
Expand Down
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
--emoji-size: 1.2em;
--sidebar-name-font-family: Orbitron, var(--base-font-family);
--sidebar-name-font-weight: 800;
--heading-h4-font-size: 1.2rem;
}

@media (min-width: 1200px) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "audiomotion-analyzer",
"description": "High-resolution real-time graphic audio spectrum analyzer JavaScript module with no dependencies.",
"version": "3.3.0",
"version": "3.4.0",
"main": "./src/audioMotion-analyzer.js",
"module": "./src/audioMotion-analyzer.js",
"types": "./src/index.d.ts",
Expand Down
Loading

0 comments on commit 411d767

Please sign in to comment.