audiomotion-analyzer 4.0.0-beta.2 → 4.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -33
- package/package.json +1 -1
- package/src/audioMotion-analyzer.js +161 -107
- package/src/index.d.ts +15 -6
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ What users are saying:
|
|
|
35
35
|
+ Optional effects: LED bars, luminance bars, mirroring and reflection, radial spectrum
|
|
36
36
|
+ Comes with 3 predefined color gradients - easily add your own!
|
|
37
37
|
+ Fullscreen support, ready for retina / HiDPI displays
|
|
38
|
-
+ Zero-dependency native ES6+ module (ESM), \~
|
|
38
|
+
+ Zero-dependency native ES6+ module (ESM), \~25kB minified
|
|
39
39
|
|
|
40
40
|
## Online demos
|
|
41
41
|
|
|
@@ -119,12 +119,15 @@ options = {<br>
|
|
|
119
119
|
  [audioCtx](#audioctx-audiocontext-object): *undefined*, // constructor only<br>
|
|
120
120
|
  [barSpace](#barspace-number): **0.1**,<br>
|
|
121
121
|
  [bgAlpha](#bgalpha-number): **0.7**,<br>
|
|
122
|
+
  [channelLayout](#channellayout-string): **'single'**,<br>
|
|
122
123
|
  [connectSpeakers](#connectspeakers-boolean): **true**, // constructor only<br>
|
|
123
124
|
  [fftSize](#fftsize-number): **8192**,<br>
|
|
124
125
|
  [fillAlpha](#fillalpha-number): **1**,<br>
|
|
125
126
|
  [frequencyScale](#frequencyscale-string): **'log'**,<br>
|
|
126
127
|
  [fsElement](#fselement-htmlelement-object): *undefined*, // constructor only<br>
|
|
127
128
|
  [gradient](#gradient-string): **'classic'**,<br>
|
|
129
|
+
  [gradientLeft](#gradientleft-string): *undefined*,<br>
|
|
130
|
+
  [gradientRight](#gradientright-string): *undefined*,<br>
|
|
128
131
|
  [height](#height-number): *undefined*,<br>
|
|
129
132
|
  [ledBars](#ledbars-boolean): **false**,<br>
|
|
130
133
|
  [linearAmplitude](#linearamplitude-boolean): **false**,<br>
|
|
@@ -158,7 +161,7 @@ options = {<br>
|
|
|
158
161
|
  [spinSpeed](#spinspeed-number): **0**,<br>
|
|
159
162
|
  [splitGradient](#splitgradient-boolean): **false**,<br>
|
|
160
163
|
  [start](#start-boolean): **true**,<br>
|
|
161
|
-
  [stereo](#stereo-boolean): **false
|
|
164
|
+
  [stereo](#stereo-deprecated-boolean): **false**, // DEPRECATED - use channelLayout instead<br>
|
|
162
165
|
  [useCanvas](#usecanvas-boolean): **true**,<br>
|
|
163
166
|
  [volume](#volume-number): **1**,<br>
|
|
164
167
|
  [weightingFilter](#weightingFilter-string): **''**<br>
|
|
@@ -315,6 +318,23 @@ Defaults to **0.7**.
|
|
|
315
318
|
|
|
316
319
|
[2D rendering context](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D) used for drawing in audioMotion's *Canvas*.
|
|
317
320
|
|
|
321
|
+
### `channelLayout` *string*
|
|
322
|
+
|
|
323
|
+
*Available since v4.0.0*
|
|
324
|
+
|
|
325
|
+
Defines the number and layout of analyzer channels.
|
|
326
|
+
|
|
327
|
+
channelLayout | description
|
|
328
|
+
-------------- |------------
|
|
329
|
+
'single' | Single channel analyzer, representing the combined output of both left and right channels.
|
|
330
|
+
'dualVertical' | Dual channel analyzer, with left channel shown at the top and right channel at the bottom.
|
|
331
|
+
'dualCombined' | Left and right channel graphs are shown overlaid. Works best with semi-transparent **Graph** [`mode`](#mode-number) or [`outlineBars`](#outlinebars-boolean).
|
|
332
|
+
|
|
333
|
+
!> When a *dual* layout is selected, any mono (single channel) audio source connected to the analyzer will output sound only from the left speaker,
|
|
334
|
+
unless a stereo source is simultaneously connected to the analyzer, which will force the mono input to be upmixed to stereo.
|
|
335
|
+
|
|
336
|
+
See also [`gradientLeft`](#gradientleft-string), [`gradientRight`](#gradientright-string) and [`splitGradient`](#splitgradient-boolean).
|
|
337
|
+
|
|
318
338
|
### `connectedSources` *array* *(Read only)*
|
|
319
339
|
|
|
320
340
|
*Available since v3.0.0*
|
|
@@ -398,8 +418,21 @@ Name of the color gradient used for analyzer graphs.
|
|
|
398
418
|
|
|
399
419
|
It must be a built-in or [registered](#registergradient-name-options-) gradient name. Built-in gradients are *'classic'*, *'prism'* and *'rainbow'*.
|
|
400
420
|
|
|
421
|
+
See also [`gradientLeft`](#gradientleft-string) and [`gradientRight`](#gradientright-string).
|
|
422
|
+
|
|
401
423
|
Defaults to **'classic'**.
|
|
402
424
|
|
|
425
|
+
### `gradientLeft` *string*
|
|
426
|
+
### `gradientRight` *string*
|
|
427
|
+
|
|
428
|
+
*Available since v4.0.0*
|
|
429
|
+
|
|
430
|
+
When using a dual [`channelLayout`](#channellayout-string), different gradients can be selected for the left and right channels.
|
|
431
|
+
|
|
432
|
+
When [`channelLayout`](#channellayout-string) is set to *'single'*, the gradient selected by `gradientLeft` is used.
|
|
433
|
+
|
|
434
|
+
The [`gradient`](#gradient-string) property can be used as a shorthand to set the same gradient for both channels. Its read value returns only the left (or single) channel gradient though.
|
|
435
|
+
|
|
403
436
|
### `height` *number*
|
|
404
437
|
### `width` *number*
|
|
405
438
|
|
|
@@ -655,7 +688,7 @@ When *true*, the spectrum analyzer is rendered in a circular shape, with radial
|
|
|
655
688
|
In radial visualization, [`ledBars`](#ledbars-boolean) and [`lumiBars`](#lumibars-boolean) effects are disabled, and
|
|
656
689
|
[`showPeaks`](#showpeaks-boolean) has no effect for [**Graph** mode](#mode-number).
|
|
657
690
|
|
|
658
|
-
When [`
|
|
691
|
+
When [`channelLayout`](#channellayout-string) is set to *'dualVertical'*, a larger diameter is used and the right channel bars are rendered towards the center of the analyzer.
|
|
659
692
|
|
|
660
693
|
See also [`spinSpeed`](#spinspeed-number).
|
|
661
694
|
|
|
@@ -782,24 +815,13 @@ When *true*, the gradient will be split between both channels, so each channel w
|
|
|
782
815
|
|:--:|:--:|
|
|
783
816
|
|  |  |
|
|
784
817
|
|
|
785
|
-
This option has no effect on horizontal gradients, or when [`
|
|
818
|
+
This option has no effect on horizontal gradients (except in [`radial`](#radial-boolean) visualization - see note in [`registerGradient()`](#registergradient-name-options-)), or when [`channelLayout`](#channellayout-string) is set to *'single'* or *'dualCombined'*.
|
|
786
819
|
|
|
787
820
|
Defaults to **false**.
|
|
788
821
|
|
|
789
|
-
### `stereo` *boolean*
|
|
822
|
+
### `stereo` **(DEPRECATED)** *boolean*
|
|
790
823
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
When *true*, the spectrum analyzer will display separate graphs for the left and right audio channels.
|
|
794
|
-
|
|
795
|
-
Notes:
|
|
796
|
-
- Stereo tracks will always output stereo audio, even if `stereo` is set to *false* (in such case the analyzer graph will represent both channels combined);
|
|
797
|
-
- Mono (single channel) tracks will output audio only on the left channel when `stereo` is *true*, unless you have another stereo source simultaneously
|
|
798
|
-
connected to the analyzer, which will force the mono source to be upmixed to stereo.
|
|
799
|
-
|
|
800
|
-
See also [`splitGradient`](#splitgradient-boolean).
|
|
801
|
-
|
|
802
|
-
Defaults to **false**.
|
|
824
|
+
**This property will be removed in version 5** - Use [`channelLayout`](#channellayout-string) instead.
|
|
803
825
|
|
|
804
826
|
### `useCanvas` *boolean*
|
|
805
827
|
|
|
@@ -1010,7 +1032,7 @@ Returns an array with current data for each analyzer bar. Each array element is
|
|
|
1010
1032
|
|
|
1011
1033
|
`hold` values are integers and indicate the hold time (in frames) for the current peak. The maximum value is 30 and means the peak has just been set, while negative values mean the peak is currently falling down.
|
|
1012
1034
|
|
|
1013
|
-
Please note that `hold` and `value` will have only one element when [`
|
|
1035
|
+
Please note that `hold` and `value` will have only one element when [`channelLayout`](#channellayout-string) is set to *'single'*, but `peak` is always a two-element array.
|
|
1014
1036
|
|
|
1015
1037
|
You can use this method to create your own visualizations using the analyzer data. See [this pen](https://codepen.io/hvianna/pen/ZEKWWJb) for usage example.
|
|
1016
1038
|
|
|
@@ -1043,31 +1065,25 @@ Use this method inside your callback function to create additional visual effect
|
|
|
1043
1065
|
|
|
1044
1066
|
Registers a custom color gradient.
|
|
1045
1067
|
|
|
1046
|
-
`name` must be a non-empty
|
|
1068
|
+
`name` must be a non-empty string that will be used to select this gradient, via the [`gradient`](#gradient-string) property.
|
|
1069
|
+
|
|
1047
1070
|
`options` must be an object as shown below:
|
|
1048
1071
|
|
|
1049
1072
|
```js
|
|
1050
1073
|
const options = {
|
|
1051
1074
|
bgColor: '#011a35', // background color (optional) - defaults to '#111'
|
|
1052
1075
|
dir: 'h', // add this property to create a horizontal gradient (optional)
|
|
1053
|
-
colorStops: [ // list your gradient colors in this array (at least
|
|
1076
|
+
colorStops: [ // list your gradient colors in this array (at least one color is required)
|
|
1054
1077
|
'red', // colors may be defined in any valid CSS format
|
|
1055
1078
|
{ pos: .6, color: '#ff0' }, // use an object to adjust the offset (0 to 1) of a colorStop
|
|
1056
|
-
'hsl( 120, 100%, 50% )'
|
|
1079
|
+
'hsl( 120, 100%, 50% )'
|
|
1057
1080
|
]
|
|
1058
1081
|
}
|
|
1059
1082
|
|
|
1060
1083
|
audioMotion.registerGradient( 'myGradient', options );
|
|
1061
1084
|
```
|
|
1062
1085
|
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
```js
|
|
1066
|
-
import AudioMotionAnalyzer, { GradientOptions } from 'audiomotion-analyzer'
|
|
1067
|
-
|
|
1068
|
-
const options: GradientOptions = {
|
|
1069
|
-
⋮
|
|
1070
|
-
```
|
|
1086
|
+
?> During [`radial`](#radial-boolean) visualization all gradients are rendered in radial direction, so the horizontal flag (`dir: 'h'`) has no effect.
|
|
1071
1087
|
|
|
1072
1088
|
Additional information about [gradient color-stops](https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient/addColorStop).
|
|
1073
1089
|
|
|
@@ -1264,11 +1280,15 @@ document.getElementById('stop').addEventListener( 'click', () => myAudio.pause()
|
|
|
1264
1280
|
See [Changelog.md](Changelog.md)
|
|
1265
1281
|
|
|
1266
1282
|
|
|
1267
|
-
##
|
|
1283
|
+
## Contributing
|
|
1284
|
+
|
|
1285
|
+
If you want to send feedback, ask a question, or need help with something, please use the [**Discussions**](https://github.com/hvianna/audioMotion-analyzer/discussions) area on GitHub.
|
|
1286
|
+
|
|
1287
|
+
I would love to see your cool projects using **audioMotion-analyzer** -- post them in the *Show and tell* section of [Discussions](https://github.com/hvianna/audioMotion-analyzer/discussions)!
|
|
1268
1288
|
|
|
1269
|
-
|
|
1289
|
+
For **bug reports** and **feature requests**, feel free to [open an issue](https://github.com/hvianna/audioMotion-analyzer/issues).
|
|
1270
1290
|
|
|
1271
|
-
|
|
1291
|
+
If you want to submit a **Pull Request**, please branch it off the project's `develop` branch.
|
|
1272
1292
|
|
|
1273
1293
|
And if you're feeling generous, maybe:
|
|
1274
1294
|
|
|
@@ -1279,5 +1299,5 @@ And if you're feeling generous, maybe:
|
|
|
1279
1299
|
|
|
1280
1300
|
## License
|
|
1281
1301
|
|
|
1282
|
-
audioMotion-analyzer copyright (c) 2018-
|
|
1302
|
+
audioMotion-analyzer copyright (c) 2018-2023 [Henrique Avila Vianna](https://henriquevianna.com)<br>
|
|
1283
1303
|
Licensed under the [GNU Affero General Public License, version 3 or later](https://www.gnu.org/licenses/agpl.html).
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "audiomotion-analyzer",
|
|
3
3
|
"description": "High-resolution real-time graphic audio spectrum analyzer JavaScript module with no dependencies.",
|
|
4
|
-
"version": "4.0.0-beta.
|
|
4
|
+
"version": "4.0.0-beta.4",
|
|
5
5
|
"main": "./src/audioMotion-analyzer.js",
|
|
6
6
|
"module": "./src/audioMotion-analyzer.js",
|
|
7
7
|
"types": "./src/index.d.ts",
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* audioMotion-analyzer
|
|
3
3
|
* High-resolution real-time graphic audio spectrum analyzer JS module
|
|
4
4
|
*
|
|
5
|
-
* @version 4.0.0-beta.
|
|
5
|
+
* @version 4.0.0-beta.4
|
|
6
6
|
* @author Henrique Avila Vianna <hvianna@gmail.com> <https://henriquevianna.com>
|
|
7
7
|
* @license AGPL-3.0-or-later
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
const VERSION = '4.0.0-beta.
|
|
10
|
+
const VERSION = '4.0.0-beta.4';
|
|
11
11
|
|
|
12
12
|
// internal constants
|
|
13
13
|
const TAU = 2 * Math.PI,
|
|
@@ -16,6 +16,9 @@ const TAU = 2 * Math.PI,
|
|
|
16
16
|
C_1 = 8.17579892; // frequency for C -1
|
|
17
17
|
|
|
18
18
|
const CANVAS_BACKGROUND_COLOR = '#000',
|
|
19
|
+
CHANNEL_COMBINED = 'dualCombined',
|
|
20
|
+
CHANNEL_SINGLE = 'single',
|
|
21
|
+
CHANNEL_VERTICAL = 'dualVertical',
|
|
19
22
|
GRADIENT_DEFAULT_BGCOLOR = '#111',
|
|
20
23
|
FILTER_NONE = '',
|
|
21
24
|
FILTER_A = 'A',
|
|
@@ -54,7 +57,7 @@ const ERR_AUDIO_CONTEXT_FAIL = [ 'ERR_AUDIO_CONTEXT_FAIL', 'Could not create
|
|
|
54
57
|
ERR_INVALID_AUDIO_SOURCE = [ 'ERR_INVALID_AUDIO_SOURCE', 'Audio source must be an instance of HTMLMediaElement or AudioNode' ],
|
|
55
58
|
ERR_GRADIENT_INVALID_NAME = [ 'ERR_GRADIENT_INVALID_NAME', 'Gradient name must be a non-empty string' ],
|
|
56
59
|
ERR_GRADIENT_NOT_AN_OBJECT = [ 'ERR_GRADIENT_NOT_AN_OBJECT', 'Gradient options must be an object' ],
|
|
57
|
-
ERR_GRADIENT_MISSING_COLOR = [ 'ERR_GRADIENT_MISSING_COLOR', 'Gradient must
|
|
60
|
+
ERR_GRADIENT_MISSING_COLOR = [ 'ERR_GRADIENT_MISSING_COLOR', 'Gradient colorStops must be a non-empty array' ];
|
|
58
61
|
|
|
59
62
|
class AudioMotionError extends Error {
|
|
60
63
|
constructor( error, value ) {
|
|
@@ -65,6 +68,9 @@ class AudioMotionError extends Error {
|
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
// helper function
|
|
72
|
+
const deprecate = ( name, alternative ) => console.warn( `${name} is deprecated. Use ${alternative} instead.` );
|
|
73
|
+
|
|
68
74
|
// AudioMotionAnalyzer class
|
|
69
75
|
|
|
70
76
|
export default class AudioMotionAnalyzer {
|
|
@@ -80,8 +86,10 @@ export default class AudioMotionAnalyzer {
|
|
|
80
86
|
|
|
81
87
|
this._ready = false;
|
|
82
88
|
|
|
83
|
-
// Initialize internal
|
|
84
|
-
this._gradients = {};
|
|
89
|
+
// Initialize internal gradient objects
|
|
90
|
+
this._gradients = {}; // registered gradients
|
|
91
|
+
this._gradientNames = []; // names of the currently selected gradients for channels 0 and 1
|
|
92
|
+
this._canvasGradients = []; // actual CanvasGradient objects for channels 0 and 1
|
|
85
93
|
|
|
86
94
|
// Register built-in gradients
|
|
87
95
|
this.registerGradient( GRADIENT_CLASSIC, {
|
|
@@ -147,13 +155,13 @@ export default class AudioMotionAnalyzer {
|
|
|
147
155
|
Connection routing:
|
|
148
156
|
===================
|
|
149
157
|
|
|
150
|
-
for
|
|
158
|
+
for dual channel modes: +---> analyzer[0] ---+
|
|
151
159
|
| |
|
|
152
160
|
(source) ---> input ---> splitter ---+ +---> merger ---> output ---> (destination)
|
|
153
161
|
| |
|
|
154
162
|
+---> analyzer[1] ---+
|
|
155
163
|
|
|
156
|
-
for
|
|
164
|
+
for single channel mode:
|
|
157
165
|
|
|
158
166
|
(source) ---> input -----------------------> analyzer[0] ---------------------> output ---> (destination)
|
|
159
167
|
|
|
@@ -303,6 +311,27 @@ export default class AudioMotionAnalyzer {
|
|
|
303
311
|
this._calcAux();
|
|
304
312
|
}
|
|
305
313
|
|
|
314
|
+
get channelLayout() {
|
|
315
|
+
return this._chLayout;
|
|
316
|
+
}
|
|
317
|
+
set channelLayout( value ) {
|
|
318
|
+
const MODES = [ CHANNEL_SINGLE, CHANNEL_VERTICAL, CHANNEL_COMBINED ];
|
|
319
|
+
this._chLayout = MODES[ Math.max( 0, MODES.findIndex( el => el.toLowerCase() == ( '' + value ).toLowerCase() ) ) ];
|
|
320
|
+
|
|
321
|
+
// update node connections
|
|
322
|
+
this._input.disconnect();
|
|
323
|
+
this._input.connect( this._chLayout != CHANNEL_SINGLE ? this._splitter : this._analyzer[0] );
|
|
324
|
+
this._analyzer[0].disconnect();
|
|
325
|
+
if ( this._outNodes.length ) // connect analyzer only if the output is connected to other nodes
|
|
326
|
+
this._analyzer[0].connect( this._chLayout != CHANNEL_SINGLE ? this._merger : this._output );
|
|
327
|
+
|
|
328
|
+
// update properties affected by channel layout
|
|
329
|
+
this._calcAux();
|
|
330
|
+
this._createScales();
|
|
331
|
+
this._calcLeds();
|
|
332
|
+
this._makeGrad();
|
|
333
|
+
}
|
|
334
|
+
|
|
306
335
|
get fftSize() {
|
|
307
336
|
return this._analyzer[0].fftSize;
|
|
308
337
|
}
|
|
@@ -325,14 +354,24 @@ export default class AudioMotionAnalyzer {
|
|
|
325
354
|
}
|
|
326
355
|
|
|
327
356
|
get gradient() {
|
|
328
|
-
return this.
|
|
357
|
+
return this._gradientNames[0];
|
|
329
358
|
}
|
|
330
359
|
set gradient( value ) {
|
|
331
|
-
|
|
332
|
-
|
|
360
|
+
this._setGradient( value );
|
|
361
|
+
}
|
|
333
362
|
|
|
334
|
-
|
|
335
|
-
this.
|
|
363
|
+
get gradientLeft() {
|
|
364
|
+
return this._gradientNames[0];
|
|
365
|
+
}
|
|
366
|
+
set gradientLeft( value ) {
|
|
367
|
+
this._setGradient( value, 0 );
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
get gradientRight() {
|
|
371
|
+
return this._gradientNames[1];
|
|
372
|
+
}
|
|
373
|
+
set gradientRight( value ) {
|
|
374
|
+
this._setGradient( value, 1 );
|
|
336
375
|
}
|
|
337
376
|
|
|
338
377
|
get height() {
|
|
@@ -516,23 +555,12 @@ export default class AudioMotionAnalyzer {
|
|
|
516
555
|
}
|
|
517
556
|
|
|
518
557
|
get stereo() {
|
|
519
|
-
|
|
558
|
+
deprecate( 'stereo', 'channelLayout' );
|
|
559
|
+
return this._chLayout != CHANNEL_SINGLE;
|
|
520
560
|
}
|
|
521
561
|
set stereo( value ) {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
// update node connections
|
|
525
|
-
this._input.disconnect();
|
|
526
|
-
this._input.connect( this._stereo ? this._splitter : this._analyzer[0] );
|
|
527
|
-
this._analyzer[0].disconnect();
|
|
528
|
-
if ( this._outNodes.length ) // connect analyzer only if the output is connected to other nodes
|
|
529
|
-
this._analyzer[0].connect( this._stereo ? this._merger : this._output );
|
|
530
|
-
|
|
531
|
-
// update properties affected by stereo
|
|
532
|
-
this._calcAux();
|
|
533
|
-
this._createScales();
|
|
534
|
-
this._calcLeds();
|
|
535
|
-
this._makeGrad();
|
|
562
|
+
deprecate( 'stereo', 'channelLayout' );
|
|
563
|
+
this.channelLayout = value ? CHANNEL_VERTICAL : CHANNEL_SINGLE;
|
|
536
564
|
}
|
|
537
565
|
|
|
538
566
|
get volume() {
|
|
@@ -661,7 +689,7 @@ export default class AudioMotionAnalyzer {
|
|
|
661
689
|
// when connecting the first node, also connect the analyzer nodes to the merger / output nodes
|
|
662
690
|
if ( this._outNodes.length == 1 ) {
|
|
663
691
|
for ( const i of [0,1] )
|
|
664
|
-
this._analyzer[ i ].connect( (
|
|
692
|
+
this._analyzer[ i ].connect( ( this._chLayout == CHANNEL_SINGLE && ! i ? this._output : this._merger ), 0, i );
|
|
665
693
|
}
|
|
666
694
|
}
|
|
667
695
|
|
|
@@ -746,7 +774,7 @@ export default class AudioMotionAnalyzer {
|
|
|
746
774
|
|
|
747
775
|
const startBin = this._freqToBin( startFreq ),
|
|
748
776
|
endBin = endFreq ? this._freqToBin( endFreq ) : startBin,
|
|
749
|
-
chnCount = this.
|
|
777
|
+
chnCount = this._chLayout == CHANNEL_SINGLE ? 1 : 2;
|
|
750
778
|
|
|
751
779
|
let energy = 0;
|
|
752
780
|
for ( let channel = 0; channel < chnCount; channel++ ) {
|
|
@@ -770,7 +798,7 @@ export default class AudioMotionAnalyzer {
|
|
|
770
798
|
if ( typeof options !== 'object' )
|
|
771
799
|
throw new AudioMotionError( ERR_GRADIENT_NOT_AN_OBJECT );
|
|
772
800
|
|
|
773
|
-
if ( options.colorStops
|
|
801
|
+
if ( ! Array.isArray( options.colorStops ) || ! options.colorStops.length )
|
|
774
802
|
throw new AudioMotionError( ERR_GRADIENT_MISSING_COLOR );
|
|
775
803
|
|
|
776
804
|
this._gradients[ name ] = {
|
|
@@ -779,8 +807,8 @@ export default class AudioMotionAnalyzer {
|
|
|
779
807
|
colorStops: options.colorStops
|
|
780
808
|
};
|
|
781
809
|
|
|
782
|
-
// if the registered gradient is the
|
|
783
|
-
if (
|
|
810
|
+
// if the registered gradient is one of the currently selected gradients, regenerate them
|
|
811
|
+
if ( this._gradientNames.includes( name ) )
|
|
784
812
|
this._makeGrad();
|
|
785
813
|
}
|
|
786
814
|
|
|
@@ -918,10 +946,10 @@ export default class AudioMotionAnalyzer {
|
|
|
918
946
|
_calcAux() {
|
|
919
947
|
const canvas = this.canvas,
|
|
920
948
|
isRadial = this._radial,
|
|
921
|
-
isDual = this.
|
|
949
|
+
isDual = this._chLayout == CHANNEL_VERTICAL && ! isRadial,
|
|
922
950
|
centerX = canvas.width >> 1;
|
|
923
951
|
|
|
924
|
-
this._radius = Math.min( canvas.width, canvas.height ) * ( this.
|
|
952
|
+
this._radius = Math.min( canvas.width, canvas.height ) * ( this._chLayout == CHANNEL_VERTICAL ? .375 : .125 ) | 0;
|
|
925
953
|
this._barSpacePx = Math.min( this._barWidth - 1, ( this._barSpace > 0 && this._barSpace < 1 ) ? this._barWidth * this._barSpace : this._barSpace );
|
|
926
954
|
this._isBandsMode = this._mode % 10 != 0;
|
|
927
955
|
this._isOctaveBands = this._isBandsMode && this._frequencyScale == SCALE_LOG;
|
|
@@ -929,7 +957,7 @@ export default class AudioMotionAnalyzer {
|
|
|
929
957
|
this._isLumiBars = this._lumiBars && this._isBandsMode && ! isRadial;
|
|
930
958
|
this._isAlphaBars = this._alphaBars && ! this._isLumiBars && this._mode != 10;
|
|
931
959
|
this._isOutline = this._outlineBars && this._isBandsMode && ! this._isLumiBars && ! this._isLedDisplay;
|
|
932
|
-
this._maximizeLeds =
|
|
960
|
+
this._maximizeLeds = this._chLayout != CHANNEL_VERTICAL || this._reflexRatio > 0 && ! this._isLumiBars;
|
|
933
961
|
|
|
934
962
|
this._channelHeight = canvas.height - ( isDual && ! this._isLedDisplay ? .5 : 0 ) >> isDual;
|
|
935
963
|
this._analyzerHeight = this._channelHeight * ( this._isLumiBars || isRadial ? 1 : 1 - this._reflexRatio ) | 0;
|
|
@@ -1221,7 +1249,7 @@ export default class AudioMotionAnalyzer {
|
|
|
1221
1249
|
freqLabels = [],
|
|
1222
1250
|
frequencyScale= this._frequencyScale,
|
|
1223
1251
|
initialX = this._initialX,
|
|
1224
|
-
|
|
1252
|
+
isDual = this._chLayout == CHANNEL_VERTICAL,
|
|
1225
1253
|
isMirror = this._mirror,
|
|
1226
1254
|
isNoteLabels = this._noteLabels,
|
|
1227
1255
|
scale = [ 'C',, 'D',, 'E', 'F',, 'G',, 'A',, 'B' ], // for note labels (no sharp notes)
|
|
@@ -1253,14 +1281,14 @@ export default class AudioMotionAnalyzer {
|
|
|
1253
1281
|
}
|
|
1254
1282
|
|
|
1255
1283
|
// in radial stereo mode, the scale is positioned exactly between both channels, by making the canvas a bit larger than the inner diameter
|
|
1256
|
-
canvasR.width = canvasR.height = ( this._radius << 1 ) + (
|
|
1284
|
+
canvasR.width = canvasR.height = ( this._radius << 1 ) + ( isDual * scaleHeight );
|
|
1257
1285
|
|
|
1258
1286
|
const radius = canvasR.width >> 1, // this is also used as the center X and Y coordinates of the circular scale canvas
|
|
1259
1287
|
radialY = radius - scaleHeight * .7; // vertical position of text labels in the circular scale
|
|
1260
1288
|
|
|
1261
1289
|
// helper function
|
|
1262
1290
|
const radialLabel = ( x, label ) => {
|
|
1263
|
-
if ( isNoteLabels && !
|
|
1291
|
+
if ( isNoteLabels && ! isDual && ! ['C','E','G'].includes( label[0] ) )
|
|
1264
1292
|
return;
|
|
1265
1293
|
|
|
1266
1294
|
const angle = TAU * ( x / canvas.width ),
|
|
@@ -1338,7 +1366,7 @@ export default class AudioMotionAnalyzer {
|
|
|
1338
1366
|
isBandsMode = this._isBandsMode,
|
|
1339
1367
|
isOutline = this._isOutline,
|
|
1340
1368
|
isRadial = this._radial,
|
|
1341
|
-
|
|
1369
|
+
channelLayout = this._chLayout,
|
|
1342
1370
|
lineWidth = +this.lineWidth, // make sure the damn thing is a number!
|
|
1343
1371
|
mirrorMode = this._mirror,
|
|
1344
1372
|
channelHeight = this._channelHeight,
|
|
@@ -1434,7 +1462,7 @@ export default class AudioMotionAnalyzer {
|
|
|
1434
1462
|
const ledPosY = height => Math.max( 0, ( height * ledCount | 0 ) * ( ledHeight + ledSpaceV ) - ledSpaceV );
|
|
1435
1463
|
|
|
1436
1464
|
// select background color
|
|
1437
|
-
const bgColor = ( ! this.showBgColor || isLedDisplay && ! this.overlay ) ? '#000' : this._gradients[ this.
|
|
1465
|
+
const bgColor = ( ! this.showBgColor || isLedDisplay && ! this.overlay ) ? '#000' : this._gradients[ this._gradientNames[0] ].bgColor;
|
|
1438
1466
|
|
|
1439
1467
|
// compute the effective bar width, considering the selected bar spacing
|
|
1440
1468
|
// if led effect is active, ensure at least the spacing from led definitions
|
|
@@ -1446,18 +1474,19 @@ export default class AudioMotionAnalyzer {
|
|
|
1446
1474
|
|
|
1447
1475
|
let currentEnergy = 0;
|
|
1448
1476
|
|
|
1449
|
-
const nBars
|
|
1477
|
+
const nBars = this._bars.length,
|
|
1478
|
+
nChannels = channelLayout == CHANNEL_SINGLE ? 1 : 2;
|
|
1450
1479
|
|
|
1451
|
-
for ( let channel = 0; channel <
|
|
1480
|
+
for ( let channel = 0; channel < nChannels; channel++ ) {
|
|
1452
1481
|
|
|
1453
|
-
const channelTop = channelHeight * channel + channelGap * channel,
|
|
1482
|
+
const channelTop = channelLayout == CHANNEL_VERTICAL ? channelHeight * channel + channelGap * channel : 0,
|
|
1454
1483
|
channelBottom = channelTop + channelHeight,
|
|
1455
1484
|
analyzerBottom = channelTop + analyzerHeight - ( isLedDisplay && ! this._maximizeLeds ? ledSpaceV : 0 );
|
|
1456
1485
|
|
|
1457
1486
|
if ( useCanvas ) {
|
|
1458
1487
|
// clear the channel area, if in overlay mode
|
|
1459
1488
|
// this is done per channel to clear any residue below 0 off the top channel (especially in line graph mode with lineWidth > 1)
|
|
1460
|
-
if ( this.overlay )
|
|
1489
|
+
if ( this.overlay && ( ! isRadial || channel == 0 ) )
|
|
1461
1490
|
ctx.clearRect( 0, channelTop - channelGap, canvas.width, channelHeight + channelGap );
|
|
1462
1491
|
|
|
1463
1492
|
// fill the analyzer background if needed (not overlay or overlay + showBgColor)
|
|
@@ -1468,7 +1497,7 @@ export default class AudioMotionAnalyzer {
|
|
|
1468
1497
|
ctx.fillStyle = bgColor;
|
|
1469
1498
|
|
|
1470
1499
|
// exclude the reflection area when overlay is true and reflexAlpha == 1 (avoids alpha over alpha difference, in case bgAlpha < 1)
|
|
1471
|
-
if ( ! isRadial || channel == 0 )
|
|
1500
|
+
if ( ! isRadial && channelLayout != CHANNEL_COMBINED || channel == 0 )
|
|
1472
1501
|
ctx.fillRect( initialX, channelTop - channelGap, analyzerWidth, ( this.overlay && this.reflexAlpha == 1 ? analyzerHeight : channelHeight ) + channelGap );
|
|
1473
1502
|
|
|
1474
1503
|
ctx.globalAlpha = 1;
|
|
@@ -1527,7 +1556,7 @@ export default class AudioMotionAnalyzer {
|
|
|
1527
1556
|
ctx.lineWidth = isOutline ? Math.min( lineWidth, width / 2 ) : lineWidth;
|
|
1528
1557
|
|
|
1529
1558
|
// set selected gradient for fill and stroke
|
|
1530
|
-
ctx.fillStyle = ctx.strokeStyle = this.
|
|
1559
|
+
ctx.fillStyle = ctx.strokeStyle = this._canvasGradients[ channel ];
|
|
1531
1560
|
} // if ( useCanvas )
|
|
1532
1561
|
|
|
1533
1562
|
// get a new array of data from the FFT
|
|
@@ -1599,7 +1628,7 @@ export default class AudioMotionAnalyzer {
|
|
|
1599
1628
|
barHeight = isLedDisplay ? ledPosY( barHeight ) : barHeight * maxBarHeight | 0;
|
|
1600
1629
|
|
|
1601
1630
|
// invert bar for radial channel 1
|
|
1602
|
-
if ( isRadial && channel == 1 )
|
|
1631
|
+
if ( isRadial && channel == 1 && channelLayout == CHANNEL_VERTICAL )
|
|
1603
1632
|
barHeight *= -1;
|
|
1604
1633
|
|
|
1605
1634
|
// bar width may need small adjustments for some bars, when barSpace == 0
|
|
@@ -1611,7 +1640,7 @@ export default class AudioMotionAnalyzer {
|
|
|
1611
1640
|
if ( mode == 10 ) {
|
|
1612
1641
|
// compute the average between the initial bar (i==0) and the next one
|
|
1613
1642
|
// used to smooth the curve when the initial posX is off the screen, in mirror and radial modes
|
|
1614
|
-
const nextBarAvg = i ? 0 : ( this._normalizedB( fftData[ this._bars[1].binLo ] ) * maxBarHeight * (
|
|
1643
|
+
const nextBarAvg = i ? 0 : ( this._normalizedB( fftData[ this._bars[1].binLo ] ) * maxBarHeight * ( channel && isRadial && channelLayout == CHANNEL_VERTICAL ? -1 : 1 ) + barHeight ) / 2;
|
|
1615
1644
|
|
|
1616
1645
|
if ( isRadial ) {
|
|
1617
1646
|
if ( i == 0 )
|
|
@@ -1715,7 +1744,7 @@ export default class AudioMotionAnalyzer {
|
|
|
1715
1744
|
else if ( ! isRadial )
|
|
1716
1745
|
ctx.fillRect( posX, analyzerBottom - peak * maxBarHeight, adjWidth, 2 );
|
|
1717
1746
|
else if ( mode != 10 ) // radial - no peaks for mode 10
|
|
1718
|
-
radialPoly( posX, peak * maxBarHeight * (
|
|
1747
|
+
radialPoly( posX, peak * maxBarHeight * ( channel && channelLayout == CHANNEL_VERTICAL ? -1 : 1 ), adjWidth, -2 );
|
|
1719
1748
|
}
|
|
1720
1749
|
|
|
1721
1750
|
} // for ( let i = 0; i < nBars; i++ )
|
|
@@ -1761,8 +1790,8 @@ export default class AudioMotionAnalyzer {
|
|
|
1761
1790
|
// Reflex effect
|
|
1762
1791
|
if ( this._reflexRatio > 0 && ! isLumiBars ) {
|
|
1763
1792
|
let posY, height;
|
|
1764
|
-
if ( this.reflexFit ||
|
|
1765
|
-
posY =
|
|
1793
|
+
if ( this.reflexFit || channelLayout == CHANNEL_VERTICAL ) { // always fit reflex in vertical stereo mode
|
|
1794
|
+
posY = channelLayout == CHANNEL_VERTICAL && channel == 0 ? channelHeight + channelGap : 0;
|
|
1766
1795
|
height = channelHeight - analyzerHeight;
|
|
1767
1796
|
}
|
|
1768
1797
|
else {
|
|
@@ -1785,10 +1814,10 @@ export default class AudioMotionAnalyzer {
|
|
|
1785
1814
|
ctx.globalAlpha = 1;
|
|
1786
1815
|
}
|
|
1787
1816
|
|
|
1788
|
-
} // for ( let channel = 0; channel <
|
|
1817
|
+
} // for ( let channel = 0; channel < nChannels; channel++ ) {
|
|
1789
1818
|
|
|
1790
1819
|
// Update energy
|
|
1791
|
-
energy.val = currentEnergy / ( nBars <<
|
|
1820
|
+
energy.val = currentEnergy / ( nBars << ( nChannels - 1 ) );
|
|
1792
1821
|
if ( energy.val >= energy.peak ) {
|
|
1793
1822
|
energy.peak = energy.val;
|
|
1794
1823
|
energy.hold = 30;
|
|
@@ -1847,7 +1876,7 @@ export default class AudioMotionAnalyzer {
|
|
|
1847
1876
|
// call callback function, if defined
|
|
1848
1877
|
if ( this.onCanvasDraw ) {
|
|
1849
1878
|
ctx.save();
|
|
1850
|
-
ctx.fillStyle = ctx.strokeStyle = this.
|
|
1879
|
+
ctx.fillStyle = ctx.strokeStyle = this._canvasGradients[0];
|
|
1851
1880
|
this.onCanvasDraw( this );
|
|
1852
1881
|
ctx.restore();
|
|
1853
1882
|
}
|
|
@@ -1893,8 +1922,9 @@ export default class AudioMotionAnalyzer {
|
|
|
1893
1922
|
const ctx = this._canvasCtx,
|
|
1894
1923
|
canvas = ctx.canvas,
|
|
1895
1924
|
isLumiBars = this._isLumiBars,
|
|
1896
|
-
|
|
1897
|
-
|
|
1925
|
+
isRadial = this._radial,
|
|
1926
|
+
gradientHeight = isLumiBars ? canvas.height : canvas.height * ( 1 - this._reflexRatio * ( this._chLayout != CHANNEL_VERTICAL ) ) | 0,
|
|
1927
|
+
// for vertical stereo we keep the full canvas height and handle the reflex areas while generating the color stops
|
|
1898
1928
|
analyzerRatio = 1 - this._reflexRatio,
|
|
1899
1929
|
initialX = this._initialX;
|
|
1900
1930
|
|
|
@@ -1904,70 +1934,72 @@ export default class AudioMotionAnalyzer {
|
|
|
1904
1934
|
maxRadius = Math.min( centerX, centerY ),
|
|
1905
1935
|
radius = this._radius;
|
|
1906
1936
|
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
let grad;
|
|
1937
|
+
for ( let chn = 0; chn < 2; chn++ ) {
|
|
1938
|
+
const currGradient = this._gradients[ this._gradientNames[ chn ] ],
|
|
1939
|
+
colorStops = currGradient.colorStops,
|
|
1940
|
+
isHorizontal = currGradient.dir == 'h';
|
|
1912
1941
|
|
|
1913
|
-
|
|
1914
|
-
grad = ctx.createRadialGradient( centerX, centerY, maxRadius, centerX, centerY, radius - ( maxRadius - radius ) * this._stereo );
|
|
1915
|
-
else
|
|
1916
|
-
grad = ctx.createLinearGradient( ...( isHorizontal ? [ initialX, 0, initialX + this._analyzerWidth, 0 ] : [ 0, 0, 0, gradientHeight ] ) );
|
|
1942
|
+
let grad;
|
|
1917
1943
|
|
|
1918
|
-
|
|
1919
|
-
|
|
1944
|
+
if ( isRadial )
|
|
1945
|
+
grad = ctx.createRadialGradient( centerX, centerY, maxRadius, centerX, centerY, radius - ( maxRadius - radius ) * ( this._chLayout == CHANNEL_VERTICAL ) );
|
|
1946
|
+
else
|
|
1947
|
+
grad = ctx.createLinearGradient( ...( isHorizontal ? [ initialX, 0, initialX + this._analyzerWidth, 0 ] : [ 0, 0, 0, gradientHeight ] ) );
|
|
1920
1948
|
|
|
1921
|
-
|
|
1922
|
-
|
|
1949
|
+
if ( colorStops ) {
|
|
1950
|
+
const dual = this._chLayout == CHANNEL_VERTICAL && ! this._splitGradient && ( ! isHorizontal || isRadial );
|
|
1923
1951
|
|
|
1924
|
-
|
|
1925
|
-
|
|
1952
|
+
// helper function
|
|
1953
|
+
const addColorStop = ( offset, colorInfo ) => grad.addColorStop( offset, colorInfo.color || colorInfo );
|
|
1926
1954
|
|
|
1927
|
-
|
|
1955
|
+
for ( let channel = 0; channel < 1 + dual; channel++ ) {
|
|
1956
|
+
colorStops.forEach( ( colorInfo, index ) => {
|
|
1928
1957
|
|
|
1929
|
-
|
|
1958
|
+
const maxIndex = colorStops.length - 1;
|
|
1930
1959
|
|
|
1931
|
-
|
|
1932
|
-
if ( dual )
|
|
1933
|
-
offset /= 2;
|
|
1960
|
+
let offset = colorInfo.pos !== undefined ? colorInfo.pos : index / Math.max( 1, maxIndex );
|
|
1934
1961
|
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
// skip the first reflex area in split mode
|
|
1939
|
-
if ( ! dual && offset > .5 * analyzerRatio )
|
|
1940
|
-
offset += .5 * this._reflexRatio;
|
|
1941
|
-
}
|
|
1962
|
+
// in dual mode (not split), use half the original offset for each channel
|
|
1963
|
+
if ( dual )
|
|
1964
|
+
offset /= 2;
|
|
1942
1965
|
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
offset = 1 - ( colorInfo.pos !== undefined ? colorInfo.pos : revIndex / maxIndex ) / 2;
|
|
1966
|
+
// constrain the offset within the useful analyzer areas (avoid reflex areas)
|
|
1967
|
+
if ( this._chLayout == CHANNEL_VERTICAL && ! isLumiBars && ! isRadial && ! isHorizontal ) {
|
|
1968
|
+
offset *= analyzerRatio;
|
|
1969
|
+
// skip the first reflex area in split mode
|
|
1970
|
+
if ( ! dual && offset > .5 * analyzerRatio )
|
|
1971
|
+
offset += .5 * this._reflexRatio;
|
|
1950
1972
|
}
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1973
|
+
|
|
1974
|
+
// only for non-split gradient
|
|
1975
|
+
if ( channel == 1 ) {
|
|
1976
|
+
// add colors in reverse order if radial or lumi are active
|
|
1977
|
+
if ( isRadial || isLumiBars ) {
|
|
1978
|
+
const revIndex = maxIndex - index;
|
|
1979
|
+
colorInfo = colorStops[ revIndex ];
|
|
1980
|
+
offset = 1 - ( colorInfo.pos !== undefined ? colorInfo.pos : revIndex / Math.max( 1, maxIndex ) ) / 2;
|
|
1981
|
+
}
|
|
1982
|
+
else {
|
|
1983
|
+
// if the first offset is not 0, create an additional color stop to prevent bleeding from the first channel
|
|
1984
|
+
if ( index == 0 && offset > 0 )
|
|
1985
|
+
addColorStop( .5, colorInfo );
|
|
1986
|
+
// bump the offset to the second half of the gradient
|
|
1987
|
+
offset += .5;
|
|
1988
|
+
}
|
|
1957
1989
|
}
|
|
1958
|
-
}
|
|
1959
1990
|
|
|
1960
|
-
|
|
1961
|
-
|
|
1991
|
+
// add gradient color stop
|
|
1992
|
+
addColorStop( offset, colorInfo );
|
|
1962
1993
|
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1994
|
+
// create additional color stop at the end of first channel to prevent bleeding
|
|
1995
|
+
if ( this._chLayout == CHANNEL_VERTICAL && index == maxIndex && offset < .5 )
|
|
1996
|
+
addColorStop( .5, colorInfo );
|
|
1997
|
+
});
|
|
1998
|
+
}
|
|
1967
1999
|
}
|
|
1968
|
-
}
|
|
1969
2000
|
|
|
1970
|
-
|
|
2001
|
+
this._canvasGradients[ chn ] = grad;
|
|
2002
|
+
} // for (chn)
|
|
1971
2003
|
}
|
|
1972
2004
|
|
|
1973
2005
|
/**
|
|
@@ -2061,6 +2093,25 @@ export default class AudioMotionAnalyzer {
|
|
|
2061
2093
|
this.onCanvasResize( reason, this );
|
|
2062
2094
|
}
|
|
2063
2095
|
|
|
2096
|
+
/**
|
|
2097
|
+
* Select a gradient for one or both channels
|
|
2098
|
+
*
|
|
2099
|
+
* @param {string} name gradient name
|
|
2100
|
+
* @param [{number}] desired channel (0 or 1) - if empty or invalid, sets both channels
|
|
2101
|
+
*/
|
|
2102
|
+
_setGradient( name, channel ) {
|
|
2103
|
+
if ( ! this._gradients.hasOwnProperty( name ) )
|
|
2104
|
+
throw new AudioMotionError( ERR_UNKNOWN_GRADIENT, name );
|
|
2105
|
+
|
|
2106
|
+
if ( ! [0,1].includes( channel ) ) {
|
|
2107
|
+
this._gradientNames[1] = name;
|
|
2108
|
+
channel = 0;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
this._gradientNames[ channel ] = name;
|
|
2112
|
+
this._makeGrad();
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2064
2115
|
/**
|
|
2065
2116
|
* Set object properties
|
|
2066
2117
|
*/
|
|
@@ -2072,6 +2123,7 @@ export default class AudioMotionAnalyzer {
|
|
|
2072
2123
|
ansiBands : false,
|
|
2073
2124
|
barSpace : 0.1,
|
|
2074
2125
|
bgAlpha : 0.7,
|
|
2126
|
+
channelLayout : CHANNEL_SINGLE,
|
|
2075
2127
|
fftSize : 8192,
|
|
2076
2128
|
fillAlpha : 1,
|
|
2077
2129
|
frequencyScale : SCALE_LOG,
|
|
@@ -2105,7 +2157,6 @@ export default class AudioMotionAnalyzer {
|
|
|
2105
2157
|
spinSpeed : 0,
|
|
2106
2158
|
splitGradient : false,
|
|
2107
2159
|
start : true,
|
|
2108
|
-
stereo : false,
|
|
2109
2160
|
useCanvas : true,
|
|
2110
2161
|
volume : 1,
|
|
2111
2162
|
weightingFilter: FILTER_NONE
|
|
@@ -2114,8 +2165,11 @@ export default class AudioMotionAnalyzer {
|
|
|
2114
2165
|
// callback functions properties
|
|
2115
2166
|
const callbacks = [ 'onCanvasDraw', 'onCanvasResize' ];
|
|
2116
2167
|
|
|
2168
|
+
// properties undefined by default
|
|
2169
|
+
const defaultUndefined = [ 'gradientLeft', 'gradientRight', 'height', 'width', 'stereo' ];
|
|
2170
|
+
|
|
2117
2171
|
// build an array of valid properties; `start` is not an actual property and is handled after setting everything else
|
|
2118
|
-
const validProps = Object.keys( defaults ).filter( e => e != 'start' ).concat( callbacks,
|
|
2172
|
+
const validProps = Object.keys( defaults ).filter( e => e != 'start' ).concat( callbacks, defaultUndefined );
|
|
2119
2173
|
|
|
2120
2174
|
if ( useDefaults || options === undefined )
|
|
2121
2175
|
options = { ...defaults, ...options }; // merge options with defaults
|
package/src/index.d.ts
CHANGED
|
@@ -11,10 +11,13 @@ export interface Options {
|
|
|
11
11
|
ansiBands?: boolean;
|
|
12
12
|
barSpace?: number;
|
|
13
13
|
bgAlpha?: number;
|
|
14
|
+
channelLayout?: ChannelLayout;
|
|
14
15
|
fftSize?: number;
|
|
15
16
|
fillAlpha?: number;
|
|
16
17
|
frequencyScale?: FrequencyScale;
|
|
17
18
|
gradient?: string;
|
|
19
|
+
gradientLeft?: string;
|
|
20
|
+
gradientRight?: string;
|
|
18
21
|
height?: number;
|
|
19
22
|
ledBars?: boolean;
|
|
20
23
|
linearAmplitude?: boolean;
|
|
@@ -71,6 +74,8 @@ export interface ConstructorOptions extends Options {
|
|
|
71
74
|
source?: HTMLMediaElement | AudioNode;
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
export type ChannelLayout = "single" | "dualVertical" | "dualCombined";
|
|
78
|
+
|
|
74
79
|
export type EnergyPreset = "peak" | "bass" | "lowMid" | "mid" | "highMid" | "treble";
|
|
75
80
|
|
|
76
81
|
export type FrequencyScale = "bark" | "linear" | "log" | "mel";
|
|
@@ -79,15 +84,10 @@ export type GradientColorStop = string | { pos: number; color: string };
|
|
|
79
84
|
|
|
80
85
|
export type WeightingFilter = "" | "A" | "B" | "C" | "D" | "468";
|
|
81
86
|
|
|
82
|
-
type ArrayTwoOrMore<T> = {
|
|
83
|
-
0: T
|
|
84
|
-
1: T
|
|
85
|
-
} & Array<T>;
|
|
86
|
-
|
|
87
87
|
export interface GradientOptions {
|
|
88
88
|
bgColor: string;
|
|
89
89
|
dir?: "h";
|
|
90
|
-
colorStops:
|
|
90
|
+
colorStops: GradientColorStop[];
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
export interface LedParameters {
|
|
@@ -114,6 +114,9 @@ declare class AudioMotionAnalyzer {
|
|
|
114
114
|
|
|
115
115
|
public bgAlpha: number;
|
|
116
116
|
|
|
117
|
+
get channelLayout(): ChannelLayout;
|
|
118
|
+
set channelLayout(value: ChannelLayout);
|
|
119
|
+
|
|
117
120
|
get connectedSources(): AudioNode[];
|
|
118
121
|
get connectedTo(): AudioNode[];
|
|
119
122
|
|
|
@@ -133,6 +136,12 @@ declare class AudioMotionAnalyzer {
|
|
|
133
136
|
get gradient(): string;
|
|
134
137
|
set gradient(value: string);
|
|
135
138
|
|
|
139
|
+
get gradientLeft(): string;
|
|
140
|
+
set gradientLeft(value: string);
|
|
141
|
+
|
|
142
|
+
get gradientRight(): string;
|
|
143
|
+
set gradientRight(value: string);
|
|
144
|
+
|
|
136
145
|
get height(): number;
|
|
137
146
|
set height(h: number);
|
|
138
147
|
|