@storyteller-platform/ghost-story 0.0.1

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.
Files changed (135) hide show
  1. package/LICENSE.md +611 -0
  2. package/README.md +18 -0
  3. package/dist/api/APIOptions.cjs +16 -0
  4. package/dist/api/APIOptions.d.cts +18 -0
  5. package/dist/api/APIOptions.d.ts +18 -0
  6. package/dist/api/APIOptions.js +0 -0
  7. package/dist/api/Recognition.cjs +263 -0
  8. package/dist/api/Recognition.d.cts +77 -0
  9. package/dist/api/Recognition.d.ts +77 -0
  10. package/dist/api/Recognition.js +233 -0
  11. package/dist/api/VoiceActivityDetection.cjs +77 -0
  12. package/dist/api/VoiceActivityDetection.d.cts +24 -0
  13. package/dist/api/VoiceActivityDetection.d.ts +24 -0
  14. package/dist/api/VoiceActivityDetection.js +43 -0
  15. package/dist/audio/AudioConverter.cjs +331 -0
  16. package/dist/audio/AudioConverter.d.cts +53 -0
  17. package/dist/audio/AudioConverter.d.ts +53 -0
  18. package/dist/audio/AudioConverter.js +310 -0
  19. package/dist/audio/AudioFormat.cjs +151 -0
  20. package/dist/audio/AudioFormat.d.cts +25 -0
  21. package/dist/audio/AudioFormat.d.ts +25 -0
  22. package/dist/audio/AudioFormat.js +123 -0
  23. package/dist/audio/AudioSource.cjs +119 -0
  24. package/dist/audio/AudioSource.d.cts +33 -0
  25. package/dist/audio/AudioSource.d.ts +33 -0
  26. package/dist/audio/AudioSource.js +88 -0
  27. package/dist/audio/index.cjs +74 -0
  28. package/dist/audio/index.d.cts +6 -0
  29. package/dist/audio/index.d.ts +6 -0
  30. package/dist/audio/index.js +54 -0
  31. package/dist/cli/bin.cjs +277 -0
  32. package/dist/cli/bin.d.cts +1 -0
  33. package/dist/cli/bin.d.ts +1 -0
  34. package/dist/cli/bin.js +275 -0
  35. package/dist/cli/config.cjs +347 -0
  36. package/dist/cli/config.d.cts +33 -0
  37. package/dist/cli/config.d.ts +33 -0
  38. package/dist/cli/config.js +285 -0
  39. package/dist/cli/install.cjs +334 -0
  40. package/dist/cli/install.d.cts +62 -0
  41. package/dist/cli/install.d.ts +62 -0
  42. package/dist/cli/install.js +316 -0
  43. package/dist/cli/whisper-server.cjs +172 -0
  44. package/dist/cli/whisper-server.d.cts +24 -0
  45. package/dist/cli/whisper-server.d.ts +24 -0
  46. package/dist/cli/whisper-server.js +152 -0
  47. package/dist/config.cjs +60 -0
  48. package/dist/config.d.cts +12 -0
  49. package/dist/config.d.ts +12 -0
  50. package/dist/config.js +32 -0
  51. package/dist/convert.cjs +88 -0
  52. package/dist/convert.d.cts +12 -0
  53. package/dist/convert.d.ts +12 -0
  54. package/dist/convert.js +63 -0
  55. package/dist/encodings/Ascii.cjs +75 -0
  56. package/dist/encodings/Ascii.d.cts +13 -0
  57. package/dist/encodings/Ascii.d.ts +13 -0
  58. package/dist/encodings/Ascii.js +48 -0
  59. package/dist/encodings/Base64.cjs +155 -0
  60. package/dist/encodings/Base64.d.cts +5 -0
  61. package/dist/encodings/Base64.d.ts +5 -0
  62. package/dist/encodings/Base64.js +129 -0
  63. package/dist/encodings/TextEncodingsCommon.cjs +16 -0
  64. package/dist/encodings/TextEncodingsCommon.d.cts +6 -0
  65. package/dist/encodings/TextEncodingsCommon.d.ts +6 -0
  66. package/dist/encodings/TextEncodingsCommon.js +0 -0
  67. package/dist/index.cjs +153 -0
  68. package/dist/index.d.cts +15 -0
  69. package/dist/index.d.ts +15 -0
  70. package/dist/index.js +140 -0
  71. package/dist/recognition/AmazonTranscribeSTT.cjs +188 -0
  72. package/dist/recognition/AmazonTranscribeSTT.d.cts +21 -0
  73. package/dist/recognition/AmazonTranscribeSTT.d.ts +21 -0
  74. package/dist/recognition/AmazonTranscribeSTT.js +160 -0
  75. package/dist/recognition/AzureCognitiveServicesSTT.cjs +124 -0
  76. package/dist/recognition/AzureCognitiveServicesSTT.d.cts +21 -0
  77. package/dist/recognition/AzureCognitiveServicesSTT.d.ts +21 -0
  78. package/dist/recognition/AzureCognitiveServicesSTT.js +95 -0
  79. package/dist/recognition/DeepgramSTT.cjs +172 -0
  80. package/dist/recognition/DeepgramSTT.d.cts +23 -0
  81. package/dist/recognition/DeepgramSTT.d.ts +23 -0
  82. package/dist/recognition/DeepgramSTT.js +153 -0
  83. package/dist/recognition/GoogleCloudSTT.cjs +125 -0
  84. package/dist/recognition/GoogleCloudSTT.d.cts +35 -0
  85. package/dist/recognition/GoogleCloudSTT.d.ts +35 -0
  86. package/dist/recognition/GoogleCloudSTT.js +107 -0
  87. package/dist/recognition/OpenAICloudSTT.cjs +180 -0
  88. package/dist/recognition/OpenAICloudSTT.d.cts +29 -0
  89. package/dist/recognition/OpenAICloudSTT.d.ts +29 -0
  90. package/dist/recognition/OpenAICloudSTT.js +150 -0
  91. package/dist/recognition/WhisperCppSTT.cjs +296 -0
  92. package/dist/recognition/WhisperCppSTT.d.cts +40 -0
  93. package/dist/recognition/WhisperCppSTT.d.ts +40 -0
  94. package/dist/recognition/WhisperCppSTT.js +275 -0
  95. package/dist/recognition/WhisperServerSTT.cjs +119 -0
  96. package/dist/recognition/WhisperServerSTT.d.cts +24 -0
  97. package/dist/recognition/WhisperServerSTT.d.ts +24 -0
  98. package/dist/recognition/WhisperServerSTT.js +105 -0
  99. package/dist/utilities/FileSystem.cjs +54 -0
  100. package/dist/utilities/FileSystem.d.cts +3 -0
  101. package/dist/utilities/FileSystem.d.ts +3 -0
  102. package/dist/utilities/FileSystem.js +20 -0
  103. package/dist/utilities/Locale.cjs +46 -0
  104. package/dist/utilities/Locale.d.cts +9 -0
  105. package/dist/utilities/Locale.d.ts +9 -0
  106. package/dist/utilities/Locale.js +20 -0
  107. package/dist/utilities/ObjectUtilities.cjs +41 -0
  108. package/dist/utilities/ObjectUtilities.d.cts +3 -0
  109. package/dist/utilities/ObjectUtilities.d.ts +3 -0
  110. package/dist/utilities/ObjectUtilities.js +7 -0
  111. package/dist/utilities/Timeline.cjs +120 -0
  112. package/dist/utilities/Timeline.d.cts +23 -0
  113. package/dist/utilities/Timeline.d.ts +23 -0
  114. package/dist/utilities/Timeline.js +94 -0
  115. package/dist/utilities/Timing.cjs +287 -0
  116. package/dist/utilities/Timing.d.cts +64 -0
  117. package/dist/utilities/Timing.d.ts +64 -0
  118. package/dist/utilities/Timing.js +256 -0
  119. package/dist/utilities/WhisperTimeline.cjs +344 -0
  120. package/dist/utilities/WhisperTimeline.d.cts +86 -0
  121. package/dist/utilities/WhisperTimeline.d.ts +86 -0
  122. package/dist/utilities/WhisperTimeline.js +313 -0
  123. package/dist/vad/ActiveGate.cjs +357 -0
  124. package/dist/vad/ActiveGate.d.cts +53 -0
  125. package/dist/vad/ActiveGate.d.ts +53 -0
  126. package/dist/vad/ActiveGate.js +329 -0
  127. package/dist/vad/ActiveGateOg.cjs +1366 -0
  128. package/dist/vad/ActiveGateOg.d.cts +33 -0
  129. package/dist/vad/ActiveGateOg.d.ts +33 -0
  130. package/dist/vad/ActiveGateOg.js +1341 -0
  131. package/dist/vad/Silero.cjs +174 -0
  132. package/dist/vad/Silero.d.cts +25 -0
  133. package/dist/vad/Silero.d.ts +25 -0
  134. package/dist/vad/Silero.js +153 -0
  135. package/package.json +125 -0
@@ -0,0 +1,1366 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var ActiveGateOg_exports = {};
20
+ __export(ActiveGateOg_exports, {
21
+ createDynamicUint16Array: () => createDynamicUint16Array,
22
+ detectVoiceActivity: () => detectVoiceActivity
23
+ });
24
+ module.exports = __toCommonJS(ActiveGateOg_exports);
25
+ var import_promises = require("fs/promises");
26
+ var import_convert = require("../convert.cjs");
27
+ var import_Ascii = require("../encodings/Ascii.cjs");
28
+ var import_ObjectUtilities = require("../utilities/ObjectUtilities.cjs");
29
+ async function detectVoiceActivity(filepath, options) {
30
+ var _a;
31
+ const { rawAudio } = await ensureRawAudio(filepath);
32
+ const channelCount = rawAudio.audioChannels.length;
33
+ const firstChannel = rawAudio.audioChannels[0];
34
+ if (!firstChannel) {
35
+ throw new Error("no audio channels found");
36
+ }
37
+ const sampleCount = firstChannel.length;
38
+ const sampleRate = rawAudio.sampleRate;
39
+ const audioDuration = getRawAudioDuration(rawAudio);
40
+ options = (0, import_ObjectUtilities.extendDeep)(defaultAdaptiveGateOptions, options);
41
+ const gateVAD = new AdaptiveGateVAD(sampleRate, channelCount, options);
42
+ const frameDuration = 0.01;
43
+ const frameRecords = [];
44
+ for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
45
+ const timePosition = sampleIndex / sampleRate;
46
+ for (let channelIndex = 0; channelIndex < channelCount; channelIndex++) {
47
+ const channel = rawAudio.audioChannels[channelIndex];
48
+ if (!channel) {
49
+ throw new Error(`channel ${channelIndex} not found`);
50
+ }
51
+ const sample = channel[sampleIndex];
52
+ if (sample === void 0) {
53
+ throw new Error(`sample at index ${sampleIndex} not found`);
54
+ }
55
+ gateVAD.process(sample, channelIndex);
56
+ }
57
+ const lastRecord = frameRecords[frameRecords.length - 1];
58
+ if (frameRecords.length == 0 || lastRecord && timePosition > lastRecord.timePosition + frameDuration) {
59
+ const record = {
60
+ timePosition,
61
+ loudness: gateVAD.loudnessEstimator.currentLoudness,
62
+ minimumLoudness: gateVAD.minimumLoudnessEstimator.currentPeak,
63
+ maximumLoudness: gateVAD.maximumLoudnessEstimator.currentPeak
64
+ };
65
+ frameRecords.push(record);
66
+ }
67
+ }
68
+ const frameActive = [];
69
+ for (let i = 0; i < frameRecords.length; i++) {
70
+ frameActive[i] = false;
71
+ }
72
+ {
73
+ const backwardExtensionFrameCount = Math.floor(
74
+ options.backwardExtensionDuration / frameDuration
75
+ );
76
+ const relativeThreshold = options.relativeThreshold;
77
+ let extendedActivityStartIndex = frameRecords.length;
78
+ for (let i = frameRecords.length - 1; i >= 0; i--) {
79
+ const record = frameRecords[i];
80
+ if (!record) {
81
+ continue;
82
+ }
83
+ const referenceLoudness = Math.max(record.maximumLoudness, -30);
84
+ let isActive = false;
85
+ if (i >= extendedActivityStartIndex) {
86
+ isActive = true;
87
+ }
88
+ if (record.loudness >= referenceLoudness + relativeThreshold) {
89
+ isActive = true;
90
+ extendedActivityStartIndex = Math.max(
91
+ i - backwardExtensionFrameCount,
92
+ 0
93
+ );
94
+ }
95
+ frameActive[i] = isActive;
96
+ }
97
+ }
98
+ const timeline = [];
99
+ for (let i = 0; i < frameRecords.length; i++) {
100
+ const record = frameRecords[i];
101
+ if (!record) {
102
+ console.warn("[ghost-story] No record found for frame", i);
103
+ continue;
104
+ }
105
+ const isActive = frameActive[i];
106
+ const activityText = isActive ? "active" : "inactive";
107
+ const startTime = record.timePosition;
108
+ const endTime = Math.min(startTime + frameDuration, audioDuration);
109
+ if (timeline.length == 0 || ((_a = timeline.at(-1)) == null ? void 0 : _a.text) != activityText) {
110
+ timeline.push({
111
+ type: "segment",
112
+ text: activityText,
113
+ startTime,
114
+ endTime
115
+ });
116
+ } else {
117
+ timeline.at(-1).endTime = endTime;
118
+ }
119
+ }
120
+ return timeline;
121
+ }
122
+ function getRawAudioDuration(rawAudio) {
123
+ if (rawAudio.audioChannels.length == 0 || rawAudio.sampleRate == 0 || !rawAudio.audioChannels[0]) {
124
+ return 0;
125
+ }
126
+ return rawAudio.audioChannels[0].length / rawAudio.sampleRate;
127
+ }
128
+ async function ensureRawAudio(input) {
129
+ const inputAsRawAudio = await decodeToChannels(input);
130
+ return inputAsRawAudio;
131
+ }
132
+ async function decodeToChannels(input) {
133
+ const outputPath = await (0, import_convert.fileToWav)(input);
134
+ const waveAudio = await readFileAsBinary(outputPath);
135
+ return decodeWaveToRawAudio(waveAudio);
136
+ }
137
+ function decodeWaveToRawAudio(waveFileBuffer, ignoreTruncatedChunks = true, ignoreOverflowingDataChunks = true) {
138
+ const rawAudio = decodeWaveToFloat32Channels(
139
+ waveFileBuffer,
140
+ ignoreTruncatedChunks,
141
+ ignoreOverflowingDataChunks
142
+ );
143
+ return { rawAudio };
144
+ }
145
+ class AdaptiveGateVAD {
146
+ constructor(sampleRate, channelCount, options) {
147
+ this.sampleRate = sampleRate;
148
+ this.channelCount = channelCount;
149
+ this.options = options;
150
+ this.channelHighpassFilters = [];
151
+ this.channelLowpassFilters = [];
152
+ for (let i = 0; i < this.channelCount; i++) {
153
+ this.channelHighpassFilters.push(
154
+ createHighpassFilter(this.sampleRate, options.lowCutoff)
155
+ );
156
+ this.channelLowpassFilters.push(
157
+ createLowpassFilter(this.sampleRate, options.highCutoff)
158
+ );
159
+ }
160
+ this.loudnessEstimator = new LoudnessEstimator({
161
+ sampleRate: this.sampleRate,
162
+ channelCount: this.channelCount,
163
+ positiveAdaptationRate: options.positiveAdaptationRate,
164
+ negativeAdaptationRate: options.negativeAdaptationRate,
165
+ initialEstimate: -60,
166
+ minimumLoudness: -60,
167
+ applyKWeighting: false
168
+ });
169
+ const ticksPerSecond = this.sampleRate * this.channelCount;
170
+ this.minimumLoudnessEstimator = new DecayingPeakEstimator(
171
+ {
172
+ kind: "minimum",
173
+ decayPerSecond: options.peakLoudnessDecay,
174
+ initialPeak: -60
175
+ },
176
+ ticksPerSecond
177
+ );
178
+ this.maximumLoudnessEstimator = new DecayingPeakEstimator(
179
+ {
180
+ kind: "maximum",
181
+ decayPerSecond: options.peakLoudnessDecay,
182
+ initialPeak: -60
183
+ },
184
+ ticksPerSecond
185
+ );
186
+ }
187
+ channelHighpassFilters;
188
+ channelLowpassFilters;
189
+ loudnessEstimator;
190
+ minimumLoudnessEstimator;
191
+ maximumLoudnessEstimator;
192
+ process(sample, channelIndex) {
193
+ const highpassFilter = this.channelHighpassFilters[channelIndex];
194
+ const lowpassFilter = this.channelLowpassFilters[channelIndex];
195
+ if (!highpassFilter || !lowpassFilter) {
196
+ throw new Error(`filters for channel ${channelIndex} not found`);
197
+ }
198
+ sample = highpassFilter.filter(sample);
199
+ sample = lowpassFilter.filter(sample);
200
+ this.loudnessEstimator.process(sample, channelIndex);
201
+ const currentLoudness = this.loudnessEstimator.currentLoudness;
202
+ this.minimumLoudnessEstimator.process(currentLoudness);
203
+ if (currentLoudness >= -60) {
204
+ this.maximumLoudnessEstimator.process(currentLoudness);
205
+ }
206
+ }
207
+ }
208
+ const defaultAdaptiveGateOptions = {
209
+ lowCutoff: 100,
210
+ highCutoff: 1e3,
211
+ positiveAdaptationRate: 400,
212
+ negativeAdaptationRate: 10,
213
+ peakLoudnessDecay: 4,
214
+ backwardExtensionDuration: 0.2,
215
+ relativeThreshold: -15
216
+ };
217
+ class LoudnessEstimator {
218
+ constructor(options) {
219
+ this.options = options;
220
+ const initialMeanSquares = decibelsToGainFactor(options.initialEstimate) ** 2;
221
+ const ticksPerSecond = this.options.sampleRate * this.options.channelCount;
222
+ for (let i = 0; i < options.channelCount; i++) {
223
+ const weightingFilter = new KWeightingFilter(options.sampleRate);
224
+ const channelMeanSquares = new SmoothEstimator(
225
+ options.positiveAdaptationRate / ticksPerSecond,
226
+ options.negativeAdaptationRate / ticksPerSecond,
227
+ initialMeanSquares
228
+ );
229
+ this.channelFilters.push(weightingFilter);
230
+ this.channelMeanSquares.push(channelMeanSquares);
231
+ }
232
+ this.minPower = decibelsToGainFactor(options.minimumLoudness) ** 2;
233
+ }
234
+ channelFilters = [];
235
+ channelMeanSquares = [];
236
+ minPower;
237
+ process(sample, channel) {
238
+ let filteredSample;
239
+ if (this.options.applyKWeighting) {
240
+ const filter = this.channelFilters[channel];
241
+ if (!filter) {
242
+ throw new Error(`channel filter ${channel} not found`);
243
+ }
244
+ filteredSample = filter.process(sample);
245
+ } else {
246
+ filteredSample = sample;
247
+ }
248
+ const filteredSampleSquared = filteredSample ** 2;
249
+ const channelMeanSquares = this.channelMeanSquares[channel];
250
+ if (!channelMeanSquares) {
251
+ throw new Error(`channel mean squares ${channel} not found`);
252
+ }
253
+ channelMeanSquares.update(filteredSampleSquared);
254
+ channelMeanSquares.estimate = Math.max(
255
+ channelMeanSquares.estimate,
256
+ this.minPower
257
+ );
258
+ }
259
+ get currentLoudness() {
260
+ let totalMeanSquares = 0;
261
+ for (let i = 0; i < this.options.channelCount; i++) {
262
+ const channelMeanSquare = this.channelMeanSquares[i];
263
+ if (!channelMeanSquare) {
264
+ throw new Error(`channel mean square ${i} not found`);
265
+ }
266
+ totalMeanSquares += channelMeanSquare.estimate;
267
+ }
268
+ const rms = Math.sqrt(totalMeanSquares / this.options.channelCount);
269
+ const rmsDecibels = gainFactorToDecibels(rms);
270
+ return rmsDecibels;
271
+ }
272
+ getCurrentRMSForChannel(channel) {
273
+ const channelMeanSquare = this.channelMeanSquares[channel];
274
+ if (!channelMeanSquare) {
275
+ throw new Error(`channel mean square ${channel} not found`);
276
+ }
277
+ return Math.sqrt(channelMeanSquare.estimate);
278
+ }
279
+ }
280
+ class DecayingPeakEstimator {
281
+ constructor(options, ticksPerSecond) {
282
+ this.options = options;
283
+ this.ticksPerSecond = ticksPerSecond;
284
+ this.currentPeak = options.initialPeak;
285
+ this.decayPerTick = this.options.decayPerSecond / this.ticksPerSecond;
286
+ this.process = options.kind === "maximum" ? this.processMaximum.bind(this) : this.processMinimum.bind(this);
287
+ }
288
+ decayPerTick;
289
+ currentPeak;
290
+ process;
291
+ processMaximum(value) {
292
+ this.currentPeak -= this.decayPerTick;
293
+ this.currentPeak = Math.max(value, this.currentPeak);
294
+ }
295
+ processMinimum(value) {
296
+ this.currentPeak += this.decayPerTick;
297
+ this.currentPeak = Math.min(value, this.currentPeak);
298
+ }
299
+ }
300
+ function createLowpassFilter(sampleRate, cutoffFrequency, q = 0.7071) {
301
+ return createFilter("lowpass", sampleRate, cutoffFrequency, q, 0);
302
+ }
303
+ function createHighpassFilter(sampleRate, cutoffFrequency, q = 0.7071) {
304
+ return createFilter("highpass", sampleRate, cutoffFrequency, q, 0);
305
+ }
306
+ function createHighshelfFilter(sampleRate, midpointFrequency, gain) {
307
+ return createFilter("highshelf", sampleRate, midpointFrequency, 0, gain);
308
+ }
309
+ function createFilter(filterType, sampleRate, frequency, q, gain) {
310
+ const coefficients = getFilterCoefficients(
311
+ filterType,
312
+ sampleRate,
313
+ frequency,
314
+ q,
315
+ gain
316
+ );
317
+ return new BiquadFilter(coefficients);
318
+ }
319
+ class BiquadFilter {
320
+ b0 = 0;
321
+ b1 = 0;
322
+ b2 = 0;
323
+ a1 = 0;
324
+ a2 = 0;
325
+ prevInput1 = 0;
326
+ prevInput2 = 0;
327
+ prevOutput1 = 0;
328
+ prevOutput2 = 0;
329
+ constructor(coefficients) {
330
+ this.setCoefficients(coefficients);
331
+ }
332
+ filter(sample) {
333
+ const filteredSample = this.b0 * sample + this.b1 * this.prevInput1 + this.b2 * this.prevInput2 - this.a1 * this.prevOutput1 - this.a2 * this.prevOutput2;
334
+ this.prevInput2 = this.prevInput1;
335
+ this.prevInput1 = sample;
336
+ this.prevOutput2 = this.prevOutput1;
337
+ this.prevOutput1 = filteredSample;
338
+ return filteredSample;
339
+ }
340
+ filterSamplesInPlace(samples) {
341
+ for (let i = 0; i < samples.length; i++) {
342
+ const sample = samples[i];
343
+ if (sample === void 0) {
344
+ throw new Error(`sample at index ${i} not found`);
345
+ }
346
+ samples[i] = this.filter(sample);
347
+ }
348
+ }
349
+ reset() {
350
+ this.prevInput1 = 0;
351
+ this.prevInput2 = 0;
352
+ this.prevOutput1 = 0;
353
+ this.prevOutput2 = 0;
354
+ }
355
+ setCoefficients(coefficients) {
356
+ this.b0 = coefficients.b0;
357
+ this.b1 = coefficients.b1;
358
+ this.b2 = coefficients.b2;
359
+ this.a1 = coefficients.a1;
360
+ this.a2 = coefficients.a2;
361
+ }
362
+ }
363
+ function getFilterCoefficients(filterType, sampleRate, centerFrequency, q, gain) {
364
+ const nyquistFrequency = sampleRate / 2;
365
+ const freqRatio = clamp(centerFrequency / nyquistFrequency, 0, 1);
366
+ return filterCoefficientsFunction[filterType](freqRatio, q, gain);
367
+ }
368
+ function getLowpassFilterCoefficients(freqRatio, q, _gain) {
369
+ let b0;
370
+ let b1;
371
+ let b2;
372
+ let a0;
373
+ let a1;
374
+ let a2;
375
+ if (freqRatio == 1) {
376
+ b0 = 1;
377
+ b1 = 0;
378
+ b2 = 0;
379
+ a0 = 1;
380
+ a1 = 0;
381
+ a2 = 0;
382
+ } else {
383
+ const theta = Math.PI * freqRatio;
384
+ const alpha = Math.sin(theta) / (2 * Math.pow(10, q / 20));
385
+ const cosw = Math.cos(theta);
386
+ const beta = (1 - cosw) / 2;
387
+ b0 = beta;
388
+ b1 = 2 * beta;
389
+ b2 = beta;
390
+ a0 = 1 + alpha;
391
+ a1 = -2 * cosw;
392
+ a2 = 1 - alpha;
393
+ }
394
+ return normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
395
+ }
396
+ function getHighpassFilterCoefficients(freqRatio, q, _gain) {
397
+ let b0;
398
+ let b1;
399
+ let b2;
400
+ let a0;
401
+ let a1;
402
+ let a2;
403
+ if (freqRatio == 1) {
404
+ b0 = 0;
405
+ b1 = 0;
406
+ b2 = 0;
407
+ a0 = 1;
408
+ a1 = 0;
409
+ a2 = 0;
410
+ } else if (freqRatio == 0) {
411
+ b0 = 1;
412
+ b1 = 0;
413
+ b2 = 0;
414
+ a0 = 1;
415
+ a1 = 0;
416
+ a2 = 0;
417
+ } else {
418
+ const theta = Math.PI * freqRatio;
419
+ const alpha = Math.sin(theta) / (2 * Math.pow(10, q / 20));
420
+ const cosw = Math.cos(theta);
421
+ const beta = (1 + cosw) / 2;
422
+ b0 = beta;
423
+ b1 = -2 * beta;
424
+ b2 = beta;
425
+ a0 = 1 + alpha;
426
+ a1 = -2 * cosw;
427
+ a2 = 1 - alpha;
428
+ }
429
+ return normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
430
+ }
431
+ function getBandpassFilterCoefficients(freqRatio, q, _gain = 0) {
432
+ let b0;
433
+ let b1;
434
+ let b2;
435
+ let a0;
436
+ let a1;
437
+ let a2;
438
+ let coefficients;
439
+ if (freqRatio > 0 && freqRatio < 1) {
440
+ const w0 = Math.PI * freqRatio;
441
+ if (q > 0) {
442
+ const alpha = Math.sin(w0) / (2 * q);
443
+ const k = Math.cos(w0);
444
+ b0 = alpha;
445
+ b1 = 0;
446
+ b2 = -alpha;
447
+ a0 = 1 + alpha;
448
+ a1 = -2 * k;
449
+ a2 = 1 - alpha;
450
+ coefficients = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
451
+ } else {
452
+ coefficients = { b0: 1, b1: 0, b2: 0, a1: 0, a2: 0 };
453
+ }
454
+ } else {
455
+ coefficients = { b0: 0, b1: 0, b2: 0, a1: 0, a2: 0 };
456
+ }
457
+ return coefficients;
458
+ }
459
+ function getLowShelfFilterCoefficients(freqRatio, _q = 0, gain) {
460
+ let b0;
461
+ let b1;
462
+ let b2;
463
+ let a0;
464
+ let a1;
465
+ let a2;
466
+ let coefficients;
467
+ const S = 1;
468
+ const A = Math.pow(10, gain / 40);
469
+ if (freqRatio == 1) {
470
+ coefficients = { b0: A * A, b1: 0, b2: 0, a1: 0, a2: 0 };
471
+ } else if (freqRatio == 0) {
472
+ coefficients = { b0: 1, b1: 0, b2: 0, a1: 0, a2: 0 };
473
+ } else {
474
+ const w0 = Math.PI * freqRatio;
475
+ const alpha = 1 / 2 * Math.sin(w0) * Math.sqrt((A + 1 / A) * (1 / S - 1) + 2);
476
+ const k = Math.cos(w0);
477
+ const k2 = 2 * Math.sqrt(A) * alpha;
478
+ const Ap1 = A + 1;
479
+ const Am1 = A - 1;
480
+ b0 = A * (Ap1 - Am1 * k + k2);
481
+ b1 = 2 * A * (Am1 - Ap1 * k);
482
+ b2 = A * (Ap1 - Am1 * k - k2);
483
+ a0 = Ap1 + Am1 * k + k2;
484
+ a1 = -2 * (Am1 + Ap1 * k);
485
+ a2 = Ap1 + Am1 * k - k2;
486
+ coefficients = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
487
+ }
488
+ return coefficients;
489
+ }
490
+ function getHighShelfFilterCoefficients(freqRatio, _q = 0, gain) {
491
+ let b0;
492
+ let b1;
493
+ let b2;
494
+ let a0;
495
+ let a1;
496
+ let a2;
497
+ let coefficients;
498
+ const A = Math.pow(10, gain / 40);
499
+ if (freqRatio == 1) {
500
+ coefficients = { b0: 1, b1: 0, b2: 0, a1: 0, a2: 0 };
501
+ } else if (freqRatio > 0) {
502
+ const w0 = Math.PI * freqRatio;
503
+ const S = 1;
504
+ const alpha = 0.5 * Math.sin(w0) * Math.sqrt((A + 1 / A) * (1 / S - 1) + 2);
505
+ const k = Math.cos(w0);
506
+ const k2 = 2 * Math.sqrt(A) * alpha;
507
+ const Ap1 = A + 1;
508
+ const Am1 = A - 1;
509
+ b0 = A * (Ap1 + Am1 * k + k2);
510
+ b1 = -2 * A * (Am1 + Ap1 * k);
511
+ b2 = A * (Ap1 + Am1 * k - k2);
512
+ a0 = Ap1 - Am1 * k + k2;
513
+ a1 = 2 * (Am1 - Ap1 * k);
514
+ a2 = Ap1 - Am1 * k - k2;
515
+ coefficients = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
516
+ } else {
517
+ coefficients = { b0: A * A, b1: 0, b2: 0, a1: 0, a2: 0 };
518
+ }
519
+ return coefficients;
520
+ }
521
+ function getPeakingFilterCoefficients(freqRatio, q, gain) {
522
+ let b0;
523
+ let b1;
524
+ let b2;
525
+ let a0;
526
+ let a1;
527
+ let a2;
528
+ let coefficients;
529
+ const A = Math.pow(10, gain / 40);
530
+ if (freqRatio > 0 && freqRatio < 1) {
531
+ if (q > 0) {
532
+ const w0 = Math.PI * freqRatio;
533
+ const alpha = Math.sin(w0) / (2 * q);
534
+ const k = Math.cos(w0);
535
+ b0 = 1 + alpha * A;
536
+ b1 = -2 * k;
537
+ b2 = 1 - alpha * A;
538
+ a0 = 1 + alpha / A;
539
+ a1 = -2 * k;
540
+ a2 = 1 - alpha / A;
541
+ coefficients = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
542
+ } else {
543
+ coefficients = { b0: A * A, b1: 0, b2: 0, a1: 0, a2: 0 };
544
+ }
545
+ } else {
546
+ coefficients = { b0: 1, b1: 0, b2: 0, a1: 0, a2: 0 };
547
+ }
548
+ return coefficients;
549
+ }
550
+ function getNotchFilterCoefficients(freqRatio, q, _gain) {
551
+ let b0;
552
+ let b1;
553
+ let b2;
554
+ let a0;
555
+ let a1;
556
+ let a2;
557
+ let coefficients;
558
+ if (freqRatio > 0 && freqRatio < 1) {
559
+ if (q > 0) {
560
+ const w0 = Math.PI * freqRatio;
561
+ const alpha = Math.sin(w0) / (2 * q);
562
+ const k = Math.cos(w0);
563
+ b0 = 1;
564
+ b1 = -2 * k;
565
+ b2 = 1;
566
+ a0 = 1 + alpha;
567
+ a1 = -2 * k;
568
+ a2 = 1 - alpha;
569
+ coefficients = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
570
+ } else {
571
+ coefficients = { b0: 0, b1: 0, b2: 0, a1: 0, a2: 0 };
572
+ }
573
+ } else {
574
+ coefficients = { b0: 1, b1: 0, b2: 0, a1: 0, a2: 0 };
575
+ }
576
+ return coefficients;
577
+ }
578
+ function getAllpassFilterCoefficients(freqRatio, q, _gain) {
579
+ let b0;
580
+ let b1;
581
+ let b2;
582
+ let a0;
583
+ let a1;
584
+ let a2;
585
+ let coefficients;
586
+ if (freqRatio > 0 && freqRatio < 1) {
587
+ if (q > 0) {
588
+ const w0 = Math.PI * freqRatio;
589
+ const alpha = Math.sin(w0) / (2 * q);
590
+ const k = Math.cos(w0);
591
+ b0 = 1 - alpha;
592
+ b1 = -2 * k;
593
+ b2 = 1 + alpha;
594
+ a0 = 1 + alpha;
595
+ a1 = -2 * k;
596
+ a2 = 1 - alpha;
597
+ coefficients = normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2);
598
+ } else {
599
+ coefficients = { b0: -1, b1: 0, b2: 0, a1: 0, a2: 0 };
600
+ }
601
+ } else {
602
+ coefficients = { b0: 1, b1: 0, b2: 0, a1: 0, a2: 0 };
603
+ }
604
+ return coefficients;
605
+ }
606
+ function normalizeFilterCoefficients(b0, b1, b2, a0, a1, a2) {
607
+ const scale = 1 / a0;
608
+ return {
609
+ b0: b0 * scale,
610
+ b1: b1 * scale,
611
+ b2: b2 * scale,
612
+ a1: a1 * scale,
613
+ a2: a2 * scale
614
+ };
615
+ }
616
+ function clamp(num, min, max) {
617
+ return Math.max(min, Math.min(max, num));
618
+ }
619
+ const filterCoefficientsFunction = {
620
+ lowpass: getLowpassFilterCoefficients,
621
+ highpass: getHighpassFilterCoefficients,
622
+ bandpass: getBandpassFilterCoefficients,
623
+ lowshelf: getLowShelfFilterCoefficients,
624
+ highshelf: getHighShelfFilterCoefficients,
625
+ peaking: getPeakingFilterCoefficients,
626
+ notch: getNotchFilterCoefficients,
627
+ allpass: getAllpassFilterCoefficients
628
+ };
629
+ class SmoothEstimator {
630
+ constructor(positiveAdaptationRate, negativeAdaptationRate, initialEstimate = 0) {
631
+ this.positiveAdaptationRate = positiveAdaptationRate;
632
+ this.negativeAdaptationRate = negativeAdaptationRate;
633
+ this.estimate = initialEstimate;
634
+ }
635
+ estimate;
636
+ update(target, adaptaionRateFactor = 1) {
637
+ const residual = target - this.estimate;
638
+ const adaptationRate = residual >= 0 ? this.positiveAdaptationRate : this.negativeAdaptationRate;
639
+ const stepSize = residual * adaptationRate * adaptaionRateFactor;
640
+ this.estimate += stepSize;
641
+ }
642
+ updateDamped(target, dampingReference, dampingCurvature, adaptationRateFactor = 1) {
643
+ const residual = target - this.estimate;
644
+ const scaledResidualMagnitude = Math.abs(residual) * dampingCurvature;
645
+ const dampingFactor = scaledResidualMagnitude / (scaledResidualMagnitude + dampingReference);
646
+ const adaptationRate = residual >= 0 ? this.positiveAdaptationRate : this.negativeAdaptationRate;
647
+ const stepSize = residual * adaptationRate * adaptationRateFactor * dampingFactor;
648
+ this.estimate += stepSize;
649
+ }
650
+ }
651
+ class KWeightingFilter {
652
+ constructor(sampleRate, useStandard44100Filters = false) {
653
+ this.sampleRate = sampleRate;
654
+ this.useStandard44100Filters = useStandard44100Filters;
655
+ if (useStandard44100Filters) {
656
+ this.highShelfFilter = new BiquadFilter({
657
+ b0: 1.53512485958697,
658
+ b1: -2.69169618940638,
659
+ b2: 1.19839281085285,
660
+ a1: -1.69065929318241,
661
+ a2: 0.73248077421585
662
+ });
663
+ this.highPassFilter = new BiquadFilter({
664
+ b0: 1,
665
+ b1: -2,
666
+ b2: 1,
667
+ a1: -1.99004745483398,
668
+ a2: 0.99007225036621
669
+ });
670
+ } else {
671
+ this.highShelfFilter = createHighshelfFilter(sampleRate, 2e3, 4);
672
+ this.highPassFilter = createHighpassFilter(sampleRate, 1.5, 0.01);
673
+ }
674
+ }
675
+ highShelfFilter;
676
+ highPassFilter;
677
+ process(sample) {
678
+ let outputSample = sample;
679
+ outputSample = this.highShelfFilter.filter(outputSample);
680
+ outputSample = this.highPassFilter.filter(outputSample);
681
+ return outputSample;
682
+ }
683
+ }
684
+ function gainFactorToDecibels(gainFactor) {
685
+ return gainFactor <= 1e-5 ? -100 : 20 * Math.log10(gainFactor);
686
+ }
687
+ function decibelsToGainFactor(decibels) {
688
+ return decibels <= -100 ? 0 : Math.pow(10, 0.05 * decibels);
689
+ }
690
+ function decodeWaveToFloat32Channels(waveData, ignoreTruncatedChunks = true, ignoreOverflowingDataChunks = true) {
691
+ const {
692
+ decodedAudioBuffer,
693
+ sampleRate,
694
+ channelCount,
695
+ bitDepth,
696
+ sampleFormat
697
+ } = decodeWaveToBuffer(
698
+ waveData,
699
+ ignoreTruncatedChunks,
700
+ ignoreOverflowingDataChunks
701
+ );
702
+ const audioChannels = bufferToFloat32Channels(
703
+ decodedAudioBuffer,
704
+ channelCount,
705
+ bitDepth,
706
+ sampleFormat
707
+ );
708
+ return {
709
+ audioChannels,
710
+ sampleRate
711
+ };
712
+ }
713
+ function decodeWaveToBuffer(waveData, ignoreTruncatedChunks = true, ignoreOverflowingDataChunks = true) {
714
+ let readOffset = 0;
715
+ const riffId = (0, import_Ascii.decodeAscii)(waveData.subarray(readOffset, readOffset + 4));
716
+ if (riffId !== "RIFF") {
717
+ throw new Error("Not a valid wave file. No RIFF id found at offset 0.");
718
+ }
719
+ readOffset += 4;
720
+ let riffChunkSize = readUint32LE(waveData, readOffset);
721
+ readOffset += 4;
722
+ const waveId = (0, import_Ascii.decodeAscii)(waveData.subarray(readOffset, readOffset + 4));
723
+ if (waveId !== "WAVE") {
724
+ throw new Error("Not a valid wave file. No WAVE id found at offset 8.");
725
+ }
726
+ if (ignoreOverflowingDataChunks && riffChunkSize === 4294967295) {
727
+ riffChunkSize = waveData.length - 8;
728
+ }
729
+ if (riffChunkSize < waveData.length - 8) {
730
+ throw new Error(
731
+ `RIFF chunk length ${riffChunkSize} is smaller than the remaining size of the buffer (${waveData.length - 8})`
732
+ );
733
+ }
734
+ if (!ignoreTruncatedChunks && riffChunkSize > waveData.length - 8) {
735
+ throw new Error(
736
+ `RIFF chunk length (${riffChunkSize}) is greater than the remaining size of the buffer (${waveData.length - 8})`
737
+ );
738
+ }
739
+ readOffset += 4;
740
+ let formatSubChunkBodyBuffer;
741
+ const dataBuffers = [];
742
+ while (true) {
743
+ const subChunkIdentifier = (0, import_Ascii.decodeAscii)(
744
+ waveData.subarray(readOffset, readOffset + 4)
745
+ );
746
+ readOffset += 4;
747
+ let subChunkSize = readUint32LE(waveData, readOffset);
748
+ readOffset += 4;
749
+ if (!ignoreTruncatedChunks && subChunkSize > waveData.length - readOffset) {
750
+ throw new Error(
751
+ `Encountered a '${subChunkIdentifier}' subchunk with a size of ${subChunkSize} which is greater than the remaining size of the buffer (${waveData.length - readOffset})`
752
+ );
753
+ }
754
+ if (subChunkIdentifier === "fmt ") {
755
+ formatSubChunkBodyBuffer = waveData.subarray(
756
+ readOffset,
757
+ readOffset + subChunkSize
758
+ );
759
+ } else if (subChunkIdentifier === "data") {
760
+ if (!formatSubChunkBodyBuffer) {
761
+ throw new Error(
762
+ "A data subchunk was encountered before a format subchunk"
763
+ );
764
+ }
765
+ if (ignoreOverflowingDataChunks && subChunkSize === 4294967295) {
766
+ subChunkSize = waveData.length - readOffset;
767
+ }
768
+ const subChunkData = waveData.subarray(
769
+ readOffset,
770
+ readOffset + subChunkSize
771
+ );
772
+ dataBuffers.push(subChunkData);
773
+ }
774
+ readOffset += subChunkSize;
775
+ if (readOffset >= waveData.length) {
776
+ break;
777
+ }
778
+ }
779
+ if (!formatSubChunkBodyBuffer) {
780
+ throw new Error("No format subchunk was found in the wave file");
781
+ }
782
+ if (dataBuffers.length === 0) {
783
+ throw new Error("No data subchunks were found in the wave file");
784
+ }
785
+ const waveFormat = WaveFormatHeader.deserializeFrom(formatSubChunkBodyBuffer);
786
+ const sampleFormat = waveFormat.sampleFormat;
787
+ const channelCount = waveFormat.channelCount;
788
+ const sampleRate = waveFormat.sampleRate;
789
+ const bitDepth = waveFormat.bitDepth;
790
+ const speakerPositionMask = waveFormat.speakerPositionMask;
791
+ const decodedAudioBuffer = concatUint8Arrays(dataBuffers);
792
+ return {
793
+ decodedAudioBuffer,
794
+ sampleRate,
795
+ channelCount,
796
+ bitDepth,
797
+ sampleFormat,
798
+ speakerPositionMask
799
+ };
800
+ }
801
+ function concatUint8Arrays(arrays) {
802
+ return concatTypedArrays(Uint8Array, arrays);
803
+ }
804
+ function concatTypedArrays(TypedArrayConstructor, arrays) {
805
+ let totalLength = 0;
806
+ for (const array of arrays) {
807
+ totalLength += array.length;
808
+ }
809
+ const result = new TypedArrayConstructor(totalLength);
810
+ let writeOffset = 0;
811
+ for (const array of arrays) {
812
+ result.set(array, writeOffset);
813
+ writeOffset += array.length;
814
+ }
815
+ return result;
816
+ }
817
+ function readUint16LE(buffer, offset) {
818
+ const byte0 = buffer[offset];
819
+ const byte1 = buffer[offset + 1];
820
+ if (byte0 === void 0 || byte1 === void 0) {
821
+ throw new Error(`buffer access out of bounds at offset ${offset}`);
822
+ }
823
+ return byte0 | byte1 << 8;
824
+ }
825
+ function writeUint16LE(buffer, value, offset) {
826
+ if (value < 0 || value > 65535) {
827
+ throw new Error(
828
+ `Value ${value} is outside the range of a 16-bit unsigned integer`
829
+ );
830
+ }
831
+ buffer[offset] = value & 255;
832
+ buffer[offset + 1] = value >>> 8 & 255;
833
+ }
834
+ function readUint32LE(buffer, offset) {
835
+ return readInt32LE(buffer, offset) >>> 0;
836
+ }
837
+ function writeUint32LE(buffer, value, offset) {
838
+ if (value < 0 || value > 4294967295) {
839
+ throw new Error(
840
+ `Value ${value} is outside the range of a 32-bit unsigned integer`
841
+ );
842
+ }
843
+ buffer[offset] = value & 255;
844
+ buffer[offset + 1] = value >>> 8 & 255;
845
+ buffer[offset + 2] = value >>> 16 & 255;
846
+ buffer[offset + 3] = value >>> 24 & 255;
847
+ }
848
+ class WaveFormatHeader {
849
+ sampleFormat;
850
+ // 2 bytes LE
851
+ channelCount;
852
+ // 2 bytes LE
853
+ sampleRate;
854
+ // 4 bytes LE
855
+ get byteRate() {
856
+ return this.sampleRate * this.bytesPerSample * this.channelCount;
857
+ }
858
+ // 4 bytes LE
859
+ get blockAlign() {
860
+ return this.bytesPerSample * this.channelCount;
861
+ }
862
+ // 2 bytes LE
863
+ bitDepth;
864
+ // 2 bytes LE
865
+ speakerPositionMask;
866
+ // 4 bytes LE
867
+ get guid() {
868
+ return sampleFormatToGuid[this.sampleFormat];
869
+ }
870
+ // 16 bytes BE
871
+ get bytesPerSample() {
872
+ return this.bitDepth / 8;
873
+ }
874
+ constructor(channelCount, sampleRate, bitDepth, sampleFormat, speakerPositionMask = 0) {
875
+ this.sampleFormat = sampleFormat;
876
+ this.channelCount = channelCount;
877
+ this.sampleRate = sampleRate;
878
+ this.bitDepth = bitDepth;
879
+ this.speakerPositionMask = speakerPositionMask;
880
+ }
881
+ serialize(useExtensibleFormat) {
882
+ const sampleFormatId = this.sampleFormat;
883
+ const serializedSize = sampleFormatToSerializedSize[sampleFormatId];
884
+ const result = new Uint8Array(serializedSize);
885
+ writeAscii(result, "fmt ", 0);
886
+ writeUint32LE(result, serializedSize - 8, 4);
887
+ writeUint16LE(result, sampleFormatId, 8);
888
+ writeUint16LE(result, this.channelCount, 10);
889
+ writeUint32LE(result, this.sampleRate, 12);
890
+ writeUint32LE(result, this.byteRate, 16);
891
+ writeUint16LE(result, this.blockAlign, 20);
892
+ writeUint16LE(result, this.bitDepth, 22);
893
+ if (useExtensibleFormat) {
894
+ writeUint16LE(result, serializedSize - 26, 24);
895
+ writeUint16LE(result, this.bitDepth, 26);
896
+ writeUint32LE(result, this.speakerPositionMask, 28);
897
+ if (this.guid) {
898
+ result.set(decodeHex(this.guid), 32);
899
+ } else {
900
+ throw new Error(
901
+ `Extensible format is not supported for sample format ${this.sampleFormat}`
902
+ );
903
+ }
904
+ }
905
+ return result;
906
+ }
907
+ static deserializeFrom(formatChunkBody) {
908
+ let sampleFormat = readUint16LE(formatChunkBody, 0);
909
+ const channelCount = readUint16LE(formatChunkBody, 2);
910
+ const sampleRate = readUint32LE(formatChunkBody, 4);
911
+ const bitDepth = readUint16LE(formatChunkBody, 14);
912
+ let speakerPositionMask = 0;
913
+ if (sampleFormat === 65534) {
914
+ if (formatChunkBody.length < 40) {
915
+ throw new Error(
916
+ `Format subchunk specifies a format id of 65534 (extensible) but its body size is ${formatChunkBody.length} bytes, which is smaller than the minimum expected of 40 bytes`
917
+ );
918
+ }
919
+ speakerPositionMask = readUint16LE(formatChunkBody, 20);
920
+ const guid = encodeHex(formatChunkBody.subarray(24, 40));
921
+ if (guid === sampleFormatToGuid[SampleFormat.PCM]) {
922
+ sampleFormat = SampleFormat.PCM;
923
+ } else if (guid === sampleFormatToGuid[SampleFormat.Float]) {
924
+ sampleFormat = SampleFormat.Float;
925
+ } else if (guid === sampleFormatToGuid[SampleFormat.Alaw]) {
926
+ sampleFormat = SampleFormat.Alaw;
927
+ } else if (guid === sampleFormatToGuid[SampleFormat.Mulaw]) {
928
+ sampleFormat = SampleFormat.Mulaw;
929
+ } else {
930
+ throw new Error(
931
+ `Unsupported format GUID in extended format subchunk: ${guid}`
932
+ );
933
+ }
934
+ }
935
+ if (sampleFormat === SampleFormat.PCM) {
936
+ if (bitDepth !== 8 && bitDepth !== 16 && bitDepth !== 24 && bitDepth !== 32) {
937
+ throw new Error(
938
+ `PCM audio has a bit depth of ${bitDepth}, which is not supported`
939
+ );
940
+ }
941
+ } else if (sampleFormat === SampleFormat.Float) {
942
+ if (bitDepth !== 32 && bitDepth !== 64) {
943
+ throw new Error(
944
+ `IEEE float audio has a bit depth of ${bitDepth}, which is not supported`
945
+ );
946
+ }
947
+ } else if (sampleFormat === SampleFormat.Alaw) {
948
+ if (bitDepth !== 8) {
949
+ throw new Error(
950
+ `Alaw audio has a bit depth of ${bitDepth}, which is not supported`
951
+ );
952
+ }
953
+ } else if (sampleFormat === SampleFormat.Mulaw) {
954
+ if (bitDepth !== 8) {
955
+ throw new Error(
956
+ `Mulaw audio has a bit depth of ${bitDepth}, which is not supported`
957
+ );
958
+ }
959
+ } else {
960
+ throw new Error(`Wave audio format id ${sampleFormat} is not supported`);
961
+ }
962
+ return new WaveFormatHeader(
963
+ channelCount,
964
+ sampleRate,
965
+ bitDepth,
966
+ sampleFormat,
967
+ speakerPositionMask
968
+ );
969
+ }
970
+ }
971
+ const SampleFormat = {
972
+ PCM: 1,
973
+ Float: 3,
974
+ Alaw: 6,
975
+ Mulaw: 7
976
+ };
977
+ const sampleFormatToSerializedSize = {
978
+ [SampleFormat.PCM]: 24,
979
+ [SampleFormat.Float]: 26,
980
+ [SampleFormat.Alaw]: 26,
981
+ [SampleFormat.Mulaw]: 26,
982
+ 65534: 48
983
+ };
984
+ const sampleFormatToGuid = {
985
+ [SampleFormat.PCM]: "0100000000001000800000aa00389b71",
986
+ [SampleFormat.Float]: "0300000000001000800000aa00389b71",
987
+ [SampleFormat.Alaw]: "0600000000001000800000aa00389b71",
988
+ [SampleFormat.Mulaw]: "0700000000001000800000aa00389b71"
989
+ };
990
+ function bufferToFloat32Channels(audioBuffer, channelCount, sourceBitDepth, sourceSampleFormat) {
991
+ let interleavedChannels;
992
+ if (sourceSampleFormat === SampleFormat.PCM && sourceBitDepth === 16) {
993
+ interleavedChannels = int16PcmToFloat32(bytesLEToInt16Array(audioBuffer));
994
+ } else {
995
+ throw new Error(`Unsupported PCM bit depth: ${sourceBitDepth}`);
996
+ }
997
+ audioBuffer = new Uint8Array(0);
998
+ return deinterleaveChannels(interleavedChannels, channelCount);
999
+ }
1000
+ function readInt32LE(buffer, offset) {
1001
+ const byte0 = buffer[offset];
1002
+ const byte1 = buffer[offset + 1];
1003
+ const byte2 = buffer[offset + 2];
1004
+ const byte3 = buffer[offset + 3];
1005
+ if (byte0 === void 0 || byte1 === void 0 || byte2 === void 0 || byte3 === void 0) {
1006
+ throw new Error(`buffer access out of bounds at offset ${offset}`);
1007
+ }
1008
+ const value = byte0 | byte1 << 8 | byte2 << 16 | byte3 << 24;
1009
+ return value;
1010
+ }
1011
+ function interleaveChannels(channels) {
1012
+ const channelCount = channels.length;
1013
+ const firstChannel = channels[0];
1014
+ if (!firstChannel) {
1015
+ throw new Error("Empty channel array received");
1016
+ }
1017
+ if (channelCount === 1) {
1018
+ return firstChannel;
1019
+ }
1020
+ const sampleCount = firstChannel.length;
1021
+ const result = new Float32Array(sampleCount * channelCount);
1022
+ let writeIndex = 0;
1023
+ for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
1024
+ for (let channelIndex = 0; channelIndex < channelCount; channelIndex++) {
1025
+ const channel = channels[channelIndex];
1026
+ if (!channel) {
1027
+ throw new Error(`channel ${channelIndex} not found`);
1028
+ }
1029
+ const sample = channel[sampleIndex];
1030
+ if (sample === void 0) {
1031
+ throw new Error(
1032
+ `sample at index ${sampleIndex} not found in channel ${channelIndex}`
1033
+ );
1034
+ }
1035
+ result[writeIndex++] = sample;
1036
+ }
1037
+ }
1038
+ return result;
1039
+ }
1040
+ function deinterleaveChannels(interleavedChannels, channelCount) {
1041
+ if (channelCount < 1) {
1042
+ throw new Error(
1043
+ `Invalid channel count of ${channelCount} received, which is smaller than 1`
1044
+ );
1045
+ }
1046
+ if (channelCount === 1) {
1047
+ return [interleavedChannels];
1048
+ }
1049
+ if (interleavedChannels.length % channelCount !== 0) {
1050
+ throw new Error(
1051
+ `Size of interleaved channels (${interleaveChannels.length}) is not a multiple of channel count (${channelCount})`
1052
+ );
1053
+ }
1054
+ const sampleCount = interleavedChannels.length / channelCount;
1055
+ const channels = [];
1056
+ for (let i = 0; i < channelCount; i++) {
1057
+ channels.push(new Float32Array(sampleCount));
1058
+ }
1059
+ let readIndex = 0;
1060
+ for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
1061
+ for (let channelIndex = 0; channelIndex < channelCount; channelIndex++) {
1062
+ const channel = channels[channelIndex];
1063
+ if (!channel) {
1064
+ throw new Error(`channel ${channelIndex} not found`);
1065
+ }
1066
+ const sample = interleavedChannels[readIndex++];
1067
+ if (sample === void 0) {
1068
+ throw new Error(
1069
+ `interleaved sample at index ${readIndex - 1} not found`
1070
+ );
1071
+ }
1072
+ channel[sampleIndex] = sample;
1073
+ }
1074
+ }
1075
+ return channels;
1076
+ }
1077
+ function int16PcmToFloat32(input) {
1078
+ const sampleCount = input.length;
1079
+ const output = new Float32Array(sampleCount);
1080
+ for (let i = 0; i < sampleCount; i++) {
1081
+ const sample = input[i];
1082
+ if (sample === void 0) {
1083
+ throw new Error(`input sample at index ${i} not found`);
1084
+ }
1085
+ output[i] = sample * (1 / 32768);
1086
+ }
1087
+ return output;
1088
+ }
1089
+ function writeAscii(buffer, asciiString, writeStartOffset) {
1090
+ const writeEndOffset = Math.min(
1091
+ writeStartOffset + asciiString.length,
1092
+ buffer.length
1093
+ );
1094
+ let readOffset = 0;
1095
+ let writeOffset = writeStartOffset;
1096
+ while (writeOffset < writeEndOffset) {
1097
+ const charCode = asciiString.charCodeAt(readOffset++);
1098
+ if (charCode >= 128) {
1099
+ throw new Error(
1100
+ `Character '${asciiString[readOffset]}' (code: ${charCode}) at offset ${readOffset} can't be encoded as ASCII`
1101
+ );
1102
+ }
1103
+ buffer[writeOffset++] = charCode;
1104
+ }
1105
+ }
1106
+ const isLittleEndianArch = testIfLittleEndian();
1107
+ function testIfLittleEndian() {
1108
+ const uint16Array = new Uint16Array([4386]);
1109
+ const bytes = new Uint8Array(uint16Array.buffer);
1110
+ return bytes[0] === 34;
1111
+ }
1112
+ function reverseByteGroups(bytes, groupSize) {
1113
+ const result = bytes.slice();
1114
+ reverseByteGroupsInPlace(result, groupSize);
1115
+ return result;
1116
+ }
1117
+ function reverseByteGroupsInPlace(bytes, groupSize) {
1118
+ if (bytes.length % groupSize !== 0) {
1119
+ throw new Error(`Byte count must be an integer multiple of the group size.`);
1120
+ }
1121
+ const halfGroupSize = Math.floor(groupSize / 2);
1122
+ for (let offset = 0; offset < bytes.length; offset += groupSize) {
1123
+ const groupFirstElementOffset = offset;
1124
+ const groupLastElementOffset = offset + groupSize - 1;
1125
+ for (let i = 0; i < halfGroupSize; i++) {
1126
+ const offset1 = groupFirstElementOffset + i;
1127
+ const offset2 = groupLastElementOffset - i;
1128
+ const valueAtOffset1 = bytes[offset1];
1129
+ const valueAtOffset2 = bytes[offset2];
1130
+ if (valueAtOffset1 === void 0 || valueAtOffset2 === void 0) {
1131
+ throw new Error(
1132
+ `bytes access out of bounds at offsets ${offset1}, ${offset2}`
1133
+ );
1134
+ }
1135
+ bytes[offset1] = valueAtOffset2;
1136
+ bytes[offset2] = valueAtOffset1;
1137
+ }
1138
+ }
1139
+ }
1140
+ function reverseByteGroupsIfBigEndian(bytes, groupSize) {
1141
+ if (isLittleEndianArch) {
1142
+ return bytes;
1143
+ } else {
1144
+ return reverseByteGroups(bytes, groupSize);
1145
+ }
1146
+ }
1147
+ function bytesLEToInt16Array(bytes) {
1148
+ bytes = reverseByteGroupsIfBigEndian(bytes, 2);
1149
+ return new Int16Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 2);
1150
+ }
1151
+ class DynamicTypedArray {
1152
+ constructor(TypedArrayConstructor, initialCapacity = 4) {
1153
+ this.TypedArrayConstructor = TypedArrayConstructor;
1154
+ this.elements = new TypedArrayConstructor(initialCapacity);
1155
+ }
1156
+ elements;
1157
+ length = 0;
1158
+ add(newElement) {
1159
+ const newLength = this.length + 1;
1160
+ if (newLength > this.capacity) {
1161
+ this.ensureCapacity(newLength);
1162
+ }
1163
+ this.elements[this.length] = newElement;
1164
+ this.length = newLength;
1165
+ }
1166
+ addMany(...newElements) {
1167
+ this.addArray(newElements);
1168
+ }
1169
+ addArray(newElements) {
1170
+ const newLength = this.length + newElements.length;
1171
+ if (newLength > this.capacity) {
1172
+ this.ensureCapacity(newLength);
1173
+ }
1174
+ this.elements.set(newElements, this.length);
1175
+ this.length = newLength;
1176
+ }
1177
+ ensureCapacity(requiredCapacity) {
1178
+ if (requiredCapacity > this.capacity) {
1179
+ const newCapacity = requiredCapacity * 2;
1180
+ const newElements = new this.TypedArrayConstructor(newCapacity);
1181
+ newElements.set(this.toTypedArray());
1182
+ this.elements = newElements;
1183
+ }
1184
+ }
1185
+ get capacity() {
1186
+ return this.elements.length;
1187
+ }
1188
+ toTypedArray() {
1189
+ return this.elements.subarray(0, this.length);
1190
+ }
1191
+ clear() {
1192
+ this.length = 0;
1193
+ }
1194
+ }
1195
+ function createDynamicUint8Array(initialCapacity) {
1196
+ return new DynamicTypedArray(Uint8Array, initialCapacity);
1197
+ }
1198
+ function createDynamicUint16Array(initialCapacity) {
1199
+ return new DynamicTypedArray(Uint16Array, initialCapacity);
1200
+ }
1201
+ async function readFileAsBinary(filePath) {
1202
+ const chunkSize = 2 ** 20;
1203
+ const fileInfo = await (0, import_promises.stat)(filePath);
1204
+ const fileSize = fileInfo.size;
1205
+ const fileReader = new FileReader(filePath);
1206
+ const buffer = new Uint8Array(chunkSize);
1207
+ const result = createDynamicUint8Array(fileSize);
1208
+ while (!fileReader.isFinished) {
1209
+ const chunk = await fileReader.readChunk(buffer);
1210
+ result.addArray(chunk);
1211
+ }
1212
+ return result.toTypedArray();
1213
+ }
1214
+ class FileReader {
1215
+ constructor(filePath) {
1216
+ this.filePath = filePath;
1217
+ }
1218
+ fileHandle;
1219
+ finished = false;
1220
+ disposed = false;
1221
+ readOffset = 0;
1222
+ async readChunk(buffer) {
1223
+ if (this.isDisposed) {
1224
+ throw new Error(`FileReader has been disposed`);
1225
+ }
1226
+ await this.openIfNeeded();
1227
+ let bufferWriteOffset = 0;
1228
+ while (bufferWriteOffset < buffer.length) {
1229
+ const remainingSizeInBuffer = buffer.length - bufferWriteOffset;
1230
+ let bytesRead;
1231
+ try {
1232
+ ;
1233
+ ({ bytesRead } = await this.fileHandle.read(buffer, {
1234
+ offset: bufferWriteOffset,
1235
+ length: remainingSizeInBuffer,
1236
+ position: this.readOffset
1237
+ }));
1238
+ } catch (e) {
1239
+ await this.dispose();
1240
+ throw e;
1241
+ }
1242
+ if (bytesRead === 0) {
1243
+ this.finished = true;
1244
+ await this.dispose();
1245
+ break;
1246
+ }
1247
+ bufferWriteOffset += bytesRead;
1248
+ this.readOffset += bytesRead;
1249
+ }
1250
+ return buffer.subarray(0, bufferWriteOffset);
1251
+ }
1252
+ async openIfNeeded() {
1253
+ if (this.isDisposed) {
1254
+ throw new Error(`FileReader has been disposed`);
1255
+ }
1256
+ if (this.isOpened) {
1257
+ return;
1258
+ }
1259
+ this.fileHandle = await (0, import_promises.open)(this.filePath, "r");
1260
+ }
1261
+ async dispose() {
1262
+ if (this.isDisposed) {
1263
+ return;
1264
+ }
1265
+ if (this.isOpened) {
1266
+ try {
1267
+ await this.fileHandle.close();
1268
+ } catch (_e) {
1269
+ }
1270
+ }
1271
+ this.disposed = true;
1272
+ this.readOffset = 0;
1273
+ this.fileHandle = void 0;
1274
+ }
1275
+ get isOpened() {
1276
+ return this.fileHandle !== void 0;
1277
+ }
1278
+ get isDisposed() {
1279
+ return this.disposed;
1280
+ }
1281
+ get isFinished() {
1282
+ return this.finished;
1283
+ }
1284
+ }
1285
+ function encodeHex(buffer) {
1286
+ const asciiBuffer = encodeHexAsAsciiBuffer(buffer);
1287
+ return (0, import_Ascii.decodeAscii)(asciiBuffer);
1288
+ }
1289
+ function encodeHexAsAsciiBuffer(buffer) {
1290
+ const bufferLen = buffer.length;
1291
+ const charCodes = new Uint8Array(bufferLen * 2);
1292
+ let readOffset = 0;
1293
+ let writeOffset = 0;
1294
+ while (readOffset < bufferLen) {
1295
+ const value = buffer[readOffset++];
1296
+ if (value === void 0) {
1297
+ throw new Error(`buffer value at offset ${readOffset - 1} not found`);
1298
+ }
1299
+ const valueHigh4Bits = value >>> 4 & 15;
1300
+ const valueLow4Bits = value & 15;
1301
+ const highCharCode = hexCharCodeLookup[valueHigh4Bits];
1302
+ const lowCharCode = hexCharCodeLookup[valueLow4Bits];
1303
+ if (highCharCode === void 0 || lowCharCode === void 0) {
1304
+ throw new Error(`hex char code lookup failed for value ${value}`);
1305
+ }
1306
+ charCodes[writeOffset++] = highCharCode;
1307
+ charCodes[writeOffset++] = lowCharCode;
1308
+ }
1309
+ return charCodes;
1310
+ }
1311
+ function decodeHex(hexString) {
1312
+ const hexLength = hexString.length;
1313
+ if (hexLength % 2 !== 0) {
1314
+ throw new Error(
1315
+ `Hexadecimal string doesn't have an even number of characters`
1316
+ );
1317
+ }
1318
+ const buffer = new Uint8Array(hexLength / 2);
1319
+ let readOffset = 0;
1320
+ let writeOffset = 0;
1321
+ while (readOffset < hexLength) {
1322
+ const valueHigh4Bits = hexCharCodeToValue(
1323
+ hexString.charCodeAt(readOffset++)
1324
+ );
1325
+ const valueLow4Bits = hexCharCodeToValue(hexString.charCodeAt(readOffset++));
1326
+ const value = valueHigh4Bits << 4 | valueLow4Bits;
1327
+ buffer[writeOffset++] = value;
1328
+ }
1329
+ return buffer;
1330
+ }
1331
+ function hexCharCodeToValue(hexCharCode) {
1332
+ if (hexCharCode >= 48 && hexCharCode <= 57) {
1333
+ return hexCharCode - 48;
1334
+ } else if (hexCharCode >= 97 && hexCharCode <= 102) {
1335
+ return 10 + hexCharCode - 97;
1336
+ } else if (hexCharCode >= 65 && hexCharCode <= 70) {
1337
+ return 10 + hexCharCode - 65;
1338
+ } else {
1339
+ throw new Error(
1340
+ `Can't decode character '${String.fromCharCode(hexCharCode)}' (code: ${hexCharCode}) as hexadecimal`
1341
+ );
1342
+ }
1343
+ }
1344
+ const hexCharCodeLookup = new Uint8Array([
1345
+ 48,
1346
+ 49,
1347
+ 50,
1348
+ 51,
1349
+ 52,
1350
+ 53,
1351
+ 54,
1352
+ 55,
1353
+ 56,
1354
+ 57,
1355
+ 97,
1356
+ 98,
1357
+ 99,
1358
+ 100,
1359
+ 101,
1360
+ 102
1361
+ ]);
1362
+ // Annotate the CommonJS export names for ESM import in node:
1363
+ 0 && (module.exports = {
1364
+ createDynamicUint16Array,
1365
+ detectVoiceActivity
1366
+ });