loudness-worklet 1.4.2 → 1.5.0
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 +81 -24
- package/dist/index.d.ts +11 -2
- package/dist/index.js +64 -12
- package/package.json +22 -2
package/README.md
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# Loudness Audio Worklet Processor
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/loudness-worklet)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
A loudness meter for the `Web Audio API`, based on the [ITU-R BS.1770-5](https://www.itu.int/rec/R-REC-BS.1770) standard and implemented as an AudioWorkletProcessor.
|
|
4
7
|
|
|
5
8
|
[](https://lcweden.github.io/loudness-audio-worklet-processor/)
|
|
6
9
|
|
|
10
|
+
<p align="center"><a href="https://lcweden.github.io/loudness-audio-worklet-processor/">Demo</a></p>
|
|
11
|
+
|
|
7
12
|
## Features
|
|
8
13
|
|
|
9
14
|
- **Loudness Measurement**: Compliant with the **ITU-R BS.1770-5** standard.
|
|
@@ -13,6 +18,15 @@ A loudness meter for the `Web Audio API`, based on the [ITU-R BS.1770-5](https:/
|
|
|
13
18
|
|
|
14
19
|
## Installation
|
|
15
20
|
|
|
21
|
+
### CDN
|
|
22
|
+
|
|
23
|
+
Import directly in your code:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
const module = new URL("https://lcweden.github.io/loudness-audio-worklet-processor/loudness.worklet.js");
|
|
27
|
+
audioContext.audioWorklet.addModule(module);
|
|
28
|
+
```
|
|
29
|
+
|
|
16
30
|
### Download
|
|
17
31
|
|
|
18
32
|
1. Download the pre-built file: [loudness.worklet.js](https://lcweden.github.io/loudness-audio-worklet-processor/loudness.worklet.js).
|
|
@@ -22,13 +36,36 @@ A loudness meter for the `Web Audio API`, based on the [ITU-R BS.1770-5](https:/
|
|
|
22
36
|
audioContext.audioWorklet.addModule("loudness.worklet.js");
|
|
23
37
|
```
|
|
24
38
|
|
|
25
|
-
###
|
|
39
|
+
### NPM
|
|
26
40
|
|
|
27
|
-
|
|
41
|
+
Install via [npm](https://www.npmjs.com/package/loudness-worklet):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install loudness-worklet
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Use helper functions to create and load the worklet:
|
|
28
48
|
|
|
29
49
|
```javascript
|
|
30
|
-
|
|
31
|
-
|
|
50
|
+
import { createLoudnessWorklet, LoudnessWorkletNode } from "loudness-worklet";
|
|
51
|
+
|
|
52
|
+
const worklet = await createLoudnessWorklet(audioContext, {
|
|
53
|
+
processorOptions: {
|
|
54
|
+
interval: 0.1,
|
|
55
|
+
capacity: 600
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// or
|
|
60
|
+
|
|
61
|
+
await LoudnessWorkletNode.loadModule(audioContext);
|
|
62
|
+
|
|
63
|
+
const worklet = new LoudnessWorkletNode(audioContext, {
|
|
64
|
+
processorOptions: {
|
|
65
|
+
interval: 0.1,
|
|
66
|
+
capacity: 600
|
|
67
|
+
}
|
|
68
|
+
});
|
|
32
69
|
```
|
|
33
70
|
|
|
34
71
|
## Quick Start
|
|
@@ -41,29 +78,38 @@ This example shows the easiest way to get started with the Loudness Audio Workle
|
|
|
41
78
|
<!doctype html>
|
|
42
79
|
<html>
|
|
43
80
|
<body>
|
|
81
|
+
<button>Share Screen</button>
|
|
44
82
|
<pre></pre>
|
|
45
83
|
<script>
|
|
84
|
+
const script = "https://lcweden.github.io/loudness-audio-worklet-processor/loudness.worklet.js";
|
|
85
|
+
const button = document.querySelector("button");
|
|
46
86
|
const pre = document.querySelector("pre");
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
87
|
+
|
|
88
|
+
button.onclick = async () => {
|
|
89
|
+
// Get the screen stream with audio, for example a youtube tab
|
|
90
|
+
const mediaStream = await navigator.mediaDevices.getDisplayMedia({ audio: true });
|
|
50
91
|
const context = new AudioContext();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
92
|
+
|
|
93
|
+
// Load the loudness worklet processor
|
|
94
|
+
await context.audioWorklet.addModule(script);
|
|
95
|
+
|
|
96
|
+
// Create the audio node from the stream
|
|
97
|
+
const source = new MediaStreamAudioSourceNode(context, { mediaStream });
|
|
98
|
+
// Create the loudness worklet node
|
|
99
|
+
const worklet = new AudioWorkletNode(context, "loudness-processor", {
|
|
100
|
+
processorOptions: {
|
|
101
|
+
interval: 0.1,
|
|
102
|
+
capacity: 600 // it means 1 minute of history can be stored
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
worklet.port.onmessage = (event) => {
|
|
107
|
+
pre.textContent = JSON.stringify(event.data, null, 2);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Connect the nodes
|
|
111
|
+
source.connect(worklet);
|
|
112
|
+
};
|
|
67
113
|
</script>
|
|
68
114
|
</body>
|
|
69
115
|
</html>
|
|
@@ -85,6 +131,17 @@ await context.audioWorklet.addModule("loudness.worklet.js");
|
|
|
85
131
|
const source = new AudioBufferSourceNode(context, { buffer: audioBuffer });
|
|
86
132
|
const worklet = new AudioWorkletNode(context, "loudness-processor");
|
|
87
133
|
|
|
134
|
+
// Or using the helper function
|
|
135
|
+
//
|
|
136
|
+
// import { createLoudnessWorklet } from "loudness-worklet";
|
|
137
|
+
//
|
|
138
|
+
// const worklet = await createLoudnessWorklet(audioContext, {
|
|
139
|
+
// processorOptions: {
|
|
140
|
+
// interval: 0.1,
|
|
141
|
+
// capacity: 600
|
|
142
|
+
// }
|
|
143
|
+
// });
|
|
144
|
+
|
|
88
145
|
worklet.port.onmessage = (event) => {
|
|
89
146
|
console.log("Loudness Data:", event.data);
|
|
90
147
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
interface LoudnessWorkletProcessorOptions {
|
|
2
|
+
numberOfInputs?: AudioWorkletNodeOptions["numberOfInputs"];
|
|
3
|
+
numberOfOutputs?: AudioWorkletNodeOptions["numberOfOutputs"];
|
|
4
|
+
outputChannelCount?: AudioWorkletNodeOptions["outputChannelCount"];
|
|
5
|
+
processorOptions?: {
|
|
6
|
+
interval?: number;
|
|
7
|
+
capacity?: number;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
1
10
|
declare class LoudnessWorkletNode extends AudioWorkletNode {
|
|
2
|
-
constructor(context: BaseAudioContext, options?:
|
|
11
|
+
constructor(context: BaseAudioContext, options?: LoudnessWorkletProcessorOptions);
|
|
3
12
|
static loadModule(context: BaseAudioContext): Promise<void>;
|
|
4
13
|
}
|
|
5
|
-
declare function createLoudnessWorklet(context: BaseAudioContext, options?:
|
|
14
|
+
declare function createLoudnessWorklet(context: BaseAudioContext, options?: LoudnessWorkletProcessorOptions): Promise<AudioWorkletNode>;
|
|
6
15
|
export { createLoudnessWorklet, LoudnessWorkletNode };
|
package/dist/index.js
CHANGED
|
@@ -2,11 +2,11 @@ const i = `/**
|
|
|
2
2
|
* A lightweight and efficient AudioWorklet for real-time loudness measurement in the browser, compliant with the ITU-R BS.1770-5 standard.
|
|
3
3
|
*
|
|
4
4
|
* @file loudness.worklet.js
|
|
5
|
-
* @version 1.
|
|
5
|
+
* @version 1.5.0
|
|
6
6
|
* @author lcweden
|
|
7
7
|
* @license MIT
|
|
8
|
-
* @see
|
|
9
|
-
* @date 2025-
|
|
8
|
+
* @see https://github.com/lcweden/loudness-audio-worklet-processor.git
|
|
9
|
+
* @date 2025-10-07T13:01:56.024Z
|
|
10
10
|
*/\r
|
|
11
11
|
\r
|
|
12
12
|
class O {
|
|
@@ -35,12 +35,14 @@ class O {
|
|
|
35
35
|
* Sets new filter coefficients.
|
|
36
36
|
* @param { number[] } a - Feedback coefficients [a1, a2]
|
|
37
37
|
* @param { number[] } b - Feedforward coefficients [b0, b1, b2]
|
|
38
|
+
* @returns { void }
|
|
38
39
|
*/
|
|
39
40
|
set(e, r) {
|
|
40
41
|
this.#t.set((e.length = 2, e)), this.#e.set((r.length = 3, r));
|
|
41
42
|
}
|
|
42
43
|
/**
|
|
43
44
|
* Resets the filter state.
|
|
45
|
+
* @returns { void }
|
|
44
46
|
*/
|
|
45
47
|
reset() {
|
|
46
48
|
this.#s.fill(0), this.#r.fill(0);
|
|
@@ -52,22 +54,45 @@ class d {
|
|
|
52
54
|
#s = 0;
|
|
53
55
|
#r = 0;
|
|
54
56
|
#n = 0;
|
|
57
|
+
/**
|
|
58
|
+
* Creates a new CircularBuffer with given capacity.
|
|
59
|
+
* @param { number } capacity - The maximum number of items the buffer can hold.
|
|
60
|
+
*/
|
|
55
61
|
constructor(e) {
|
|
56
62
|
this.#e = e || 0, this.#t = new Array(e);
|
|
57
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Adds an item to the buffer.
|
|
66
|
+
* @param item - The item to add to the buffer.
|
|
67
|
+
* @returns { void }
|
|
68
|
+
*/
|
|
58
69
|
push(e) {
|
|
59
70
|
this.#t[this.#r] = e, this.isFull() ? this.#s = (this.#s + 1) % this.#e : this.#n++, this.#r = (this.#r + 1) % this.#e;
|
|
60
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Removes and returns the oldest item from the buffer.
|
|
74
|
+
* @returns { T | undefined }
|
|
75
|
+
*/
|
|
61
76
|
pop() {
|
|
62
77
|
if (this.isEmpty())
|
|
63
78
|
return;
|
|
64
79
|
const e = this.#t[this.#s];
|
|
65
80
|
return this.#s = (this.#s + 1) % this.#e, this.#n--, e;
|
|
66
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Returns the oldest item from the buffer without removing it.
|
|
84
|
+
* @returns { T | undefined }
|
|
85
|
+
*/
|
|
67
86
|
peek() {
|
|
68
87
|
if (!this.isEmpty())
|
|
69
88
|
return this.#t[this.#s];
|
|
70
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Returns a slice of the buffer contents.
|
|
92
|
+
* @param { number } start - The starting index of the slice (inclusive).
|
|
93
|
+
* @param { number } end - The ending index of the slice (exclusive).
|
|
94
|
+
* @returns { T[] }
|
|
95
|
+
*/
|
|
71
96
|
slice(e = 0, r = this.#n) {
|
|
72
97
|
if (e < 0 && (e = 0), r > this.#n && (r = this.#n), e >= r)
|
|
73
98
|
return [];
|
|
@@ -78,18 +103,29 @@ class d {
|
|
|
78
103
|
}
|
|
79
104
|
return n;
|
|
80
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Checks if the buffer is empty.
|
|
108
|
+
* @returns { boolean }
|
|
109
|
+
*/
|
|
81
110
|
isEmpty() {
|
|
82
111
|
return this.#n === 0;
|
|
83
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Checks if the buffer is full.
|
|
115
|
+
* @returns { boolean }
|
|
116
|
+
*/
|
|
84
117
|
isFull() {
|
|
85
118
|
return this.#n === this.#e;
|
|
86
119
|
}
|
|
120
|
+
/** @type { number } */
|
|
87
121
|
get length() {
|
|
88
122
|
return this.#n;
|
|
89
123
|
}
|
|
124
|
+
/** @type { number } */
|
|
90
125
|
get capacity() {
|
|
91
126
|
return this.#e;
|
|
92
127
|
}
|
|
128
|
+
/** @type { IterableIterator<T> } */
|
|
93
129
|
*[Symbol.iterator]() {
|
|
94
130
|
for (let e = 0; e < this.#n; e++) {
|
|
95
131
|
const r = (this.#s + e) % this.#e;
|
|
@@ -209,6 +245,10 @@ const L = {
|
|
|
209
245
|
class F {
|
|
210
246
|
#t;
|
|
211
247
|
#e;
|
|
248
|
+
/**
|
|
249
|
+
* Creates an instance of the filter.
|
|
250
|
+
* @param coefficients - The filter coefficients.
|
|
251
|
+
*/
|
|
212
252
|
constructor(e) {
|
|
213
253
|
this.#t = e, this.#e = Array(e.length).fill(0);
|
|
214
254
|
}
|
|
@@ -224,6 +264,10 @@ class F {
|
|
|
224
264
|
return n;
|
|
225
265
|
}
|
|
226
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Resets the filter state.
|
|
269
|
+
* @returns { void }
|
|
270
|
+
*/
|
|
227
271
|
reset() {
|
|
228
272
|
this.#e.fill(0);
|
|
229
273
|
}
|
|
@@ -372,19 +416,27 @@ class X extends AudioWorkletProcessor {
|
|
|
372
416
|
}
|
|
373
417
|
}
|
|
374
418
|
registerProcessor("loudness-processor", X);
|
|
375
|
-
`,
|
|
376
|
-
class
|
|
377
|
-
constructor(n,
|
|
378
|
-
super(n, t,
|
|
419
|
+
`, t = "loudness-processor";
|
|
420
|
+
class o extends AudioWorkletNode {
|
|
421
|
+
constructor(n, s) {
|
|
422
|
+
super(n, t, s);
|
|
379
423
|
}
|
|
380
424
|
static async loadModule(n) {
|
|
381
|
-
return
|
|
425
|
+
return r(n);
|
|
382
426
|
}
|
|
383
427
|
}
|
|
384
|
-
async function
|
|
385
|
-
return await
|
|
428
|
+
async function h(e, n) {
|
|
429
|
+
return await r(e), new AudioWorkletNode(e, t, n);
|
|
430
|
+
}
|
|
431
|
+
async function r(e) {
|
|
432
|
+
const n = new Blob([i], { type: "application/javascript" }), s = URL.createObjectURL(n);
|
|
433
|
+
try {
|
|
434
|
+
await e.audioWorklet.addModule(s);
|
|
435
|
+
} finally {
|
|
436
|
+
URL.revokeObjectURL(s);
|
|
437
|
+
}
|
|
386
438
|
}
|
|
387
439
|
export {
|
|
388
|
-
|
|
389
|
-
|
|
440
|
+
o as LoudnessWorkletNode,
|
|
441
|
+
h as createLoudnessWorklet
|
|
390
442
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loudness-worklet",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "A lightweight and efficient AudioWorklet for real-time loudness measurement in the browser, compliant with the ITU-R BS.1770-5 standard.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"web-audio",
|
|
7
|
+
"web-audio-api",
|
|
8
|
+
"audio-meter",
|
|
9
|
+
"audio-worklet",
|
|
10
|
+
"loudness",
|
|
11
|
+
"loudness-meter",
|
|
12
|
+
"browser-audio",
|
|
13
|
+
"ebu-r128",
|
|
14
|
+
"itu-r-bs1770",
|
|
15
|
+
"audio-processing",
|
|
16
|
+
"audio-analysis",
|
|
17
|
+
"true-peak",
|
|
18
|
+
"lufs",
|
|
19
|
+
"lra",
|
|
20
|
+
"javascript",
|
|
21
|
+
"typescript",
|
|
22
|
+
"lightweight"
|
|
23
|
+
],
|
|
5
24
|
"type": "module",
|
|
6
25
|
"module": "./dist/index.js",
|
|
7
26
|
"types": "./dist/index.d.ts",
|
|
@@ -18,7 +37,8 @@
|
|
|
18
37
|
"author": "lcweden",
|
|
19
38
|
"homepage": "https://lcweden.github.io/loudness-audio-worklet-processor/",
|
|
20
39
|
"repository": {
|
|
21
|
-
"
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/lcweden/loudness-audio-worklet-processor.git"
|
|
22
42
|
},
|
|
23
43
|
"bugs": {
|
|
24
44
|
"url": "https://github.com/lcweden/loudness-audio-worklet-processor/issues"
|