echogarden 1.4.2 → 1.4.4

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 (34) hide show
  1. package/README.md +1 -1
  2. package/data/tables/lcid-table.json +9 -0
  3. package/dist/alignment/DTWMfccSequenceAlignment.d.ts +1 -1
  4. package/dist/alignment/DTWMfccSequenceAlignment.js +9 -5
  5. package/dist/alignment/DTWMfccSequenceAlignment.js.map +1 -1
  6. package/dist/alignment/DTWSequenceAlignmentWindowed.js +4 -4
  7. package/dist/alignment/DTWSequenceAlignmentWindowed.js.map +1 -1
  8. package/dist/alignment/SpeechAlignment.js +1 -1
  9. package/dist/alignment/SpeechAlignment.js.map +1 -1
  10. package/dist/alignment/TextAlignment.d.ts +8 -1
  11. package/dist/alignment/TextAlignment.js +99 -6
  12. package/dist/alignment/TextAlignment.js.map +1 -1
  13. package/dist/api/Alignment.js +1 -1
  14. package/dist/api/Alignment.js.map +1 -1
  15. package/dist/math/VectorMath.d.ts +17 -15
  16. package/dist/math/VectorMath.js +53 -26
  17. package/dist/math/VectorMath.js.map +1 -1
  18. package/dist/synthesis/EspeakTTS.js +4 -5
  19. package/dist/synthesis/EspeakTTS.js.map +1 -1
  20. package/dist/tests/Test.js +23 -0
  21. package/dist/tests/Test.js.map +1 -1
  22. package/dist/utilities/PackageManager.js +4 -0
  23. package/dist/utilities/PackageManager.js.map +1 -1
  24. package/docs/Tasklist.md +4 -1
  25. package/package.json +6 -6
  26. package/src/alignment/DTWMfccSequenceAlignment.ts +11 -5
  27. package/src/alignment/DTWSequenceAlignmentWindowed.ts +4 -4
  28. package/src/alignment/SpeechAlignment.ts +1 -1
  29. package/src/alignment/TextAlignment.ts +144 -6
  30. package/src/api/Alignment.ts +1 -1
  31. package/src/math/VectorMath.ts +78 -43
  32. package/src/synthesis/EspeakTTS.ts +6 -8
  33. package/src/tests/Test.ts +27 -1
  34. package/src/utilities/PackageManager.ts +4 -0
@@ -1,3 +1,5 @@
1
+ import { clip } from "../utilities/Utilities.js"
2
+
1
3
  export function covarianceMatrixOfSamples(samples: number[][], weights?: number[], biased = false) {
2
4
  if (samples.length == 0) {
3
5
  throw new Error('No vectors given')
@@ -434,7 +436,7 @@ export function averageMeanSquaredError(actual: number[][], expected: number[][]
434
436
  return sum / vectorCount
435
437
  }
436
438
 
437
- export function meanSquaredError(actual: number[], expected: number[]) {
439
+ export function meanSquaredError(actual: ArrayLike<number>, expected: ArrayLike<number>) {
438
440
  if (actual.length != expected.length) {
439
441
  throw new Error('Vectors are not the same length')
440
442
  }
@@ -454,18 +456,18 @@ export function meanSquaredError(actual: number[], expected: number[]) {
454
456
  return sum / featureCount
455
457
  }
456
458
 
457
- export function euclidianDistance(vector1: number[], vector2: number[]) {
459
+ export function euclidianDistance(vector1: ArrayLike<number>, vector2: ArrayLike<number>) {
458
460
  return Math.sqrt(squaredEuclidianDistance(vector1, vector2))
459
461
  }
460
462
 
461
- export function squaredEuclidianDistance(vector1: number[], vector2: number[]) {
462
- if (vector1.length != vector2.length) {
463
+ export function squaredEuclidianDistance(vector1: ArrayLike<number>, vector2: ArrayLike<number>) {
464
+ if (vector1.length !== vector2.length) {
463
465
  throw new Error('Vectors are not the same length')
464
466
  }
465
467
 
466
468
  const elementCount = vector1.length
467
469
 
468
- if (elementCount == 0) {
470
+ if (elementCount === 0) {
469
471
  return 0
470
472
  }
471
473
 
@@ -478,16 +480,41 @@ export function squaredEuclidianDistance(vector1: number[], vector2: number[]) {
478
480
  return sum
479
481
  }
480
482
 
481
- export function cosineDistance(vector1: number[], vector2: number[]) {
483
+ export function euclidianDistance13Dim(vector1: ArrayLike<number>, vector2: ArrayLike<number>) {
484
+ return Math.sqrt(squaredEuclidianDistance13Dim(vector1, vector2))
485
+ }
486
+
487
+ export function squaredEuclidianDistance13Dim(vector1: ArrayLike<number>, vector2: ArrayLike<number>) {
488
+ // Assumes the input has 13 dimensions (optimized for 13-dimensional MFCC vectors)
489
+
490
+ const result =
491
+ (vector1[0] - vector2[0]) ** 2 +
492
+ (vector1[1] - vector2[1]) ** 2 +
493
+ (vector1[2] - vector2[2]) ** 2 +
494
+ (vector1[3] - vector2[3]) ** 2 +
495
+ (vector1[4] - vector2[4]) ** 2 +
496
+ (vector1[5] - vector2[5]) ** 2 +
497
+ (vector1[6] - vector2[6]) ** 2 +
498
+ (vector1[7] - vector2[7]) ** 2 +
499
+ (vector1[8] - vector2[8]) ** 2 +
500
+ (vector1[9] - vector2[9]) ** 2 +
501
+ (vector1[10] - vector2[10]) ** 2 +
502
+ (vector1[11] - vector2[11]) ** 2 +
503
+ (vector1[12] - vector2[12]) ** 2
504
+
505
+ return result
506
+ }
507
+
508
+ export function cosineDistance(vector1: ArrayLike<number>, vector2: ArrayLike<number>) {
482
509
  return 1 - cosineSimilarity(vector1, vector2)
483
510
  }
484
511
 
485
- export function cosineSimilarity(vector1: number[], vector2: number[]) {
486
- if (vector1.length != vector2.length) {
512
+ export function cosineSimilarity(vector1: ArrayLike<number>, vector2: ArrayLike<number>) {
513
+ if (vector1.length !== vector2.length) {
487
514
  throw new Error('Vectors are not the same length')
488
515
  }
489
516
 
490
- if (vector1.length == 0) {
517
+ if (vector1.length === 0) {
491
518
  return 0
492
519
  }
493
520
 
@@ -499,42 +526,28 @@ export function cosineSimilarity(vector1: number[], vector2: number[]) {
499
526
  let squaredMagnitude2 = 0.0
500
527
 
501
528
  for (let i = 0; i < elementCount; i++) {
502
- dotProduct += vector1[i] * vector2[i]
529
+ const element1 = vector1[i]
530
+ const element2 = vector2[i]
503
531
 
504
- squaredMagnitude1 += vector1[i] ** 2
505
- squaredMagnitude2 += vector2[i] ** 2
506
- }
532
+ dotProduct += element1 * element2
507
533
 
508
- const result = dotProduct / (Math.sqrt(squaredMagnitude1) * Math.sqrt(squaredMagnitude2) + 1e-40)
509
-
510
- return zeroIfNaN(result)
511
- }
512
-
513
- export function minkowskiDistance(vector1: number[], vector2: number[], power: number) {
514
- if (vector1.length != vector2.length) {
515
- throw new Error('Vectors are not the same length')
534
+ squaredMagnitude1 += element1 ** 2
535
+ squaredMagnitude2 += element2 ** 2
516
536
  }
517
537
 
518
- const elementCount = vector1.length
538
+ let result = dotProduct / (Math.sqrt(squaredMagnitude1) * Math.sqrt(squaredMagnitude2) + 1e-40)
519
539
 
520
- if (elementCount == 0) {
521
- return 0
522
- }
540
+ result = zeroIfNaN(result)
541
+ result = clip(result, -1.0, 1.0)
523
542
 
524
- let sum = 0.0
525
-
526
- for (let i = 0; i < elementCount; i++) {
527
- sum += Math.abs(vector1[i] - vector2[i]) ** power
528
- }
529
-
530
- return sum ** (1 / power)
543
+ return result
531
544
  }
532
545
 
533
- export function cosineDistancePrecomputedMagnitudes(vector1: number[], vector2: number[], magnitude1: number, magnitude2: number) {
546
+ export function cosineDistancePrecomputedMagnitudes(vector1: ArrayLike<number>, vector2: ArrayLike<number>, magnitude1: number, magnitude2: number) {
534
547
  return 1 - cosineSimilarityPrecomputedMagnitudes(vector1, vector2, magnitude1, magnitude2)
535
548
  }
536
549
 
537
- export function cosineSimilarityPrecomputedMagnitudes(vector1: number[], vector2: number[], magnitude1: number, magnitude2: number) {
550
+ export function cosineSimilarityPrecomputedMagnitudes(vector1: ArrayLike<number>, vector2: ArrayLike<number>, magnitude1: number, magnitude2: number) {
538
551
  if (vector1.length != vector2.length) {
539
552
  throw new Error('Vectors are not the same length')
540
553
  }
@@ -551,11 +564,33 @@ export function cosineSimilarityPrecomputedMagnitudes(vector1: number[], vector2
551
564
  dotProduct += vector1[i] * vector2[i]
552
565
  }
553
566
 
554
- const result = dotProduct / (magnitude1 * magnitude2)
567
+ let result = dotProduct / (magnitude1 * magnitude2 + 1e-40)
555
568
 
556
- return zeroIfNaN(result)
569
+ result = zeroIfNaN(result)
570
+ result = clip(result, -1.0, 1.0)
571
+
572
+ return result
557
573
  }
558
574
 
575
+ export function minkowskiDistance(vector1: ArrayLike<number>, vector2: ArrayLike<number>, power: number) {
576
+ if (vector1.length != vector2.length) {
577
+ throw new Error('Vectors are not the same length')
578
+ }
579
+
580
+ const elementCount = vector1.length
581
+
582
+ if (elementCount == 0) {
583
+ return 0
584
+ }
585
+
586
+ let sum = 0.0
587
+
588
+ for (let i = 0; i < elementCount; i++) {
589
+ sum += Math.abs(vector1[i] - vector2[i]) ** power
590
+ }
591
+
592
+ return sum ** (1 / power)
593
+ }
559
594
 
560
595
  export function subtractVectors(vector1: number[], vector2: number[]) {
561
596
  if (vector1.length != vector2.length) {
@@ -571,7 +606,7 @@ export function subtractVectors(vector1: number[], vector2: number[]) {
571
606
  return result
572
607
  }
573
608
 
574
- export function sumVector(vector: number[]) {
609
+ export function sumVector(vector: ArrayLike<number>) {
575
610
  let result = 0.0
576
611
 
577
612
  for (let i = 0; i < vector.length; i++) {
@@ -581,7 +616,7 @@ export function sumVector(vector: number[]) {
581
616
  return result
582
617
  }
583
618
 
584
- export function dotProduct(vector1: number[], vector2: number[]) {
619
+ export function dotProduct(vector1: ArrayLike<number>, vector2: ArrayLike<number>) {
585
620
  if (vector1.length != vector2.length) {
586
621
  throw new Error('Vectors are not the same length')
587
622
  }
@@ -597,7 +632,7 @@ export function dotProduct(vector1: number[], vector2: number[]) {
597
632
  return result
598
633
  }
599
634
 
600
- export function magnitude(vector: number[]) {
635
+ export function magnitude(vector: ArrayLike<number>) {
601
636
  const featureCount = vector.length
602
637
 
603
638
  let squaredMagnitude = 0.0
@@ -609,11 +644,11 @@ export function magnitude(vector: number[]) {
609
644
  return Math.sqrt(squaredMagnitude)
610
645
  }
611
646
 
612
- export function maxValue(vector: number[]) {
647
+ export function maxValue(vector: ArrayLike<number>) {
613
648
  return vector[indexOfMax(vector)]
614
649
  }
615
650
 
616
- export function indexOfMax(vector: number[]) {
651
+ export function indexOfMax(vector: ArrayLike<number>) {
617
652
  if (vector.length == 0) {
618
653
  return -1
619
654
  }
@@ -631,11 +666,11 @@ export function indexOfMax(vector: number[]) {
631
666
  return result
632
667
  }
633
668
 
634
- export function minValue(vector: number[]) {
669
+ export function minValue(vector: ArrayLike<number>) {
635
670
  return vector[indexOfMin(vector)]
636
671
  }
637
672
 
638
- export function indexOfMin(vector: number[]) {
673
+ export function indexOfMin(vector: ArrayLike<number>) {
639
674
  let minValue = Infinity
640
675
  let result = -1
641
676
 
@@ -140,13 +140,11 @@ export async function preprocessAndSynthesize(text: string, language: string, es
140
140
  }
141
141
 
142
142
  export async function synthesizeFragments(fragments: string[], espeakOptions: EspeakOptions) {
143
- const logger = new Logger()
144
-
145
143
  espeakOptions = extendDeep(defaultEspeakOptions, espeakOptions)
146
144
 
147
- const sampleRate = await getSampleRate()
145
+ const voice = espeakOptions.voice
148
146
 
149
- //fragments = fragments.filter(fragment => fragment.trim() != '')
147
+ const sampleRate = await getSampleRate()
150
148
 
151
149
  if (fragments.length === 0) {
152
150
  return {
@@ -156,9 +154,11 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
156
154
  }
157
155
  }
158
156
 
157
+ const canInsertSeparators = !['roa/an', 'art/eo', 'trk/ky', 'zlw/pl', 'zle/uk'].includes(voice)
158
+
159
159
  let textWithMarkers: string
160
160
 
161
- if (espeakOptions.insertSeparators) {
161
+ if (canInsertSeparators) {
162
162
  textWithMarkers = `() | `
163
163
  } else {
164
164
  textWithMarkers = `() `
@@ -173,7 +173,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
173
173
  .replaceAll('<', '&lt;')
174
174
  .replaceAll('>', '&gt;')
175
175
 
176
- if (espeakOptions.insertSeparators) {
176
+ if (espeakOptions.insertSeparators && canInsertSeparators) {
177
177
  const separator = ` | `
178
178
 
179
179
  textWithMarkers += `<mark name="s-${i}"/>${separator}${fragment}${separator}<mark name="e-${i}"/>`
@@ -186,8 +186,6 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
186
186
  }
187
187
  }
188
188
 
189
- //log(textWithMarkers)
190
-
191
189
  const { rawAudio, events } = await synthesize(textWithMarkers, { ...espeakOptions, ssml: true })
192
190
 
193
191
  // Add first marker if missing
package/src/tests/Test.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { getTokenRepetitionScore, logToStderr, setupProgramTerminationListeners, writeToStderr } from '../utilities/Utilities.js'
2
2
  import { makeTarballsForInstalledPackages } from '../utilities/TarballMaker.js'
3
- import { testEspeakSynthesisWithPrePhonemizedInputs, testKirshenbaumPhonemization } from '../synthesis/EspeakTTS.js'
3
+ import { defaultEspeakOptions, listVoices, synthesize, testEspeakSynthesisWithPrePhonemizedInputs, testKirshenbaumPhonemization } from '../synthesis/EspeakTTS.js'
4
+ import { getRawAudioDuration } from '../audio/AudioUtilities.js'
5
+ import { alignText } from '../alignment/TextAlignment.js'
4
6
 
5
7
  const log = logToStderr
6
8
 
@@ -21,5 +23,29 @@ setupProgramTerminationListeners()
21
23
 
22
24
  //await makeTarballsForInstalledPackages(true)
23
25
 
26
+ /*
27
+ const voices = await listVoices()
28
+
29
+ for (const voice of voices) {
30
+ const result = await synthesize('|', { ...defaultEspeakOptions, voice: voice.identifier })
31
+
32
+ if (getRawAudioDuration(result.rawAudio) > 0.25) {
33
+ log(voice.identifier)
34
+ }
35
+ }
36
+ */
37
+ /*
38
+ await alignText(
39
+ `
40
+ Una mañana de invierno, un coche tirado por tres caballos pasó por en medio de Uzquiano y sin detenerse, siguió camino de Peña Cerrada. El coche había salido de Vitoria horas antes y llevaba tres viajeros, una muchachita vestida de blanco, talle alto, gabán, esclavina, gran sombrero Pamela, de moda por los años treinta y cinco al cuarenta, una criada vieja, de aspecto de dueña, enlutada, con peluca rojiza y toca blanca, y un hombre joven, alto, elegante, vestido de negro, con pantalón estrecho, entravillado y sombrero de copa.
41
+ `,
42
+ 'es',
43
+ `
44
+ One winter morning, a car drawn by three horses passed through the middle of Uzquiano and without stopping, continued on its way to Peña Cerrada. The car had left Vitoria hours before and was carrying three passengers, a little girl dressed in white, high-waisted, overcoat, cape, large Pamela hat, fashionable in the 1930s to 1940s, an old maid, with the appearance of a mistress, in mourning, with a reddish wig and a white cap, and a young, tall, elegant man, dressed in black, with narrow pants, a bow tie and a top hat.
45
+ `,
46
+ 'en',
47
+ )
48
+ */
49
+
24
50
  process.exit(0)
25
51
 
@@ -185,4 +185,8 @@ const packageVersionTagResolutionLookup: { [packageName: string]: string } = {
185
185
 
186
186
  'xenova-multilingual-e5-small-quantized': '20240504',
187
187
  'xenova-nllb-200-distilled-600M-quantized': '20240505',
188
+ 'xenova-multilingual-e5-small-fp16': '20240514',
189
+ 'xenova-multilingual-e5-base-fp16': '20240514',
190
+ 'xenova-multilingual-e5-base-quantized': '20240514',
191
+ 'xenova-multilingual-e5-large-quantized': '20240514',
188
192
  }