echogarden 1.3.3 → 1.4.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.
@@ -257,7 +257,7 @@ export async function detectTextLanguage(input: string, options: TextLanguageDet
257
257
  case 'tinyld': {
258
258
  const { detectLanguage } = await import('../text-language-detection/TinyLDLanguageDetection.js')
259
259
 
260
- logger.start('Detecting text language using tinyld')
260
+ logger.start('Detect text language using tinyld')
261
261
 
262
262
  detectedLanguageProbabilities = await detectLanguage(input)
263
263
 
@@ -267,7 +267,7 @@ export async function detectTextLanguage(input: string, options: TextLanguageDet
267
267
  case 'fasttext': {
268
268
  const { detectLanguage } = await import('../text-language-detection/FastTextLanguageDetection.js')
269
269
 
270
- logger.start('Detecting text language using FastText')
270
+ logger.start('Detect text language using FastText')
271
271
 
272
272
  detectedLanguageProbabilities = await detectLanguage(input)
273
273
 
@@ -54,7 +54,7 @@ async function synthesizeSegments(segments: string[], options: SynthesisOptions,
54
54
  options = extendDeep(defaultSynthesisOptions, options)
55
55
 
56
56
  if (!options.language && !options.voice) {
57
- logger.start('No language or voice specified. Detecting language')
57
+ logger.start('No language or voice specified. Detect language')
58
58
 
59
59
  let segmentsPlainText = segments
60
60
 
@@ -26,7 +26,7 @@ export async function preprocessAndSynthesize(text: string, language: string, es
26
26
 
27
27
  let lowerCaseLanguageCode = language.toLowerCase()
28
28
 
29
- if (lowerCaseLanguageCode == 'en-gb') {
29
+ if (lowerCaseLanguageCode === 'en-gb') {
30
30
  lowerCaseLanguageCode = 'en-gb-x-rp'
31
31
  }
32
32
 
@@ -44,9 +44,9 @@ export async function preprocessAndSynthesize(text: string, language: string, es
44
44
 
45
45
  for (let i = 0; i < words.length; i++) {
46
46
  const currentWord = words[i]
47
- const previousWord = words[i-1]
47
+ const previousWord = words[i - 1]
48
48
 
49
- if (i > 0 && currentWord == previousWord && !wordCharacterPattern.test(currentWord)) {
49
+ if (i > 0 && currentWord === previousWord && !wordCharacterPattern.test(currentWord)) {
50
50
  wordsWithMerges[wordsWithMerges.length - 1] += currentWord
51
51
  } else {
52
52
  wordsWithMerges.push(currentWord)
@@ -144,7 +144,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
144
144
 
145
145
  //fragments = fragments.filter(fragment => fragment.trim() != '')
146
146
 
147
- if (fragments.length == 0) {
147
+ if (fragments.length === 0) {
148
148
  return {
149
149
  rawAudio: getEmptyRawAudio(1, sampleRate),
150
150
  timeline: [] as Timeline,
@@ -152,7 +152,13 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
152
152
  }
153
153
  }
154
154
 
155
- let textWithMarkers = '() '
155
+ let textWithMarkers: string
156
+
157
+ if (espeakOptions.insertSeparators) {
158
+ textWithMarkers = `() | `
159
+ } else {
160
+ textWithMarkers = `() `
161
+ }
156
162
 
157
163
  for (let i = 0; i < fragments.length; i++) {
158
164
  let fragment = fragments[i]
@@ -180,6 +186,21 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
180
186
 
181
187
  const { rawAudio, events } = await synthesize(textWithMarkers, { ...espeakOptions, ssml: true })
182
188
 
189
+ // Add first marker if missing
190
+ if (fragments.length > 0) {
191
+ const firstMarkerEvent = events.find(event => event.type === 'mark')
192
+
193
+ if (firstMarkerEvent && firstMarkerEvent.id === 'e-0') {
194
+ events.unshift({
195
+ type: 'mark',
196
+ text_position: 0,
197
+ word_length: 0,
198
+ audio_position: 0,
199
+ id: 's-0',
200
+ })
201
+ }
202
+ }
203
+
183
204
  // Build word timeline from events
184
205
  const wordTimeline: Timeline = fragments.map(word => ({
185
206
  type: 'word',
@@ -210,16 +231,16 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
210
231
  const currentPhoneTimeline = currentTokenEntry.timeline!
211
232
  const lastPhoneEntry = currentPhoneTimeline[currentPhoneTimeline.length - 1]
212
233
 
213
- if (lastPhoneEntry && lastPhoneEntry.endTime == -1) {
234
+ if (lastPhoneEntry && lastPhoneEntry.endTime === -1) {
214
235
  lastPhoneEntry.endTime = eventTime
215
236
  }
216
237
 
217
- if (event.type == 'word') {
218
- if (!event.id || currentPhoneTimeline.length == 0) {
238
+ if (event.type === 'word') {
239
+ if (!event.id || currentPhoneTimeline.length === 0) {
219
240
  continue
220
241
  }
221
242
 
222
- if (currentTokenEntry.endTime == -1) {
243
+ if (currentTokenEntry.endTime === -1) {
223
244
  currentTokenEntry.endTime = eventTime
224
245
  }
225
246
 
@@ -230,7 +251,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
230
251
  endTime: -1,
231
252
  timeline: []
232
253
  })
233
- } else if (event.type == 'phoneme') {
254
+ } else if (event.type === 'phoneme') {
234
255
  const phoneText = event.id as string
235
256
 
236
257
  if (!phoneText || phoneText.startsWith('(')) {
@@ -246,7 +267,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
246
267
 
247
268
  currentTokenEntry.text += phoneText
248
269
  currentTokenEntry.startTime = currentPhoneTimeline[0].startTime
249
- } else if (event.type == 'mark') {
270
+ } else if (event.type === 'mark') {
250
271
  const markerName = event.id! as string
251
272
 
252
273
  if (markerName.startsWith('s-')) {
@@ -276,13 +297,13 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
276
297
 
277
298
  wordIndex += 1
278
299
 
279
- if (wordIndex == wordTimeline.length) {
300
+ if (wordIndex === wordTimeline.length) {
280
301
  break
281
302
  }
282
303
  } else {
283
304
  continue
284
305
  }
285
- } else if (event.type == 'end') {
306
+ } else if (event.type === 'end') {
286
307
  clauseEndIndexes.push(wordIndex)
287
308
  }
288
309
  }
@@ -293,11 +314,11 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
293
314
  for (const [index, wordEntry] of wordTimeline.entries()) {
294
315
  const tokenTimeline = wordEntry.timeline
295
316
 
296
- if (index == 0) {
317
+ if (index === 0) {
297
318
  continue
298
319
  }
299
320
 
300
- if (!tokenTimeline || tokenTimeline.length == 0) {
321
+ if (!tokenTimeline || tokenTimeline.length === 0) {
301
322
  throw new Error('Unexpected: token timeline should exist and have at least one token')
302
323
  }
303
324
 
@@ -309,7 +330,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
309
330
 
310
331
  const wordReferenceIPA = wordReferencePhonemes.join(' ')
311
332
 
312
- if (wordReferenceIPA.trim().length == 0) {
333
+ if (wordReferenceIPA.trim().length === 0) {
313
334
  continue
314
335
  }
315
336
 
@@ -382,7 +403,7 @@ export async function synthesizeFragments(fragments: string[], espeakOptions: Es
382
403
 
383
404
  for (let entryIndex = clauseStartIndex; entryIndex <= clauseEndIndex && entryIndex < wordTimeline.length; entryIndex++) {
384
405
  const wordEntry = wordTimeline[entryIndex]
385
- if (newClause.startTime == -1) {
406
+ if (newClause.startTime === -1) {
386
407
  newClause.startTime = wordEntry.startTime
387
408
  }
388
409
 
@@ -438,7 +459,7 @@ export async function synthesize(text: string, espeakOptions: EspeakOptions) {
438
459
  }
439
460
 
440
461
  for (const event of events) {
441
- if (event.type == 'word') {
462
+ if (event.type === 'word') {
442
463
  const textPosition = event.text_position - 1;
443
464
  (event as any)['text'] = text.substring(textPosition, textPosition + event.word_length)
444
465
  }
@@ -110,3 +110,18 @@ export async function getDeflateCompressionMetricsForString(str: string) {
110
110
  ratio: originalStringBytes.length / compressedStringBytes.length
111
111
  }
112
112
  }
113
+
114
+ export function computeDeltas(data: Float32Array) {
115
+ const deltas = new Float32Array(data.length)
116
+
117
+ let val = 0
118
+
119
+ for (let i = 0; i < data.length; i++) {
120
+ const delta = Math.floor(data[i] - val)
121
+ deltas[i] = delta
122
+
123
+ val += delta
124
+ }
125
+
126
+ return deltas
127
+ }
@@ -0,0 +1,237 @@
1
+ import { logToStderr } from "./Utilities.js"
2
+
3
+ ////////////////////////////////////////////////////////////////////////////////////
4
+ // Encode
5
+ ////////////////////////////////////////////////////////////////////////////////////
6
+ export function encodeSignedInt32(value: number, outEncodedData: number[]) {
7
+ if (value < -2147483648 || value > 2147483647) {
8
+ throw new Error('Value must be between -2147483648 and 2147483647')
9
+ }
10
+
11
+ while (true) {
12
+ const lowest7Bits = value & 127
13
+
14
+ value >>= 7
15
+
16
+ if (
17
+ (value === 0 && (lowest7Bits & 64) === 0) ||
18
+ (value === -1 && (lowest7Bits & 64) !== 0)) {
19
+ outEncodedData.push(lowest7Bits)
20
+
21
+ return outEncodedData
22
+ } else {
23
+ outEncodedData.push(lowest7Bits | 128)
24
+ }
25
+ }
26
+ }
27
+
28
+ export function encodeSignedInt32sFast(value: number, outEncodedData: number[]) {
29
+ const absValue = Math.abs(value)
30
+ //const absMask = value >> 31
31
+ //const absValue = (value ^ absMask) - absMask
32
+
33
+ if (absValue < (2 ** 6)) {
34
+ outEncodedData.push(
35
+ (value & 127)
36
+ )
37
+ } else if (absValue < (2 ** 13)) {
38
+ outEncodedData.push(
39
+ (value & 127) | 128,
40
+ (value >> 7) & 127
41
+ )
42
+ } else if (absValue < (2 ** 20)) {
43
+ outEncodedData.push(
44
+ (value & 127) | 128,
45
+ ((value >> 7) & 127) | 128,
46
+ (value >> 14) & 127
47
+ )
48
+ } else if (absValue < (2 ** 27)) {
49
+ outEncodedData.push(
50
+ (value & 127) | 128,
51
+ ((value >> 7) & 127) | 128,
52
+ ((value >> 14) & 127) | 128,
53
+ (value >> 21) & 127
54
+ )
55
+ } else if (value < (2 ** 31) && value >= -(2 ** 31)) {
56
+ outEncodedData.push(
57
+ (value & 127) | 128,
58
+ ((value >> 7) & 127) | 128,
59
+ ((value >> 14) & 127) | 128,
60
+ ((value >> 21) & 127) | 128,
61
+ (value >> 28) & 127
62
+ )
63
+ } else {
64
+ throw new Error(`Value must be between -2147483648 and 2147483647`)
65
+ }
66
+ }
67
+
68
+ ////////////////////////////////////////////////////////////////////////////////////
69
+ // Decode
70
+ ////////////////////////////////////////////////////////////////////////////////////
71
+ export function decodeSignedInt32s(encodedData: ArrayLike<number>, outDecodedValues: number[]) {
72
+ for (let readIndex = 0; readIndex < encodedData.length;) {
73
+ let currentDecodedValue = 0
74
+ let shiftAmount = 0
75
+
76
+ while (true) {
77
+ const encodedByte = encodedData[readIndex++]
78
+ const lowest7Bits = encodedByte & 127
79
+
80
+ currentDecodedValue |= lowest7Bits << shiftAmount
81
+
82
+ // If 8th bit is 0, then this is the last byte in the sequence
83
+ if ((encodedByte & 128) === 0) {
84
+ // If 7th bit is 1, then the value is negative
85
+ if ((encodedByte & 64) !== 0) {
86
+ // If the value should be negative
87
+ // Ensure that the value is encoded as a negative number by
88
+ // setting all higher bits to 1
89
+ currentDecodedValue |= -1 << Math.min(shiftAmount + 7, 31)
90
+ }
91
+
92
+ break
93
+ }
94
+
95
+ if (readIndex === encodedData.length) {
96
+ throw new Error(`Invalid LEB128 data. Last encoded byte sequence is truncated.`)
97
+ }
98
+
99
+ shiftAmount += 7
100
+
101
+ if (shiftAmount > 31) {
102
+ throw new Error(`LEB128 sequence can't be decoded. Byte sequence extends beyond the range of a signed 32 bit integer.`)
103
+ }
104
+ }
105
+
106
+ outDecodedValues.push(currentDecodedValue)
107
+ }
108
+
109
+ return outDecodedValues
110
+ }
111
+
112
+ export function decodeSignedInt32sFast(encodedData: ArrayLike<number>, outDecodedValues: number[]) {
113
+ for (let readIndex = 0; readIndex < encodedData.length;) {
114
+ const byte0 = encodedData[readIndex++]
115
+
116
+ if ((byte0 & 128) === 0) {
117
+ let decodedValue =
118
+ (byte0 & 127)
119
+
120
+ if ((byte0 & 64) !== 0) {
121
+ decodedValue |= -1 << 7
122
+ }
123
+
124
+ outDecodedValues.push(decodedValue)
125
+
126
+ continue
127
+ }
128
+
129
+ const byte1 = encodedData[readIndex++]
130
+
131
+ if ((byte1 & 128) === 0) {
132
+ let decodedValue =
133
+ (byte0 & 127) |
134
+ (byte1 & 127) << 7
135
+
136
+ if ((byte1 & 64) !== 0) {
137
+ decodedValue |= -1 << 14
138
+ }
139
+
140
+ outDecodedValues.push(decodedValue)
141
+
142
+ continue
143
+ }
144
+
145
+ const byte2 = encodedData[readIndex++]
146
+
147
+ if ((byte2 & 128) === 0) {
148
+ let decodedValue =
149
+ (byte0 & 127) |
150
+ (byte1 & 127) << 7 |
151
+ (byte2 & 127) << 14
152
+
153
+ if ((byte2 & 64) !== 0) {
154
+ decodedValue |= -1 << 21
155
+ }
156
+
157
+ outDecodedValues.push(decodedValue)
158
+
159
+ continue
160
+ }
161
+
162
+ const byte3 = encodedData[readIndex++]
163
+
164
+ if ((byte3 & 128) === 0) {
165
+ let decodedValue =
166
+ (byte0 & 127) |
167
+ (byte1 & 127) << 7 |
168
+ (byte2 & 127) << 14 |
169
+ (byte3 & 127) << 21
170
+
171
+ if ((byte3 & 64) !== 0) {
172
+ decodedValue |= -1 << 28
173
+ }
174
+
175
+ outDecodedValues.push(decodedValue)
176
+
177
+ continue
178
+ }
179
+
180
+ const byte4 = encodedData[readIndex++]
181
+
182
+ if ((byte4 & 128) === 0) {
183
+ let decodedValue =
184
+ (byte0 & 127) |
185
+ (byte1 & 127) << 7 |
186
+ (byte2 & 127) << 14 |
187
+ (byte3 & 127) << 21 |
188
+ (byte4 & 127) << 28
189
+
190
+ if ((byte4 & 64) !== 0) {
191
+ decodedValue |= -1 << 31
192
+ }
193
+
194
+ outDecodedValues.push(decodedValue)
195
+
196
+ continue
197
+ }
198
+
199
+ if (readIndex >= encodedData.length) {
200
+ throw new Error(`Invalid LEB128 data. Last encoded byte sequence is truncated.`)
201
+ } else {
202
+ throw new Error(`LEB128 sequence can't be decoded. Encoded byte sequence represents a value that extends beyond the range of a signed 32 bit integer.`)
203
+ }
204
+ }
205
+
206
+ return outDecodedValues
207
+ }
208
+
209
+ ////////////////////////////////////////////////////////////////////////////////////
210
+ // Tests
211
+ ////////////////////////////////////////////////////////////////////////////////////
212
+ export function testLeb128() {
213
+ const encodedBytes: number[] = []
214
+ const decodedValues: number[] = []
215
+
216
+ function runTest(testValue: number) {
217
+ encodedBytes.length = 0
218
+ decodedValues.length = 0
219
+
220
+ encodeSignedInt32sFast(testValue, encodedBytes)
221
+ decodeSignedInt32sFast(encodedBytes, decodedValues)
222
+
223
+ if (decodedValues[0] !== testValue) {
224
+ throw new Error(`Expected ${testValue} but got ${decodedValues[0]}`)
225
+ }
226
+ }
227
+
228
+ for (let i = -(2 ** 22); i < 2 ** 22; i++) {
229
+ if (i % 1000000 === 0) {
230
+ logToStderr(i)
231
+ }
232
+
233
+ runTest(i)
234
+ }
235
+
236
+ const x = 1
237
+ }