Skip to content

Commit bc691c4

Browse files
committed
Adds documentation
1 parent f2ab6f9 commit bc691c4

34 files changed

+2248
-490
lines changed

.eslintrc.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
"parser": "@typescript-eslint/parser",
88
"parserOptions": { "project": ["./tsconfig.json"] },
99
"plugins": [
10-
"@typescript-eslint"
10+
"@typescript-eslint",
11+
"eslint-plugin-tsdoc"
1112
],
1213
"rules": {
1314
"indent": ["error", 2, { "SwitchCase": 1 }],
1415
"semi": ["error", "always"],
15-
"lines-between-class-members": ["error", "always"]
16+
"lines-between-class-members": ["error", "always"],
17+
"tsdoc/syntax": "warn"
1618
},
1719
"ignorePatterns": [
1820
"rollup.config.js",

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.DS_Store
22
node_modules
3-
coverage
3+
coverage
4+
.vscode

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"console": "integratedTerminal",
88
"internalConsoleOptions": "neverOpen",
99
"disableOptimisticBPs": true,
10-
"program": "${workspaceFolder}/jest",
10+
"program": "${workspaceFolder}",
1111
"cwd": "${workspaceFolder}",
1212
"args": [
1313
"--runInBand",

README.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
1-
# Advanced Analyser Node
2-
3-
Advanced Analyser Node aims to be an enhanced version of the native Analyser Node. Both Audio nodes provide real-time frequency and time-domain analysis information.
4-
5-
## Why this exists?
6-
The native Analyser Node offers two primary features: Request frequency data (`.getFloatFrequencyData|.getByteFrequencyData`) and time-domain data (`.getFloatTimeDomainData|.getByteTimeDomainData`). The main problem is that the Analyser Node only gives you the data at the time of the request, meaning that when you request for the frequency data, the node will apply the Fast Fourier Transform to the last n audio samples (n is the fftSize property), or in the case of time-domain data, the last n audio samples.
1+
[![view on npm](https://badgen.net/npm/v/jsdoc-to-markdown)](https://www.npmjs.org/package/jsdoc-to-markdown)
72

8-
That's good enough if you are creating an audio visualization of the data currently being played, as the usual approach is to create a loop that requests and draws the data every frame (and if you're doing that, you should probably stick to the native Analyser Node as it will give you better performance).
3+
# Advanced Analyser Node
94

10-
The problem happens when you need to display the data **over time** (ex: Spectrograms, the waveform of the whole track). As the native Analyser Node gives you the data at the request time, it's impossible to guarantee that all requests will be evenly spaced in time. That means you will have inconsistent data overlaps or even skip some samples altogether. Depending on your goal, overlapping or skipping samples are not a problem per se; the issue is the inconsistency as the interval between samples will be completely based on your loop FPS.
5+
Advanced Analyser Node aims to be an enhanced version of the native Analyser Node. It provides real-time frequency and time-domain analysis information.
116

12-
The Advanced Analyser Node provides all the native version features (with a slightly different API), but also gives you the option of registering events that will be consistently triggered based on its configuration. For advanced users, you also have the option of choosing between different window functions.
137

14-
## Installation
8+
## Getting started
159

1610
Using npm:
1711
```bash
@@ -22,7 +16,6 @@ Using yarn:
2216
yarn add --dev advanced-analyser-node
2317
```
2418

25-
2619
## Usage
2720

2821
```javascript
@@ -60,9 +53,18 @@ init();
6053
const data = await analyserNode.getByteFrequencyData() // Differently from the native implementation, the request methods are asynchronous, and do not take an array as parameter
6154
```
6255

63-
6456
## Documentation
57+
[You can find the documentation here](docs/DOC.md).
58+
59+
60+
## Why this exists?
61+
The native Analyser Node offers two primary features: Request frequency data (`.getFloatFrequencyData|.getByteFrequencyData`) and time-domain data (`.getFloatTimeDomainData|.getByteTimeDomainData`). The main problem is that the Analyser Node only gives you the data at the time of the request, meaning that when you request for the frequency data, the node will apply the Fast Fourier Transform to the last n audio samples (n is the fftSize property), or in the case of time-domain data, the last n audio samples.
6562

63+
That's good enough if you are creating an audio visualization of the data currently being played, as the usual approach is to create a loop that requests and draws the data every frame (and if you're doing that, you should probably stick to the native Analyser Node as it will give you better performance).
64+
65+
The problem happens when you need to display the data **over time** (ex: Spectrograms, the waveform of the whole track). As the native Analyser Node gives you the data at the request time, it's impossible to guarantee that all requests will be evenly spaced in time. That means you will have inconsistent data overlaps or even skip some samples altogether. Depending on your goal, overlapping or skipping samples are not a problem per se; the issue is the inconsistency as the interval between samples will be completely based on your loop FPS.
66+
67+
The Advanced Analyser Node provides all the native version features (with a slightly different API), but also gives you the option of registering events that will be consistently triggered based on its configuration. For advanced users, you also have the option of choosing between different window functions.
6668

6769
## Caveats
6870

demo/demo1.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
const [floatFrequencyButton, byteFrequencyButton, floatTimeDomainButton, byteTimeDomainButton] = document.querySelectorAll('button')
3333

34-
const stream = await navigator.mediaDevices.getUserMedia({
34+
const stream = await navigator.mediaDevices.getUserMedia({
3535
audio: true,
3636
video: false
3737
})
@@ -44,6 +44,7 @@
4444
snapshotCanvas.width = 1024
4545

4646
const context = new AudioContext({ sampleRate: SAMPLE_RATE })
47+
4748
const nativeAnalyserNode = context.createAnalyser()
4849
const audioSource = context.createMediaStreamSource(stream);
4950

dist/bundle.js

Lines changed: 168 additions & 41 deletions
Large diffs are not rendered by default.

dist/bundle.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/processor.worklet.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/src/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './node';
2+
export { WindowFunctionTypes, AdvancedAnalyserNodeProperties, EventListenerTypes, } from './types';
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { AdvancedAnalyserNodeProperties, EventListenerTypes, Listener, WindowFunctionTypes } from "../types";
2+
/**
3+
* The Audio Node class. Do not instantiate this class directly.
4+
* Use the `createAdvancedAnalyserNode` method instead.
5+
*/
6+
export declare class AdvancedAnalyserNode extends AudioWorkletNode {
7+
private _portMapId;
8+
private _portMap;
9+
private _fftSize;
10+
private _samplesBetweenTransforms?;
11+
private _timeDomainSamplesCount?;
12+
private _windowFunction;
13+
private _minDecibels;
14+
private _maxDecibels;
15+
private _smoothingTimeConstant;
16+
readonly channelCount: number;
17+
readonly numberOfInputs: number;
18+
readonly numberOfOutputs: number;
19+
readonly channelCountMode: ChannelCountMode;
20+
readonly channelInterpretation: ChannelInterpretation;
21+
/**
22+
* The size of the FFT used for frequency-domain analysis (in sample-frames).
23+
* This MUST be a power of two in the range 32 to 32768. The default value is 2048.
24+
* Note that large FFT sizes can be costly to compute.
25+
*
26+
* @defaultValue 2048
27+
*/
28+
get fftSize(): number;
29+
set fftSize(value: number);
30+
set samplesBetweenTransforms(value: number);
31+
get samplesBetweenTransforms(): number;
32+
get frequencyBinCount(): number;
33+
set timeDomainSamplesCount(value: number);
34+
get timeDomainSamplesCount(): number;
35+
set windowFunction(value: WindowFunctionTypes);
36+
get windowFunction(): WindowFunctionTypes;
37+
/**
38+
* Represents the minimum power value in the scaling range for the FFT analysis data,
39+
* for conversion to unsigned byte values.
40+
* Basically, this specifies the minimum value for the range of results when using `getByteFrequencyData()`
41+
* or listening to the `bytefrequencydata` event, in which any frequencies with an amplitude of minDecibels
42+
* or lower will be returned as 0.
43+
*
44+
* An exception will be thrown if set to more than or equal to maxDecibels.
45+
* @defaultValue -100 dB
46+
*/
47+
get minDecibels(): number;
48+
set minDecibels(value: number);
49+
/**
50+
* Represents the maximum power value in the scaling range for the FFT analysis data,
51+
* for conversion to unsigned byte values.
52+
* Basically, this specifies the maximum value for the range of results when using `getByteFrequencyData()`
53+
* or listening to the `bytefrequencydata` event, in which any frequencies with an amplitude of maxDecibels
54+
* or higher will be returned as 255.
55+
*
56+
* An exception will be thrown if set to less than or equal to maxDecibels.
57+
* @defaultValue -30 dB
58+
*/
59+
get maxDecibels(): number;
60+
set maxDecibels(value: number);
61+
/**
62+
* Represents the averaging constant with the last analysis frame.
63+
* It's basically an average between the current buffer and the last buffer the AnalyserNode processed,
64+
* and results in a much smoother set of value changes over time.
65+
*
66+
* @defaultValue 0. No averaging is applied.
67+
*/
68+
get smoothingTimeConstant(): number;
69+
set smoothingTimeConstant(value: number);
70+
private _eventListenersCount;
71+
/**
72+
* The Audiio Node class. Do not instantiate this class directly.
73+
* Use the `createAdvancedAnalyserNode` method, which registers this Worklet before instantiating it
74+
*/
75+
constructor(context: BaseAudioContext, properties: AdvancedAnalyserNodeProperties);
76+
private _uniqId;
77+
private _postMessage;
78+
onprocessorerror: (err: Event) => void;
79+
private _onmessage;
80+
private _updateProcessorOptions;
81+
private _postIdentifiedDataRequest;
82+
getFloatFrequencyData(): Promise<Float32Array>;
83+
getByteFrequencyData(): Promise<Uint8Array>;
84+
getFloatTimeDomainData(): Promise<Float32Array>;
85+
getByteTimeDomainData(): Promise<Uint8Array>;
86+
private _pushEventListener;
87+
private _removeEventListener;
88+
addEventListener(type: EventListenerTypes.bytefrequencydata | EventListenerTypes.bytetimedomaindata, listener: Listener<Uint8Array>): void;
89+
addEventListener(type: EventListenerTypes.frequencydata | EventListenerTypes.timedomaindata, listener: Listener<Float32Array>): void;
90+
addEventListener(type: "processorerror", listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
91+
removeEventListener(type: "processorerror" | EventListenerTypes, listener: EventListenerOrEventListenerObject | Listener<ArrayBuffer>, options?: boolean | EventListenerOptions): void;
92+
}

0 commit comments

Comments
 (0)