echogarden 1.6.2 → 1.7.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 (86) hide show
  1. package/data/schemas/options.json +30 -4
  2. package/dist/api/SourceSeparation.d.ts +3 -2
  3. package/dist/api/SourceSeparation.js +10 -8
  4. package/dist/api/SourceSeparation.js.map +1 -1
  5. package/dist/api/Synthesis.js +3 -1
  6. package/dist/api/Synthesis.js.map +1 -1
  7. package/dist/api/TextTranslation.d.ts +3 -1
  8. package/dist/api/TextTranslation.js +12 -6
  9. package/dist/api/TextTranslation.js.map +1 -1
  10. package/dist/build-tools/MakeTarballsForInstalledPackages.d.ts +1 -0
  11. package/dist/build-tools/MakeTarballsForInstalledPackages.js +20 -0
  12. package/dist/build-tools/MakeTarballsForInstalledPackages.js.map +1 -0
  13. package/dist/cli/CLI.js +4 -3
  14. package/dist/cli/CLI.js.map +1 -1
  15. package/dist/dsp/FFT.d.ts +2 -3
  16. package/dist/dsp/FFT.js +25 -23
  17. package/dist/dsp/FFT.js.map +1 -1
  18. package/dist/nlp/Segmentation.js +2 -1
  19. package/dist/nlp/Segmentation.js.map +1 -1
  20. package/dist/nlp/TextNormalizer.d.ts +2 -0
  21. package/dist/nlp/TextNormalizer.js +51 -0
  22. package/dist/nlp/TextNormalizer.js.map +1 -1
  23. package/dist/recognition/WhisperSTT.d.ts +2 -0
  24. package/dist/recognition/WhisperSTT.js +7 -6
  25. package/dist/recognition/WhisperSTT.js.map +1 -1
  26. package/dist/source-separation/MDXNetSourceSeparation.d.ts +20 -2
  27. package/dist/source-separation/MDXNetSourceSeparation.js +134 -76
  28. package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
  29. package/dist/subtitles/Subtitles.js +2 -1
  30. package/dist/subtitles/Subtitles.js.map +1 -1
  31. package/dist/synthesis/EspeakTTS.js +5 -5
  32. package/dist/synthesis/EspeakTTS.js.map +1 -1
  33. package/dist/tests/Test.js +0 -1
  34. package/dist/tests/Test.js.map +1 -1
  35. package/dist/text-translation/GoogleTranslateTextTranslation.d.ts +9 -3
  36. package/dist/text-translation/GoogleTranslateTextTranslation.js +59 -29
  37. package/dist/text-translation/GoogleTranslateTextTranslation.js.map +1 -1
  38. package/dist/utilities/OnnxUtilities.d.ts +1 -0
  39. package/dist/utilities/OnnxUtilities.js +5 -5
  40. package/dist/utilities/OnnxUtilities.js.map +1 -1
  41. package/dist/utilities/PackageManager.js +3 -0
  42. package/dist/utilities/PackageManager.js.map +1 -1
  43. package/dist/utilities/StringUtilities.d.ts +28 -0
  44. package/dist/utilities/StringUtilities.js +150 -0
  45. package/dist/utilities/StringUtilities.js.map +1 -0
  46. package/dist/utilities/TarballMaker.d.ts +3 -4
  47. package/dist/utilities/TarballMaker.js +6 -19
  48. package/dist/utilities/TarballMaker.js.map +1 -1
  49. package/dist/utilities/Timeline.js +2 -1
  50. package/dist/utilities/Timeline.js.map +1 -1
  51. package/dist/utilities/Utilities.d.ts +1 -33
  52. package/dist/utilities/Utilities.js +3 -176
  53. package/dist/utilities/Utilities.js.map +1 -1
  54. package/dist/utilities/WebReader.js +1 -1
  55. package/dist/utilities/WebReader.js.map +1 -1
  56. package/dist/utilities/WikipediaReader.js +1 -1
  57. package/dist/utilities/WikipediaReader.js.map +1 -1
  58. package/dist/utilities/WindowedList.d.ts +10 -0
  59. package/dist/utilities/WindowedList.js +36 -0
  60. package/dist/utilities/WindowedList.js.map +1 -0
  61. package/docs/Engines.md +1 -1
  62. package/docs/Options.md +8 -2
  63. package/package.json +8 -9
  64. package/src/api/SourceSeparation.ts +15 -10
  65. package/src/api/Synthesis.ts +3 -1
  66. package/src/api/TextTranslation.ts +17 -9
  67. package/src/build-tools/MakeTarballsForInstalledPackages.ts +25 -0
  68. package/src/cli/CLI.ts +4 -3
  69. package/src/dsp/FFT.ts +30 -33
  70. package/src/nlp/Segmentation.ts +2 -1
  71. package/src/nlp/TextNormalizer.ts +60 -0
  72. package/src/recognition/WhisperSTT.ts +7 -6
  73. package/src/source-separation/MDXNetSourceSeparation.ts +183 -85
  74. package/src/subtitles/Subtitles.ts +2 -1
  75. package/src/synthesis/EspeakTTS.ts +5 -5
  76. package/src/tests/Test.ts +0 -4
  77. package/src/text-translation/GoogleTranslateTextTranslation.ts +91 -30
  78. package/src/utilities/OnnxUtilities.ts +7 -8
  79. package/src/utilities/PackageManager.ts +3 -0
  80. package/src/utilities/StringUtilities.ts +203 -0
  81. package/src/utilities/TarballMaker.ts +6 -23
  82. package/src/utilities/Timeline.ts +2 -1
  83. package/src/utilities/Utilities.ts +4 -237
  84. package/src/utilities/WebReader.ts +1 -1
  85. package/src/utilities/WikipediaReader.ts +1 -1
  86. package/src/utilities/WindowedList.ts +45 -0
@@ -1,28 +1,32 @@
1
1
  import type * as Onnx from 'onnxruntime-node'
2
- import { RawAudio } from '../audio/AudioUtilities.js';
3
- import { binBufferToComplex, complexToBinBuffer, getWindowWeights, stftr, stiftr } from '../dsp/FFT.js';
4
- import { ComplexNumber } from '../math/VectorMath.js';
5
- import { logToStderr } from '../utilities/Utilities.js';
6
- import { Logger } from '../utilities/Logger.js';
7
- import { OnnxExecutionProvider, getOnnxSessionOptions } from '../utilities/OnnxUtilities.js';
2
+ import { getEmptyRawAudio, RawAudio } from '../audio/AudioUtilities.js'
3
+ import { getWindowWeights, stftrGenerator, stiftr, WindowType } from '../dsp/FFT.js'
4
+ import { logToStderr } from '../utilities/Utilities.js'
5
+ import { Logger } from '../utilities/Logger.js'
6
+ import { OnnxExecutionProvider, dmlProviderAvailable, getOnnxSessionOptions } from '../utilities/OnnxUtilities.js'
7
+ import chalk from 'chalk'
8
+ import { WindowedList } from '../utilities/WindowedList.js'
8
9
 
9
10
  const log = logToStderr
10
11
 
11
12
  export async function isolate(
12
13
  rawAudio: RawAudio,
13
14
  modelFilePath: string,
15
+ modelProfile: MDXNetModelProfile,
14
16
  executionProviders: OnnxExecutionProvider[]) {
15
17
 
16
- const model = new MDXNet(modelFilePath, executionProviders)
18
+ const model = new MDXNet(modelFilePath, modelProfile, executionProviders)
17
19
 
18
20
  return model.processAudio(rawAudio)
19
21
  }
20
22
 
21
23
  export class MDXNet {
22
24
  session?: Onnx.InferenceSession
25
+ onnxSessionOptions?: Onnx.InferenceSession.SessionOptions
23
26
 
24
27
  constructor(
25
28
  public readonly modelFilePath: string,
29
+ public readonly modelProfile: MDXNetModelProfile,
26
30
  public readonly executionProviders: OnnxExecutionProvider[]) {
27
31
  }
28
32
 
@@ -31,77 +35,104 @@ export class MDXNet {
31
35
  throw new Error(`Input audio must be stereo`)
32
36
  }
33
37
 
34
- if (rawAudio.sampleRate != 44100) {
35
- throw new Error(`Input audio must have a sample rate of 44100 Hz`)
38
+ if (rawAudio.sampleRate !== this.modelProfile.sampleRate) {
39
+ throw new Error(`Input audio must have a sample rate of ${this.modelProfile.sampleRate} Hz`)
36
40
  }
37
41
 
42
+ if (rawAudio.audioChannels[0].length === 0) {
43
+ return getEmptyRawAudio(rawAudio.audioChannels.length, rawAudio.sampleRate)
44
+ }
45
+
46
+ const logger = new Logger()
47
+
48
+ await logger.startAsync(`Initialize MDXNet model`)
49
+
38
50
  await this.initializeSessionIfNeeded()
39
51
 
40
52
  const Onnx = await import('onnxruntime-node')
41
53
 
42
- const logger = new Logger()
43
-
44
- const session = this.session!
54
+ const sampleRate = this.modelProfile.sampleRate
55
+ const fftSize = this.modelProfile.fftSize
56
+ const fftWindowSize = this.modelProfile.fftWindowSize
57
+ const fftHopSize = this.modelProfile.fftHopSize
58
+ const fftWindowType = this.modelProfile.fftWindowType
45
59
 
46
- const sampleRate = rawAudio.sampleRate
47
- const fftSize = 6144
48
- const fftCount = 2048
49
- const fftWindowSize = fftSize
50
- const fftHopSize = 1024
60
+ const binCount = this.modelProfile.binCount
51
61
 
52
- const segmentSize = 256
53
- const segmentHopSize = 240
62
+ const segmentSize = this.modelProfile.segmentSize
63
+ const segmentHopSize = this.modelProfile.segmentHopSize
54
64
 
55
65
  const sampleCount = rawAudio.audioChannels[0].length
56
66
 
57
- logger.start('Compute STFT of full waveform')
67
+ const fftSizeReciprocal = 1 / fftSize
58
68
 
59
- const fftFramesLeft = await stftr(rawAudio.audioChannels[0], fftSize, fftWindowSize, fftHopSize, 'hann')
60
- const fftFramesRight = await stftr(rawAudio.audioChannels[1], fftSize, fftWindowSize, fftHopSize, 'hann')
69
+ // Initialize generators for STFT frames for each channel
70
+ const fftFramesLeftGenerator = stftrGenerator(rawAudio.audioChannels[0], fftSize, fftWindowSize, fftHopSize, fftWindowType)
71
+ const fftFramesRightGenerator = stftrGenerator(rawAudio.audioChannels[1], fftSize, fftWindowSize, fftHopSize, fftWindowType)
61
72
 
62
- const fftFramesLeftComplex = fftFramesLeft.map(frame => binBufferToComplex(frame).slice(0, fftCount))
63
- const fftFramesRightComplex = fftFramesRight.map(frame => binBufferToComplex(frame).slice(0, fftCount))
73
+ // Initial windowed lists to store recently computed STFT frames
74
+ const fftFramesLeftWindowedList = new WindowedList<Float32Array>(segmentSize)
75
+ const fftFramesRightWindowedList = new WindowedList<Float32Array>(segmentSize)
64
76
 
65
77
  const audioForSegments: Float32Array[][] = []
66
78
 
67
- for (let segmentOffset = 0; segmentOffset < fftFramesLeft.length; segmentOffset += segmentHopSize) {
68
- const timePosition = segmentOffset * (fftHopSize / sampleRate)
79
+ for (let segmentStartFrameOffset = 0; ; segmentStartFrameOffset += segmentHopSize) {
80
+ const segmentEndFrameOffset = segmentStartFrameOffset + segmentSize
81
+
82
+ const timePosition = segmentStartFrameOffset * (fftHopSize / sampleRate)
83
+
84
+ await logger.startAsync(`Compute STFT of segment at time position ${timePosition.toFixed(2)}`, undefined, chalk.magentaBright)
85
+
86
+ while (fftFramesLeftWindowedList.endOffset < segmentEndFrameOffset) {
87
+ const nextLeftFrameResult = await fftFramesLeftGenerator.next()
88
+
89
+ if (nextLeftFrameResult.done) {
90
+ break
91
+ }
92
+
93
+ const nextRightFrameResult = await fftFramesRightGenerator.next()
94
+
95
+ if (nextRightFrameResult.done) {
96
+ break
97
+ }
98
+
99
+ fftFramesLeftWindowedList.add(nextLeftFrameResult.value)
100
+ fftFramesRightWindowedList.add(nextRightFrameResult.value)
101
+ }
102
+
103
+ const fftFramesForSegment = [
104
+ fftFramesLeftWindowedList.slice(segmentStartFrameOffset, segmentEndFrameOffset),
105
+ fftFramesRightWindowedList.slice(segmentStartFrameOffset, segmentEndFrameOffset)
106
+ ]
69
107
 
70
- logger.start(`Process segment at time position ${timePosition.toFixed(2)}`)
108
+ const segmentLength = fftFramesForSegment[0].length
71
109
 
72
- const fftFramesLeftComplexForSegment = fftFramesLeftComplex.slice(segmentOffset, segmentOffset + segmentSize)
73
- const fftFramesRightComplexForSegment = fftFramesRightComplex.slice(segmentOffset, segmentOffset + segmentSize)
110
+ const isLastSegment = segmentLength < segmentSize
74
111
 
75
- const segmentLength = fftFramesLeftComplexForSegment.length
112
+ await logger.startAsync(`Reshape STFT frames`)
76
113
 
77
- const flattenedInputTensor = new Float32Array(1 * 4 * fftCount * segmentSize)
114
+ const flattenedInputTensor = new Float32Array(1 * 4 * binCount * segmentSize)
78
115
 
79
116
  {
80
117
  let writePosition = 0
81
118
 
82
- for (let tensorChannelIndex = 0; tensorChannelIndex < 4; tensorChannelIndex++) {
83
- const isEvenTensorChannelIndex = tensorChannelIndex % 2 === 0
84
- const inChannelIndex = tensorChannelIndex < 2 ? 0 : 1
119
+ // 4 tensor elements are structured as:
120
+ // <Channel 0 real> <Channel 0 imaginary> <Channel 1 real> <Channel 1 imaginary>
121
+ for (let tensorElementIndex = 0; tensorElementIndex < 4; tensorElementIndex++) {
122
+ const isRealComponentTensorElementIndex = tensorElementIndex % 2 === 0
123
+ const audioChannelIndex = tensorElementIndex < 2 ? 0 : 1
85
124
 
86
- for (let binIndex = 0; binIndex < fftCount; binIndex++) {
125
+ for (let binIndex = 0; binIndex < binCount; binIndex++) {
87
126
  for (let frameIndex = 0; frameIndex < segmentSize; frameIndex++) {
88
127
  let value = 0
89
128
 
90
- if (frameIndex < segmentLength && binIndex >= 0) {
91
- let frame: ComplexNumber[]
92
-
93
- if (inChannelIndex === 0) {
94
- frame = fftFramesLeftComplexForSegment[frameIndex]
95
- } else {
96
- frame = fftFramesRightComplexForSegment[frameIndex]
97
- }
98
-
99
- const bin = frame[binIndex]
129
+ if (frameIndex < segmentLength) {
130
+ const frame = fftFramesForSegment[audioChannelIndex][frameIndex]
100
131
 
101
- if (isEvenTensorChannelIndex) {
102
- value = bin.real
132
+ if (isRealComponentTensorElementIndex) {
133
+ value = frame[binIndex << 1]
103
134
  } else {
104
- value = bin.imaginary
135
+ value = frame[(binIndex << 1) + 1]
105
136
  }
106
137
  }
107
138
 
@@ -111,51 +142,47 @@ export class MDXNet {
111
142
  }
112
143
  }
113
144
 
114
- const inputTensor = new Onnx.Tensor('float32', flattenedInputTensor, [1, 4, 2048, 256])
145
+ await logger.startAsync(`Process with MDXNet model (ONNX provider: ${this.onnxSessionOptions!.executionProviders!.join(', ')})`)
115
146
 
116
- logger.start('Run MDXNet model')
147
+ const inputTensor = new Onnx.Tensor('float32', flattenedInputTensor, [1, 4, binCount, segmentSize])
117
148
 
118
- const { output: outputTensor } = await session.run({ input: inputTensor })
149
+ const { output: outputTensor } = await this.session!.run({ input: inputTensor })
119
150
 
120
- logger.start('Process MDXNet model output')
151
+ await logger.startAsync('Reshape processed frames')
121
152
 
122
153
  const flattenedOutputTensor = outputTensor.data as Float32Array
123
154
 
124
- const outputChannelComplexFrames: ComplexNumber[][][] = []
155
+ const outputSegmentFramesForChannel: Float32Array[][] = []
125
156
 
126
157
  {
127
158
  for (let outChannelIndex = 0; outChannelIndex < 2; outChannelIndex++) {
128
- const framesForChannel: ComplexNumber[][] = []
159
+ const framesForChannel: Float32Array[] = []
129
160
 
130
- for (let frameIndex = 0; frameIndex < 256; frameIndex++) {
131
- const frame: ComplexNumber[] = []
132
-
133
- for (let binIndex = 0; binIndex < fftSize; binIndex++) {
134
- frame.push({ real: 0, imaginary: 0 })
135
- }
161
+ for (let frameIndex = 0; frameIndex < segmentSize; frameIndex++) {
162
+ const frame = new Float32Array(fftSize)
136
163
 
137
164
  framesForChannel.push(frame)
138
165
  }
139
166
 
140
- outputChannelComplexFrames.push(framesForChannel)
167
+ outputSegmentFramesForChannel.push(framesForChannel)
141
168
  }
142
169
 
143
170
  let readPosition = 0
144
171
 
145
172
  for (let tensorChannelIndex = 0; tensorChannelIndex < 4; tensorChannelIndex++) {
146
- const isEvenTensorChannelIndex = tensorChannelIndex % 2 === 0
147
- const outChannelIndex = tensorChannelIndex < 2 ? 0 : 1
173
+ const isRealTensorChannelIndex = tensorChannelIndex % 2 === 0
174
+ const audioChannelIndex = tensorChannelIndex < 2 ? 0 : 1
148
175
 
149
- const binsForOutputChannel = outputChannelComplexFrames[outChannelIndex]
176
+ const framesForOutputChannel = outputSegmentFramesForChannel[audioChannelIndex]
150
177
 
151
- for (let binIndex = 0; binIndex < 2048; binIndex++) {
152
- for (let frameIndex = 0; frameIndex < 256; frameIndex++) {
153
- const bin = binsForOutputChannel[frameIndex][binIndex]
178
+ for (let binIndex = 0; binIndex < binCount; binIndex++) {
179
+ for (let frameIndex = 0; frameIndex < segmentSize; frameIndex++) {
180
+ const outFrame = framesForOutputChannel[frameIndex]
154
181
 
155
- if (isEvenTensorChannelIndex) {
156
- bin.real = flattenedOutputTensor[readPosition++]
182
+ if (isRealTensorChannelIndex) {
183
+ outFrame[binIndex << 1] = flattenedOutputTensor[readPosition++] * fftSizeReciprocal
157
184
  } else {
158
- bin.imaginary = flattenedOutputTensor[readPosition++]
185
+ outFrame[(binIndex << 1) + 1] = flattenedOutputTensor[readPosition++] * fftSizeReciprocal
159
186
  }
160
187
  }
161
188
  }
@@ -164,29 +191,29 @@ export class MDXNet {
164
191
 
165
192
  const outputAudioChannels: Float32Array[] = []
166
193
 
167
- logger.start(`Compute inverse STFT for segment`)
168
- for (let channelIndex = 0; channelIndex < 2; channelIndex++) {
169
- const fftSizeReciprocal = 1 / fftSize
170
-
171
- let outputChannelFlattenedFrames = outputChannelComplexFrames[channelIndex]
172
- .map(frame => complexToBinBuffer(frame).map(value => value * fftSizeReciprocal))
194
+ await logger.startAsync(`Compute inverse STFT of model output for segment`)
173
195
 
196
+ for (let channelIndex = 0; channelIndex < 2; channelIndex++) {
174
197
  const samples = await stiftr(
175
- outputChannelFlattenedFrames,
198
+ outputSegmentFramesForChannel[channelIndex],
176
199
  fftSize,
177
200
  fftWindowSize,
178
201
  fftHopSize,
179
- 'hann')
202
+ fftWindowType)
180
203
 
181
204
  outputAudioChannels.push(samples)
182
205
  }
183
206
 
184
207
  audioForSegments.push(outputAudioChannels)
208
+
209
+ if (isLastSegment) {
210
+ break
211
+ }
185
212
  }
186
213
 
187
214
  // Join segments using overlapping Hann windows
188
- logger.start(`Join segments`)
189
- const concatenatedAudioChannels = [new Float32Array(sampleCount), new Float32Array(sampleCount)]
215
+ await logger.startAsync(`Join segments`)
216
+ const joinedSegments = [new Float32Array(sampleCount), new Float32Array(sampleCount)]
190
217
 
191
218
  {
192
219
  const segmentCount = audioForSegments.length
@@ -213,7 +240,7 @@ export class MDXNet {
213
240
  const weight = windowWeights[segmentSampleOffset]
214
241
 
215
242
  for (let channelIndex = 0; channelIndex < 2; channelIndex++) {
216
- concatenatedAudioChannels[channelIndex][sampleIndex] += segmentSamples[channelIndex][segmentSampleOffset] * weight
243
+ joinedSegments[channelIndex][sampleIndex] += segmentSamples[channelIndex][segmentSampleOffset] * weight
217
244
  }
218
245
 
219
246
  sumOfWeightsForSample[sampleIndex] += weight
@@ -222,12 +249,12 @@ export class MDXNet {
222
249
 
223
250
  for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) {
224
251
  for (let channelIndex = 0; channelIndex < 2; channelIndex++) {
225
- concatenatedAudioChannels[channelIndex][sampleIndex] /= sumOfWeightsForSample[sampleIndex] + 1e-8
252
+ joinedSegments[channelIndex][sampleIndex] /= sumOfWeightsForSample[sampleIndex] + 1e-8
226
253
  }
227
254
  }
228
255
  }
229
256
 
230
- const isolatedRawAudio: RawAudio = { audioChannels: concatenatedAudioChannels, sampleRate }
257
+ const isolatedRawAudio: RawAudio = { audioChannels: joinedSegments, sampleRate }
231
258
 
232
259
  logger.end()
233
260
 
@@ -241,8 +268,79 @@ export class MDXNet {
241
268
 
242
269
  const Onnx = await import('onnxruntime-node')
243
270
 
244
- const onnxSessionOptions = getOnnxSessionOptions({ executionProviders: this.executionProviders })
271
+ this.onnxSessionOptions = getOnnxSessionOptions({ executionProviders: this.executionProviders })
272
+
273
+ this.session = await Onnx.InferenceSession.create(this.modelFilePath, this.onnxSessionOptions)
274
+ }
275
+ }
276
+
277
+ export function getDefaultMDXNetProviders() : OnnxExecutionProvider[] {
278
+ if (dmlProviderAvailable()) {
279
+ return ['dml', 'cpu']
280
+ } else {
281
+ return []
282
+ }
283
+ }
284
+
285
+ export function getProfileForMDXNetModelName(modelName: MDXNetModelName) {
286
+ if (['UVR_MDXNET_1_9703', 'UVR_MDXNET_2_9682', 'UVR_MDXNET_3_9662', 'UVR_MDXNET_KARA'].includes(modelName)) {
287
+ return mdxNetModelProfile1
288
+ }
245
289
 
246
- this.session = await Onnx.InferenceSession.create(this.modelFilePath, onnxSessionOptions)
290
+ if (['UVR_MDXNET_Main', 'Kim_Vocal_1', 'Kim_Vocal_2'].includes(modelName)) {
291
+ return mdxNetModelProfile2
247
292
  }
293
+
294
+ throw new Error(`Unsupported model name: '${modelName}'`)
295
+ }
296
+
297
+ export const mdxNetModelProfile1: MDXNetModelProfile = {
298
+ sampleRate: 44100,
299
+
300
+ fftSize: 6144,
301
+ fftWindowSize: 6144,
302
+ fftHopSize: 1024,
303
+ fftWindowType: 'hann',
304
+
305
+ binCount: 2048,
306
+
307
+ segmentSize: 256,
308
+ segmentHopSize: 224,
309
+ }
310
+
311
+ export const mdxNetModelProfile2: MDXNetModelProfile = {
312
+ sampleRate: 44100,
313
+
314
+ fftSize: 7680,
315
+ fftWindowSize: 7680,
316
+ fftHopSize: 1024,
317
+ fftWindowType: 'hann',
318
+
319
+ binCount: 3072,
320
+
321
+ segmentSize: 256,
322
+ segmentHopSize: 224,
248
323
  }
324
+
325
+ export interface MDXNetModelProfile {
326
+ sampleRate: number
327
+
328
+ fftSize: number
329
+ fftWindowSize: number
330
+ fftHopSize: number
331
+ fftWindowType: WindowType
332
+
333
+ binCount: number
334
+
335
+ segmentSize: number
336
+ segmentHopSize: number
337
+ }
338
+
339
+ export type MDXNetModelName =
340
+ 'UVR_MDXNET_1_9703' |
341
+ 'UVR_MDXNET_2_9682' |
342
+ 'UVR_MDXNET_3_9662' |
343
+ 'UVR_MDXNET_KARA' |
344
+ 'UVR_MDXNET_Main' |
345
+ 'Kim_Vocal_1' |
346
+ 'Kim_Vocal_2'
@@ -1,11 +1,12 @@
1
1
  import { htmlToText } from 'html-to-text'
2
2
 
3
- import { formatHMS, formatMS, secondsToHMS, secondsToMS, startsWithAnyOf } from '../utilities/Utilities.js'
3
+ import { secondsToHMS, secondsToMS } from '../utilities/Utilities.js'
4
4
  import { isWord, isWordOrSymbolWord } from '../nlp/Segmentation.js'
5
5
  import { charactersToWriteAhead } from '../audio/AudioPlayer.js'
6
6
  import { Timeline, TimelineEntry } from '../utilities/Timeline.js'
7
7
  import { readFile } from '../utilities/FileSystem.js'
8
8
  import { deepClone } from '../utilities/ObjectUtilities.js'
9
+ import { formatHMS, formatMS, startsWithAnyOf } from '../utilities/StringUtilities.js'
9
10
 
10
11
  export async function subtitlesFileToText(filename: string) {
11
12
  return subtitlesToText(await readFile(filename, 'utf8'))
@@ -1,10 +1,10 @@
1
- import { concatFloat32Arrays, logToStderr, objToString, simplifyPunctuationCharacters } from '../utilities/Utilities.js'
1
+ import { concatFloat32Arrays, logToStderr, formatObjectToString } from '../utilities/Utilities.js'
2
2
  import { int16PcmToFloat32 } from '../audio/AudioBufferConversion.js'
3
3
  import { Logger } from '../utilities/Logger.js'
4
4
  import { WasmMemoryManager } from '../utilities/WasmMemoryManager.js'
5
5
  import { RawAudio, getEmptyRawAudio } from '../audio/AudioUtilities.js'
6
6
  import { playAudioWithTimelinePhones } from '../audio/AudioPlayer.js'
7
- import { getNormalizedFragmentsForSpeech } from '../nlp/TextNormalizer.js'
7
+ import { getNormalizedFragmentsForSpeech, simplifyPunctuationCharacters } from '../nlp/TextNormalizer.js'
8
8
  import { ipaPhoneToKirshenbaum } from '../nlp/PhoneConversion.js'
9
9
  import { splitToWords, wordCharacterPattern } from '../nlp/Segmentation.js'
10
10
  import { Lexicon, tryGetFirstLexiconSubstitution } from '../nlp/Lexicon.js'
@@ -276,11 +276,11 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
276
276
  const markerIndex = parseInt(markerName.substring(2))
277
277
 
278
278
  if (markerIndex != wordIndex) {
279
- throw new Error(`Word start marker for index ${wordIndex} is not consistent with word index. The words were: ${objToString(fragments)}`)
279
+ throw new Error(`Word start marker for index ${wordIndex} is not consistent with word index. The words were: ${formatObjectToString(fragments)}`)
280
280
  }
281
281
 
282
282
  if (currentPhoneTimeline.length > 0) {
283
- throw new Error(`Word entry ${wordIndex} already has phones before its start marker was seen. The words were: ${objToString(fragments)}`)
283
+ throw new Error(`Word entry ${wordIndex} already has phones before its start marker was seen. The words were: ${formatObjectToString(fragments)}`)
284
284
  }
285
285
 
286
286
  currentWordEntry.startTime = eventTime
@@ -289,7 +289,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
289
289
  const markerIndex = parseInt(markerName.substring(2))
290
290
 
291
291
  if (markerIndex != wordIndex) {
292
- throw new Error(`Word end marker for index ${wordIndex} is not consistent with word index. The words were: ${objToString(fragments)}`)
292
+ throw new Error(`Word end marker for index ${wordIndex} is not consistent with word index. The words were: ${formatObjectToString(fragments)}`)
293
293
  }
294
294
 
295
295
  currentWordEntry.startTime = currentTokenTimeline[0].startTime
package/src/tests/Test.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { makeTarballsForInstalledPackages } from '../utilities/TarballMaker.js'
2
1
  import { logToStderr, setupProgramTerminationListeners } from '../utilities/Utilities.js'
3
2
 
4
3
  const log = logToStderr
@@ -8,7 +7,4 @@ setupProgramTerminationListeners()
8
7
  //process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
9
8
  //process.env.http_proxy = 'http://localhost:8080'
10
9
 
11
- //await makeTarballsForInstalledPackages(true)
12
-
13
10
  process.exit(0)
14
-