loudness-worklet 1.5.1 → 1.6.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 CHANGED
@@ -244,20 +244,20 @@ const worklet = new AudioWorkletNode(context, "loudness-processor", {
244
244
  Measurement results are sent back to the main thread via `port.onmessage` with the following format:
245
245
 
246
246
  ```typescript
247
- type AudioLoudnessSnapshot = {
247
+ type LoudnessMeasurements = {
248
+ momentaryLoudness: number;
249
+ shortTermLoudness: number;
250
+ integratedLoudness: number;
251
+ maximumMomentaryLoudness: number;
252
+ maximumShortTermLoudness: number;
253
+ maximumTruePeakLevel: number;
254
+ loudnessRange: number;
255
+ };
256
+
257
+ type LoudnessSnapshot = {
248
258
  currentFrame: number;
249
259
  currentTime: number;
250
- currentMetrics: [
251
- {
252
- momentaryLoudness: number;
253
- shortTermLoudness: number;
254
- integratedLoudness: number;
255
- maximumMomentaryLoudness: number;
256
- maximumShortTermLoudness: number;
257
- maximumTruePeakLevel: number;
258
- loudnessRange: number;
259
- }
260
- ];
260
+ currentMeasurements: LoudnessMeasurements[];
261
261
  };
262
262
  ```
263
263
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loudness-worklet",
3
- "version": "1.5.1",
3
+ "version": "1.6.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
5
  "keywords": [
6
6
  "web-audio",
@@ -18,20 +18,22 @@
18
18
  "lufs",
19
19
  "lra",
20
20
  "javascript",
21
- "typescript",
22
- "lightweight"
21
+ "typescript"
23
22
  ],
24
23
  "type": "module",
25
- "module": "./dist/index.js",
26
- "types": "./dist/index.d.ts",
24
+ "main": "./packages/lib/dist/index.js",
25
+ "types": "./packages/lib/dist/index.d.ts",
27
26
  "exports": {
28
27
  ".": {
29
- "import": "./dist/index.js",
30
- "types": "./dist/index.d.ts"
28
+ "types": "./packages/lib/dist/index.d.ts",
29
+ "default": "./packages/lib/dist/index.js"
31
30
  }
32
31
  },
33
32
  "files": [
34
- "dist"
33
+ "packages/lib/dist"
34
+ ],
35
+ "workspaces": [
36
+ "packages/*"
35
37
  ],
36
38
  "license": "MIT",
37
39
  "author": "lcweden",
@@ -44,29 +46,11 @@
44
46
  "url": "https://github.com/lcweden/loudness-worklet/issues"
45
47
  },
46
48
  "scripts": {
47
- "dev": "vite --mode dev",
48
- "demo": "vite --mode demo",
49
- "test": "vitest",
50
- "build": "vite build --mode static && vite build --mode demo",
51
- "lib": "vite build --mode static && vite build --mode lib && tsc -p tsconfig.lib.json",
52
- "prepare": "npm run lib",
53
- "preview": "vite preview --mode demo",
54
- "format": "prettier --write ."
49
+ "format": "biome format --write",
50
+ "lint": "biome lint --write"
55
51
  },
56
52
  "devDependencies": {
57
- "@solidjs/router": "^0.15.3",
58
- "@tailwindcss/vite": "^4.1.4",
59
- "@types/audioworklet": "^0.0.85",
60
- "@types/node": "^22.14.1",
61
- "daisyui": "^5.0.28",
62
- "echarts": "^6.0.0",
63
- "prettier": "^3.5.3",
64
- "prettier-plugin-tailwindcss": "^0.6.11",
65
- "solid-js": "^1.9.5",
66
- "tailwindcss": "^4.1.4",
67
- "typescript": "~5.7.2",
68
- "vite": "^6.3.1",
69
- "vite-plugin-solid": "^2.11.6",
70
- "vitest": "^3.2.2"
53
+ "@biomejs/biome": "2.3.8",
54
+ "@types/node": "^24.10.1"
71
55
  }
72
56
  }
@@ -0,0 +1,34 @@
1
+ export declare function createLoudnessWorklet(context: BaseAudioContext, options?: LoudnessWorkletProcessorOptions): Promise<AudioWorkletNode>;
2
+
3
+ export declare type LoudnessMeasurements = {
4
+ momentaryLoudness: number;
5
+ shortTermLoudness: number;
6
+ integratedLoudness: number;
7
+ maximumMomentaryLoudness: number;
8
+ maximumShortTermLoudness: number;
9
+ maximumTruePeakLevel: number;
10
+ loudnessRange: number;
11
+ };
12
+
13
+ export declare type LoudnessSnapshot = {
14
+ currentFrame: number;
15
+ currentTime: number;
16
+ currentMeasurements: LoudnessMeasurements[];
17
+ };
18
+
19
+ export declare class LoudnessWorkletNode extends AudioWorkletNode {
20
+ constructor(context: BaseAudioContext, options?: LoudnessWorkletProcessorOptions);
21
+ static loadModule(context: BaseAudioContext): Promise<void>;
22
+ }
23
+
24
+ export declare interface LoudnessWorkletProcessorOptions {
25
+ numberOfInputs?: AudioWorkletNodeOptions["numberOfInputs"];
26
+ numberOfOutputs?: AudioWorkletNodeOptions["numberOfOutputs"];
27
+ outputChannelCount?: AudioWorkletNodeOptions["outputChannelCount"];
28
+ processorOptions?: {
29
+ interval?: number;
30
+ capacity?: number;
31
+ };
32
+ }
33
+
34
+ export { }
@@ -1,142 +1,10 @@
1
- const i = `/**
2
- * A lightweight and efficient AudioWorklet for real-time loudness measurement in the browser, compliant with the ITU-R BS.1770-5 standard.
3
- *
4
- * @file loudness.worklet.js
5
- * @version 1.5.1
6
- * @author lcweden
7
- * @license MIT
8
- * @see https://github.com/lcweden/loudness-worklet.git
9
- * @date 2025-11-18T12:38:50.840Z
10
- */\r
11
- \r
12
- class O {
13
- #t = new Float32Array(2);
14
- #e = new Float32Array(3);
15
- #s = new Float32Array(2);
16
- #r = new Float32Array(2);
17
- /**
18
- * Creates a new BiquadraticFilter with given coefficients.
19
- * @param { number[] } a - Feedback coefficients [a1, a2]
20
- * @param { number[] } b - Feedforward coefficients [b0, b1, b2]
21
- */
22
- constructor(e, r) {
23
- this.reset(), this.set(e, r);
24
- }
25
- /**
26
- * Processes a single input sample and returns the filtered output.
27
- * @param { number } input - The input sample.
28
- * @returns { number } - The filtered output sample.
29
- */
30
- process(e) {
31
- const r = this.#e[0] * e + this.#e[1] * this.#s[0] + this.#e[2] * this.#s[1] - this.#t[0] * this.#r[0] - this.#t[1] * this.#r[1];
32
- return this.#s[1] = this.#s[0], this.#s[0] = e, this.#r[1] = this.#r[0], this.#r[0] = r, r;
33
- }
34
- /**
35
- * Sets new filter coefficients.
36
- * @param { number[] } a - Feedback coefficients [a1, a2]
37
- * @param { number[] } b - Feedforward coefficients [b0, b1, b2]
38
- * @returns { void }
39
- */
40
- set(e, r) {
41
- this.#t.set((e.length = 2, e)), this.#e.set((r.length = 3, r));
42
- }
43
- /**
44
- * Resets the filter state.
45
- * @returns { void }
46
- */
47
- reset() {
48
- this.#s.fill(0), this.#r.fill(0);
49
- }
50
- }
51
- class d {
52
- #t;
53
- #e;
54
- #s = 0;
55
- #r = 0;
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
- */
61
- constructor(e) {
62
- this.#e = e || 0, this.#t = new Array(e);
63
- }
64
- /**
65
- * Adds an item to the buffer.
66
- * @param item - The item to add to the buffer.
67
- * @returns { void }
68
- */
69
- push(e) {
70
- this.#t[this.#r] = e, this.isFull() ? this.#s = (this.#s + 1) % this.#e : this.#n++, this.#r = (this.#r + 1) % this.#e;
71
- }
72
- /**
73
- * Removes and returns the oldest item from the buffer.
74
- * @returns { T | undefined }
75
- */
76
- pop() {
77
- if (this.isEmpty())
78
- return;
79
- const e = this.#t[this.#s];
80
- return this.#s = (this.#s + 1) % this.#e, this.#n--, e;
81
- }
82
- /**
83
- * Returns the oldest item from the buffer without removing it.
84
- * @returns { T | undefined }
85
- */
86
- peek() {
87
- if (!this.isEmpty())
88
- return this.#t[this.#s];
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
- */
96
- slice(e = 0, r = this.#n) {
97
- if (e < 0 && (e = 0), r > this.#n && (r = this.#n), e >= r)
98
- return [];
99
- const n = [];
100
- for (let s = e; s < r; s++) {
101
- const u = (this.#s + s) % this.#e;
102
- n.push(this.#t[u]);
103
- }
104
- return n;
105
- }
106
- /**
107
- * Checks if the buffer is empty.
108
- * @returns { boolean }
109
- */
110
- isEmpty() {
111
- return this.#n === 0;
112
- }
113
- /**
114
- * Checks if the buffer is full.
115
- * @returns { boolean }
116
- */
117
- isFull() {
118
- return this.#n === this.#e;
119
- }
120
- /** @type { number } */
121
- get length() {
122
- return this.#n;
123
- }
124
- /** @type { number } */
125
- get capacity() {
126
- return this.#e;
127
- }
128
- /** @type { IterableIterator<T> } */
129
- *[Symbol.iterator]() {
130
- for (let e = 0; e < this.#n; e++) {
131
- const r = (this.#s + e) % this.#e;
132
- yield this.#t[r];
133
- }
134
- }
135
- }
136
- const L = {
137
- highshelf: { a: [-1.69065929318241, 0.73248077421585], b: [1.53512485958697, -2.69169618940638, 1.19839281085285] },
1
+ const i = `const d = {
2
+ highshelf: {
3
+ a: [-1.69065929318241, 0.73248077421585],
4
+ b: [1.53512485958697, -2.69169618940638, 1.19839281085285]
5
+ },
138
6
  highpass: { a: [-1.99004745483398, 0.99007225036621], b: [1, -2, 1] }
139
- }, R = {
7
+ }, L = {
140
8
  lowpass: {
141
9
  phase0: [
142
10
  0.001708984375,
@@ -195,12 +63,32 @@ const L = {
195
63
  0.001708984375
196
64
  ]
197
65
  }
198
- }, G = {
66
+ }, O = {
199
67
  1: { mono: 1 },
200
68
  2: { L: 1, R: 1 },
201
69
  6: { L: 1, R: 1, C: 1, LFE: 0, Ls: 1.41, Rs: 1.41 },
202
- 8: { L: 1, R: 1, C: 1, LFE: 0, Lss: 1.41, Rss: 1.41, Lrs: 1, Rrs: 1 },
203
- 10: { L: 1, R: 1, C: 1, LFE: 0, Ls: 1.41, Rs: 1.41, Tfl: 1, Tfr: 1, Tbl: 1, Tbr: 1 },
70
+ 8: {
71
+ L: 1,
72
+ R: 1,
73
+ C: 1,
74
+ LFE: 0,
75
+ Lss: 1.41,
76
+ Rss: 1.41,
77
+ Lrs: 1,
78
+ Rrs: 1
79
+ },
80
+ 10: {
81
+ L: 1,
82
+ R: 1,
83
+ C: 1,
84
+ LFE: 0,
85
+ Ls: 1.41,
86
+ Rs: 1.41,
87
+ Tfl: 1,
88
+ Tfr: 1,
89
+ Tbl: 1,
90
+ Tbr: 1
91
+ },
204
92
  12: {
205
93
  L: 1,
206
94
  R: 1,
@@ -241,8 +129,47 @@ const L = {
241
129
  BtFL: 1,
242
130
  BtFR: 1
243
131
  }
244
- }, U = 0.4, B = 0.1, Y = 3, C = 0.1, j = 0.1, q = 0.95, w = 12.04, z = -70, K = -10, J = -70, Q = -20;
245
- class F {
132
+ }, U = 0.4, G = 0.1, Y = 3, B = 0.1, j = 0.1, q = 0.95, C = 12.04, z = -70, K = -10, J = -70, Q = -20;
133
+ class x {
134
+ #t = new Float32Array(2);
135
+ #e = new Float32Array(3);
136
+ #s = new Float32Array(2);
137
+ #r = new Float32Array(2);
138
+ /**
139
+ * Creates a new BiquadraticFilter with given coefficients.
140
+ * @param { number[] } a - Feedback coefficients [a1, a2]
141
+ * @param { number[] } b - Feedforward coefficients [b0, b1, b2]
142
+ */
143
+ constructor(e, r) {
144
+ this.reset(), this.set(e, r);
145
+ }
146
+ /**
147
+ * Processes a single input sample and returns the filtered output.
148
+ * @param { number } input - The input sample.
149
+ * @returns { number } - The filtered output sample.
150
+ */
151
+ process(e) {
152
+ const r = this.#e[0] * e + this.#e[1] * this.#s[0] + this.#e[2] * this.#s[1] - this.#t[0] * this.#r[0] - this.#t[1] * this.#r[1];
153
+ return this.#s[1] = this.#s[0], this.#s[0] = e, this.#r[1] = this.#r[0], this.#r[0] = r, r;
154
+ }
155
+ /**
156
+ * Sets new filter coefficients.
157
+ * @param { number[] } a - Feedback coefficients [a1, a2]
158
+ * @param { number[] } b - Feedforward coefficients [b0, b1, b2]
159
+ * @returns { void }
160
+ */
161
+ set(e, r) {
162
+ e.length = 2, this.#t.set(e), r.length = 3, this.#e.set(r);
163
+ }
164
+ /**
165
+ * Resets the filter state.
166
+ * @returns { void }
167
+ */
168
+ reset() {
169
+ this.#s.fill(0), this.#r.fill(0);
170
+ }
171
+ }
172
+ class R {
246
173
  #t;
247
174
  #e;
248
175
  /**
@@ -272,11 +199,96 @@ class F {
272
199
  this.#e.fill(0);
273
200
  }
274
201
  }
202
+ class F {
203
+ #t;
204
+ #e;
205
+ #s;
206
+ #r;
207
+ #n;
208
+ /**
209
+ * Creates a new CircularBuffer with given capacity.
210
+ * @param { number } capacity - The maximum number of items the buffer can hold.
211
+ */
212
+ constructor(e) {
213
+ this.#e = e || 0, this.#t = new Array(e), this.#s = 0, this.#r = 0, this.#n = 0;
214
+ }
215
+ /**
216
+ * Adds an item to the buffer.
217
+ * @param item - The item to add to the buffer.
218
+ * @returns { void }
219
+ */
220
+ push(e) {
221
+ this.#t[this.#r] = e, this.isFull() ? this.#s = (this.#s + 1) % this.#e : this.#n++, this.#r = (this.#r + 1) % this.#e;
222
+ }
223
+ /**
224
+ * Removes and returns the oldest item from the buffer.
225
+ * @returns { T | undefined }
226
+ */
227
+ pop() {
228
+ if (this.isEmpty())
229
+ return;
230
+ const e = this.#t[this.#s];
231
+ return this.#t[this.#s] = void 0, this.#s = (this.#s + 1) % this.#e, this.#n--, e;
232
+ }
233
+ /**
234
+ * Returns the oldest item from the buffer without removing it.
235
+ * @returns { T | undefined }
236
+ */
237
+ peek() {
238
+ if (!this.isEmpty())
239
+ return this.#t[this.#s];
240
+ }
241
+ /**
242
+ * Returns a slice of the buffer contents.
243
+ * @param { number } start - The starting index of the slice (inclusive).
244
+ * @param { number } end - The ending index of the slice (exclusive).
245
+ * @returns { T[] }
246
+ */
247
+ slice(e, r) {
248
+ if (e >= r)
249
+ return [];
250
+ const n = [];
251
+ for (let s = Math.max(0, e); s < Math.min(this.#n, r); s++) {
252
+ const u = (this.#s + s) % this.#e;
253
+ n.push(this.#t[u]);
254
+ }
255
+ return n;
256
+ }
257
+ /**
258
+ * Checks if the buffer is empty.
259
+ * @returns { boolean }
260
+ */
261
+ isEmpty() {
262
+ return this.#n === 0;
263
+ }
264
+ /**
265
+ * Checks if the buffer is full.
266
+ * @returns { boolean }
267
+ */
268
+ isFull() {
269
+ return this.#n === this.#e;
270
+ }
271
+ /** @type { number } */
272
+ get length() {
273
+ return this.#n;
274
+ }
275
+ /** @type { number } */
276
+ get capacity() {
277
+ return this.#e;
278
+ }
279
+ /** @type { IterableIterator<T> } */
280
+ *[Symbol.iterator]() {
281
+ for (let e = 0; e < this.#n; e++) {
282
+ const r = (this.#s + e) % this.#e;
283
+ yield this.#t[r];
284
+ }
285
+ }
286
+ }
275
287
  class X extends AudioWorkletProcessor {
276
288
  capacity = null;
277
289
  interval = null;
278
290
  lastTime = 0;
279
- metrics = [];
291
+ measurements = [];
280
292
  kWeightingFilters = [];
281
293
  truePeakFilters = [];
282
294
  momentaryEnergyBuffers = [];
@@ -295,7 +307,15 @@ class X extends AudioWorkletProcessor {
295
307
  this.capacity = s ?? null, this.interval = u ?? null;
296
308
  }
297
309
  for (let s = 0; s < r; s++)
298
- this.momentaryEnergyRunningSums[s] = 0, this.momentarySampleAccumulators[s] = 0, this.momentaryEnergyBuffers[s] = new d(Math.round(sampleRate * U)), this.momentaryLoudnessHistories[s] = this.capacity ? new d(Math.ceil(this.capacity / B)) : new Array(), this.shortTermEnergyRunningSums[s] = 0, this.shortTermSampleAccumulators[s] = 0, this.shortTermEnergyBuffers[s] = new d(Math.round(sampleRate * Y)), this.shortTermLoudnessHistories[s] = this.capacity ? new d(Math.ceil(this.capacity / C)) : new Array(), this.metrics[s] = {
310
+ this.momentaryEnergyRunningSums[s] = 0, this.momentarySampleAccumulators[s] = 0, this.momentaryEnergyBuffers[s] = new F(
311
+ Math.round(sampleRate * U)
312
+ ), this.momentaryLoudnessHistories[s] = this.capacity ? new F(
313
+ Math.ceil(this.capacity / G)
314
+ ) : [], this.shortTermEnergyRunningSums[s] = 0, this.shortTermSampleAccumulators[s] = 0, this.shortTermEnergyBuffers[s] = new F(
315
+ Math.round(sampleRate * Y)
316
+ ), this.shortTermLoudnessHistories[s] = this.capacity ? new F(
317
+ Math.ceil(this.capacity / B)
318
+ ) : [], this.measurements[s] = {
299
319
  momentaryLoudness: Number.NEGATIVE_INFINITY,
300
320
  shortTermLoudness: Number.NEGATIVE_INFINITY,
301
321
  integratedLoudness: Number.NEGATIVE_INFINITY,
@@ -309,42 +329,69 @@ class X extends AudioWorkletProcessor {
309
329
  const n = e.length;
310
330
  for (let s = 0; s < n; s++) {
311
331
  if (!e[s].length) continue;
312
- const u = e[s], c = u.length, A = u[0].length, H = Object.values(G[c] || G[1]), x = Math.pow(10, -w / 20);
313
- (!this.kWeightingFilters[s] || this.kWeightingFilters[s].length !== c) && (this.kWeightingFilters[s] = Array.from({ length: c }, () => [
314
- new O(L.highshelf.a, L.highshelf.b),
315
- new O(L.highpass.a, L.highpass.b)
316
- ])), (!this.truePeakFilters[s] || this.truePeakFilters[s].length !== c) && (this.truePeakFilters[s] = Array.from({ length: c }, () => [
317
- new F(R.lowpass.phase0),
318
- new F(R.lowpass.phase1),
319
- new F(R.lowpass.phase2),
320
- new F(R.lowpass.phase3)
321
- ]));
332
+ const u = e[s], c = u.length, A = u[0].length, H = Object.values(
333
+ O[c] || O[1]
334
+ ), v = 10 ** (-C / 20);
335
+ (!this.kWeightingFilters[s] || this.kWeightingFilters[s].length !== c) && (this.kWeightingFilters[s] = Array.from(
336
+ { length: c },
337
+ () => [
338
+ new x(
339
+ d.highshelf.a,
340
+ d.highshelf.b
341
+ ),
342
+ new x(
343
+ d.highpass.a,
344
+ d.highpass.b
345
+ )
346
+ ]
347
+ )), (!this.truePeakFilters[s] || this.truePeakFilters[s].length !== c) && (this.truePeakFilters[s] = Array.from(
348
+ { length: c },
349
+ () => [
350
+ new R(
351
+ L.lowpass.phase0
352
+ ),
353
+ new R(
354
+ L.lowpass.phase1
355
+ ),
356
+ new R(
357
+ L.lowpass.phase2
358
+ ),
359
+ new R(
360
+ L.lowpass.phase3
361
+ )
362
+ ]
363
+ ));
322
364
  for (let o = 0; o < A; o++) {
323
365
  let i = 0;
324
366
  for (let t = 0; t < c; t++) {
325
- const h = u[t][o], [y, T] = this.kWeightingFilters[s][t], m = y.process(h), f = T.process(m) ** 2, v = H[t] ?? 1;
326
- i += f * v;
327
- const P = u[t][o] * x, k = sampleRate >= 96e3 ? 2 : 4, b = [];
367
+ const h = u[t][o], [y, T] = this.kWeightingFilters[s][t], m = y.process(h), f = T.process(m) ** 2, w = H[t] ?? 1;
368
+ i += f * w;
369
+ const P = u[t][o] * v, k = sampleRate >= 96e3 ? 2 : 4, b = [];
328
370
  for (let N = 0; N < k; N++) {
329
371
  const D = this.truePeakFilters[s][t][N];
330
372
  b.push(Math.abs(D.process(P)));
331
373
  }
332
- const W = 20 * Math.log10(Math.max(...b)) + w, V = this.metrics[s].maximumTruePeakLevel;
333
- this.metrics[s].maximumTruePeakLevel = Math.max(V, W);
374
+ const W = 20 * Math.log10(Math.max(...b)) + C, V = this.measurements[s].maximumTruePeakLevel;
375
+ this.measurements[s].maximumTruePeakLevel = Math.max(
376
+ V,
377
+ W
378
+ );
334
379
  }
335
- const g = i, p = this.momentaryEnergyBuffers[s].peek() ?? 0, I = this.momentaryEnergyBuffers[s].isFull() ? p : 0;
380
+ const g = i, E = this.momentaryEnergyBuffers[s].peek() ?? 0, I = this.momentaryEnergyBuffers[s].isFull() ? E : 0;
336
381
  this.momentaryEnergyRunningSums[s] += g - I, this.momentaryEnergyBuffers[s].push(g);
337
- const E = this.shortTermEnergyBuffers[s].peek() ?? 0, l = this.shortTermEnergyBuffers[s].isFull() ? E : 0;
382
+ const p = this.shortTermEnergyBuffers[s].peek() ?? 0, l = this.shortTermEnergyBuffers[s].isFull() ? p : 0;
338
383
  if (this.shortTermEnergyRunningSums[s] += g - l, this.shortTermEnergyBuffers[s].push(g), this.momentaryEnergyBuffers[s].isFull()) {
339
384
  const t = this.momentaryEnergyRunningSums[s] / this.momentaryEnergyBuffers[s].capacity, h = this.#s(t);
340
- this.metrics[s].momentaryLoudness = h, this.metrics[s].maximumMomentaryLoudness = Math.max(
341
- this.metrics[s].maximumMomentaryLoudness,
385
+ this.measurements[s].momentaryLoudness = h, this.measurements[s].maximumMomentaryLoudness = Math.max(
386
+ this.measurements[s].maximumMomentaryLoudness,
342
387
  h
343
388
  );
344
389
  }
345
390
  }
346
391
  this.momentarySampleAccumulators[s] += A;
347
- const _ = Math.round(sampleRate * B);
392
+ const _ = Math.round(
393
+ sampleRate * G
394
+ );
348
395
  for (; this.momentarySampleAccumulators[s] >= _; ) {
349
396
  if (this.momentaryEnergyBuffers[s].isFull()) {
350
397
  const o = this.momentaryEnergyRunningSums[s] / this.momentaryEnergyBuffers[s].capacity, i = this.#s(o);
@@ -353,44 +400,77 @@ class X extends AudioWorkletProcessor {
353
400
  this.momentarySampleAccumulators[s] -= _;
354
401
  }
355
402
  this.shortTermSampleAccumulators[s] += A;
356
- const M = Math.round(sampleRate * C);
403
+ const M = Math.round(
404
+ sampleRate * B
405
+ );
357
406
  for (; this.shortTermSampleAccumulators[s] >= M; ) {
358
407
  if (this.shortTermEnergyBuffers[s].isFull()) {
359
408
  const o = this.shortTermEnergyRunningSums[s] / this.shortTermEnergyBuffers[s].capacity, i = this.#s(o);
360
- this.metrics[s].shortTermLoudness = i, this.metrics[s].maximumShortTermLoudness = Math.max(
361
- this.metrics[s].maximumShortTermLoudness,
409
+ this.measurements[s].shortTermLoudness = i, this.measurements[s].maximumShortTermLoudness = Math.max(
410
+ this.measurements[s].maximumShortTermLoudness,
362
411
  i
363
412
  ), this.shortTermLoudnessHistories[s].push(i);
364
413
  }
365
414
  this.shortTermSampleAccumulators[s] -= M;
366
415
  }
367
416
  if (this.momentaryLoudnessHistories[s].length > 2) {
368
- const o = Array.from(this.momentaryLoudnessHistories[s]).filter(
369
- (i) => i > z
370
- );
417
+ const o = Array.from(
418
+ this.momentaryLoudnessHistories[s]
419
+ ).filter((i) => i > z);
371
420
  if (o.length > 2) {
372
- const i = o.map(this.#r), p = i.reduce((t, h) => t + h, 0) / i.length, E = this.#s(p) + K, l = o.filter((t) => t > E);
421
+ const i = o.map(
422
+ this.#r
423
+ ), E = i.reduce(
424
+ (t, h) => t + h,
425
+ 0
426
+ ) / i.length, p = this.#s(
427
+ E
428
+ ) + K, l = o.filter(
429
+ (t) => t > p
430
+ );
373
431
  if (l.length > 2) {
374
- const t = l.map(this.#r), y = t.reduce((m, a) => m + a, 0) / t.length, T = this.#s(y);
375
- this.metrics[s].integratedLoudness = T;
432
+ const t = l.map(
433
+ this.#r
434
+ ), y = t.reduce(
435
+ (m, a) => m + a,
436
+ 0
437
+ ) / t.length, T = this.#s(
438
+ y
439
+ );
440
+ this.measurements[s].integratedLoudness = T;
376
441
  }
377
442
  }
378
443
  }
379
444
  if (this.shortTermLoudnessHistories[s].length > 2) {
380
- const o = Array.from(this.shortTermLoudnessHistories[s]).filter(
381
- (i) => i > J
382
- );
445
+ const o = Array.from(
446
+ this.shortTermLoudnessHistories[s]
447
+ ).filter((i) => i > J);
383
448
  if (o.length > 2) {
384
- const i = o.map(this.#r), p = i.reduce((t, h) => t + h, 0) / i.length, E = this.#s(p) + Q, l = o.filter((t) => t > E);
449
+ const i = o.map(
450
+ this.#r
451
+ ), E = i.reduce(
452
+ (t, h) => t + h,
453
+ 0
454
+ ) / i.length, p = this.#s(
455
+ E
456
+ ) + Q, l = o.filter(
457
+ (t) => t > p
458
+ );
385
459
  if (l.length > 2) {
386
- const t = l.toSorted((m, a) => m - a), [h, y] = [
460
+ const t = l.toSorted(
461
+ (m, a) => m - a
462
+ ), [h, y] = [
387
463
  j,
388
464
  q
389
465
  ].map((m) => {
390
- const a = Math.floor(m * (t.length - 1)), f = Math.ceil(m * (t.length - 1));
466
+ const a = Math.floor(
467
+ m * (t.length - 1)
468
+ ), f = Math.ceil(
469
+ m * (t.length - 1)
470
+ );
391
471
  return f === a ? t[a] : t[a] + (t[f] - t[a]) * (m * (t.length - 1) - a);
392
472
  }), T = y - h;
393
- this.metrics[s].loudnessRange = T;
473
+ this.measurements[s].loudnessRange = T;
394
474
  }
395
475
  }
396
476
  }
@@ -399,7 +479,11 @@ class X extends AudioWorkletProcessor {
399
479
  }
400
480
  #t() {
401
481
  if (currentTime - this.lastTime >= Number(this.interval)) {
402
- const e = { currentFrame, currentTime, currentMetrics: this.metrics };
482
+ const e = {
483
+ currentFrame,
484
+ currentTime,
485
+ currentMeasurements: this.measurements
486
+ };
403
487
  this.port.postMessage(e), this.lastTime = currentTime;
404
488
  }
405
489
  }
@@ -412,7 +496,7 @@ class X extends AudioWorkletProcessor {
412
496
  return -0.691 + 10 * Math.log10(Math.max(e, Number.EPSILON));
413
497
  }
414
498
  #r(e) {
415
- return Math.pow(10, (e + 0.691) / 10);
499
+ return 10 ** ((e + 0.691) / 10);
416
500
  }
417
501
  }
418
502
  registerProcessor("loudness-processor", X);
@@ -425,7 +509,7 @@ class h extends AudioWorkletNode {
425
509
  return r(n);
426
510
  }
427
511
  }
428
- async function o(e, n) {
512
+ async function a(e, n) {
429
513
  return await r(e), new AudioWorkletNode(e, t, n);
430
514
  }
431
515
  async function r(e) {
@@ -438,5 +522,5 @@ async function r(e) {
438
522
  }
439
523
  export {
440
524
  h as LoudnessWorkletNode,
441
- o as createLoudnessWorklet
525
+ a as createLoudnessWorklet
442
526
  };
package/dist/index.d.ts DELETED
@@ -1,15 +0,0 @@
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
- }
10
- declare class LoudnessWorkletNode extends AudioWorkletNode {
11
- constructor(context: BaseAudioContext, options?: LoudnessWorkletProcessorOptions);
12
- static loadModule(context: BaseAudioContext): Promise<void>;
13
- }
14
- declare function createLoudnessWorklet(context: BaseAudioContext, options?: LoudnessWorkletProcessorOptions): Promise<AudioWorkletNode>;
15
- export { createLoudnessWorklet, LoudnessWorkletNode };