echogarden 3.1.0 → 3.3.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 (96) hide show
  1. package/data/lexicons/heteronyms.en.json +1 -1
  2. package/data/lexicons/words.en.json +32 -0
  3. package/dist/api/Synthesis.js +2 -2
  4. package/dist/api/Synthesis.js.map +1 -1
  5. package/dist/encodings/Ascii.d.ts +1 -3
  6. package/dist/encodings/Ascii.d.ts.map +1 -1
  7. package/dist/encodings/Ascii.js +13 -9
  8. package/dist/encodings/Ascii.js.map +1 -1
  9. package/dist/encodings/Base64.d.ts.map +1 -1
  10. package/dist/encodings/Base64.js +9 -0
  11. package/dist/encodings/Base64.js.map +1 -1
  12. package/dist/encodings/Hex.d.ts.map +1 -1
  13. package/dist/encodings/Hex.js +11 -2
  14. package/dist/encodings/Hex.js.map +1 -1
  15. package/dist/encodings/Utf16.d.ts +1 -3
  16. package/dist/encodings/Utf16.d.ts.map +1 -1
  17. package/dist/encodings/Utf16.js +13 -9
  18. package/dist/encodings/Utf16.js.map +1 -1
  19. package/dist/encodings/Utf32.d.ts.map +1 -1
  20. package/dist/encodings/Utf32.js +6 -0
  21. package/dist/encodings/Utf32.js.map +1 -1
  22. package/dist/encodings/Utf8.d.ts +9 -5
  23. package/dist/encodings/Utf8.d.ts.map +1 -1
  24. package/dist/encodings/Utf8.js +36 -78
  25. package/dist/encodings/Utf8.js.map +1 -1
  26. package/dist/nlp/Segmentation.d.ts.map +1 -1
  27. package/dist/nlp/Segmentation.js +4 -1
  28. package/dist/nlp/Segmentation.js.map +1 -1
  29. package/dist/nlp/TextNormalizer.js +8 -1
  30. package/dist/nlp/TextNormalizer.js.map +1 -1
  31. package/dist/synthesis/AzureCognitiveServicesTTS.js +1 -1
  32. package/dist/synthesis/AzureCognitiveServicesTTS.js.map +1 -1
  33. package/dist/synthesis/EspeakTTS.d.ts.map +1 -1
  34. package/dist/synthesis/EspeakTTS.js +21 -6
  35. package/dist/synthesis/EspeakTTS.js.map +1 -1
  36. package/dist/synthesis/MicrosoftEdgeTTS.js +1 -1
  37. package/dist/synthesis/MicrosoftEdgeTTS.js.map +1 -1
  38. package/dist/utilities/FileSystem.d.ts +12 -7
  39. package/dist/utilities/FileSystem.d.ts.map +1 -1
  40. package/dist/utilities/FileSystem.js +196 -79
  41. package/dist/utilities/FileSystem.js.map +1 -1
  42. package/dist/utilities/FileWriter.d.ts +1 -0
  43. package/dist/utilities/FileWriter.d.ts.map +1 -1
  44. package/dist/utilities/FileWriter.js +8 -1
  45. package/dist/utilities/FileWriter.js.map +1 -1
  46. package/dist/utilities/ObjectUtilities.d.ts.map +1 -1
  47. package/dist/utilities/ObjectUtilities.js +15 -13
  48. package/dist/utilities/ObjectUtilities.js.map +1 -1
  49. package/dist/utilities/PackageManager.js +2 -2
  50. package/dist/utilities/PackageManager.js.map +1 -1
  51. package/dist/utilities/PathUtilities.d.ts +1 -0
  52. package/dist/utilities/PathUtilities.d.ts.map +1 -1
  53. package/dist/utilities/PathUtilities.js +18 -0
  54. package/dist/utilities/PathUtilities.js.map +1 -1
  55. package/dist/utilities/StringUtilities.d.ts.map +1 -1
  56. package/dist/utilities/StringUtilities.js.map +1 -1
  57. package/dist/utilities/Timer.d.ts +7 -3
  58. package/dist/utilities/Timer.d.ts.map +1 -1
  59. package/dist/utilities/Timer.js +42 -30
  60. package/dist/utilities/Timer.js.map +1 -1
  61. package/package.json +15 -14
  62. package/src/api/Synthesis.ts +2 -2
  63. package/src/encodings/Ascii.ts +14 -10
  64. package/src/encodings/Base64.ts +9 -0
  65. package/src/encodings/Hex.ts +11 -2
  66. package/src/encodings/Utf16.ts +14 -10
  67. package/src/encodings/Utf32.ts +6 -0
  68. package/src/encodings/Utf8.ts +45 -82
  69. package/src/nlp/Segmentation.ts +5 -1
  70. package/src/nlp/TextNormalizer.ts +11 -1
  71. package/src/synthesis/AzureCognitiveServicesTTS.ts +1 -1
  72. package/src/synthesis/EspeakTTS.ts +22 -7
  73. package/src/synthesis/MicrosoftEdgeTTS.ts +1 -1
  74. package/src/utilities/FileSystem.ts +224 -85
  75. package/src/utilities/FileWriter.ts +11 -1
  76. package/src/utilities/ObjectUtilities.ts +19 -15
  77. package/src/utilities/PackageManager.ts +2 -2
  78. package/src/utilities/PathUtilities.ts +19 -0
  79. package/src/utilities/StringUtilities.ts +0 -2
  80. package/src/utilities/Timer.ts +57 -37
  81. package/tsconfig.json +51 -53
  82. package/dist/encodings/HtmlEscape.d.ts +0 -2
  83. package/dist/encodings/HtmlEscape.d.ts.map +0 -1
  84. package/dist/encodings/HtmlEscape.js +0 -30
  85. package/dist/encodings/HtmlEscape.js.map +0 -1
  86. package/dist/encodings/LEB128.d.ts +0 -16
  87. package/dist/encodings/LEB128.d.ts.map +0 -1
  88. package/dist/encodings/LEB128.js +0 -248
  89. package/dist/encodings/LEB128.js.map +0 -1
  90. package/dist/utilities/StringBuilder.d.ts +0 -11
  91. package/dist/utilities/StringBuilder.d.ts.map +0 -1
  92. package/dist/utilities/StringBuilder.js +0 -39
  93. package/dist/utilities/StringBuilder.js.map +0 -1
  94. package/src/encodings/HtmlEscape.ts +0 -39
  95. package/src/encodings/LEB128.ts +0 -362
  96. package/src/utilities/StringBuilder.ts +0 -45
@@ -1,5 +1,8 @@
1
- import { EncodeIntoResult } from "./TextEncodingsCommon.js"
1
+ import { EncodeIntoResult } from './TextEncodingsCommon.js'
2
2
 
3
+ //////////////////////////////////////////////////////////////////////////////
4
+ // UTF-8 Encoding
5
+ //////////////////////////////////////////////////////////////////////////////
3
6
  export function encodeUtf8(text: string) {
4
7
  const textEncoder = new TextEncoder()
5
8
 
@@ -14,104 +17,64 @@ export function encodeUtf8Into(text: string, outputArray: Uint8Array): EncodeInt
14
17
  return result
15
18
  }
16
19
 
17
- export function decodeUtf8(encodedString: Uint8Array) {
18
- const maxChunkLength = 2 ** 24
20
+ export class ChunkedUtf8Encoder {
21
+ private readonly textEncoder = new TextEncoder()
19
22
 
20
- const decoder = new ChunkedUtf8Decoder()
23
+ private pendingHighSurrogate = ''
21
24
 
22
- for (let offset = 0; offset < encodedString.length; offset += maxChunkLength) {
23
- const chunk = encodedString.subarray(offset, offset + maxChunkLength)
25
+ writeChunk(stringChunk: string): Uint8Array {
26
+ if (this.pendingHighSurrogate !== '') {
27
+ stringChunk = this.pendingHighSurrogate + stringChunk
24
28
 
25
- decoder.writeChunk(chunk)
26
- }
29
+ this.pendingHighSurrogate = ''
30
+ }
27
31
 
28
- return decoder.toString()
29
- }
32
+ const lastCodeUnit = stringChunk.charCodeAt(stringChunk.length - 1)
30
33
 
31
- export class ChunkedUtf8Decoder {
32
- private str = ''
33
- private readonly textDecoder = new TextDecoder('utf-8')
34
+ if (lastCodeUnit >= 0xD800 && lastCodeUnit <= 0xDBFF) {
35
+ this.pendingHighSurrogate = stringChunk[stringChunk.length - 1]
34
36
 
35
- writeChunk(chunk: Uint8Array) {
36
- const decodedChunk = this.textDecoder.decode(chunk, { stream: true })
37
+ stringChunk = stringChunk.substring(0, stringChunk.length - 1)
38
+ }
37
39
 
38
- this.str += decodedChunk
40
+ return this.textEncoder.encode(stringChunk)
39
41
  }
40
42
 
41
- toString() {
42
- return this.str
43
+ finalize(): Uint8Array {
44
+ const result = this.textEncoder.encode(this.pendingHighSurrogate)
45
+
46
+ this.pendingHighSurrogate = ''
47
+
48
+ return result
43
49
  }
44
50
  }
45
51
 
46
- //////////////////////////////////////////////////////////////////////////////////////////////
47
- // Pure JavaScript implementations
48
- //////////////////////////////////////////////////////////////////////////////////////////////
49
- function encodeUtf8Into_JS(str: string, outputArray: Uint8Array): EncodeIntoResult {
50
- let readOffset = 0
51
- let writeOffset = 0
52
-
53
- while (readOffset < str.length) {
54
- const charCode = str.codePointAt(readOffset++)!
55
-
56
- if (charCode <= 0x7f) {
57
- outputArray[writeOffset++] = charCode
58
- } else if (charCode <= 0x7ff) {
59
- outputArray[writeOffset++] = 0xc0 | (charCode >>> 6)
60
- outputArray[writeOffset++] = 0x80 | (charCode & 63)
61
- } else if (charCode <= 0xffff) {
62
- outputArray[writeOffset++] = 0xe0 | (charCode >>> 12)
63
- outputArray[writeOffset++] = 0x80 | ((charCode >>> 6) & 63)
64
- outputArray[writeOffset++] = 0x80 | (charCode & 63)
65
- } else if (charCode <= 0x10ffff) {
66
- outputArray[writeOffset++] = 0xf0 | (charCode >>> 18)
67
- outputArray[writeOffset++] = 0x80 | ((charCode >>> 12) & 63)
68
- outputArray[writeOffset++] = 0x80 | ((charCode >>> 6) & 63)
69
- outputArray[writeOffset++] = 0x80 | (charCode & 63)
70
-
71
- readOffset++
72
- }
52
+ //////////////////////////////////////////////////////////////////////////////
53
+ // UTF-8 Decoding
54
+ //////////////////////////////////////////////////////////////////////////////
55
+ export function decodeUtf8(utf8Bytes: Uint8Array) {
56
+ const maxChunkLength = 2 ** 24
57
+
58
+ const chunkedUtf8Decoder = new ChunkedUtf8Decoder()
59
+
60
+ let resultString = ''
61
+
62
+ for (let offset = 0; offset < utf8Bytes.length; offset += maxChunkLength) {
63
+ const utf8Chunk = utf8Bytes.subarray(offset, offset + maxChunkLength)
64
+ const stringChunk = chunkedUtf8Decoder.writeChunk(utf8Chunk)
65
+
66
+ resultString += stringChunk
73
67
  }
74
68
 
75
- return { read: str.length, written: writeOffset }
69
+ return resultString
76
70
  }
77
71
 
78
- function decodeUtf8_JS(utf8Bytes: Uint8Array): string {
79
- let decodedString = ''
80
-
81
- let readOffset = 0
82
-
83
- while (readOffset < utf8Bytes.length) {
84
- const leadByte = utf8Bytes[readOffset++]
85
-
86
- let outputCodePoint: number
87
-
88
- if (leadByte >>> 7 === 0) {
89
- outputCodePoint = leadByte
90
- } else if (leadByte >>> 5 === 6) {
91
- outputCodePoint =
92
- (leadByte & 31) << 6 |
93
- (utf8Bytes[readOffset++] & 63)
94
- } else if (leadByte >>> 4 === 14) {
95
- outputCodePoint =
96
- (leadByte & 15) << 12 |
97
- (utf8Bytes[readOffset++] & 63) << 6 |
98
- (utf8Bytes[readOffset++] & 63)
99
- } else if (leadByte >>> 3 === 30) {
100
- outputCodePoint =
101
- (leadByte & 7) << 18 |
102
- (utf8Bytes[readOffset++] & 63) << 12 |
103
- (utf8Bytes[readOffset++] & 63) << 6 |
104
- (utf8Bytes[readOffset++] & 63)
105
- } else {
106
- throw new Error(`Invalid UTF-8 stream: An invalid lead byte value encountered at position ${readOffset}`)
107
- }
72
+ export class ChunkedUtf8Decoder {
73
+ private readonly textDecoder = new TextDecoder('utf-8')
108
74
 
109
- decodedString += String.fromCodePoint(outputCodePoint)
110
- }
75
+ writeChunk(chunk: Uint8Array) {
76
+ const decodedChunk = this.textDecoder.decode(chunk, { stream: true })
111
77
 
112
- if (readOffset > utf8Bytes.length) {
113
- throw new Error(`UTF-8 decoding failed. Byte sequence is truncated.`)
78
+ return decodedChunk
114
79
  }
115
-
116
- return decodedString
117
80
  }
@@ -22,7 +22,11 @@ const includesEmojiSequencePattern = anyOf(
22
22
  )
23
23
  const includesEmojiSequenceRegExp = buildRegExp(includesEmojiSequencePattern)
24
24
 
25
- const symbolWordsList = ['$', '€', '¢', '£', '¥', '©', '®', '™', '%', '&', '#', '~', '@', '+', '±', '÷', '/', '\\', '^', '*', '×', '=', '≈', '¼', '½', '¾', '→', '≤', '≥']
25
+ const symbolWordsList = [
26
+ '$', '€', '¢', '£', '¥', '©', '®', '™', '%', '&', '#', '~', '@', '+', '±', '÷',
27
+ '/', '\\', '^', '*', '×', '=', '≈', '¼', '½', '¾', '→', '≤', '≥', '∞'
28
+ ]
29
+
26
30
  const includesSymbolWordPattern = anyOf(...symbolWordsList)
27
31
  const includesSymbolWordRegExp = buildRegExp(includesSymbolWordPattern)
28
32
 
@@ -31,7 +31,7 @@ export function getNormalizedFragmentsForSpeech(
31
31
 
32
32
  //const isWordPrecedingAYear = wordsPrecedingAYear.includes(lowerCaseWord)
33
33
  const isWordPrecedingAYear =
34
- isAllLettersRegExp.test(lowerCaseWord) || isSpecialCharacterBeforeYear
34
+ isAllLettersOrApostropheRegExp.test(lowerCaseWord) || isSpecialCharacterBeforeYear
35
35
 
36
36
  const followedByFourDigitYearPattern = fourDigitYearRegExp.test(nextNonWhitespaceWord)
37
37
 
@@ -284,3 +284,13 @@ const fourDigitYearRangeRegExp = buildRegExp(fourDigitYearRangePattern)
284
284
 
285
285
  const isAllLettersPattern = [inputStart, oneOrMore(unicodeProperty('Letter')), inputEnd]
286
286
  const isAllLettersRegExp = buildRegExp(isAllLettersPattern)
287
+
288
+ const isAllLettersOrApostrophePattern = [
289
+ inputStart,
290
+
291
+ unicodeProperty('Letter'),
292
+ zeroOrMore(anyOf(unicodeProperty('Letter'), `'`, `’`)),
293
+ inputEnd,
294
+ ]
295
+
296
+ const isAllLettersOrApostropheRegExp = buildRegExp(isAllLettersOrApostrophePattern)
@@ -6,7 +6,7 @@ import { Logger } from '../utilities/Logger.js'
6
6
  import { Timeline } from '../utilities/Timeline.js'
7
7
  import { RawAudio, getRawAudioDuration } from '../audio/AudioUtilities.js'
8
8
  import { concatUint8Arrays } from '../utilities/Utilities.js'
9
- import { escapeHtml } from '../encodings/HtmlEscape.js'
9
+ import { escapeHtml } from 'standard-html-escaper'
10
10
  import { SynthesisCallbacks } from '../api/Synthesis.js'
11
11
 
12
12
  export async function synthesize(
@@ -9,7 +9,7 @@ import { Lexicon, tryGetFirstLexiconSubstitution } from '../nlp/Lexicon.js'
9
9
  import { phonemizeSentence } from '../nlp/EspeakPhonemizer.js'
10
10
  import { Timeline, TimelineEntry } from '../utilities/Timeline.js'
11
11
  import { extendDeep } from '../utilities/ObjectUtilities.js'
12
- import { escapeHtml } from '../encodings/HtmlEscape.js'
12
+ import { escapeHtml } from 'standard-html-escaper'
13
13
  import * as TextSegmentation from '@echogarden/text-segmentation'
14
14
 
15
15
  import { OperationCallbacks, SynthesisCallbacks } from '../api/API.js'
@@ -257,12 +257,29 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
257
257
  }
258
258
  }
259
259
 
260
- const canInsertSeparators = !['roa/an', 'art/eo', 'trk/ky', 'zlw/pl', 'zle/uk'].includes(voice)
260
+ const separatorString = ` | `
261
+
262
+ const canInsertSeparators = ![
263
+ 'roa/an',
264
+ 'an',
265
+ 'art/eo',
266
+ 'eo',
267
+ 'trk/ky',
268
+ 'ky',
269
+ 'zlw/pl',
270
+ 'pl',
271
+ 'zle/uk',
272
+ 'uk',
273
+ 'gmw/nl',
274
+ 'nl'
275
+ ].includes(voice)
261
276
 
262
277
  let textWithMarkers: string
263
278
 
264
- if (canInsertSeparators) {
265
- textWithMarkers = `() | `
279
+ // Added `espeakOptions.insertSeparators` here because I'm not sure if adding the separator
280
+ // here is completely necessary, and it is causing issues with some languages.
281
+ if (espeakOptions.insertSeparators && canInsertSeparators) {
282
+ textWithMarkers = `()${separatorString}`
266
283
  } else {
267
284
  textWithMarkers = `() `
268
285
  }
@@ -280,9 +297,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
280
297
  }
281
298
 
282
299
  if (espeakOptions.insertSeparators && canInsertSeparators) {
283
- const separator = ` | `
284
-
285
- textWithMarkers += `<mark name="s-${i}"/>${separator}${fragment}${separator}<mark name="e-${i}"/>`
300
+ textWithMarkers += `<mark name="s-${i}"/>${separatorString}${fragment}${separatorString}<mark name="e-${i}"/>`
286
301
  } else {
287
302
  if (fragment.endsWith('.')) {
288
303
  fragment += ' ()'
@@ -8,7 +8,7 @@ import { concatUint8Arrays, getRandomHexString, logToStderr, sha256AsHex } from
8
8
  import { RawAudio, getEmptyRawAudio, getRawAudioDuration } from '../audio/AudioUtilities.js'
9
9
  import { Timer } from '../utilities/Timer.js'
10
10
  import { decodeUtf8, encodeUtf8 } from '../encodings/Utf8.js'
11
- import { escapeHtml } from '../encodings/HtmlEscape.js'
11
+ import { escapeHtml } from 'standard-html-escaper'
12
12
  import { requestHttp } from 'easier-http-request'
13
13
  import { VoiceListRequestCallbacks, SynthesisCallbacks } from '../api/API.js'
14
14