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.
- package/data/schemas/options.json +30 -4
- package/dist/api/SourceSeparation.d.ts +3 -2
- package/dist/api/SourceSeparation.js +10 -8
- package/dist/api/SourceSeparation.js.map +1 -1
- package/dist/api/Synthesis.js +3 -1
- package/dist/api/Synthesis.js.map +1 -1
- package/dist/api/TextTranslation.d.ts +3 -1
- package/dist/api/TextTranslation.js +12 -6
- package/dist/api/TextTranslation.js.map +1 -1
- package/dist/build-tools/MakeTarballsForInstalledPackages.d.ts +1 -0
- package/dist/build-tools/MakeTarballsForInstalledPackages.js +20 -0
- package/dist/build-tools/MakeTarballsForInstalledPackages.js.map +1 -0
- package/dist/cli/CLI.js +4 -3
- package/dist/cli/CLI.js.map +1 -1
- package/dist/dsp/FFT.d.ts +2 -3
- package/dist/dsp/FFT.js +25 -23
- package/dist/dsp/FFT.js.map +1 -1
- package/dist/nlp/Segmentation.js +2 -1
- package/dist/nlp/Segmentation.js.map +1 -1
- package/dist/nlp/TextNormalizer.d.ts +2 -0
- package/dist/nlp/TextNormalizer.js +51 -0
- package/dist/nlp/TextNormalizer.js.map +1 -1
- package/dist/recognition/WhisperSTT.d.ts +2 -0
- package/dist/recognition/WhisperSTT.js +7 -6
- package/dist/recognition/WhisperSTT.js.map +1 -1
- package/dist/source-separation/MDXNetSourceSeparation.d.ts +20 -2
- package/dist/source-separation/MDXNetSourceSeparation.js +134 -76
- package/dist/source-separation/MDXNetSourceSeparation.js.map +1 -1
- package/dist/subtitles/Subtitles.js +2 -1
- package/dist/subtitles/Subtitles.js.map +1 -1
- package/dist/synthesis/EspeakTTS.js +5 -5
- package/dist/synthesis/EspeakTTS.js.map +1 -1
- package/dist/tests/Test.js +0 -1
- package/dist/tests/Test.js.map +1 -1
- package/dist/text-translation/GoogleTranslateTextTranslation.d.ts +9 -3
- package/dist/text-translation/GoogleTranslateTextTranslation.js +59 -29
- package/dist/text-translation/GoogleTranslateTextTranslation.js.map +1 -1
- package/dist/utilities/OnnxUtilities.d.ts +1 -0
- package/dist/utilities/OnnxUtilities.js +5 -5
- package/dist/utilities/OnnxUtilities.js.map +1 -1
- package/dist/utilities/PackageManager.js +3 -0
- package/dist/utilities/PackageManager.js.map +1 -1
- package/dist/utilities/StringUtilities.d.ts +28 -0
- package/dist/utilities/StringUtilities.js +150 -0
- package/dist/utilities/StringUtilities.js.map +1 -0
- package/dist/utilities/TarballMaker.d.ts +3 -4
- package/dist/utilities/TarballMaker.js +6 -19
- package/dist/utilities/TarballMaker.js.map +1 -1
- package/dist/utilities/Timeline.js +2 -1
- package/dist/utilities/Timeline.js.map +1 -1
- package/dist/utilities/Utilities.d.ts +1 -33
- package/dist/utilities/Utilities.js +3 -176
- package/dist/utilities/Utilities.js.map +1 -1
- package/dist/utilities/WebReader.js +1 -1
- package/dist/utilities/WebReader.js.map +1 -1
- package/dist/utilities/WikipediaReader.js +1 -1
- package/dist/utilities/WikipediaReader.js.map +1 -1
- package/dist/utilities/WindowedList.d.ts +10 -0
- package/dist/utilities/WindowedList.js +36 -0
- package/dist/utilities/WindowedList.js.map +1 -0
- package/docs/Engines.md +1 -1
- package/docs/Options.md +8 -2
- package/package.json +8 -9
- package/src/api/SourceSeparation.ts +15 -10
- package/src/api/Synthesis.ts +3 -1
- package/src/api/TextTranslation.ts +17 -9
- package/src/build-tools/MakeTarballsForInstalledPackages.ts +25 -0
- package/src/cli/CLI.ts +4 -3
- package/src/dsp/FFT.ts +30 -33
- package/src/nlp/Segmentation.ts +2 -1
- package/src/nlp/TextNormalizer.ts +60 -0
- package/src/recognition/WhisperSTT.ts +7 -6
- package/src/source-separation/MDXNetSourceSeparation.ts +183 -85
- package/src/subtitles/Subtitles.ts +2 -1
- package/src/synthesis/EspeakTTS.ts +5 -5
- package/src/tests/Test.ts +0 -4
- package/src/text-translation/GoogleTranslateTextTranslation.ts +91 -30
- package/src/utilities/OnnxUtilities.ts +7 -8
- package/src/utilities/PackageManager.ts +3 -0
- package/src/utilities/StringUtilities.ts +203 -0
- package/src/utilities/TarballMaker.ts +6 -23
- package/src/utilities/Timeline.ts +2 -1
- package/src/utilities/Utilities.ts +4 -237
- package/src/utilities/WebReader.ts +1 -1
- package/src/utilities/WikipediaReader.ts +1 -1
- 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 {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
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
|
|
35
|
-
throw new Error(`Input audio must have a sample rate of
|
|
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
|
|
43
|
-
|
|
44
|
-
const
|
|
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
|
|
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 =
|
|
53
|
-
const segmentHopSize =
|
|
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
|
-
|
|
67
|
+
const fftSizeReciprocal = 1 / fftSize
|
|
58
68
|
|
|
59
|
-
|
|
60
|
-
const
|
|
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
|
-
|
|
63
|
-
const
|
|
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
|
|
68
|
-
const
|
|
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
|
-
|
|
108
|
+
const segmentLength = fftFramesForSegment[0].length
|
|
71
109
|
|
|
72
|
-
const
|
|
73
|
-
const fftFramesRightComplexForSegment = fftFramesRightComplex.slice(segmentOffset, segmentOffset + segmentSize)
|
|
110
|
+
const isLastSegment = segmentLength < segmentSize
|
|
74
111
|
|
|
75
|
-
|
|
112
|
+
await logger.startAsync(`Reshape STFT frames`)
|
|
76
113
|
|
|
77
|
-
const flattenedInputTensor = new Float32Array(1 * 4 *
|
|
114
|
+
const flattenedInputTensor = new Float32Array(1 * 4 * binCount * segmentSize)
|
|
78
115
|
|
|
79
116
|
{
|
|
80
117
|
let writePosition = 0
|
|
81
118
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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 <
|
|
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
|
|
91
|
-
|
|
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 (
|
|
102
|
-
value =
|
|
132
|
+
if (isRealComponentTensorElementIndex) {
|
|
133
|
+
value = frame[binIndex << 1]
|
|
103
134
|
} else {
|
|
104
|
-
value =
|
|
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
|
-
|
|
145
|
+
await logger.startAsync(`Process with MDXNet model (ONNX provider: ${this.onnxSessionOptions!.executionProviders!.join(', ')})`)
|
|
115
146
|
|
|
116
|
-
|
|
147
|
+
const inputTensor = new Onnx.Tensor('float32', flattenedInputTensor, [1, 4, binCount, segmentSize])
|
|
117
148
|
|
|
118
|
-
const { output: outputTensor } = await session
|
|
149
|
+
const { output: outputTensor } = await this.session!.run({ input: inputTensor })
|
|
119
150
|
|
|
120
|
-
logger.
|
|
151
|
+
await logger.startAsync('Reshape processed frames')
|
|
121
152
|
|
|
122
153
|
const flattenedOutputTensor = outputTensor.data as Float32Array
|
|
123
154
|
|
|
124
|
-
const
|
|
155
|
+
const outputSegmentFramesForChannel: Float32Array[][] = []
|
|
125
156
|
|
|
126
157
|
{
|
|
127
158
|
for (let outChannelIndex = 0; outChannelIndex < 2; outChannelIndex++) {
|
|
128
|
-
const framesForChannel:
|
|
159
|
+
const framesForChannel: Float32Array[] = []
|
|
129
160
|
|
|
130
|
-
for (let frameIndex = 0; frameIndex <
|
|
131
|
-
const frame
|
|
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
|
-
|
|
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
|
|
147
|
-
const
|
|
173
|
+
const isRealTensorChannelIndex = tensorChannelIndex % 2 === 0
|
|
174
|
+
const audioChannelIndex = tensorChannelIndex < 2 ? 0 : 1
|
|
148
175
|
|
|
149
|
-
const
|
|
176
|
+
const framesForOutputChannel = outputSegmentFramesForChannel[audioChannelIndex]
|
|
150
177
|
|
|
151
|
-
for (let binIndex = 0; binIndex <
|
|
152
|
-
for (let frameIndex = 0; frameIndex <
|
|
153
|
-
const
|
|
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 (
|
|
156
|
-
|
|
182
|
+
if (isRealTensorChannelIndex) {
|
|
183
|
+
outFrame[binIndex << 1] = flattenedOutputTensor[readPosition++] * fftSizeReciprocal
|
|
157
184
|
} else {
|
|
158
|
-
|
|
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.
|
|
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
|
-
|
|
198
|
+
outputSegmentFramesForChannel[channelIndex],
|
|
176
199
|
fftSize,
|
|
177
200
|
fftWindowSize,
|
|
178
201
|
fftHopSize,
|
|
179
|
-
|
|
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.
|
|
189
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
252
|
+
joinedSegments[channelIndex][sampleIndex] /= sumOfWeightsForSample[sampleIndex] + 1e-8
|
|
226
253
|
}
|
|
227
254
|
}
|
|
228
255
|
}
|
|
229
256
|
|
|
230
|
-
const isolatedRawAudio: RawAudio = { audioChannels:
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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,
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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
|
-
|