echogarden 2.6.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/data/lexicons/heteronyms.en.json +6 -2
  2. package/data/lexicons/words.en.json +379 -19
  3. package/dist/alignment/SemanticTextAlignment.js +6 -7
  4. package/dist/alignment/SemanticTextAlignment.js.map +1 -1
  5. package/dist/api/Alignment.js +2 -2
  6. package/dist/api/Alignment.js.map +1 -1
  7. package/dist/api/Recognition.js +2 -2
  8. package/dist/api/Recognition.js.map +1 -1
  9. package/dist/api/SourceSeparation.js +1 -1
  10. package/dist/api/SpeechTranslation.js +2 -2
  11. package/dist/api/SpeechTranslation.js.map +1 -1
  12. package/dist/api/Synthesis.js +7 -7
  13. package/dist/api/Synthesis.js.map +1 -1
  14. package/dist/api/TimelineTranslationAlignment.js +2 -2
  15. package/dist/api/TimelineTranslationAlignment.js.map +1 -1
  16. package/dist/api/TranslationAlignment.js +2 -2
  17. package/dist/api/TranslationAlignment.js.map +1 -1
  18. package/dist/audio/AudioBufferConversion.d.ts +5 -6
  19. package/dist/audio/AudioBufferConversion.js +16 -248
  20. package/dist/audio/AudioBufferConversion.js.map +1 -1
  21. package/dist/audio/AudioPlayer.js +2 -2
  22. package/dist/audio/AudioPlayer.js.map +1 -1
  23. package/dist/audio/AudioRecorder.js +1 -1
  24. package/dist/audio/AudioRecorder.js.map +1 -1
  25. package/dist/audio/AudioUtilities.d.ts +2 -8
  26. package/dist/audio/AudioUtilities.js +4 -3
  27. package/dist/audio/AudioUtilities.js.map +1 -1
  28. package/dist/cli/CLI.js +4 -4
  29. package/dist/cli/CLI.js.map +1 -1
  30. package/dist/codecs/FFMpegTranscoder.d.ts +1 -4
  31. package/dist/codecs/TIMITCodec.js +1 -2
  32. package/dist/codecs/TIMITCodec.js.map +1 -1
  33. package/dist/denoising/RNNoise.js +5 -5
  34. package/dist/denoising/RNNoise.js.map +1 -1
  35. package/dist/dsp/FFT.js +13 -19
  36. package/dist/dsp/FFT.js.map +1 -1
  37. package/dist/dsp/Rubberband.js +5 -5
  38. package/dist/dsp/Rubberband.js.map +1 -1
  39. package/dist/dsp/Sonic.js +6 -6
  40. package/dist/dsp/Sonic.js.map +1 -1
  41. package/dist/dsp/SpeexResampler.js +11 -11
  42. package/dist/dsp/SpeexResampler.js.map +1 -1
  43. package/dist/encodings/Ascii.js +1 -1
  44. package/dist/encodings/Ascii.js.map +1 -1
  45. package/dist/encodings/Utf16.js +1 -1
  46. package/dist/encodings/Utf16.js.map +1 -1
  47. package/dist/encodings/Utf8.js +1 -1
  48. package/dist/encodings/Utf8.js.map +1 -1
  49. package/dist/nlp/EspeakPhonemizer.js +1 -1
  50. package/dist/nlp/EspeakPhonemizer.js.map +1 -1
  51. package/dist/nlp/Segmentation.d.ts +13 -10
  52. package/dist/nlp/Segmentation.js +129 -106
  53. package/dist/nlp/Segmentation.js.map +1 -1
  54. package/dist/nlp/TextNormalizer.js +74 -42
  55. package/dist/nlp/TextNormalizer.js.map +1 -1
  56. package/dist/recognition/AmazonTranscribeSTT.js +2 -2
  57. package/dist/recognition/AmazonTranscribeSTT.js.map +1 -1
  58. package/dist/recognition/SileroSTT.js +2 -2
  59. package/dist/recognition/SileroSTT.js.map +1 -1
  60. package/dist/recognition/WhisperSTT.js +4 -16
  61. package/dist/recognition/WhisperSTT.js.map +1 -1
  62. package/dist/subtitles/Subtitles.js +52 -7
  63. package/dist/subtitles/Subtitles.js.map +1 -1
  64. package/dist/synthesis/AwsPollyTTS.d.ts +1 -4
  65. package/dist/synthesis/CoquiServerTTS.d.ts +1 -4
  66. package/dist/synthesis/DeepgramTTS.d.ts +1 -4
  67. package/dist/synthesis/ElevenLabsTTS.d.ts +1 -4
  68. package/dist/synthesis/ElevenLabsTTS.js +11 -10
  69. package/dist/synthesis/ElevenLabsTTS.js.map +1 -1
  70. package/dist/synthesis/EspeakTTS.js +8 -8
  71. package/dist/synthesis/EspeakTTS.js.map +1 -1
  72. package/dist/synthesis/FliteTTS.d.ts +1 -4
  73. package/dist/synthesis/GnuSpeechTTS.d.ts +1 -7
  74. package/dist/synthesis/GoogleCloudTTS.d.ts +1 -4
  75. package/dist/synthesis/KokoroTTS.js +21 -10
  76. package/dist/synthesis/KokoroTTS.js.map +1 -1
  77. package/dist/synthesis/SapiTTS.js +1 -2
  78. package/dist/synthesis/SapiTTS.js.map +1 -1
  79. package/dist/synthesis/SvoxPicoTTS.js +25 -25
  80. package/dist/synthesis/SvoxPicoTTS.js.map +1 -1
  81. package/dist/text-translation/DeepLTextTranslation.js +4 -3
  82. package/dist/text-translation/DeepLTextTranslation.js.map +1 -1
  83. package/dist/text-translation/NLLBTextTranslation.js +7 -6
  84. package/dist/text-translation/NLLBTextTranslation.js.map +1 -1
  85. package/dist/utilities/StringUtilities.d.ts +1 -1
  86. package/dist/utilities/StringUtilities.js +5 -5
  87. package/dist/utilities/StringUtilities.js.map +1 -1
  88. package/dist/utilities/Timeline.d.ts +2 -3
  89. package/dist/utilities/Timeline.js +96 -147
  90. package/dist/utilities/Timeline.js.map +1 -1
  91. package/dist/utilities/WikipediaReader.js +3 -3
  92. package/dist/utilities/WikipediaReader.js.map +1 -1
  93. package/dist/voice-activity-detection/WebRtcVAD.js +4 -4
  94. package/dist/voice-activity-detection/WebRtcVAD.js.map +1 -1
  95. package/docs/Tasklist.md +1 -6
  96. package/package.json +13 -11
  97. package/src/alignment/SemanticTextAlignment.ts +6 -7
  98. package/src/api/Alignment.ts +2 -2
  99. package/src/api/Recognition.ts +2 -2
  100. package/src/api/SourceSeparation.ts +1 -1
  101. package/src/api/SpeechTranslation.ts +2 -2
  102. package/src/api/Synthesis.ts +7 -7
  103. package/src/api/TimelineTranslationAlignment.ts +2 -2
  104. package/src/api/TranslationAlignment.ts +2 -2
  105. package/src/audio/AudioBufferConversion.ts +17 -263
  106. package/src/audio/AudioPlayer.ts +3 -3
  107. package/src/audio/AudioRecorder.ts +1 -1
  108. package/src/audio/AudioUtilities.ts +5 -3
  109. package/src/cli/CLI.ts +4 -4
  110. package/src/codecs/TIMITCodec.ts +1 -2
  111. package/src/denoising/RNNoise.ts +5 -5
  112. package/src/dsp/FFT.ts +22 -19
  113. package/src/dsp/Rubberband.ts +5 -5
  114. package/src/dsp/Sonic.ts +6 -6
  115. package/src/dsp/SpeexResampler.ts +11 -11
  116. package/src/encodings/Ascii.ts +1 -1
  117. package/src/encodings/Utf16.ts +1 -1
  118. package/src/encodings/Utf8.ts +1 -1
  119. package/src/nlp/EspeakPhonemizer.ts +1 -1
  120. package/src/nlp/Segmentation.ts +146 -111
  121. package/src/nlp/TextNormalizer.ts +94 -52
  122. package/src/recognition/AmazonTranscribeSTT.ts +2 -2
  123. package/src/recognition/SileroSTT.ts +2 -2
  124. package/src/recognition/WhisperSTT.ts +4 -18
  125. package/src/subtitles/Subtitles.ts +69 -8
  126. package/src/synthesis/ElevenLabsTTS.ts +12 -11
  127. package/src/synthesis/EspeakTTS.ts +9 -8
  128. package/src/synthesis/KokoroTTS.ts +24 -12
  129. package/src/synthesis/SapiTTS.ts +1 -2
  130. package/src/synthesis/SvoxPicoTTS.ts +27 -25
  131. package/src/text-translation/DeepLTextTranslation.ts +4 -3
  132. package/src/text-translation/NLLBTextTranslation.ts +8 -6
  133. package/src/typings/Fillers.d.ts +0 -16
  134. package/src/utilities/StringUtilities.ts +5 -6
  135. package/src/utilities/Timeline.ts +100 -170
  136. package/src/utilities/WikipediaReader.ts +3 -3
  137. package/src/voice-activity-detection/WebRtcVAD.ts +5 -4
  138. package/dist/codecs/WaveCodec.d.ts +0 -19
  139. package/dist/codecs/WaveCodec.js +0 -224
  140. package/dist/codecs/WaveCodec.js.map +0 -1
  141. package/dist/nlp/CompromiseNLP.d.ts +0 -15
  142. package/dist/nlp/CompromiseNLP.js +0 -79
  143. package/dist/nlp/CompromiseNLP.js.map +0 -1
  144. package/dist/utilities/BinaryArrayConversion.d.ts +0 -14
  145. package/dist/utilities/BinaryArrayConversion.js +0 -92
  146. package/dist/utilities/BinaryArrayConversion.js.map +0 -1
  147. package/dist/utilities/WasmMemoryManager.d.ts +0 -153
  148. package/dist/utilities/WasmMemoryManager.js +0 -440
  149. package/dist/utilities/WasmMemoryManager.js.map +0 -1
  150. package/src/codecs/WaveCodec.ts +0 -281
  151. package/src/nlp/CompromiseNLP.ts +0 -119
  152. package/src/utilities/BinaryArrayConversion.ts +0 -117
  153. package/src/utilities/WasmMemoryManager.ts +0 -566
@@ -1,297 +1,51 @@
1
- import * as AlawMulaw from 'alawmulaw'
2
- import * as BinaryArrayConversion from '../utilities/BinaryArrayConversion.js'
3
- import { BitDepth, SampleFormat } from '../codecs/WaveCodec.js'
1
+ import * as WaveCodec from '@echogarden/wave-codec'
2
+ import { BitDepth, SampleFormat } from '@echogarden/wave-codec'
4
3
 
5
4
  /////////////////////////////////////////////////////////////////////////////////////////////
6
5
  // Low level audio sample conversions
7
6
  /////////////////////////////////////////////////////////////////////////////////////////////
8
7
  export function encodeToAudioBuffer(audioChannels: Float32Array[], targetBitDepth: BitDepth = 16, targetSampleFormat: SampleFormat = SampleFormat.PCM): Uint8Array {
9
- const interleavedChannels = interleaveChannels(audioChannels)
10
-
11
- audioChannels = [] // Zero the array references to allow the GC to free up memory, if possible
12
-
13
- if (targetSampleFormat === SampleFormat.PCM) {
14
- if (targetBitDepth === 8) {
15
- return BinaryArrayConversion.int8ToBuffer(float32ToInt8Pcm(interleavedChannels))
16
- } else if (targetBitDepth === 16) {
17
- return BinaryArrayConversion.int16ToBufferLE(float32ToInt16Pcm(interleavedChannels))
18
- } else if (targetBitDepth === 24) {
19
- return BinaryArrayConversion.int24ToBufferLE(float32ToInt24Pcm(interleavedChannels))
20
- } else if (targetBitDepth === 32) {
21
- return BinaryArrayConversion.int32ToBufferLE(float32ToInt32Pcm(interleavedChannels))
22
- } else {
23
- throw new Error(`Unsupported PCM bit depth: ${targetBitDepth}`)
24
- }
25
- } else if (targetSampleFormat === SampleFormat.Float) {
26
- if (targetBitDepth === 32) {
27
- return BinaryArrayConversion.float32ToBufferLE(interleavedChannels)
28
- } else if (targetBitDepth === 64) {
29
- return BinaryArrayConversion.float64ToBufferLE(BinaryArrayConversion.float32Tofloat64(interleavedChannels))
30
- } else {
31
- throw new Error(`Unsupported float bit depth: ${targetBitDepth}`)
32
- }
33
- } else if (targetSampleFormat === SampleFormat.Alaw) {
34
- if (targetBitDepth === 8) {
35
- return AlawMulaw.alaw.encode(float32ToInt16Pcm(interleavedChannels))
36
- } else {
37
- throw new Error(`Unsupported alaw bit depth: ${targetBitDepth}`)
38
- }
39
- } else if (targetSampleFormat === SampleFormat.Mulaw) {
40
- if (targetBitDepth === 8) {
41
- return AlawMulaw.mulaw.encode(float32ToInt16Pcm(interleavedChannels))
42
- } else {
43
- throw new Error(`Unsupported mulaw bit depth: ${targetBitDepth}`)
44
- }
45
- } else {
46
- throw new Error(`Unsupported audio format: ${targetSampleFormat}`)
47
- }
48
- }
49
-
50
- export function decodeToChannels(audioBuffer: Uint8Array, channelCount: number, sourceBitDepth: number, sourceSampleFormat: SampleFormat) {
51
- let interleavedChannels: Float32Array
52
-
53
- if (sourceSampleFormat === SampleFormat.PCM) {
54
- if (sourceBitDepth === 8) {
55
- interleavedChannels = int8PcmToFloat32(BinaryArrayConversion.bufferToInt8(audioBuffer))
56
- } else if (sourceBitDepth === 16) {
57
- interleavedChannels = int16PcmToFloat32(BinaryArrayConversion.bufferLEToInt16(audioBuffer))
58
- } else if (sourceBitDepth === 24) {
59
- interleavedChannels = int24PcmToFloat32(BinaryArrayConversion.bufferLEToInt24(audioBuffer))
60
- } else if (sourceBitDepth === 32) {
61
- interleavedChannels = int32PcmToFloat32(BinaryArrayConversion.bufferLEToInt32(audioBuffer))
62
- } else {
63
- throw new Error(`Unsupported PCM bit depth: ${sourceBitDepth}`)
64
- }
65
- } else if (sourceSampleFormat === SampleFormat.Float) {
66
- if (sourceBitDepth === 32) {
67
- interleavedChannels = BinaryArrayConversion.bufferLEToFloat32(audioBuffer)
68
- } else if (sourceBitDepth === 64) {
69
- interleavedChannels = BinaryArrayConversion.float64Tofloat32(BinaryArrayConversion.bufferLEToFloat64(audioBuffer))
70
- } else {
71
- throw new Error(`Unsupported float bit depth: ${sourceBitDepth}`)
72
- }
73
- } else if (sourceSampleFormat === SampleFormat.Alaw) {
74
- if (sourceBitDepth === 8) {
75
- interleavedChannels = int16PcmToFloat32(AlawMulaw.alaw.decode(audioBuffer))
76
- } else {
77
- throw new Error(`Unsupported alaw bit depth: ${sourceBitDepth}`)
78
- }
79
- } else if (sourceSampleFormat === SampleFormat.Mulaw) {
80
- if (sourceBitDepth === 8) {
81
- interleavedChannels = int16PcmToFloat32(AlawMulaw.mulaw.decode(audioBuffer))
82
- } else {
83
- throw new Error(`Unsupported mulaw bit depth: ${sourceBitDepth}`)
84
- }
85
- } else {
86
- throw new Error(`Unsupported audio format: ${sourceSampleFormat}`)
87
- }
88
-
89
- audioBuffer = new Uint8Array(0) // Zero the buffer reference to allow the GC to free up memory, if possible
90
-
91
- return deInterleaveChannels(interleavedChannels, channelCount)
8
+ return WaveCodec.float32ChannelsToBuffer(audioChannels, targetBitDepth, targetSampleFormat)
92
9
  }
93
10
 
94
- // Int8 PCM <-> Float32 conversion
95
- export function int8PcmToFloat32(input: Int8Array) {
96
- const sampleCount = input.length
97
-
98
- const output = new Float32Array(sampleCount)
99
-
100
- for (let i = 0; i < sampleCount; i++) {
101
- output[i] = input[i] / 128
102
- }
103
-
104
- return output
11
+ export function decodeToChannels(audioBuffer: Uint8Array, channelCount: number, sourceBitDepth: BitDepth, sourceSampleFormat: SampleFormat) {
12
+ return WaveCodec.bufferToFloat32Channels(audioBuffer, channelCount, sourceBitDepth, sourceSampleFormat)
105
13
  }
106
14
 
107
- export function float32ToInt8Pcm(input: Float32Array) {
108
- const sampleCount = input.length
109
-
110
- const output = new Int8Array(sampleCount)
111
-
112
- for (let i = 0; i < sampleCount; i++) {
113
- const int8Sample = input[i] * 128
114
-
115
- if (int8Sample < -128) {
116
- output[i] = -128
117
- } else if (int8Sample > 127) {
118
- output[i] = 127
119
- } else {
120
- output[i] = int8Sample
121
- }
122
- }
123
-
124
- return output
15
+ export function float32ToUint8Pcm(input: Float32Array) {
16
+ return WaveCodec.float32ToUint8Pcm(input)
125
17
  }
126
18
 
127
- // Int16 PCM <-> Float32 conversion
128
19
  export function int16PcmToFloat32(input: Int16Array) {
129
- const sampleCount = input.length
130
-
131
- const output = new Float32Array(sampleCount)
132
-
133
- for (let i = 0; i < sampleCount; i++) {
134
- output[i] = input[i] / 32768
135
- }
136
-
137
- return output
20
+ return WaveCodec.int16PcmToFloat32(input)
138
21
  }
139
22
 
140
23
  export function float32ToInt16Pcm(input: Float32Array) {
141
- const sampleCount = input.length
142
-
143
- const output = new Int16Array(sampleCount)
144
-
145
- for (let i = 0; i < sampleCount; i++) {
146
- const int16Sample = input[i] * 32768
147
-
148
- if (int16Sample < -32768) {
149
- output[i] = -32768
150
- } else if (int16Sample > 32767) {
151
- output[i] = 32767
152
- } else {
153
- output[i] = int16Sample
154
- }
155
- }
156
-
157
- return output
24
+ return WaveCodec.float32ToInt16Pcm(input)
158
25
  }
159
26
 
160
- // Int24 PCM <-> Float32 conversion (uses int32 for storage)
161
27
  export function int24PcmToFloat32(input: Int32Array) {
162
- const sampleCount = input.length
163
-
164
- const output = new Float32Array(sampleCount)
165
-
166
- for (let i = 0; i < sampleCount; i++) {
167
- output[i] = input[i] / 8388608
168
- }
169
-
170
- return output
28
+ return WaveCodec.int24PcmToFloat32(input)
171
29
  }
172
30
 
173
31
  export function float32ToInt24Pcm(input: Float32Array) {
174
- const sampleCount = input.length
175
-
176
- const output = new Int32Array(sampleCount)
177
-
178
- for (let i = 0; i < sampleCount; i++) {
179
- const int24Sample = input[i] * 8388608
180
-
181
- if (int24Sample < -8388608) {
182
- output[i] = -8388608
183
- } else if (int24Sample > 8388607) {
184
- output[i] = 8388607
185
- } else {
186
- output[i] = int24Sample
187
- }
188
- }
189
-
190
- return output
32
+ return WaveCodec.float32ToInt24Pcm(input)
191
33
  }
192
34
 
193
- // Int32 PCM <-> Float32 conversion
194
35
  export function int32PcmToFloat32(input: Int32Array) {
195
- const sampleCount = input.length
196
-
197
- const output = new Float32Array(sampleCount)
198
-
199
- for (let i = 0; i < sampleCount; i++) {
200
- output[i] = input[i] / 2147483648
201
- }
202
-
203
- return output
36
+ return WaveCodec.int32PcmToFloat32(input)
204
37
  }
205
38
 
206
39
  export function float32ToInt32Pcm(input: Float32Array) {
207
- const sampleCount = input.length
208
-
209
- const output = new Int32Array(sampleCount)
210
-
211
- for (let i = 0; i < sampleCount; i++) {
212
- const int32Sample = input[i] * 2147483648
213
-
214
- if (int32Sample < -2147483648) {
215
- output[i] = -2147483648
216
- } else if (int32Sample > 2147483647) {
217
- output[i] = 2147483647
218
- } else {
219
- output[i] = int32Sample
220
- }
221
- }
222
-
223
- return output
40
+ return WaveCodec.float32ToInt32Pcm(input)
224
41
  }
225
42
 
226
- /////////////////////////////////////////////////////////////////////////////////////////////
227
- // Channel interleaving
228
- /////////////////////////////////////////////////////////////////////////////////////////////
229
43
  export function interleaveChannels(channels: Float32Array[]) {
230
- const channelCount = channels.length
231
-
232
- if (channelCount === 0) {
233
- throw new Error('Empty channel array received')
234
- }
235
-
236
- if (channelCount === 1) {
237
- return channels[0]
238
- }
239
-
240
- const sampleCount = channels[0].length
241
- const result = new Float32Array(sampleCount * channelCount)
242
-
243
- let writeIndex = 0
244
-
245
- for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
246
- for (let channelIndex = 0; channelIndex < channelCount; channelIndex++) {
247
- result[writeIndex++] = channels[channelIndex][sampleIndex]
248
- }
249
- }
250
-
251
- return result
44
+ return WaveCodec.interleaveChannels(channels)
252
45
  }
253
46
 
254
- export function deInterleaveChannels(interleavedChannels: Float32Array, channelCount: number) {
255
- if (channelCount === 0) {
256
- throw new Error('0 channel count received')
257
- }
258
-
259
- if (channelCount === 1) {
260
- return [interleavedChannels]
261
- }
262
-
263
- if (interleavedChannels.length % channelCount != 0) {
264
- throw new Error(`Size of interleaved channels (${interleaveChannels.length}) is not a multiple of channel count (${channelCount})`)
265
- }
266
-
267
- const sampleCount = interleavedChannels.length / channelCount
268
-
269
- const channels: Float32Array[] = []
270
-
271
- for (let i = 0; i < channelCount; i++) {
272
- channels.push(new Float32Array(sampleCount))
273
- }
274
-
275
- let readIndex = 0
276
-
277
- for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
278
- for (let channelIndex = 0; channelIndex < channelCount; channelIndex++) {
279
- channels[channelIndex][sampleIndex] = interleavedChannels[readIndex++]
280
- }
281
- }
282
-
283
- return channels
47
+ export function deinterleaveChannels(interleavedChannels: Float32Array, channelCount: number) {
48
+ return WaveCodec.deinterleaveChannels(interleavedChannels, channelCount)
284
49
  }
285
50
 
286
- /////////////////////////////////////////////////////////////////////////////////////////////
287
- // Utilities
288
- /////////////////////////////////////////////////////////////////////////////////////////////
289
- export function clampFloatSample(floatSample: number) {
290
- if (floatSample < -1.0) {
291
- return -1.0
292
- } else if (floatSample > 1.0) {
293
- return 1.0
294
- } else {
295
- return floatSample
296
- }
297
- }
51
+ export { type BitDepth, SampleFormat } from '@echogarden/wave-codec'
@@ -2,14 +2,14 @@ import { parentPort } from 'node:worker_threads'
2
2
 
3
3
  import { ChildProcessWithoutNullStreams, spawn } from 'child_process'
4
4
 
5
- import { RawAudio, encodeRawAudioToWave, fadeAudioInOut, getRawAudioDuration, sliceAudioChannels, sliceRawAudioByTime } from './AudioUtilities.js'
5
+ import { RawAudio, encodeRawAudioToWave, fadeAudioInOut, getRawAudioDuration, sliceAudioChannels } from './AudioUtilities.js'
6
6
  import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
7
7
 
8
8
  import { Timer } from '../utilities/Timer.js'
9
9
  import { clip, getRandomHexString, waitTimeout, writeToStderr } from '../utilities/Utilities.js'
10
10
  import { encodeToAudioBuffer, float32ToInt16Pcm, interleaveChannels } from './AudioBufferConversion.js'
11
11
  import { OpenPromise } from '../utilities/OpenPromise.js'
12
- import { Timeline, addWordTextOffsetsToTimeline } from '../utilities/Timeline.js'
12
+ import { Timeline, addWordTextOffsetsToTimelineInPlace } from '../utilities/Timeline.js'
13
13
  import { readAndParseJsonFile, readFileAsUtf8, remove, writeFile } from '../utilities/FileSystem.js'
14
14
  import { tryResolvingSoxPath } from './SoxPath.js'
15
15
  import { SignalChannel } from '../utilities/SignalChannel.js'
@@ -38,7 +38,7 @@ export async function playAudioWithWordTimeline(rawAudio: RawAudio, wordTimeline
38
38
 
39
39
  wordTimeline = deepClone(wordTimeline)
40
40
 
41
- addWordTextOffsetsToTimeline(wordTimeline, transcript)
41
+ addWordTextOffsetsToTimelineInPlace(wordTimeline, transcript)
42
42
 
43
43
  let timelineEntryIndex = 0
44
44
  let transcriptOffset = 0
@@ -6,8 +6,8 @@ import * as AudioBufferConversion from './AudioBufferConversion.js'
6
6
  import { Timer } from '../utilities/Timer.js'
7
7
  import { logToStderr } from '../utilities/Utilities.js'
8
8
  import { OpenPromise } from '../utilities/OpenPromise.js'
9
- import { SampleFormat } from '../codecs/WaveCodec.js'
10
9
  import { tryResolvingSoxPath } from './SoxPath.js'
10
+ import { SampleFormat } from './AudioBufferConversion.js'
11
11
 
12
12
  const log = logToStderr
13
13
 
@@ -1,5 +1,5 @@
1
1
  import * as FFMpegTranscoder from '../codecs/FFMpegTranscoder.js'
2
- import { SampleFormat, encodeWave, decodeWave, BitDepth } from '../codecs/WaveCodec.js'
2
+ import { SampleFormat, BitDepth, encodeWaveFromFloat32Channels, decodeWaveToFloat32Channels } from '@echogarden/wave-codec'
3
3
  import { resampleAudioSpeex } from '../dsp/SpeexResampler.js'
4
4
  import { Timeline } from '../utilities/Timeline.js'
5
5
  import { concatFloat32Arrays } from '../utilities/Utilities.js'
@@ -8,11 +8,13 @@ import { concatFloat32Arrays } from '../utilities/Utilities.js'
8
8
  // Wave encoding and decoding
9
9
  ////////////////////////////////////////////////////////////////////////////////////////////////
10
10
  export function encodeRawAudioToWave(rawAudio: RawAudio, bitDepth: BitDepth = 16, sampleFormat: SampleFormat = SampleFormat.PCM, speakerPositionMask = 0) {
11
- return encodeWave(rawAudio, bitDepth, sampleFormat, speakerPositionMask)
11
+ return encodeWaveFromFloat32Channels(rawAudio.audioChannels, rawAudio.sampleRate, bitDepth, sampleFormat, speakerPositionMask)
12
12
  }
13
13
 
14
14
  export function decodeWaveToRawAudio(waveFileBuffer: Uint8Array, ignoreTruncatedChunks = true, ignoreOverflowingDataChunks = true) {
15
- return decodeWave(waveFileBuffer, ignoreTruncatedChunks, ignoreOverflowingDataChunks)
15
+ const rawAudio = decodeWaveToFloat32Channels(waveFileBuffer, ignoreTruncatedChunks, ignoreOverflowingDataChunks)
16
+
17
+ return { rawAudio }
16
18
  }
17
19
 
18
20
  ////////////////////////////////////////////////////////////////////////////////////////////////
package/src/cli/CLI.ts CHANGED
@@ -10,10 +10,10 @@ import { SubtitlesConfig, subtitlesToText, timelineToSubtitles } from '../subtit
10
10
  import { Logger, resetActiveLogger } from '../utilities/Logger.js'
11
11
  import { isMainThread, parentPort } from 'node:worker_threads'
12
12
  import { encodeFromChannels, getDefaultFFMpegOptionsForSpeech } from '../codecs/FFMpegTranscoder.js'
13
- import { splitToParagraphs, splitToWords, wordCharacterPattern } from '../nlp/Segmentation.js'
13
+ import { splitToParagraphs, splitToWords } from '../nlp/Segmentation.js'
14
14
  import { playAudioSamplesWithKeyboardControls, playAudioWithWordTimeline } from '../audio/AudioPlayer.js'
15
15
  import { extendDeep } from '../utilities/ObjectUtilities.js'
16
- import { Timeline, TimelineEntry, addTimeOffsetToTimeline, addWordTextOffsetsToTimeline, roundTimelineProperties } from '../utilities/Timeline.js'
16
+ import { Timeline, TimelineEntry, addTimeOffsetToTimeline, addWordTextOffsetsToTimelineInPlace, roundTimelineProperties } from '../utilities/Timeline.js'
17
17
  import { ensureDir, existsSync, readAndParseJsonFile, readdir, readFileAsUtf8, writeFileSafe } from '../utilities/FileSystem.js'
18
18
  import { formatLanguageCodeWithName, getShortLanguageCode } from '../utilities/Locale.js'
19
19
  import { APIOptions } from '../api/APIOptions.js'
@@ -509,7 +509,7 @@ export async function speak(operationData: CLIOperationData) {
509
509
  const { audio: synthesizedAudio, timeline } = await API.synthesize(textSegments, options, onSegment, undefined)
510
510
 
511
511
  if (plainText) {
512
- addWordTextOffsetsToTimeline(timeline, plainText)
512
+ addWordTextOffsetsToTimelineInPlace(timeline, plainText)
513
513
  }
514
514
 
515
515
  if (outputFilenames.length > 0) {
@@ -1884,7 +1884,7 @@ async function checkOutputFilenames(outputFilenames: string[], acceptMediaOutput
1884
1884
  async function writeOutputFilesForSegment(outputFilenames: string[], index: number, total: number, audio: RawAudio, timeline: Timeline, text: string, language: string, allowOverwrite: boolean) {
1885
1885
  const digitCount = Math.max((total + 1).toString().length, 2)
1886
1886
 
1887
- const segmentWords = (await splitToWords(text, language)).filter(text => wordCharacterPattern.test(text))
1887
+ const segmentWords = (await splitToWords(text, language)).nonPunctuationWords
1888
1888
 
1889
1889
  const segmentJoinedWords = segmentWords.join(' ').trim()
1890
1890
 
@@ -1,7 +1,6 @@
1
- import { decodeToChannels } from '../audio/AudioBufferConversion.js'
1
+ import { decodeToChannels, SampleFormat } from '../audio/AudioBufferConversion.js'
2
2
  import { decodeAscii } from '../encodings/Ascii.js'
3
3
  import { readFileAsBinary } from '../utilities/FileSystem.js'
4
- import { SampleFormat } from './WaveCodec.js'
5
4
 
6
5
  export async function decodeTimitAudioFile(filename: string) {
7
6
  return decodeTimitAudio(await readFileAsBinary(filename))
@@ -1,6 +1,6 @@
1
1
  import { float32ToInt16Pcm } from '../audio/AudioBufferConversion.js'
2
2
  import { concatFloat32Arrays } from '../utilities/Utilities.js'
3
- import { WasmMemoryManager } from '../utilities/WasmMemoryManager.js'
3
+ import { wrapEmscriptenModuleHeap } from 'wasm-heap-manager'
4
4
  import { Logger } from '../utilities/Logger.js'
5
5
  import { RawAudio, cloneRawAudio } from '../audio/AudioUtilities.js'
6
6
 
@@ -24,15 +24,15 @@ export async function denoiseAudio(rawAudio: RawAudio) {
24
24
  const m = await getRnnoiseInstance()
25
25
 
26
26
  logger.start('Process with RNNoise')
27
- const wasmMemory = new WasmMemoryManager(m)
27
+ const wasmHeap = wrapEmscriptenModuleHeap(m)
28
28
 
29
29
  const stateSize = m._rnnoise_get_size()
30
30
  const frameSize = m._rnnoise_get_frame_size()
31
31
 
32
32
  const denoiseState = m._rnnoise_create(0)
33
33
 
34
- const inputRef = wasmMemory.allocFloat32Array(frameSize)
35
- const outputRef = wasmMemory.allocFloat32Array(frameSize)
34
+ const inputRef = wasmHeap.allocFloat32Array(frameSize)
35
+ const outputRef = wasmHeap.allocFloat32Array(frameSize)
36
36
 
37
37
  const floatSamples = rawAudio.audioChannels[0]
38
38
  const int16Samples = float32ToInt16Pcm(floatSamples)
@@ -70,7 +70,7 @@ export async function denoiseAudio(rawAudio: RawAudio) {
70
70
  outputNewFrame(outputRef.view.slice(), lastFrameVadProbability)
71
71
 
72
72
  m._rnnoise_destroy(denoiseState)
73
- wasmMemory.freeAll()
73
+ wasmHeap.freeAll()
74
74
 
75
75
  const int16DenoisedSamplesAsFloats = concatFloat32Arrays(processedFrames)
76
76
 
package/src/dsp/FFT.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ComplexNumber } from '../math/VectorMath.js'
2
2
  import { concatFloat32Arrays, isWasmSimdSupported } from '../utilities/Utilities.js'
3
- import { WasmMemoryManager } from '../utilities/WasmMemoryManager.js'
3
+ import { createWasmHeapManager } from 'wasm-heap-manager'
4
4
 
5
5
  // Compute short-term Fourier transform (real-valued)
6
6
  export async function stftr(samples: Float32Array, fftOrder: number, windowSize: number, hopSize: number, windowType: WindowType) {
@@ -15,7 +15,7 @@ export async function stftr(samples: Float32Array, fftOrder: number, windowSize:
15
15
 
16
16
  // Incrementally generate short-term Fourier transform frames (real-valued)
17
17
  export async function* stftrGenerator(samples: Float32Array, fftOrder: number, windowSize: number, hopSize: number, windowType: WindowType) {
18
- if (fftOrder % 2 != 0 || windowSize % 2 != 0) {
18
+ if (fftOrder % 2 !== 0 || windowSize % 2 !== 0) {
19
19
  throw new Error('FFT order and window size must be multiples of 2')
20
20
  }
21
21
 
@@ -35,17 +35,19 @@ export async function* stftrGenerator(samples: Float32Array, fftOrder: number, w
35
35
  const windowWeights = getWindowWeights(windowType, windowSize)
36
36
 
37
37
  const m = await getPFFFTInstance(await isPffftSimdSupportedForFFTOrder(fftOrder))
38
- const wasmMemory = new WasmMemoryManager(m, {
39
- wasmAlloc: m._pffft_aligned_malloc,
40
- wasmFree: m._pffft_aligned_free
41
- })
38
+
39
+ const wasmHeap = createWasmHeapManager(
40
+ () => m.HEAPU8.buffer,
41
+ m._pffft_aligned_malloc,
42
+ m._pffft_aligned_free,
43
+ )
42
44
 
43
45
  const statePtr = m._pffft_new_setup(fftOrder, 0)
44
46
 
45
47
  const sampleCount = samples.length
46
- const frameBufferRef = wasmMemory.allocFloat32Array(fftOrder)
47
- const binsBufferRef = wasmMemory.allocFloat32Array(fftOrder * 2)
48
- const workBufferRef = wasmMemory.allocFloat32Array(fftOrder * 2)
48
+ const frameBufferRef = wasmHeap.allocFloat32Array(fftOrder)
49
+ const binsBufferRef = wasmHeap.allocFloat32Array(fftOrder * 2)
50
+ const workBufferRef = wasmHeap.allocFloat32Array(fftOrder * 2)
49
51
 
50
52
  for (let offset = 0; offset < sampleCount; offset += hopSize) {
51
53
  const windowSamples = samples.subarray(offset, offset + windowSize)
@@ -68,12 +70,12 @@ export async function* stftrGenerator(samples: Float32Array, fftOrder: number, w
68
70
 
69
71
  m._pffft_destroy_setup(statePtr)
70
72
 
71
- wasmMemory.freeAll()
73
+ wasmHeap.freeAll()
72
74
  }
73
75
 
74
76
  // Compute short-term inverse Fourier transform (real-valued)
75
77
  export async function stiftr(binsForFrames: Float32Array[], fftOrder: number, windowSize: number, hopSize: number, windowType: WindowType, expectedOutputLength?: number) {
76
- if (fftOrder % 2 != 0 || windowSize % 2 != 0) {
78
+ if (fftOrder % 2 !== 0 || windowSize % 2 !== 0) {
77
79
  throw new Error('FFT order and window size must multiples of 2')
78
80
  }
79
81
 
@@ -101,16 +103,17 @@ export async function stiftr(binsForFrames: Float32Array[], fftOrder: number, wi
101
103
 
102
104
  const m = await getPFFFTInstance(await isPffftSimdSupportedForFFTOrder(fftOrder))
103
105
 
104
- const wasmMemory = new WasmMemoryManager(m, {
105
- wasmAlloc: m._pffft_aligned_malloc,
106
- wasmFree: m._pffft_aligned_free
107
- })
106
+ const wasmHeap = createWasmHeapManager(
107
+ () => m.HEAPU8.buffer,
108
+ m._pffft_aligned_malloc,
109
+ m._pffft_aligned_free,
110
+ )
108
111
 
109
112
  const statePtr = m._pffft_new_setup(fftOrder, 0)
110
113
 
111
- const frameBufferRef = wasmMemory.allocFloat32Array(fftOrder)
112
- const binsRef = wasmMemory.allocFloat32Array(fftOrder * 2)
113
- const workBufferRef = wasmMemory.allocFloat32Array(fftOrder * 2)
114
+ const frameBufferRef = wasmHeap.allocFloat32Array(fftOrder)
115
+ const binsRef = wasmHeap.allocFloat32Array(fftOrder * 2)
116
+ const workBufferRef = wasmHeap.allocFloat32Array(fftOrder * 2)
114
117
 
115
118
  const sumOfSquaredWeightsForSample = new Float32Array(outSampleCount)
116
119
 
@@ -140,7 +143,7 @@ export async function stiftr(binsForFrames: Float32Array[], fftOrder: number, wi
140
143
  }
141
144
 
142
145
  m._pffft_destroy_setup(statePtr)
143
- wasmMemory.freeAll()
146
+ wasmHeap.freeAll()
144
147
 
145
148
  // Divide each output sample by the sum of squared weights
146
149
  for (let i = 0; i < outSamples.length; i++) {
@@ -1,7 +1,7 @@
1
1
  import { RawAudio } from '../audio/AudioUtilities.js'
2
2
  import { extendDeep } from '../utilities/ObjectUtilities.js'
3
3
  import { concatFloat32Arrays } from '../utilities/Utilities.js'
4
- import { Float32ArrayRef, WasmMemoryManager } from '../utilities/WasmMemoryManager.js'
4
+ import { Float32ArrayRef, wrapEmscriptenModuleHeap } from 'wasm-heap-manager'
5
5
 
6
6
  let rubberbandInstance: any
7
7
 
@@ -14,7 +14,7 @@ export async function stretchTimePitch(rawAudio: RawAudio, speed: number, pitchS
14
14
  const sampleRate = rawAudio.sampleRate
15
15
 
16
16
  const m = await getRubberbandInstance()
17
- const wasmMemory = new WasmMemoryManager(m)
17
+ const wasmHeap = wrapEmscriptenModuleHeap(m)
18
18
 
19
19
  const optionFlags = rubberBandOptionsToFlags(options)
20
20
 
@@ -25,11 +25,11 @@ export async function stretchTimePitch(rawAudio: RawAudio, speed: number, pitchS
25
25
  const samplesRequired = m._rubberband_get_samples_required(statePtr)
26
26
  const bufferSize = Math.min(samplesRequired, sampleCount)
27
27
 
28
- const bufferChannelPtrsRef = wasmMemory.allocUint32Array(bufferSize)
28
+ const bufferChannelPtrsRef = wasmHeap.allocUint32Array(bufferSize)
29
29
  const bufferChannelRefs: Float32ArrayRef[] = []
30
30
 
31
31
  for (let i = 0; i < channelCount; i++) {
32
- const bufferChannelRef = wasmMemory.allocFloat32Array(bufferSize)
32
+ const bufferChannelRef = wasmHeap.allocFloat32Array(bufferSize)
33
33
  bufferChannelPtrsRef.view[i] = bufferChannelRef.address
34
34
 
35
35
  bufferChannelRefs.push(bufferChannelRef)
@@ -102,7 +102,7 @@ export async function stretchTimePitch(rawAudio: RawAudio, speed: number, pitchS
102
102
  }
103
103
 
104
104
  m._rubberband_delete(statePtr)
105
- wasmMemory.freeAll()
105
+ wasmHeap.freeAll()
106
106
 
107
107
  const outputAudioChannels = outputAudioChannelChunks.map(chunks => concatFloat32Arrays(chunks))
108
108
  const outputRawAudio: RawAudio = { audioChannels: outputAudioChannels, sampleRate }
package/src/dsp/Sonic.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RawAudio } from '../audio/AudioUtilities.js'
2
- import { WasmMemoryManager } from '../utilities/WasmMemoryManager.js'
2
+ import { wrapEmscriptenModuleHeap } from 'wasm-heap-manager'
3
3
 
4
4
  let sonicInstance: any
5
5
 
@@ -10,13 +10,13 @@ export async function stretchTimePitch(rawAudio: RawAudio, speed: number, pitchS
10
10
  const inputSampleCount = rawAudio.audioChannels[0].length
11
11
 
12
12
  const m = await getSonicInstance()
13
- const wasmMemory = new WasmMemoryManager(m)
13
+ const wasmHeap = wrapEmscriptenModuleHeap(m)
14
14
 
15
15
  const streamPtr = m._sonicCreateStream(sampleRate, channelCount)
16
16
  m._sonicSetSpeed(streamPtr, speed)
17
17
  m._sonicSetPitch(streamPtr, pitchScale)
18
18
 
19
- const inputSamplesRef = wasmMemory.allocFloat32Array(inputSampleCount)
19
+ const inputSamplesRef = wasmHeap.allocFloat32Array(inputSampleCount)
20
20
  inputSamplesRef.view.set(inputSamples)
21
21
 
22
22
  const writeSuccess = m._sonicWriteFloatToStream(streamPtr, inputSamplesRef.address, inputSampleCount)
@@ -33,9 +33,9 @@ export async function stretchTimePitch(rawAudio: RawAudio, speed: number, pitchS
33
33
 
34
34
  const samplesAvailable = m._sonicSamplesAvailable(streamPtr)
35
35
 
36
- const outputSamplesRef = wasmMemory.allocFloat32Array(samplesAvailable)
36
+ const outputSamplesRef = wasmHeap.allocFloat32Array(samplesAvailable)
37
37
 
38
- const samplesRead = m._sonicReadFloatFromStream(streamPtr, outputSamplesRef.address, outputSamplesRef.length)
38
+ const samplesRead = m._sonicReadFloatFromStream(streamPtr, outputSamplesRef.address, outputSamplesRef.allocatedByteCount)
39
39
 
40
40
  const outputSamples = outputSamplesRef.view.slice(0, samplesRead)
41
41
 
@@ -43,7 +43,7 @@ export async function stretchTimePitch(rawAudio: RawAudio, speed: number, pitchS
43
43
 
44
44
  m._sonicDestroyStream(streamPtr)
45
45
 
46
- wasmMemory.freeAll()
46
+ wasmHeap.freeAll()
47
47
 
48
48
  return resultAudio
49
49
  }