parakeet.js 0.0.2 → 0.0.3

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 (160) hide show
  1. package/.gitmodules +3 -0
  2. package/README.md +240 -239
  3. package/examples/hf-spaces-demo/README.md +6 -9
  4. package/examples/hf-spaces-demo/package.json +1 -1
  5. package/examples/hf-spaces-demo/src/App.js +307 -316
  6. package/examples/react-demo/package.json +19 -19
  7. package/examples/react-demo/src/App.jsx +324 -326
  8. package/examples/react-demo-dev/src/App.jsx +23 -24
  9. package/package.json +1 -1
  10. package/publish.ps1 +65 -0
  11. package/src/hub.js +235 -241
  12. package/src/parakeet.js +15 -8
  13. package/src/preprocessor.js +75 -68
  14. package/docs/parakeet-transformers-js/.gitattributes +0 -2
  15. package/docs/parakeet-transformers-js/.prettierignore +0 -8
  16. package/docs/parakeet-transformers-js/.prettierrc +0 -10
  17. package/docs/parakeet-transformers-js/.tmp_features.json +0 -1
  18. package/docs/parakeet-transformers-js/LICENSE +0 -202
  19. package/docs/parakeet-transformers-js/README.md +0 -448
  20. package/docs/parakeet-transformers-js/assets/nemo128.onnx +0 -0
  21. package/docs/parakeet-transformers-js/assets/nemo80.onnx +0 -0
  22. package/docs/parakeet-transformers-js/debug_test.js +0 -84
  23. package/docs/parakeet-transformers-js/dev/inspect_decoder.cjs +0 -9
  24. package/docs/parakeet-transformers-js/dev/inspect_joiner.cjs +0 -9
  25. package/docs/parakeet-transformers-js/dev/js_step_by_step.js +0 -249
  26. package/docs/parakeet-transformers-js/dev/parakeet_cli.js +0 -91
  27. package/docs/parakeet-transformers-js/jest.config.mjs +0 -194
  28. package/docs/parakeet-transformers-js/js_preprocessing.json +0 -225
  29. package/docs/parakeet-transformers-js/js_step_by_step.json +0 -837
  30. package/docs/parakeet-transformers-js/js_step_by_step_v2.json +0 -450
  31. package/docs/parakeet-transformers-js/js_step_by_step_v3.json +0 -450
  32. package/docs/parakeet-transformers-js/js_steps.json +0 -821
  33. package/docs/parakeet-transformers-js/package-lock.json +0 -12251
  34. package/docs/parakeet-transformers-js/package.json +0 -96
  35. package/docs/parakeet-transformers-js/src/audio_features.js +0 -178
  36. package/docs/parakeet-transformers-js/src/backends/onnx.js +0 -210
  37. package/docs/parakeet-transformers-js/src/base/feature_extraction_utils.js +0 -54
  38. package/docs/parakeet-transformers-js/src/base/image_processors_utils.js +0 -1105
  39. package/docs/parakeet-transformers-js/src/base/processing_utils.js +0 -173
  40. package/docs/parakeet-transformers-js/src/configs.js +0 -455
  41. package/docs/parakeet-transformers-js/src/env.js +0 -167
  42. package/docs/parakeet-transformers-js/src/generation/configuration_utils.js +0 -388
  43. package/docs/parakeet-transformers-js/src/generation/logits_process.js +0 -727
  44. package/docs/parakeet-transformers-js/src/generation/logits_sampler.js +0 -204
  45. package/docs/parakeet-transformers-js/src/generation/parameters.js +0 -35
  46. package/docs/parakeet-transformers-js/src/generation/stopping_criteria.js +0 -156
  47. package/docs/parakeet-transformers-js/src/generation/streamers.js +0 -225
  48. package/docs/parakeet-transformers-js/src/models/audio_spectrogram_transformer/feature_extraction_audio_spectrogram_transformer.js +0 -85
  49. package/docs/parakeet-transformers-js/src/models/auto/feature_extraction_auto.js +0 -25
  50. package/docs/parakeet-transformers-js/src/models/auto/image_processing_auto.js +0 -29
  51. package/docs/parakeet-transformers-js/src/models/auto/processing_auto.js +0 -85
  52. package/docs/parakeet-transformers-js/src/models/beit/image_processing_beit.js +0 -5
  53. package/docs/parakeet-transformers-js/src/models/bit/image_processing_bit.js +0 -5
  54. package/docs/parakeet-transformers-js/src/models/chinese_clip/image_processing_chinese_clip.js +0 -5
  55. package/docs/parakeet-transformers-js/src/models/clap/feature_extraction_clap.js +0 -159
  56. package/docs/parakeet-transformers-js/src/models/clip/image_processing_clip.js +0 -6
  57. package/docs/parakeet-transformers-js/src/models/convnext/image_processing_convnext.js +0 -46
  58. package/docs/parakeet-transformers-js/src/models/dac/feature_extraction_dac.js +0 -3
  59. package/docs/parakeet-transformers-js/src/models/deit/image_processing_deit.js +0 -6
  60. package/docs/parakeet-transformers-js/src/models/detr/image_processing_detr.js +0 -52
  61. package/docs/parakeet-transformers-js/src/models/donut/image_processing_donut.js +0 -31
  62. package/docs/parakeet-transformers-js/src/models/dpt/image_processing_dpt.js +0 -6
  63. package/docs/parakeet-transformers-js/src/models/efficientnet/image_processing_efficientnet.js +0 -14
  64. package/docs/parakeet-transformers-js/src/models/encodec/feature_extraction_encodec.js +0 -32
  65. package/docs/parakeet-transformers-js/src/models/feature_extractors.js +0 -17
  66. package/docs/parakeet-transformers-js/src/models/florence2/processing_florence2.js +0 -131
  67. package/docs/parakeet-transformers-js/src/models/gemma3n/feature_extraction_gemma3n.js +0 -97
  68. package/docs/parakeet-transformers-js/src/models/gemma3n/processing_gemma3n.js +0 -74
  69. package/docs/parakeet-transformers-js/src/models/glpn/image_processing_glpn.js +0 -5
  70. package/docs/parakeet-transformers-js/src/models/grounding_dino/image_processing_grounding_dino.js +0 -29
  71. package/docs/parakeet-transformers-js/src/models/grounding_dino/processing_grounding_dino.js +0 -101
  72. package/docs/parakeet-transformers-js/src/models/idefics3/image_processing_idefics3.js +0 -232
  73. package/docs/parakeet-transformers-js/src/models/idefics3/processing_idefics3.js +0 -136
  74. package/docs/parakeet-transformers-js/src/models/image_processors.js +0 -40
  75. package/docs/parakeet-transformers-js/src/models/janus/image_processing_janus.js +0 -27
  76. package/docs/parakeet-transformers-js/src/models/janus/processing_janus.js +0 -123
  77. package/docs/parakeet-transformers-js/src/models/jina_clip/image_processing_jina_clip.js +0 -26
  78. package/docs/parakeet-transformers-js/src/models/jina_clip/processing_jina_clip.js +0 -24
  79. package/docs/parakeet-transformers-js/src/models/llava/processing_llava.js +0 -44
  80. package/docs/parakeet-transformers-js/src/models/llava_onevision/image_processing_llava_onevision.js +0 -5
  81. package/docs/parakeet-transformers-js/src/models/mask2former/image_processing_mask2former.js +0 -5
  82. package/docs/parakeet-transformers-js/src/models/maskformer/image_processing_maskformer.js +0 -18
  83. package/docs/parakeet-transformers-js/src/models/mgp_str/processing_mgp_str.js +0 -172
  84. package/docs/parakeet-transformers-js/src/models/mobilenet_v1/image_processing_mobilenet_v1.js +0 -7
  85. package/docs/parakeet-transformers-js/src/models/mobilenet_v2/image_processing_mobilenet_v2.js +0 -7
  86. package/docs/parakeet-transformers-js/src/models/mobilenet_v3/image_processing_mobilenet_v3.js +0 -7
  87. package/docs/parakeet-transformers-js/src/models/mobilenet_v4/image_processing_mobilenet_v4.js +0 -7
  88. package/docs/parakeet-transformers-js/src/models/mobilevit/image_processing_mobilevit.js +0 -6
  89. package/docs/parakeet-transformers-js/src/models/moonshine/feature_extraction_moonshine.js +0 -26
  90. package/docs/parakeet-transformers-js/src/models/moonshine/processing_moonshine.js +0 -20
  91. package/docs/parakeet-transformers-js/src/models/nougat/image_processing_nougat.js +0 -5
  92. package/docs/parakeet-transformers-js/src/models/owlv2/image_processing_owlv2.js +0 -5
  93. package/docs/parakeet-transformers-js/src/models/owlvit/image_processing_owlvit.js +0 -12
  94. package/docs/parakeet-transformers-js/src/models/owlvit/processing_owlvit.js +0 -7
  95. package/docs/parakeet-transformers-js/src/models/paligemma/processing_paligemma.js +0 -83
  96. package/docs/parakeet-transformers-js/src/models/parakeet/feature_extraction_parakeet.js +0 -3
  97. package/docs/parakeet-transformers-js/src/models/parakeet/modeling_parakeet.js +0 -3
  98. package/docs/parakeet-transformers-js/src/models/parakeet/processing_parakeet.js +0 -3
  99. package/docs/parakeet-transformers-js/src/models/parakeet/tokenization_parakeet.js +0 -3
  100. package/docs/parakeet-transformers-js/src/models/phi3_v/image_processing_phi3_v.js +0 -163
  101. package/docs/parakeet-transformers-js/src/models/phi3_v/processing_phi3_v.js +0 -53
  102. package/docs/parakeet-transformers-js/src/models/processors.js +0 -22
  103. package/docs/parakeet-transformers-js/src/models/pvt/image_processing_pvt.js +0 -5
  104. package/docs/parakeet-transformers-js/src/models/pyannote/feature_extraction_pyannote.js +0 -85
  105. package/docs/parakeet-transformers-js/src/models/pyannote/processing_pyannote.js +0 -24
  106. package/docs/parakeet-transformers-js/src/models/qwen2_vl/image_processing_qwen2_vl.js +0 -52
  107. package/docs/parakeet-transformers-js/src/models/qwen2_vl/processing_qwen2_vl.js +0 -53
  108. package/docs/parakeet-transformers-js/src/models/rt_detr/image_processing_rt_detr.js +0 -12
  109. package/docs/parakeet-transformers-js/src/models/sam/image_processing_sam.js +0 -242
  110. package/docs/parakeet-transformers-js/src/models/sam/processing_sam.js +0 -20
  111. package/docs/parakeet-transformers-js/src/models/sapiens/image_processing_sapiens.js +0 -13
  112. package/docs/parakeet-transformers-js/src/models/seamless_m4t/feature_extraction_seamless_m4t.js +0 -175
  113. package/docs/parakeet-transformers-js/src/models/segformer/image_processing_segformer.js +0 -13
  114. package/docs/parakeet-transformers-js/src/models/siglip/image_processing_siglip.js +0 -5
  115. package/docs/parakeet-transformers-js/src/models/smolvlm/image_processing_smolvlm.js +0 -2
  116. package/docs/parakeet-transformers-js/src/models/smolvlm/processing_smolvlm.js +0 -2
  117. package/docs/parakeet-transformers-js/src/models/snac/feature_extraction_snac.js +0 -3
  118. package/docs/parakeet-transformers-js/src/models/speecht5/feature_extraction_speecht5.js +0 -4
  119. package/docs/parakeet-transformers-js/src/models/speecht5/processing_speecht5.js +0 -17
  120. package/docs/parakeet-transformers-js/src/models/swin2sr/image_processing_swin2sr.js +0 -24
  121. package/docs/parakeet-transformers-js/src/models/ultravox/processing_ultravox.js +0 -54
  122. package/docs/parakeet-transformers-js/src/models/vit/image_processing_vit.js +0 -7
  123. package/docs/parakeet-transformers-js/src/models/vitmatte/image_processing_vitmatte.js +0 -50
  124. package/docs/parakeet-transformers-js/src/models/vitpose/image_processing_vitpose.js +0 -89
  125. package/docs/parakeet-transformers-js/src/models/wav2vec2/feature_extraction_wav2vec2.js +0 -44
  126. package/docs/parakeet-transformers-js/src/models/wav2vec2/processing_wav2vec2.js +0 -17
  127. package/docs/parakeet-transformers-js/src/models/wav2vec2_with_lm/processing_wav2vec2_with_lm.js +0 -17
  128. package/docs/parakeet-transformers-js/src/models/wespeaker/feature_extraction_wespeaker.js +0 -95
  129. package/docs/parakeet-transformers-js/src/models/whisper/common_whisper.js +0 -157
  130. package/docs/parakeet-transformers-js/src/models/whisper/feature_extraction_whisper.js +0 -92
  131. package/docs/parakeet-transformers-js/src/models/whisper/generation_whisper.js +0 -89
  132. package/docs/parakeet-transformers-js/src/models/whisper/processing_whisper.js +0 -21
  133. package/docs/parakeet-transformers-js/src/models/yolos/image_processing_yolos.js +0 -12
  134. package/docs/parakeet-transformers-js/src/models.js +0 -8644
  135. package/docs/parakeet-transformers-js/src/ops/registry.js +0 -133
  136. package/docs/parakeet-transformers-js/src/ort_env.js +0 -8
  137. package/docs/parakeet-transformers-js/src/parakeet.js +0 -792
  138. package/docs/parakeet-transformers-js/src/pipelines.js +0 -3540
  139. package/docs/parakeet-transformers-js/src/processors.js +0 -16
  140. package/docs/parakeet-transformers-js/src/tokenizers.js +0 -4432
  141. package/docs/parakeet-transformers-js/src/transformers.js +0 -50
  142. package/docs/parakeet-transformers-js/src/utils/audio.js +0 -893
  143. package/docs/parakeet-transformers-js/src/utils/constants.js +0 -9
  144. package/docs/parakeet-transformers-js/src/utils/core.js +0 -259
  145. package/docs/parakeet-transformers-js/src/utils/data-structures.js +0 -574
  146. package/docs/parakeet-transformers-js/src/utils/devices.js +0 -22
  147. package/docs/parakeet-transformers-js/src/utils/dtypes.js +0 -63
  148. package/docs/parakeet-transformers-js/src/utils/generic.js +0 -35
  149. package/docs/parakeet-transformers-js/src/utils/hub.js +0 -780
  150. package/docs/parakeet-transformers-js/src/utils/image.js +0 -834
  151. package/docs/parakeet-transformers-js/src/utils/maths.js +0 -1061
  152. package/docs/parakeet-transformers-js/src/utils/tensor.js +0 -1539
  153. package/docs/parakeet-transformers-js/src/utils/video.js +0 -128
  154. package/docs/parakeet-transformers-js/test/decoder.test.js +0 -114
  155. package/docs/parakeet-transformers-js/test/encoder.test.js +0 -108
  156. package/docs/parakeet-transformers-js/test/preprocessor.test.js +0 -85
  157. package/docs/parakeet-transformers-js/test/tokenizer.test.js +0 -24
  158. package/docs/parakeet-transformers-js/test/transcribe.js +0 -89
  159. package/docs/parakeet-transformers-js/tsconfig.json +0 -21
  160. package/docs/parakeet-transformers-js/webpack.config.js +0 -223
@@ -1,1061 +0,0 @@
1
-
2
- /**
3
- * @file Helper module for mathematical processing.
4
- *
5
- * These functions and classes are only used internally,
6
- * meaning an end-user shouldn't need to access anything here.
7
- *
8
- * @module utils/maths
9
- */
10
-
11
- /**
12
- * @typedef {Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float16Array | Float32Array | Float64Array} TypedArray
13
- * @typedef {BigInt64Array | BigUint64Array} BigTypedArray
14
- * @typedef {TypedArray | BigTypedArray} AnyTypedArray
15
- */
16
-
17
- /**
18
- * @param {TypedArray} input
19
- */
20
- export function interpolate_data(input, [in_channels, in_height, in_width], [out_height, out_width], mode = 'bilinear', align_corners = false) {
21
- // TODO use mode and align_corners
22
-
23
- // Output image dimensions
24
- const x_scale = out_width / in_width;
25
- const y_scale = out_height / in_height;
26
-
27
- // Output image
28
- // @ts-ignore
29
- const out_img = new input.constructor(out_height * out_width * in_channels);
30
-
31
- // Pre-calculate strides
32
- const inStride = in_height * in_width;
33
- const outStride = out_height * out_width;
34
-
35
- for (let i = 0; i < out_height; ++i) {
36
- for (let j = 0; j < out_width; ++j) {
37
- // Calculate output offset
38
- const outOffset = i * out_width + j;
39
-
40
- // Calculate input pixel coordinates
41
- const x = (j + 0.5) / x_scale - 0.5;
42
- const y = (i + 0.5) / y_scale - 0.5;
43
-
44
- // Calculate the four nearest input pixels
45
- // We also check if the input pixel coordinates are within the image bounds
46
- let x1 = Math.floor(x);
47
- let y1 = Math.floor(y);
48
- const x2 = Math.min(x1 + 1, in_width - 1);
49
- const y2 = Math.min(y1 + 1, in_height - 1);
50
-
51
- x1 = Math.max(x1, 0);
52
- y1 = Math.max(y1, 0);
53
-
54
-
55
- // Calculate the fractional distances between the input pixel and the four nearest pixels
56
- const s = x - x1;
57
- const t = y - y1;
58
-
59
- // Perform bilinear interpolation
60
- const w1 = (1 - s) * (1 - t);
61
- const w2 = s * (1 - t);
62
- const w3 = (1 - s) * t;
63
- const w4 = s * t;
64
-
65
- // Calculate the four nearest input pixel indices
66
- const yStride = y1 * in_width;
67
- const xStride = y2 * in_width;
68
- const idx1 = yStride + x1;
69
- const idx2 = yStride + x2;
70
- const idx3 = xStride + x1;
71
- const idx4 = xStride + x2;
72
-
73
- for (let k = 0; k < in_channels; ++k) {
74
- // Calculate channel offset
75
- const cOffset = k * inStride;
76
-
77
- out_img[k * outStride + outOffset] =
78
- w1 * input[cOffset + idx1] +
79
- w2 * input[cOffset + idx2] +
80
- w3 * input[cOffset + idx3] +
81
- w4 * input[cOffset + idx4];
82
- }
83
- }
84
- }
85
-
86
- return out_img;
87
- }
88
-
89
-
90
- /**
91
- * Helper method to permute a `AnyTypedArray` directly
92
- * @template {AnyTypedArray} T
93
- * @param {T} array
94
- * @param {number[]} dims
95
- * @param {number[]} axes
96
- * @returns {[T, number[]]} The permuted array and the new shape.
97
- */
98
- export function permute_data(array, dims, axes) {
99
- // Calculate the new shape of the permuted array
100
- // and the stride of the original array
101
- const shape = new Array(axes.length);
102
- const stride = new Array(axes.length);
103
-
104
- for (let i = axes.length - 1, s = 1; i >= 0; --i) {
105
- stride[i] = s;
106
- shape[i] = dims[axes[i]];
107
- s *= shape[i];
108
- }
109
-
110
- // Precompute inverse mapping of stride
111
- const invStride = axes.map((_, i) => stride[axes.indexOf(i)]);
112
-
113
- // Create the permuted array with the new shape
114
- // @ts-ignore
115
- const permutedData = new array.constructor(array.length);
116
-
117
- // Permute the original array to the new array
118
- for (let i = 0; i < array.length; ++i) {
119
- let newIndex = 0;
120
- for (let j = dims.length - 1, k = i; j >= 0; --j) {
121
- newIndex += (k % dims[j]) * invStride[j];
122
- k = Math.floor(k / dims[j]);
123
- }
124
- permutedData[newIndex] = array[i];
125
- }
126
-
127
- return [permutedData, shape];
128
- }
129
-
130
-
131
- /**
132
- * Compute the softmax of an array of numbers.
133
- * @template {TypedArray|number[]} T
134
- * @param {T} arr The array of numbers to compute the softmax of.
135
- * @returns {T} The softmax array.
136
- */
137
- export function softmax(arr) {
138
- // Compute the maximum value in the array
139
- const maxVal = max(arr)[0];
140
-
141
- // Compute the exponentials of the array values
142
- const exps = arr.map(x => Math.exp(x - maxVal));
143
-
144
- // Compute the sum of the exponentials
145
- // @ts-ignore
146
- const sumExps = exps.reduce((acc, val) => acc + val, 0);
147
-
148
- // Compute the softmax values
149
- const softmaxArr = exps.map(x => x / sumExps);
150
-
151
- return /** @type {T} */(softmaxArr);
152
- }
153
-
154
- /**
155
- * Calculates the logarithm of the softmax function for the input array.
156
- * @template {TypedArray|number[]} T
157
- * @param {T} arr The input array to calculate the log_softmax function for.
158
- * @returns {T} The resulting log_softmax array.
159
- */
160
- export function log_softmax(arr) {
161
- // Compute the maximum value in the array
162
- const maxVal = max(arr)[0];
163
-
164
- // Compute the sum of the exponentials
165
- let sumExps = 0;
166
- for(let i = 0; i < arr.length; ++i) {
167
- sumExps += Math.exp(arr[i] - maxVal);
168
- }
169
-
170
- // Compute the log of the sum
171
- const logSum = Math.log(sumExps);
172
-
173
- // Compute the softmax values
174
- const logSoftmaxArr = arr.map(x => x - maxVal - logSum);
175
-
176
- return /** @type {T} */(logSoftmaxArr);
177
- }
178
-
179
- /**
180
- * Calculates the dot product of two arrays.
181
- * @param {number[]} arr1 The first array.
182
- * @param {number[]} arr2 The second array.
183
- * @returns {number} The dot product of arr1 and arr2.
184
- */
185
- export function dot(arr1, arr2) {
186
- let result = 0;
187
- for (let i = 0; i < arr1.length; ++i) {
188
- result += arr1[i] * arr2[i];
189
- }
190
- return result;
191
- }
192
-
193
- /**
194
- * Computes the cosine similarity between two arrays.
195
- *
196
- * @param {number[]} arr1 The first array.
197
- * @param {number[]} arr2 The second array.
198
- * @returns {number} The cosine similarity between the two arrays.
199
- */
200
- export function cos_sim(arr1, arr2) {
201
- // Calculate dot product of the two arrays
202
- const dotProduct = dot(arr1, arr2);
203
-
204
- // Calculate the magnitude of the first array
205
- const magnitudeA = magnitude(arr1);
206
-
207
- // Calculate the magnitude of the second array
208
- const magnitudeB = magnitude(arr2);
209
-
210
- // Calculate the cosine similarity
211
- const cosineSimilarity = dotProduct / (magnitudeA * magnitudeB);
212
-
213
- return cosineSimilarity;
214
- }
215
-
216
- /**
217
- * Calculates the magnitude of a given array.
218
- * @param {number[]} arr The array to calculate the magnitude of.
219
- * @returns {number} The magnitude of the array.
220
- */
221
- export function magnitude(arr) {
222
- return Math.sqrt(arr.reduce((acc, val) => acc + val * val, 0));
223
- }
224
-
225
-
226
- /**
227
- * Returns the value and index of the minimum element in an array.
228
- * @template {number[]|bigint[]|AnyTypedArray} T
229
- * @param {T} arr array of numbers.
230
- * @returns {T extends bigint[]|BigTypedArray ? [bigint, number] : [number, number]} the value and index of the minimum element, of the form: [valueOfMin, indexOfMin]
231
- * @throws {Error} If array is empty.
232
- */
233
- export function min(arr) {
234
- if (arr.length === 0) throw Error('Array must not be empty');
235
- let min = arr[0];
236
- let indexOfMin = 0;
237
- for (let i = 1; i < arr.length; ++i) {
238
- if (arr[i] < min) {
239
- min = arr[i];
240
- indexOfMin = i;
241
- }
242
- }
243
- return /** @type {T extends bigint[]|BigTypedArray ? [bigint, number] : [number, number]} */([min, indexOfMin]);
244
- }
245
-
246
-
247
- /**
248
- * Returns the value and index of the maximum element in an array.
249
- * @template {number[]|bigint[]|AnyTypedArray} T
250
- * @param {T} arr array of numbers.
251
- * @returns {T extends bigint[]|BigTypedArray ? [bigint, number] : [number, number]} the value and index of the maximum element, of the form: [valueOfMax, indexOfMax]
252
- * @throws {Error} If array is empty.
253
- */
254
- export function max(arr) {
255
- if (arr.length === 0) throw Error('Array must not be empty');
256
- let max = arr[0];
257
- let indexOfMax = 0;
258
- for (let i = 1; i < arr.length; ++i) {
259
- if (arr[i] > max) {
260
- max = arr[i];
261
- indexOfMax = i;
262
- }
263
- }
264
- return /** @type {T extends bigint[]|BigTypedArray ? [bigint, number] : [number, number]} */([max, indexOfMax]);
265
- }
266
-
267
- function isPowerOfTwo(number) {
268
- // Check if the number is greater than 0 and has only one bit set to 1
269
- return (number > 0) && ((number & (number - 1)) === 0);
270
- }
271
-
272
- /**
273
- * Implementation of Radix-4 FFT.
274
- *
275
- * P2FFT class provides functionality for performing Fast Fourier Transform on arrays
276
- * which are a power of two in length.
277
- * Code adapted from https://www.npmjs.com/package/fft.js
278
- */
279
- class P2FFT {
280
- /**
281
- * @param {number} size The size of the input array. Must be a power of two larger than 1.
282
- * @throws {Error} FFT size must be a power of two larger than 1.
283
- */
284
- constructor(size) {
285
- this.size = size | 0; // convert to a 32-bit signed integer
286
- if (this.size <= 1 || !isPowerOfTwo(this.size))
287
- throw new Error('FFT size must be a power of two larger than 1');
288
-
289
- this._csize = size << 1;
290
-
291
- this.table = new Float64Array(this.size * 2);
292
- for (let i = 0; i < this.table.length; i += 2) {
293
- const angle = Math.PI * i / this.size;
294
- this.table[i] = Math.cos(angle);
295
- this.table[i + 1] = -Math.sin(angle);
296
- }
297
-
298
- // Find size's power of two
299
- let power = 0;
300
- for (let t = 1; this.size > t; t <<= 1)
301
- ++power;
302
-
303
- // Calculate initial step's width:
304
- // * If we are full radix-4, it is 2x smaller to give inital len=8
305
- // * Otherwise it is the same as `power` to give len=4
306
- this._width = power % 2 === 0 ? power - 1 : power;
307
-
308
- // Pre-compute bit-reversal patterns
309
- this._bitrev = new Int32Array(1 << this._width);
310
- for (let j = 0; j < this._bitrev.length; ++j) {
311
- this._bitrev[j] = 0;
312
- for (let shift = 0; shift < this._width; shift += 2) {
313
- const revShift = this._width - shift - 2;
314
- this._bitrev[j] |= ((j >>> shift) & 3) << revShift;
315
- }
316
- }
317
- }
318
-
319
- /**
320
- * Create a complex number array with size `2 * size`
321
- *
322
- * @returns {Float64Array} A complex number array with size `2 * size`
323
- */
324
- createComplexArray() {
325
- return new Float64Array(this._csize);
326
- }
327
-
328
- /**
329
- * Converts a complex number representation stored in a Float64Array to an array of real numbers.
330
- *
331
- * @param {Float64Array} complex The complex number representation to be converted.
332
- * @param {number[]} [storage] An optional array to store the result in.
333
- * @returns {number[]} An array of real numbers representing the input complex number representation.
334
- */
335
- fromComplexArray(complex, storage) {
336
- const res = storage || new Array(complex.length >>> 1);
337
- for (let i = 0; i < complex.length; i += 2)
338
- res[i >>> 1] = complex[i];
339
- return res;
340
- }
341
-
342
- /**
343
- * Convert a real-valued input array to a complex-valued output array.
344
- * @param {Float64Array} input The real-valued input array.
345
- * @param {Float64Array} [storage] Optional buffer to store the output array.
346
- * @returns {Float64Array} The complex-valued output array.
347
- */
348
- toComplexArray(input, storage) {
349
- const res = storage || this.createComplexArray();
350
- for (let i = 0; i < res.length; i += 2) {
351
- res[i] = input[i >>> 1];
352
- res[i + 1] = 0;
353
- }
354
- return res;
355
- }
356
-
357
- /**
358
- * Performs a Fast Fourier Transform (FFT) on the given input data and stores the result in the output buffer.
359
- *
360
- * @param {Float64Array} out The output buffer to store the result.
361
- * @param {Float64Array} data The input data to transform.
362
- *
363
- * @throws {Error} Input and output buffers must be different.
364
- *
365
- * @returns {void}
366
- */
367
- transform(out, data) {
368
- if (out === data)
369
- throw new Error('Input and output buffers must be different');
370
-
371
- this._transform4(out, data, 1 /* DONE */);
372
- }
373
-
374
- /**
375
- * Performs a real-valued forward FFT on the given input buffer and stores the result in the given output buffer.
376
- * The input buffer must contain real values only, while the output buffer will contain complex values. The input and
377
- * output buffers must be different.
378
- *
379
- * @param {Float64Array} out The output buffer.
380
- * @param {Float64Array} data The input buffer containing real values.
381
- *
382
- * @throws {Error} If the input and output buffers are the same.
383
- */
384
- realTransform(out, data) {
385
- if (out === data)
386
- throw new Error('Input and output buffers must be different');
387
-
388
- this._realTransform4(out, data, 1 /* DONE */);
389
- }
390
-
391
- /**
392
- * Performs an inverse FFT transformation on the given `data` array, and stores the result in `out`.
393
- * The `out` array must be a different buffer than the `data` array. The `out` array will contain the
394
- * result of the transformation. The `data` array will not be modified.
395
- *
396
- * @param {Float64Array} out The output buffer for the transformed data.
397
- * @param {Float64Array} data The input data to transform.
398
- * @throws {Error} If `out` and `data` refer to the same buffer.
399
- * @returns {void}
400
- */
401
- inverseTransform(out, data) {
402
- if (out === data)
403
- throw new Error('Input and output buffers must be different');
404
-
405
- this._transform4(out, data, -1 /* DONE */);
406
- for (let i = 0; i < out.length; ++i)
407
- out[i] /= this.size;
408
- }
409
-
410
- /**
411
- * Performs a radix-4 implementation of a discrete Fourier transform on a given set of data.
412
- *
413
- * @param {Float64Array} out The output buffer for the transformed data.
414
- * @param {Float64Array} data The input buffer of data to be transformed.
415
- * @param {number} inv A scaling factor to apply to the transform.
416
- * @returns {void}
417
- */
418
- _transform4(out, data, inv) {
419
- // radix-4 implementation
420
-
421
- const size = this._csize;
422
-
423
- // Initial step (permute and transform)
424
- const width = this._width;
425
- let step = 1 << width;
426
- let len = (size / step) << 1;
427
-
428
- let outOff;
429
- let t;
430
- const bitrev = this._bitrev;
431
- if (len === 4) {
432
- for (outOff = 0, t = 0; outOff < size; outOff += len, ++t) {
433
- const off = bitrev[t];
434
- this._singleTransform2(data, out, outOff, off, step);
435
- }
436
- } else {
437
- // len === 8
438
- for (outOff = 0, t = 0; outOff < size; outOff += len, ++t) {
439
- const off = bitrev[t];
440
- this._singleTransform4(data, out, outOff, off, step, inv);
441
- }
442
- }
443
-
444
- // Loop through steps in decreasing order
445
- const table = this.table;
446
- for (step >>= 2; step >= 2; step >>= 2) {
447
- len = (size / step) << 1;
448
- const quarterLen = len >>> 2;
449
-
450
- // Loop through offsets in the data
451
- for (outOff = 0; outOff < size; outOff += len) {
452
- // Full case
453
- const limit = outOff + quarterLen - 1;
454
- for (let i = outOff, k = 0; i < limit; i += 2, k += step) {
455
- const A = i;
456
- const B = A + quarterLen;
457
- const C = B + quarterLen;
458
- const D = C + quarterLen;
459
-
460
- // Original values
461
- const Ar = out[A];
462
- const Ai = out[A + 1];
463
- const Br = out[B];
464
- const Bi = out[B + 1];
465
- const Cr = out[C];
466
- const Ci = out[C + 1];
467
- const Dr = out[D];
468
- const Di = out[D + 1];
469
-
470
- const tableBr = table[k];
471
- const tableBi = inv * table[k + 1];
472
- const MBr = Br * tableBr - Bi * tableBi;
473
- const MBi = Br * tableBi + Bi * tableBr;
474
-
475
- const tableCr = table[2 * k];
476
- const tableCi = inv * table[2 * k + 1];
477
- const MCr = Cr * tableCr - Ci * tableCi;
478
- const MCi = Cr * tableCi + Ci * tableCr;
479
-
480
- const tableDr = table[3 * k];
481
- const tableDi = inv * table[3 * k + 1];
482
- const MDr = Dr * tableDr - Di * tableDi;
483
- const MDi = Dr * tableDi + Di * tableDr;
484
-
485
- // Pre-Final values
486
- const T0r = Ar + MCr;
487
- const T0i = Ai + MCi;
488
- const T1r = Ar - MCr;
489
- const T1i = Ai - MCi;
490
- const T2r = MBr + MDr;
491
- const T2i = MBi + MDi;
492
- const T3r = inv * (MBr - MDr);
493
- const T3i = inv * (MBi - MDi);
494
-
495
- // Final values
496
- out[A] = T0r + T2r;
497
- out[A + 1] = T0i + T2i;
498
- out[B] = T1r + T3i;
499
- out[B + 1] = T1i - T3r;
500
- out[C] = T0r - T2r;
501
- out[C + 1] = T0i - T2i;
502
- out[D] = T1r - T3i;
503
- out[D + 1] = T1i + T3r;
504
- }
505
- }
506
- }
507
- }
508
-
509
- /**
510
- * Performs a radix-2 implementation of a discrete Fourier transform on a given set of data.
511
- *
512
- * @param {Float64Array} data The input buffer of data to be transformed.
513
- * @param {Float64Array} out The output buffer for the transformed data.
514
- * @param {number} outOff The offset at which to write the output data.
515
- * @param {number} off The offset at which to begin reading the input data.
516
- * @param {number} step The step size for indexing the input data.
517
- * @returns {void}
518
- */
519
- _singleTransform2(data, out, outOff, off, step) {
520
- // radix-2 implementation
521
- // NOTE: Only called for len=4
522
-
523
- const evenR = data[off];
524
- const evenI = data[off + 1];
525
- const oddR = data[off + step];
526
- const oddI = data[off + step + 1];
527
-
528
- out[outOff] = evenR + oddR;
529
- out[outOff + 1] = evenI + oddI;
530
- out[outOff + 2] = evenR - oddR;
531
- out[outOff + 3] = evenI - oddI;
532
- }
533
-
534
- /**
535
- * Performs radix-4 transformation on input data of length 8
536
- *
537
- * @param {Float64Array} data Input data array of length 8
538
- * @param {Float64Array} out Output data array of length 8
539
- * @param {number} outOff Index of output array to start writing from
540
- * @param {number} off Index of input array to start reading from
541
- * @param {number} step Step size between elements in input array
542
- * @param {number} inv Scaling factor for inverse transform
543
- *
544
- * @returns {void}
545
- */
546
- _singleTransform4(data, out, outOff, off, step, inv) {
547
- // radix-4
548
- // NOTE: Only called for len=8
549
- const step2 = step * 2;
550
- const step3 = step * 3;
551
-
552
- // Original values
553
- const Ar = data[off];
554
- const Ai = data[off + 1];
555
- const Br = data[off + step];
556
- const Bi = data[off + step + 1];
557
- const Cr = data[off + step2];
558
- const Ci = data[off + step2 + 1];
559
- const Dr = data[off + step3];
560
- const Di = data[off + step3 + 1];
561
-
562
- // Pre-Final values
563
- const T0r = Ar + Cr;
564
- const T0i = Ai + Ci;
565
- const T1r = Ar - Cr;
566
- const T1i = Ai - Ci;
567
- const T2r = Br + Dr;
568
- const T2i = Bi + Di;
569
- const T3r = inv * (Br - Dr);
570
- const T3i = inv * (Bi - Di);
571
-
572
- // Final values
573
- out[outOff] = T0r + T2r;
574
- out[outOff + 1] = T0i + T2i;
575
- out[outOff + 2] = T1r + T3i;
576
- out[outOff + 3] = T1i - T3r;
577
- out[outOff + 4] = T0r - T2r;
578
- out[outOff + 5] = T0i - T2i;
579
- out[outOff + 6] = T1r - T3i;
580
- out[outOff + 7] = T1i + T3r;
581
- }
582
-
583
- /**
584
- * Real input radix-4 implementation
585
- * @param {Float64Array} out Output array for the transformed data
586
- * @param {Float64Array} data Input array of real data to be transformed
587
- * @param {number} inv The scale factor used to normalize the inverse transform
588
- */
589
- _realTransform4(out, data, inv) {
590
- // Real input radix-4 implementation
591
- const size = this._csize;
592
-
593
- // Initial step (permute and transform)
594
- const width = this._width;
595
- let step = 1 << width;
596
- let len = (size / step) << 1;
597
-
598
- let outOff;
599
- let t;
600
- const bitrev = this._bitrev;
601
- if (len === 4) {
602
- for (outOff = 0, t = 0; outOff < size; outOff += len, ++t) {
603
- const off = bitrev[t];
604
- this._singleRealTransform2(data, out, outOff, off >>> 1, step >>> 1);
605
- }
606
- } else {
607
- // len === 8
608
- for (outOff = 0, t = 0; outOff < size; outOff += len, ++t) {
609
- const off = bitrev[t];
610
- this._singleRealTransform4(data, out, outOff, off >>> 1, step >>> 1, inv);
611
- }
612
- }
613
-
614
- // Loop through steps in decreasing order
615
- const table = this.table;
616
- for (step >>= 2; step >= 2; step >>= 2) {
617
- len = (size / step) << 1;
618
- const halfLen = len >>> 1;
619
- const quarterLen = halfLen >>> 1;
620
- const hquarterLen = quarterLen >>> 1;
621
-
622
- // Loop through offsets in the data
623
- for (outOff = 0; outOff < size; outOff += len) {
624
- for (let i = 0, k = 0; i <= hquarterLen; i += 2, k += step) {
625
- const A = outOff + i;
626
- const B = A + quarterLen;
627
- const C = B + quarterLen;
628
- const D = C + quarterLen;
629
-
630
- // Original values
631
- const Ar = out[A];
632
- const Ai = out[A + 1];
633
- const Br = out[B];
634
- const Bi = out[B + 1];
635
- const Cr = out[C];
636
- const Ci = out[C + 1];
637
- const Dr = out[D];
638
- const Di = out[D + 1];
639
-
640
- // Middle values
641
- const MAr = Ar;
642
- const MAi = Ai;
643
-
644
- const tableBr = table[k];
645
- const tableBi = inv * table[k + 1];
646
- const MBr = Br * tableBr - Bi * tableBi;
647
- const MBi = Br * tableBi + Bi * tableBr;
648
-
649
- const tableCr = table[2 * k];
650
- const tableCi = inv * table[2 * k + 1];
651
- const MCr = Cr * tableCr - Ci * tableCi;
652
- const MCi = Cr * tableCi + Ci * tableCr;
653
-
654
- const tableDr = table[3 * k];
655
- const tableDi = inv * table[3 * k + 1];
656
- const MDr = Dr * tableDr - Di * tableDi;
657
- const MDi = Dr * tableDi + Di * tableDr;
658
-
659
- // Pre-Final values
660
- const T0r = MAr + MCr;
661
- const T0i = MAi + MCi;
662
- const T1r = MAr - MCr;
663
- const T1i = MAi - MCi;
664
- const T2r = MBr + MDr;
665
- const T2i = MBi + MDi;
666
- const T3r = inv * (MBr - MDr);
667
- const T3i = inv * (MBi - MDi);
668
-
669
- // Final values
670
- out[A] = T0r + T2r;
671
- out[A + 1] = T0i + T2i;
672
- out[B] = T1r + T3i;
673
- out[B + 1] = T1i - T3r;
674
-
675
- // Output final middle point
676
- if (i === 0) {
677
- out[C] = T0r - T2r;
678
- out[C + 1] = T0i - T2i;
679
- continue;
680
- }
681
-
682
- // Do not overwrite ourselves
683
- if (i === hquarterLen)
684
- continue;
685
-
686
- const SA = outOff + quarterLen - i;
687
- const SB = outOff + halfLen - i;
688
-
689
- out[SA] = T1r - inv * T3i;
690
- out[SA + 1] = -T1i - inv * T3r;
691
- out[SB] = T0r - inv * T2r;
692
- out[SB + 1] = -T0i + inv * T2i;
693
- }
694
- }
695
- }
696
-
697
- // Complete the spectrum by adding its mirrored negative frequency components.
698
- const half = size >>> 1;
699
- for (let i = 2; i < half; i += 2) {
700
- out[size - i] = out[i];
701
- out[size - i + 1] = -out[i + 1];
702
- }
703
- }
704
-
705
- /**
706
- * Performs a single real input radix-2 transformation on the provided data
707
- *
708
- * @param {Float64Array} data The input data array
709
- * @param {Float64Array} out The output data array
710
- * @param {number} outOff The output offset
711
- * @param {number} off The input offset
712
- * @param {number} step The step
713
- *
714
- * @returns {void}
715
- */
716
- _singleRealTransform2(data, out, outOff, off, step) {
717
- // radix-2 implementation
718
- // NOTE: Only called for len=4
719
-
720
- const evenR = data[off];
721
- const oddR = data[off + step];
722
-
723
- out[outOff] = evenR + oddR;
724
- out[outOff + 1] = 0;
725
- out[outOff + 2] = evenR - oddR;
726
- out[outOff + 3] = 0;
727
- }
728
-
729
- /**
730
- * Computes a single real-valued transform using radix-4 algorithm.
731
- * This method is only called for len=8.
732
- *
733
- * @param {Float64Array} data The input data array.
734
- * @param {Float64Array} out The output data array.
735
- * @param {number} outOff The offset into the output array.
736
- * @param {number} off The offset into the input array.
737
- * @param {number} step The step size for the input array.
738
- * @param {number} inv The value of inverse.
739
- */
740
- _singleRealTransform4(data, out, outOff, off, step, inv) {
741
- // radix-4
742
- // NOTE: Only called for len=8
743
- const step2 = step * 2;
744
- const step3 = step * 3;
745
-
746
- // Original values
747
- const Ar = data[off];
748
- const Br = data[off + step];
749
- const Cr = data[off + step2];
750
- const Dr = data[off + step3];
751
-
752
- // Pre-Final values
753
- const T0r = Ar + Cr;
754
- const T1r = Ar - Cr;
755
- const T2r = Br + Dr;
756
- const T3r = inv * (Br - Dr);
757
-
758
- // Final values
759
- out[outOff] = T0r + T2r;
760
- out[outOff + 1] = 0;
761
- out[outOff + 2] = T1r;
762
- out[outOff + 3] = -T3r;
763
- out[outOff + 4] = T0r - T2r;
764
- out[outOff + 5] = 0;
765
- out[outOff + 6] = T1r;
766
- out[outOff + 7] = T3r;
767
- }
768
- }
769
-
770
- /**
771
- * NP2FFT class provides functionality for performing Fast Fourier Transform on arrays
772
- * which are not a power of two in length. In such cases, the chirp-z transform is used.
773
- *
774
- * For more information, see: https://math.stackexchange.com/questions/77118/non-power-of-2-ffts/77156#77156
775
- */
776
- class NP2FFT {
777
-
778
- /**
779
- * Constructs a new NP2FFT object.
780
- * @param {number} fft_length The length of the FFT
781
- */
782
- constructor(fft_length) {
783
- // Helper variables
784
- const a = 2 * (fft_length - 1);
785
- const b = 2 * (2 * fft_length - 1);
786
- const nextP2 = 2 ** (Math.ceil(Math.log2(b)))
787
- this.bufferSize = nextP2;
788
- this._a = a;
789
-
790
- // Define buffers
791
- // Compute chirp for transform
792
- const chirp = new Float64Array(b);
793
- const ichirp = new Float64Array(nextP2);
794
- this._chirpBuffer = new Float64Array(nextP2);
795
- this._buffer1 = new Float64Array(nextP2);
796
- this._buffer2 = new Float64Array(nextP2);
797
- this._outBuffer1 = new Float64Array(nextP2);
798
- this._outBuffer2 = new Float64Array(nextP2);
799
-
800
- // Compute complex exponentiation
801
- const theta = -2 * Math.PI / fft_length;
802
- const baseR = Math.cos(theta);
803
- const baseI = Math.sin(theta);
804
-
805
- // Precompute helper for chirp-z transform
806
- for (let i = 0; i < b >> 1; ++i) {
807
- // Compute complex power:
808
- const e = (i + 1 - fft_length) ** 2 / 2.0;
809
-
810
- // Compute the modulus and argument of the result
811
- const result_mod = Math.sqrt(baseR ** 2 + baseI ** 2) ** e;
812
- const result_arg = e * Math.atan2(baseI, baseR);
813
-
814
- // Convert the result back to rectangular form
815
- // and assign to chirp and ichirp
816
- const i2 = 2 * i;
817
- chirp[i2] = result_mod * Math.cos(result_arg);
818
- chirp[i2 + 1] = result_mod * Math.sin(result_arg);
819
-
820
- // conjugate
821
- ichirp[i2] = chirp[i2];
822
- ichirp[i2 + 1] = - chirp[i2 + 1];
823
- }
824
- this._slicedChirpBuffer = chirp.subarray(a, b);
825
-
826
- // create object to perform Fast Fourier Transforms
827
- // with `nextP2` complex numbers
828
- this._f = new P2FFT(nextP2 >> 1);
829
- this._f.transform(this._chirpBuffer, ichirp);
830
- }
831
-
832
- _transform(output, input, real) {
833
- const ib1 = this._buffer1;
834
- const ib2 = this._buffer2;
835
- const ob2 = this._outBuffer1;
836
- const ob3 = this._outBuffer2;
837
- const cb = this._chirpBuffer;
838
- const sb = this._slicedChirpBuffer;
839
- const a = this._a;
840
-
841
- if (real) {
842
- // Real multiplication
843
- for (let j = 0; j < sb.length; j += 2) {
844
- const j2 = j + 1
845
- const j3 = j >> 1;
846
-
847
- const a_real = input[j3];
848
- ib1[j] = a_real * sb[j];
849
- ib1[j2] = a_real * sb[j2];
850
- }
851
- } else {
852
- // Complex multiplication
853
- for (let j = 0; j < sb.length; j += 2) {
854
- const j2 = j + 1
855
- ib1[j] = input[j] * sb[j] - input[j2] * sb[j2];
856
- ib1[j2] = input[j] * sb[j2] + input[j2] * sb[j];
857
- }
858
- }
859
- this._f.transform(ob2, ib1);
860
-
861
- for (let j = 0; j < cb.length; j += 2) {
862
- const j2 = j + 1;
863
-
864
- ib2[j] = ob2[j] * cb[j] - ob2[j2] * cb[j2];
865
- ib2[j2] = ob2[j] * cb[j2] + ob2[j2] * cb[j];
866
- }
867
- this._f.inverseTransform(ob3, ib2);
868
-
869
- for (let j = 0; j < ob3.length; j += 2) {
870
- const a_real = ob3[j + a];
871
- const a_imag = ob3[j + a + 1];
872
- const b_real = sb[j];
873
- const b_imag = sb[j + 1];
874
-
875
- output[j] = a_real * b_real - a_imag * b_imag;
876
- output[j + 1] = a_real * b_imag + a_imag * b_real;
877
- }
878
- }
879
-
880
- transform(output, input) {
881
- this._transform(output, input, false);
882
- }
883
-
884
- realTransform(output, input) {
885
- this._transform(output, input, true);
886
- }
887
- }
888
-
889
- export class FFT {
890
- constructor(fft_length) {
891
- this.fft_length = fft_length;
892
- this.isPowerOfTwo = isPowerOfTwo(fft_length);
893
- if (this.isPowerOfTwo) {
894
- this.fft = new P2FFT(fft_length);
895
- this.outputBufferSize = 2 * fft_length;
896
- } else {
897
- this.fft = new NP2FFT(fft_length);
898
- this.outputBufferSize = this.fft.bufferSize;
899
- }
900
- }
901
-
902
- realTransform(out, input) {
903
- this.fft.realTransform(out, input);
904
- }
905
-
906
- transform(out, input) {
907
- this.fft.transform(out, input);
908
- }
909
- }
910
-
911
-
912
- /**
913
- * Performs median filter on the provided data. Padding is done by mirroring the data.
914
- * @param {AnyTypedArray} data The input array
915
- * @param {number} windowSize The window size
916
- */
917
- export function medianFilter(data, windowSize) {
918
-
919
- if (windowSize % 2 === 0 || windowSize <= 0) {
920
- throw new Error('Window size must be a positive odd number');
921
- }
922
-
923
- // @ts-ignore
924
- const outputArray = new data.constructor(data.length);
925
-
926
- // @ts-ignore
927
- const buffer = new data.constructor(windowSize); // Reusable array for storing values
928
-
929
- const halfWindowSize = Math.floor(windowSize / 2);
930
-
931
- for (let i = 0; i < data.length; ++i) {
932
- let valuesIndex = 0;
933
-
934
- for (let j = -halfWindowSize; j <= halfWindowSize; ++j) {
935
- let index = i + j;
936
- if (index < 0) {
937
- index = Math.abs(index);
938
- } else if (index >= data.length) {
939
- index = 2 * (data.length - 1) - index;
940
- }
941
-
942
- buffer[valuesIndex++] = data[index];
943
- }
944
-
945
- buffer.sort();
946
- outputArray[i] = buffer[halfWindowSize];
947
- }
948
-
949
- return outputArray;
950
- }
951
-
952
- /**
953
- * Helper function to round a number to a given number of decimals
954
- * @param {number} num The number to round
955
- * @param {number} decimals The number of decimals
956
- * @returns {number} The rounded number
957
- */
958
- export function round(num, decimals) {
959
- const pow = Math.pow(10, decimals);
960
- return Math.round(num * pow) / pow;
961
- }
962
-
963
- /**
964
- * Helper function to round a number to the nearest integer, with ties rounded to the nearest even number.
965
- * Also known as "bankers' rounding". This is the default rounding mode in python. For example:
966
- * 1.5 rounds to 2 and 2.5 rounds to 2.
967
- *
968
- * @param {number} x The number to round
969
- * @returns {number} The rounded number
970
- */
971
- export function bankers_round(x) {
972
- const r = Math.round(x);
973
- const br = Math.abs(x) % 1 === 0.5 ? (r % 2 === 0 ? r : r - 1) : r;
974
- return br;
975
- }
976
-
977
-
978
- /**
979
- * Measures similarity between two temporal sequences (e.g., input audio and output tokens
980
- * to generate token-level timestamps).
981
- * @param {number[][]} matrix
982
- * @returns {number[][]}
983
- */
984
- export function dynamic_time_warping(matrix) {
985
- const output_length = matrix.length;
986
- const input_length = matrix[0].length;
987
-
988
- const outputShape = [output_length + 1, input_length + 1];
989
-
990
- const cost = Array.from(
991
- { length: outputShape[0] },
992
- () => Array(outputShape[1]).fill(Infinity)
993
- );
994
- cost[0][0] = 0;
995
-
996
- const trace = Array.from(
997
- { length: outputShape[0] },
998
- () => Array(outputShape[1]).fill(-1)
999
- );
1000
-
1001
- for (let j = 1; j < outputShape[1]; ++j) {
1002
- for (let i = 1; i < outputShape[0]; ++i) {
1003
- const c0 = cost[i - 1][j - 1];
1004
- const c1 = cost[i - 1][j];
1005
- const c2 = cost[i][j - 1];
1006
-
1007
- let c, t;
1008
- if (c0 < c1 && c0 < c2) {
1009
- c = c0;
1010
- t = 0;
1011
- } else if (c1 < c0 && c1 < c2) {
1012
- c = c1;
1013
- t = 1;
1014
- } else {
1015
- c = c2;
1016
- t = 2;
1017
- }
1018
- cost[i][j] = matrix[i - 1][j - 1] + c;
1019
- trace[i][j] = t;
1020
- }
1021
- }
1022
-
1023
- for (let i = 0; i < outputShape[1]; ++i) { // trace[0, :] = 2
1024
- trace[0][i] = 2;
1025
- }
1026
- for (let i = 0; i < outputShape[0]; ++i) { // trace[:, 0] = 1
1027
- trace[i][0] = 1;
1028
- }
1029
-
1030
- // backtrace
1031
- let i = output_length;
1032
- let j = input_length;
1033
- let text_indices = [];
1034
- let time_indices = [];
1035
- while (i > 0 || j > 0) {
1036
- text_indices.push(i - 1);
1037
- time_indices.push(j - 1);
1038
-
1039
- switch (trace[i][j]) {
1040
- case 0:
1041
- --i; --j;
1042
- break;
1043
- case 1:
1044
- --i;
1045
- break;
1046
- case 2:
1047
- --j;
1048
- break;
1049
- default:
1050
- throw new Error(
1051
- `Internal error in dynamic time warping. Unexpected trace[${i}, ${j}]. Please file a bug report.`
1052
- )
1053
- }
1054
- }
1055
-
1056
- text_indices.reverse();
1057
- time_indices.reverse();
1058
-
1059
- return [text_indices, time_indices];
1060
-
1061
- }