echogarden 1.7.0 → 1.8.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 (54) hide show
  1. package/data/schemas/options.json +22 -10
  2. package/dist/api/Alignment.js +2 -2
  3. package/dist/api/Alignment.js.map +1 -1
  4. package/dist/api/Denoising.js +5 -4
  5. package/dist/api/Denoising.js.map +1 -1
  6. package/dist/api/Recognition.js +2 -2
  7. package/dist/api/Recognition.js.map +1 -1
  8. package/dist/api/SourceSeparation.d.ts +2 -6
  9. package/dist/api/SourceSeparation.js +8 -9
  10. package/dist/api/SourceSeparation.js.map +1 -1
  11. package/dist/api/SpeechLanguageDetection.js +2 -2
  12. package/dist/api/SpeechLanguageDetection.js.map +1 -1
  13. package/dist/api/SpeechTranslation.js +2 -2
  14. package/dist/api/SpeechTranslation.js.map +1 -1
  15. package/dist/api/Synthesis.js +5 -5
  16. package/dist/api/Synthesis.js.map +1 -1
  17. package/dist/api/TranslationAlignment.js +2 -2
  18. package/dist/api/TranslationAlignment.js.map +1 -1
  19. package/dist/audio/AudioUtilities.d.ts +5 -3
  20. package/dist/audio/AudioUtilities.js +39 -25
  21. package/dist/audio/AudioUtilities.js.map +1 -1
  22. package/dist/dsp/FFT.d.ts +2 -1
  23. package/dist/dsp/FFT.js +37 -18
  24. package/dist/dsp/FFT.js.map +1 -1
  25. package/dist/nlp/IPA.d.ts +3 -3
  26. package/dist/recognition/WhisperSTT.d.ts +5 -0
  27. package/dist/recognition/WhisperSTT.js +47 -7
  28. package/dist/recognition/WhisperSTT.js.map +1 -1
  29. package/dist/source-separation/MDXNetSourceSeparation.d.ts +8 -3
  30. package/dist/source-separation/MDXNetSourceSeparation.js +35 -13
  31. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
  32. package/dist/utilities/PackageManager.js +3 -6
  33. package/dist/utilities/PackageManager.js.map +1 -1
  34. package/dist/utilities/WasmMemoryManager.d.ts +9 -1
  35. package/dist/utilities/WasmMemoryManager.js +24 -3
  36. package/dist/utilities/WasmMemoryManager.js.map +1 -1
  37. package/docs/Options.md +9 -9
  38. package/package.json +6 -5
  39. package/src/alignment/SpeechAlignment.ts +1 -1
  40. package/src/api/Alignment.ts +2 -2
  41. package/src/api/Denoising.ts +5 -4
  42. package/src/api/Recognition.ts +3 -3
  43. package/src/api/SourceSeparation.ts +12 -16
  44. package/src/api/SpeechLanguageDetection.ts +2 -2
  45. package/src/api/SpeechTranslation.ts +2 -2
  46. package/src/api/Synthesis.ts +5 -5
  47. package/src/api/TranslationAlignment.ts +2 -2
  48. package/src/audio/AudioUtilities.ts +53 -33
  49. package/src/dsp/FFT.ts +45 -19
  50. package/src/recognition/WhisperSTT.ts +66 -8
  51. package/src/source-separation/MDXNetSourceSeparation.ts +44 -12
  52. package/src/typings/Fillers.d.ts +2 -0
  53. package/src/utilities/PackageManager.ts +3 -7
  54. package/src/utilities/WasmMemoryManager.ts +38 -4
@@ -6,6 +6,7 @@ import { Logger } from '../utilities/Logger.js'
6
6
  import { OnnxExecutionProvider, dmlProviderAvailable, getOnnxSessionOptions } from '../utilities/OnnxUtilities.js'
7
7
  import chalk from 'chalk'
8
8
  import { WindowedList } from '../utilities/WindowedList.js'
9
+ import { logLevelGreaterOrEqualTo } from '../api/API.js'
9
10
 
10
11
  const log = logToStderr
11
12
 
@@ -13,9 +14,9 @@ export async function isolate(
13
14
  rawAudio: RawAudio,
14
15
  modelFilePath: string,
15
16
  modelProfile: MDXNetModelProfile,
16
- executionProviders: OnnxExecutionProvider[]) {
17
+ options: MDXNetOptions) {
17
18
 
18
- const model = new MDXNet(modelFilePath, modelProfile, executionProviders)
19
+ const model = new MDXNet(modelFilePath, modelProfile, options)
19
20
 
20
21
  return model.processAudio(rawAudio)
21
22
  }
@@ -27,11 +28,11 @@ export class MDXNet {
27
28
  constructor(
28
29
  public readonly modelFilePath: string,
29
30
  public readonly modelProfile: MDXNetModelProfile,
30
- public readonly executionProviders: OnnxExecutionProvider[]) {
31
+ public readonly options: MDXNetOptions) {
31
32
  }
32
33
 
33
34
  async processAudio(rawAudio: RawAudio) {
34
- if (rawAudio.audioChannels.length != 2) {
35
+ if (rawAudio.audioChannels.length !== 2) {
35
36
  throw new Error(`Input audio must be stereo`)
36
37
  }
37
38
 
@@ -43,12 +44,18 @@ export class MDXNet {
43
44
  return getEmptyRawAudio(rawAudio.audioChannels.length, rawAudio.sampleRate)
44
45
  }
45
46
 
47
+ const enableTraceLogging = logLevelGreaterOrEqualTo('trace')
48
+
46
49
  const logger = new Logger()
47
50
 
48
- await logger.startAsync(`Initialize MDXNet model`)
51
+ await logger.startAsync(`Initialize session for MDX-NET model '${this.options.model!}'`)
49
52
 
50
53
  await this.initializeSessionIfNeeded()
51
54
 
55
+ logger.end()
56
+
57
+ logger.logTitledMessage(`Using ONNX execution provider`, `${this.onnxSessionOptions!.executionProviders!.join(', ')}`)
58
+
52
59
  const Onnx = await import('onnxruntime-node')
53
60
 
54
61
  const sampleRate = this.modelProfile.sampleRate
@@ -81,7 +88,11 @@ export class MDXNet {
81
88
 
82
89
  const timePosition = segmentStartFrameOffset * (fftHopSize / sampleRate)
83
90
 
84
- await logger.startAsync(`Compute STFT of segment at time position ${timePosition.toFixed(2)}`, undefined, chalk.magentaBright)
91
+ if (enableTraceLogging) {
92
+ await logger.startAsync(`Compute STFT of segment at time position ${timePosition.toFixed(2)}`, undefined, chalk.magentaBright)
93
+ } else {
94
+ await logger.startAsync(`Process segment at time position ${timePosition.toFixed(2)}`)
95
+ }
85
96
 
86
97
  while (fftFramesLeftWindowedList.endOffset < segmentEndFrameOffset) {
87
98
  const nextLeftFrameResult = await fftFramesLeftGenerator.next()
@@ -109,7 +120,9 @@ export class MDXNet {
109
120
 
110
121
  const isLastSegment = segmentLength < segmentSize
111
122
 
112
- await logger.startAsync(`Reshape STFT frames`)
123
+ if (enableTraceLogging) {
124
+ await logger.startAsync(`Reshape STFT frames`)
125
+ }
113
126
 
114
127
  const flattenedInputTensor = new Float32Array(1 * 4 * binCount * segmentSize)
115
128
 
@@ -142,13 +155,17 @@ export class MDXNet {
142
155
  }
143
156
  }
144
157
 
145
- await logger.startAsync(`Process with MDXNet model (ONNX provider: ${this.onnxSessionOptions!.executionProviders!.join(', ')})`)
158
+ if (enableTraceLogging) {
159
+ await logger.startAsync(`Process segment with MDXNet model`)
160
+ }
146
161
 
147
162
  const inputTensor = new Onnx.Tensor('float32', flattenedInputTensor, [1, 4, binCount, segmentSize])
148
163
 
149
164
  const { output: outputTensor } = await this.session!.run({ input: inputTensor })
150
165
 
151
- await logger.startAsync('Reshape processed frames')
166
+ if (enableTraceLogging) {
167
+ await logger.startAsync('Reshape processed frames')
168
+ }
152
169
 
153
170
  const flattenedOutputTensor = outputTensor.data as Float32Array
154
171
 
@@ -191,7 +208,9 @@ export class MDXNet {
191
208
 
192
209
  const outputAudioChannels: Float32Array[] = []
193
210
 
194
- await logger.startAsync(`Compute inverse STFT of model output for segment`)
211
+ if (enableTraceLogging) {
212
+ await logger.startAsync(`Compute inverse STFT of model output for segment`)
213
+ }
195
214
 
196
215
  for (let channelIndex = 0; channelIndex < 2; channelIndex++) {
197
216
  const samples = await stiftr(
@@ -268,13 +287,16 @@ export class MDXNet {
268
287
 
269
288
  const Onnx = await import('onnxruntime-node')
270
289
 
271
- this.onnxSessionOptions = getOnnxSessionOptions({ executionProviders: this.executionProviders })
290
+ const executionProviders: OnnxExecutionProvider[] =
291
+ this.options.provider ? [this.options.provider] : getDefaultMDXNetProviders()
292
+
293
+ this.onnxSessionOptions = getOnnxSessionOptions({ executionProviders })
272
294
 
273
295
  this.session = await Onnx.InferenceSession.create(this.modelFilePath, this.onnxSessionOptions)
274
296
  }
275
297
  }
276
298
 
277
- export function getDefaultMDXNetProviders() : OnnxExecutionProvider[] {
299
+ export function getDefaultMDXNetProviders(): OnnxExecutionProvider[] {
278
300
  if (dmlProviderAvailable()) {
279
301
  return ['dml', 'cpu']
280
302
  } else {
@@ -344,3 +366,13 @@ export type MDXNetModelName =
344
366
  'UVR_MDXNET_Main' |
345
367
  'Kim_Vocal_1' |
346
368
  'Kim_Vocal_2'
369
+
370
+ export interface MDXNetOptions {
371
+ model?: MDXNetModelName
372
+ provider?: OnnxExecutionProvider
373
+ }
374
+
375
+ export const defaultMDXNetOptions: MDXNetOptions = {
376
+ model: 'UVR_MDXNET_1_9703',
377
+ provider: undefined,
378
+ }
@@ -56,6 +56,8 @@ declare module '@echogarden/rnnoise-wasm'
56
56
  declare module '@echogarden/fvad-wasm'
57
57
  declare module '@echogarden/sonic-wasm'
58
58
  declare module '@echogarden/kissfft-wasm'
59
+ declare module '@echogarden/pffft-wasm'
60
+ declare module '@echogarden/pffft-wasm/simd'
59
61
  declare module '@echogarden/speex-resampler-wasm'
60
62
  declare module '@echogarden/vosk'
61
63
 
@@ -192,13 +192,9 @@ const packageVersionTagResolutionLookup: { [packageName: string]: string } = {
192
192
  'whisper.cpp-large-v3-turbo-q5_0': '20241003',
193
193
 
194
194
  // whisper.cpp binaries
195
- 'whisper.cpp-binaries-linux-x64-cpu-1.6.2': '20241001',
196
- 'whisper.cpp-binaries-windows-x64-cpu-1.6.2': '20241001',
197
- 'whisper.cpp-binaries-windows-x64-cublas-12.4.0-1.6.2': '20241002',
198
-
199
- 'whisper.cpp-binaries-linux-x64-cpu-latest': '20241003',
200
- 'whisper.cpp-binaries-windows-x64-cpu-latest': '20241003',
201
- 'whisper.cpp-binaries-windows-x64-cublas-12.4.0-latest': '20241003',
195
+ 'whisper.cpp-binaries-linux-x64-cpu-latest': '20241010',
196
+ 'whisper.cpp-binaries-windows-x64-cpu-latest': '20241010',
197
+ 'whisper.cpp-binaries-windows-x64-cublas-12.4.0-latest': '20241010',
202
198
 
203
199
  // E5 models
204
200
  'xenova-multilingual-e5-small-q8': '20240504',
@@ -1,10 +1,35 @@
1
1
  export class WasmMemoryManager {
2
2
  wasmModule: any
3
3
 
4
+ private wasmAlloc: WasmAllocMethod
5
+ private wasmFree: WasmFreeMethod
6
+
4
7
  private allocatedReferences = new Set<WasmRef>()
5
8
 
6
- constructor(wasmModule: any) {
9
+ constructor(wasmModule: any, options?: WasmMemoryManagerOptions) {
10
+ options = options ?? {}
11
+
7
12
  this.wasmModule = wasmModule
13
+
14
+ if (options.wasmAlloc) {
15
+ this.wasmAlloc = options.wasmAlloc
16
+ } else {
17
+ if (!wasmModule._malloc) {
18
+ throw new Error(`Couldn't find a '_malloc' function in the module and no custom 'wasmAlloc' was provided in the options`)
19
+ }
20
+
21
+ this.wasmAlloc = wasmModule._malloc
22
+ }
23
+
24
+ if (options.wasmFree) {
25
+ this.wasmFree = options.wasmFree
26
+ } else {
27
+ if (!wasmModule._free) {
28
+ throw new Error(`Couldn't find a '_malloc' function in the module and no custom 'wasmFree' was provided in the options`)
29
+ }
30
+
31
+ this.wasmFree = wasmModule._free
32
+ }
8
33
  }
9
34
 
10
35
  allocInt8() {
@@ -209,8 +234,9 @@ export class WasmMemoryManager {
209
234
  }
210
235
 
211
236
  private alloc(size: number) {
212
- const ptr = this.wasmModule._malloc(size)
213
- return ptr as number
237
+ const ptr = this.wasmAlloc(size)
238
+
239
+ return ptr
214
240
  }
215
241
 
216
242
  free(wasmReference: WasmRef) {
@@ -218,7 +244,7 @@ export class WasmMemoryManager {
218
244
  return
219
245
  }
220
246
 
221
- this.wasmModule._free(wasmReference.address)
247
+ this.wasmFree(wasmReference.address)
222
248
 
223
249
  this.allocatedReferences.delete(wasmReference)
224
250
  wasmReference.clearAddress()
@@ -514,3 +540,11 @@ export class Float64ArrayRef extends TypedArrayRef<Float64Array> {
514
540
 
515
541
  export type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array
516
542
  export type WasmRef = ValueRef<number> | ValueRef<string> | TypedArrayRef<TypedArray>
543
+
544
+ export interface WasmMemoryManagerOptions {
545
+ wasmAlloc?: WasmAllocMethod
546
+ wasmFree?: WasmFreeMethod
547
+ }
548
+
549
+ export type WasmAllocMethod = (size: number) => number
550
+ export type WasmFreeMethod = (address: number) => void