_synthesizeSpeechmarks()

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;
      });
  }