in src/core/awspack/AbstractTextToSpeechFeature.js [692:777]
_synthesizeSpeechmarks(params) {
return this.constructor.SERVICES.polly
.synthesizeSpeech(params)
.promise()
.then(result => {
// Convert charcodes to string
const jsonString = JSON.stringify(result.AudioStream);
const json = JSON.parse(jsonString);
const dataStr = json.data.map(c => String.fromCharCode(c)).join('');
const markTypes = {
sentence: [],
word: [],
viseme: [],
ssml: [],
};
const endMarkTypes = {
sentence: null,
word: null,
viseme: null,
ssml: null,
};
// Split by enclosing {} to create speechmark objects
const speechMarks = [...dataStr.matchAll(/\{.*?\}(?=\n|$)/gm)].map(
match => {
const mark = JSON.parse(match[0]);
// Set the duration of the last speechmark stored matching this one's type
const numMarks = markTypes[mark.type].length;
if (numMarks > 0) {
const lastMark = markTypes[mark.type][numMarks - 1];
lastMark.duration = mark.time - lastMark.time;
}
markTypes[mark.type].push(mark);
endMarkTypes[mark.type] = mark;
return mark;
}
);
// Find the time of the latest speechmark
const endTimes = [];
if (endMarkTypes.sentence) {
endTimes.push(endMarkTypes.sentence.time);
}
if (endMarkTypes.word) {
endTimes.push(endMarkTypes.word.time);
}
if (endMarkTypes.viseme) {
endTimes.push(endMarkTypes.viseme.time);
}
if (endMarkTypes.ssml) {
endTimes.push(endMarkTypes.ssml.time);
}
const endTime = Math.max(...endTimes);
// Calculate duration for the ending speechMarks of each type
if (endMarkTypes.sentence) {
endMarkTypes.sentence.duration = Math.max(
this._minEndMarkDuration,
endTime - endMarkTypes.sentence.time
);
}
if (endMarkTypes.word) {
endMarkTypes.word.duration = Math.max(
this._minEndMarkDuration,
endTime - endMarkTypes.word.time
);
}
if (endMarkTypes.viseme) {
endMarkTypes.viseme.duration = Math.max(
this._minEndMarkDuration,
endTime - endMarkTypes.viseme.time
);
}
if (endMarkTypes.ssml) {
endMarkTypes.ssml.duration = Math.max(
this._minEndMarkDuration,
endTime - endMarkTypes.ssml.time
);
}
return speechMarks;
});
}