1
0

add initial marp implementation with sample content and build configuration

This commit is contained in:
2025-09-13 18:13:22 +02:00
parent dcacc9b409
commit e5f219507f
10319 changed files with 1402023 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
import { KeyCode } from '../common/event_util.js';
import { AudioRenderer } from './audio_renderer.js';
import { AuditoryDescription } from './auditory_description.js';
import { Span } from './span.js';
export declare abstract class AbstractAudioRenderer implements AudioRenderer {
private separator_;
abstract markup(descrs: AuditoryDescription[]): string;
set separator(sep: string);
get separator(): string;
error(_key: KeyCode | string): string | null;
merge(spans: Span[]): string;
finalize(str: string): string;
pauseValue(value: string): number;
}

View File

@@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractAudioRenderer = void 0;
const engine_js_1 = require("../common/engine.js");
class AbstractAudioRenderer {
constructor() {
this.separator_ = ' ';
}
set separator(sep) {
this.separator_ = sep;
}
get separator() {
return engine_js_1.Engine.getInstance().modality === 'braille' ? '' : this.separator_;
}
error(_key) {
return null;
}
merge(spans) {
let str = '';
const len = spans.length - 1;
for (let i = 0, span; (span = spans[i]); i++) {
str += span.speech;
if (i < len) {
const sep = span.attributes['separator'];
str += sep !== undefined ? sep : this.separator;
}
}
return str;
}
finalize(str) {
return str;
}
pauseValue(value) {
let numeric;
switch (value) {
case 'long':
numeric = 750;
break;
case 'medium':
numeric = 500;
break;
case 'short':
numeric = 250;
break;
default:
numeric = parseInt(value, 10);
}
return Math.floor((numeric * engine_js_1.Engine.getInstance().getRate()) / 100);
}
}
exports.AbstractAudioRenderer = AbstractAudioRenderer;

View File

@@ -0,0 +1,11 @@
import * as EngineConst from '../common/engine_const.js';
import * as AudioUtil from './audio_util.js';
import { AuditoryDescription } from './auditory_description.js';
import { MarkupRenderer } from './markup_renderer.js';
export declare class AcssRenderer extends MarkupRenderer {
markup(descrs: AuditoryDescription[]): string;
error(key: number): string;
prosodyElement(key: EngineConst.personalityProps, value: number): string;
pause(pause: AudioUtil.Pause): string;
private prosody_;
}

View File

@@ -0,0 +1,67 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AcssRenderer = void 0;
const EngineConst = require("../common/engine_const.js");
const EventUtil = require("../common/event_util.js");
const AudioUtil = require("./audio_util.js");
const markup_renderer_js_1 = require("./markup_renderer.js");
class AcssRenderer extends markup_renderer_js_1.MarkupRenderer {
markup(descrs) {
this.setScaleFunction(-2, 2, 0, 10, 0);
const markup = AudioUtil.personalityMarkup(descrs);
const result = [];
const currentPers = { open: [] };
let pause = null;
let isString = false;
for (let i = 0, descr; (descr = markup[i]); i++) {
if (AudioUtil.isMarkupElement(descr)) {
AudioUtil.mergeMarkup(currentPers, descr);
continue;
}
if (AudioUtil.isPauseElement(descr)) {
if (isString) {
pause = AudioUtil.mergePause(pause, descr, Math.max);
}
continue;
}
const str = '"' + this.merge(descr.span) + '"';
isString = true;
if (pause) {
result.push(this.pause(pause));
pause = null;
}
const prosody = this.prosody_(currentPers);
result.push(prosody ? '(text (' + prosody + ') ' + str + ')' : str);
}
return '(exp ' + result.join(' ') + ')';
}
error(key) {
return '(error "' + EventUtil.Move.get(key) + '")';
}
prosodyElement(key, value) {
value = this.applyScaleFunction(value);
switch (key) {
case EngineConst.personalityProps.RATE:
return '(richness . ' + value + ')';
case EngineConst.personalityProps.PITCH:
return '(average-pitch . ' + value + ')';
case EngineConst.personalityProps.VOLUME:
return '(stress . ' + value + ')';
}
return '(value . ' + value + ')';
}
pause(pause) {
return ('(pause . ' +
this.pauseValue(pause[EngineConst.personalityProps.PAUSE]) +
')');
}
prosody_(pros) {
const keys = pros.open;
const result = [];
for (let i = 0, key; (key = keys[i]); i++) {
result.push(this.prosodyElement(key, pros[key]));
}
return result.join(' ');
}
}
exports.AcssRenderer = AcssRenderer;

View File

@@ -0,0 +1,10 @@
import { KeyCode } from '../common/event_util.js';
import { AuditoryDescription } from './auditory_description.js';
import { Span } from './span.js';
export interface AudioRenderer {
separator: string;
markup(descrs: AuditoryDescription[]): string;
error(key: KeyCode | string): string | null;
merge(strs: Span[]): string;
finalize(str: string): string;
}

View File

@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@@ -0,0 +1,19 @@
import * as EngineConst from '../common/engine_const.js';
import { AuditoryDescription } from './auditory_description.js';
export interface Tags {
open?: EngineConst.personalityProps[];
close?: EngineConst.personalityProps[];
[personality: string]: any;
}
export type PauseValue = number | string;
export interface Pause {
pause: PauseValue;
[personality: string]: any;
}
export type Markup = Pause | Tags;
export declare function mergePause(oldPause: Pause | null, newPause: Pause, opt_merge?: (p1: PauseValue, p2: PauseValue) => PauseValue): Pause;
export declare function mergeMarkup(oldPers: Tags, newPers: Tags): void;
export declare function sortClose(open: EngineConst.personalityProps[], descrs: Tags[]): EngineConst.personalityProps[];
export declare function personalityMarkup(descrs: AuditoryDescription[]): Markup[];
export declare function isMarkupElement(element: Markup): boolean;
export declare function isPauseElement(element: Markup): boolean;

300
node_modules/speech-rule-engine/js/audio/audio_util.js generated vendored Normal file
View File

@@ -0,0 +1,300 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergePause = mergePause;
exports.mergeMarkup = mergeMarkup;
exports.sortClose = sortClose;
exports.personalityMarkup = personalityMarkup;
exports.isMarkupElement = isMarkupElement;
exports.isPauseElement = isPauseElement;
const base_util_js_1 = require("../common/base_util.js");
const EngineConst = require("../common/engine_const.js");
const engine_js_1 = require("../common/engine.js");
const span_js_1 = require("./span.js");
function mergePause(oldPause, newPause, opt_merge) {
if (!oldPause) {
return newPause;
}
return { pause: mergePause_(oldPause.pause, newPause.pause, opt_merge) };
}
function mergePause_(oldPause, newPause, opt_merge) {
const merge = opt_merge ||
function (x, y) {
if (typeof x === 'number' && typeof y === 'number') {
return x + y;
}
if (typeof x === 'number') {
return y;
}
if (typeof y === 'number') {
return x;
}
return [oldPause, newPause].sort()[0];
};
return merge.call(null, oldPause, newPause);
}
function mergeMarkup(oldPers, newPers) {
delete oldPers.open;
newPers.close.forEach((x) => delete oldPers[x]);
newPers.open.forEach((x) => (oldPers[x] = newPers[x]));
const keys = Object.keys(oldPers);
oldPers.open = keys;
}
function sortClose(open, descrs) {
if (open.length <= 1) {
return open;
}
const result = [];
for (let i = 0, descr; (descr = descrs[i]), open.length; i++) {
if (!descr.close || !descr.close.length) {
continue;
}
descr.close.forEach(function (x) {
const index = open.indexOf(x);
if (index !== -1) {
result.unshift(x);
open.splice(index, 1);
}
});
}
return result;
}
let PersonalityRanges_ = {};
let LastOpen_ = [];
function personalityMarkup(descrs) {
PersonalityRanges_ = {};
LastOpen_ = [];
let result = [];
const currentPers = {};
for (let i = 0, descr; (descr = descrs[i]); i++) {
let pause = null;
const span = descr.descriptionSpan();
const pers = descr.personality;
const join = pers[EngineConst.personalityProps.JOIN];
delete pers[EngineConst.personalityProps.JOIN];
if (typeof pers[EngineConst.personalityProps.PAUSE] !== 'undefined') {
pause = {
[EngineConst.personalityProps.PAUSE]: pers[EngineConst.personalityProps.PAUSE]
};
delete pers[EngineConst.personalityProps.PAUSE];
}
const diff = personalityDiff_(pers, currentPers);
appendMarkup_(result, span, diff, join, pause, true);
}
result = result.concat(finaliseMarkup_());
result = simplifyMarkup_(result);
result = engine_js_1.Engine.getInstance().cleanpause ? cleanPause(result) : result;
return result;
}
function cleanPause(markup) {
while (isPauseElement(markup[0])) {
markup.shift();
}
while (isPauseElement(markup[markup.length - 1])) {
markup.pop();
}
return markup;
}
function appendElement_(markup, element) {
const last = markup[markup.length - 1];
if (!last) {
markup.push(element);
return;
}
if (isSpanElement(element) && isSpanElement(last)) {
if (typeof last.join === 'undefined') {
last.span = last.span.concat(element.span);
return;
}
const lstr = last['span'].pop();
const fstr = element['span'].shift();
last['span'].push(lstr + last.join + fstr);
last['span'] = last['span'].concat(element.span);
last.join = element.join;
return;
}
if (isPauseElement(element) && isPauseElement(last)) {
last.pause = mergePause_(last.pause, element.pause);
return;
}
markup.push(element);
}
function simplifyMarkup_(markup) {
const lastPers = {};
const result = [];
for (let i = 0, element; (element = markup[i]); i++) {
if (!isMarkupElement(element)) {
appendElement_(result, element);
continue;
}
if (!element.close || element.close.length !== 1 || element.open.length) {
copyValues_(element, lastPers);
result.push(element);
continue;
}
let nextElement = markup[i + 1];
if (!nextElement || isSpanElement(nextElement)) {
copyValues_(element, lastPers);
result.push(element);
continue;
}
const pauseElement = isPauseElement(nextElement) ? nextElement : null;
if (pauseElement) {
nextElement = markup[i + 2];
}
if (nextElement &&
isMarkupElement(nextElement) &&
nextElement.open[0] === element.close[0] &&
!nextElement.close.length &&
nextElement[nextElement.open[0]] === lastPers[nextElement.open[0]]) {
if (pauseElement) {
appendElement_(result, pauseElement);
i = i + 2;
}
else {
i = i + 1;
}
}
else {
copyValues_(element, lastPers);
result.push(element);
}
}
return result;
}
function copyValues_(from, to) {
if (from['rate']) {
to['rate'] = from['rate'];
}
if (from['pitch']) {
to['pitch'] = from['pitch'];
}
if (from['volume']) {
to['volume'] = from['volume'];
}
}
function finaliseMarkup_() {
const final = [];
for (let i = LastOpen_.length - 1; i >= 0; i--) {
const pers = LastOpen_[i];
if (pers.length) {
const markup = { open: [], close: [] };
for (let j = 0; j < pers.length; j++) {
const per = pers[j];
markup.close.push(per);
markup[per] = 0;
}
final.push(markup);
}
}
return final;
}
function isMarkupElement(element) {
return typeof element === 'object' && element.open;
}
function isPauseElement(element) {
return (typeof element === 'object' &&
Object.keys(element).length === 1 &&
Object.keys(element)[0] === EngineConst.personalityProps.PAUSE);
}
function isSpanElement(element) {
const keys = Object.keys(element);
return (typeof element === 'object' &&
((keys.length === 1 && keys[0] === 'span') ||
(keys.length === 2 &&
((keys[0] === 'span' && keys[1] === 'join') ||
(keys[1] === 'span' && keys[0] === 'join')))));
}
function appendMarkup_(markup, span, pers, join, pause, merge = false) {
if (merge) {
const last = markup[markup.length - 1];
let oldJoin;
if (last) {
oldJoin = last[EngineConst.personalityProps.JOIN];
}
if (last && !span.speech && pause && isPauseElement(last)) {
const pauseProp = EngineConst.personalityProps.PAUSE;
last[pauseProp] = mergePause_(last[pauseProp], pause[pauseProp]);
pause = null;
}
if (last &&
span.speech &&
Object.keys(pers).length === 0 &&
isSpanElement(last)) {
if (typeof oldJoin !== 'undefined') {
const lastSpan = last['span'].pop();
span = span_js_1.Span.stringAttr(lastSpan.speech + oldJoin + span.speech, lastSpan.attributes);
}
last['span'].push(span);
span = span_js_1.Span.empty();
last[EngineConst.personalityProps.JOIN] = join;
}
}
if (Object.keys(pers).length !== 0) {
markup.push(pers);
}
if (span.speech) {
markup.push({ span: [span], join: join });
}
if (pause) {
markup.push(pause);
}
}
function personalityDiff_(current, old) {
if (!old) {
return current;
}
const result = {};
for (const prop of EngineConst.personalityPropList) {
const currentValue = current[prop];
const oldValue = old[prop];
if ((!currentValue && !oldValue) ||
(currentValue && oldValue && currentValue === oldValue)) {
continue;
}
const value = currentValue || 0;
if (!isMarkupElement(result)) {
result.open = [];
result.close = [];
}
if (!currentValue) {
result.close.push(prop);
}
if (!oldValue) {
result.open.push(prop);
}
if (oldValue && currentValue) {
result.close.push(prop);
result.open.push(prop);
}
old[prop] = value;
result[prop] = value;
PersonalityRanges_[prop]
? PersonalityRanges_[prop].push(value)
: (PersonalityRanges_[prop] = [value]);
}
if (isMarkupElement(result)) {
let c = result.close.slice();
while (c.length > 0) {
let lo = LastOpen_.pop();
const loNew = (0, base_util_js_1.setdifference)(lo, c);
c = (0, base_util_js_1.setdifference)(c, lo);
lo = loNew;
if (c.length === 0) {
if (lo.length !== 0) {
LastOpen_.push(lo);
}
continue;
}
if (lo.length === 0) {
continue;
}
result.close = result.close.concat(lo);
result.open = result.open.concat(lo);
for (let i = 0, open; (open = lo[i]); i++) {
result[open] = old[open];
}
}
LastOpen_.push(result.open);
}
return result;
}

View File

@@ -0,0 +1,66 @@
import { Span } from './span.js';
interface AudioDescr {
context?: string;
text: string;
userValue?: string;
annotation?: string;
attributes?: {
[key: string]: string;
};
personality?: {
[key: string]: string;
};
layout?: string;
}
interface AudioFlags {
adjust?: boolean;
preprocess?: boolean;
correct?: boolean;
translate?: boolean;
}
export declare class AuditoryItem {
data: AuditoryDescription;
prev: AuditoryItem;
next: AuditoryItem;
constructor(data?: AuditoryDescription);
}
export declare class AuditoryList extends Set<AuditoryItem> {
annotations: AuditoryItem[];
private anchor;
constructor(descrs: AuditoryDescription[]);
first(): AuditoryItem;
last(): AuditoryItem;
push(item: AuditoryItem): void;
pop(): AuditoryItem;
delete(item: AuditoryItem): boolean;
insertAfter(descr: AuditoryDescription, item: AuditoryItem): void;
insertBefore(descr: AuditoryDescription, item: AuditoryItem): void;
prevText(item: AuditoryItem): AuditoryItem;
[Symbol.iterator](): IterableIterator<AuditoryItem>;
nextText(item: AuditoryItem): AuditoryItem;
clear(): void;
empty(): boolean;
toList(): AuditoryDescription[];
}
export declare class AuditoryDescription {
context: string;
text: string;
userValue: string;
annotation: string;
attributes: {
[key: string]: string;
};
personality: {
[key: string]: string;
};
layout: string;
static create(args: AudioDescr, flags?: AudioFlags): AuditoryDescription;
constructor({ context, text, userValue, annotation, attributes, personality, layout }: AudioDescr);
isEmpty(): boolean;
clone(): AuditoryDescription;
toString(): string;
descriptionString(): string;
descriptionSpan(): Span;
equals(that: AuditoryDescription): boolean;
}
export {};

View File

@@ -0,0 +1,185 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuditoryDescription = exports.AuditoryList = exports.AuditoryItem = void 0;
const grammar_js_1 = require("../rule_engine/grammar.js");
const span_js_1 = require("./span.js");
class AuditoryItem {
constructor(data = null) {
this.data = data;
this.prev = null;
this.next = null;
}
}
exports.AuditoryItem = AuditoryItem;
class AuditoryList extends Set {
constructor(descrs) {
super();
this.annotations = [];
this.anchor = new AuditoryItem();
this.anchor.next = this.anchor;
this.anchor.prev = this.anchor;
descrs.forEach((d) => {
const item = new AuditoryItem(d);
if (d.annotation) {
this.annotations.push(item);
}
this.push(item);
});
}
first() {
return this.empty ? null : this.anchor.next;
}
last() {
return this.empty ? null : this.anchor.prev;
}
push(item) {
item.next = this.anchor;
item.prev = this.anchor.prev;
item.prev.next = item;
this.anchor.prev = item;
super.add(item);
}
pop() {
const item = this.last();
if (!item) {
return null;
}
this.delete(item);
return item;
}
delete(item) {
if (!this.has(item)) {
return false;
}
super.delete(item);
item.prev.next = item.next;
item.next = item.prev;
return true;
}
insertAfter(descr, item) {
this.insertBefore(descr, item.next);
}
insertBefore(descr, item) {
const nitem = new AuditoryItem(descr);
if (!item || !this.has(item)) {
this.push(nitem);
return;
}
item.prev.next = nitem;
nitem.prev = item.prev;
nitem.next = item;
item.prev = nitem;
}
prevText(item) {
do {
item = item.prev;
} while (item !== this.anchor && !item.data.text);
return item === this.anchor ? null : item;
}
*[Symbol.iterator]() {
let current = this.anchor.next;
while (current !== this.anchor) {
yield current;
current = current.next;
}
}
nextText(item) {
while (item !== this.anchor && !item.data.text) {
item = item.next;
}
return item;
}
clear() {
this.anchor.next = this.anchor;
this.anchor.prev = this.anchor;
super.clear();
}
empty() {
return this.anchor.prev === this.anchor && this.anchor === this.anchor.next;
}
toList() {
const result = [];
let item = this.anchor.next;
while (item !== this.anchor) {
result.push(item.data);
item = item.next;
}
return result;
}
}
exports.AuditoryList = AuditoryList;
class AuditoryDescription {
static create(args, flags = {}) {
args.text = grammar_js_1.Grammar.getInstance().apply(args.text, flags);
return new AuditoryDescription(args);
}
constructor({ context, text, userValue, annotation, attributes, personality, layout }) {
this.context = context || '';
this.text = text || '';
this.userValue = userValue || '';
this.annotation = annotation || '';
this.attributes = attributes || {};
this.personality = personality || {};
this.layout = layout || '';
}
isEmpty() {
return (this.context.length === 0 &&
this.text.length === 0 &&
this.userValue.length === 0 &&
this.annotation.length === 0);
}
clone() {
let personality;
if (this.personality) {
personality = {};
for (const [key, val] of Object.entries(this.personality)) {
personality[key] = val;
}
}
let attributes;
if (this.attributes) {
attributes = {};
for (const [key, val] of Object.entries(this.attributes)) {
attributes[key] = val;
}
}
return new AuditoryDescription({
context: this.context,
text: this.text,
userValue: this.userValue,
annotation: this.annotation,
personality: personality,
attributes: attributes,
layout: this.layout
});
}
toString() {
return ('AuditoryDescription(context="' +
this.context +
'" ' +
' text="' +
this.text +
'" ' +
' userValue="' +
this.userValue +
'" ' +
' annotation="' +
this.annotation +
'")');
}
descriptionString() {
return this.context && this.text
? this.context + ' ' + this.text
: this.context || this.text;
}
descriptionSpan() {
return span_js_1.Span.stringAttr(this.descriptionString(), this.attributes);
}
equals(that) {
return (this.context === that.context &&
this.text === that.text &&
this.userValue === that.userValue &&
this.annotation === that.annotation);
}
}
exports.AuditoryDescription = AuditoryDescription;

View File

@@ -0,0 +1,12 @@
import * as EngineConst from '../common/engine_const.js';
import { AudioRenderer } from './audio_renderer.js';
import { AuditoryDescription } from './auditory_description.js';
import { Span } from './span.js';
export declare function setSeparator(sep: string): void;
export declare function getSeparator(): string;
export declare function markup(descrs: AuditoryDescription[]): string;
export declare function merge(strs: (Span | string)[]): string;
export declare function finalize(str: string): string;
export declare function error(key: string): string;
export declare function registerRenderer(type: EngineConst.Markup, renderer: AudioRenderer): void;
export declare function isXml(): boolean;

View File

@@ -0,0 +1,78 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setSeparator = setSeparator;
exports.getSeparator = getSeparator;
exports.markup = markup;
exports.merge = merge;
exports.finalize = finalize;
exports.error = error;
exports.registerRenderer = registerRenderer;
exports.isXml = isXml;
const engine_js_1 = require("../common/engine.js");
const EngineConst = require("../common/engine_const.js");
const acss_renderer_js_1 = require("./acss_renderer.js");
const layout_renderer_js_1 = require("./layout_renderer.js");
const punctuation_renderer_js_1 = require("./punctuation_renderer.js");
const sable_renderer_js_1 = require("./sable_renderer.js");
const span_js_1 = require("./span.js");
const ssml_renderer_js_1 = require("./ssml_renderer.js");
const string_renderer_js_1 = require("./string_renderer.js");
const xml_renderer_js_1 = require("./xml_renderer.js");
const xmlInstance = new ssml_renderer_js_1.SsmlRenderer();
const renderers = new Map([
[EngineConst.Markup.NONE, new string_renderer_js_1.StringRenderer()],
[EngineConst.Markup.COUNTING, new string_renderer_js_1.CountingRenderer()],
[EngineConst.Markup.PUNCTUATION, new punctuation_renderer_js_1.PunctuationRenderer()],
[EngineConst.Markup.LAYOUT, new layout_renderer_js_1.LayoutRenderer()],
[EngineConst.Markup.ACSS, new acss_renderer_js_1.AcssRenderer()],
[EngineConst.Markup.SABLE, new sable_renderer_js_1.SableRenderer()],
[EngineConst.Markup.VOICEXML, xmlInstance],
[EngineConst.Markup.SSML, xmlInstance]
]);
function setSeparator(sep) {
const renderer = renderers.get(engine_js_1.Engine.getInstance().markup);
if (renderer) {
renderer.separator = sep;
}
}
function getSeparator() {
const renderer = renderers.get(engine_js_1.Engine.getInstance().markup);
return renderer ? renderer.separator : '';
}
function markup(descrs) {
const renderer = renderers.get(engine_js_1.Engine.getInstance().markup);
if (!renderer) {
return '';
}
return renderer.markup(descrs);
}
function merge(strs) {
const span = strs.map((s) => {
return typeof s === 'string' ? span_js_1.Span.stringEmpty(s) : s;
});
const renderer = renderers.get(engine_js_1.Engine.getInstance().markup);
if (!renderer) {
return strs.join();
}
return renderer.merge(span);
}
function finalize(str) {
const renderer = renderers.get(engine_js_1.Engine.getInstance().markup);
if (!renderer) {
return str;
}
return renderer.finalize(str);
}
function error(key) {
const renderer = renderers.get(engine_js_1.Engine.getInstance().markup);
if (!renderer) {
return '';
}
return renderer.error(key);
}
function registerRenderer(type, renderer) {
renderers.set(type, renderer);
}
function isXml() {
return renderers.get(engine_js_1.Engine.getInstance().markup) instanceof xml_renderer_js_1.XmlRenderer;
}

View File

@@ -0,0 +1,17 @@
import * as AudioUtil from './audio_util.js';
import { AuditoryDescription } from './auditory_description.js';
import { XmlRenderer } from './xml_renderer.js';
export declare class LayoutRenderer extends XmlRenderer {
static options: {
cayleyshort: boolean;
linebreaks: boolean;
};
finalize(str: string): string;
pause(_pause: AudioUtil.Pause): string;
prosodyElement(attr: string, value: number): string;
closeTag(tag: string): string;
markup(descrs: AuditoryDescription[]): string;
private processContent;
private values;
private layoutValue;
}

View File

@@ -0,0 +1,372 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LayoutRenderer = void 0;
const debugger_js_1 = require("../common/debugger.js");
const DomUtil = require("../common/dom_util.js");
const EngineConst = require("../common/engine_const.js");
const engine_js_1 = require("../common/engine.js");
const AudioUtil = require("./audio_util.js");
const xml_renderer_js_1 = require("./xml_renderer.js");
class LayoutRenderer extends xml_renderer_js_1.XmlRenderer {
constructor() {
super(...arguments);
this.values = new Map();
}
finalize(str) {
setRelValues(this.values.get('rel'));
return setTwoDim(str);
}
pause(_pause) {
return '';
}
prosodyElement(attr, value) {
return attr === EngineConst.personalityProps.LAYOUT ? `<${value}>` : '';
}
closeTag(tag) {
return `</${tag}>`;
}
markup(descrs) {
this.values.clear();
const result = [];
let content = [];
for (const descr of descrs) {
if (!descr.layout) {
content.push(descr);
continue;
}
result.push(this.processContent(content));
content = [];
const [pref, layout, value] = this.layoutValue(descr.layout);
if (pref === 'begin') {
result.push('<' + layout + (value ? ` value="${value}"` : '') + '>');
continue;
}
if (pref === 'end') {
result.push('</' + layout + '>');
continue;
}
console.warn('Something went wrong with layout markup: ' + layout);
}
result.push(this.processContent(content));
return result.join('');
}
processContent(content) {
const result = [];
const markup = AudioUtil.personalityMarkup(content);
for (let i = 0, descr; (descr = markup[i]); i++) {
if (descr.span) {
result.push(this.merge(descr.span));
continue;
}
if (AudioUtil.isPauseElement(descr)) {
continue;
}
}
return result.join('');
}
layoutValue(layout) {
const match = layout.match(/^(begin|end|)(.*\D)(\d*)$/);
const value = match[3];
if (!value) {
return [match[1], match[2], ''];
}
layout = match[2];
if (!this.values.has(layout)) {
this.values.set(layout, {});
}
this.values.get(layout)[value] = true;
return [match[1], layout, value];
}
}
exports.LayoutRenderer = LayoutRenderer;
LayoutRenderer.options = {
cayleyshort: engine_js_1.Engine.getInstance().cayleyshort,
linebreaks: engine_js_1.Engine.getInstance().linebreaks
};
let twodExpr = '';
const handlers = {
TABLE: handleTable,
CASES: handleCases,
CAYLEY: handleCayley,
MATRIX: handleMatrix,
CELL: recurseTree,
FENCE: recurseTree,
ROW: recurseTree,
FRACTION: handleFraction,
NUMERATOR: handleFractionPart,
DENOMINATOR: handleFractionPart,
REL: handleRelation,
OP: handleRelation
};
function applyHandler(element) {
const tag = DomUtil.tagName(element);
const handler = handlers[tag];
return handler ? handler(element) : element.textContent;
}
const relValues = new Map();
function setRelValues(values) {
relValues.clear();
if (!values)
return;
const keys = Object.keys(values)
.map((x) => parseInt(x))
.sort();
for (let i = 0, key; (key = keys[i]); i++) {
relValues.set(key, i + 1);
}
}
function setTwoDim(str) {
twodExpr = '';
const dom = DomUtil.parseInput(`<all>${str}</all>`);
debugger_js_1.Debugger.getInstance().output(DomUtil.formatXml(dom.toString()));
twodExpr = recurseTree(dom);
return twodExpr;
}
function combineContent(str1, str2) {
if (!str1 || !str2) {
return str1 + str2;
}
const height1 = strHeight(str1);
const height2 = strHeight(str2);
const diff = height1 - height2;
str1 = diff < 0 ? padCell(str1, height2, strWidth(str1)) : str1;
str2 = diff > 0 ? padCell(str2, height1, strWidth(str2)) : str2;
const lines1 = str1.split(/\r\n|\r|\n/);
const lines2 = str2.split(/\r\n|\r|\n/);
const result = [];
for (let i = 0; i < lines1.length; i++) {
result.push(lines1[i] + lines2[i]);
}
return result.join('\n');
}
function recurseTree(dom) {
let result = '';
for (const child of Array.from(dom.childNodes)) {
if (child.nodeType === DomUtil.NodeType.TEXT_NODE) {
result = combineContent(result, child.textContent);
continue;
}
result = combineContent(result, applyHandler(child));
}
return result;
}
function strHeight(str) {
return str.split(/\r\n|\r|\n/).length;
}
function strWidth(str) {
return str.split(/\r\n|\r|\n/).reduce((max, x) => Math.max(x.length, max), 0);
}
function padHeight(str, height) {
const padding = height - strHeight(str);
return str + (padding > 0 ? new Array(padding + 1).join('\n') : '');
}
function padWidth(str, width) {
const lines = str.split(/\r\n|\r|\n/);
const result = [];
for (const line of lines) {
const padding = width - line.length;
result.push(line + (padding > 0 ? new Array(padding + 1).join('') : ''));
}
return result.join('\n');
}
function padCell(str, height, width) {
str = padHeight(str, height);
return padWidth(str, width);
}
function assembleRows(matrix) {
const children = Array.from(matrix.childNodes);
const mat = [];
for (const row of children) {
if (row.nodeType !== DomUtil.NodeType.ELEMENT_NODE) {
continue;
}
mat.push(handleRow(row));
}
return mat;
}
function getMaxParameters(mat) {
const maxHeight = mat.reduce((max, x) => Math.max(x.height, max), 0);
const maxWidth = [];
for (let i = 0; i < mat[0].width.length; i++) {
maxWidth.push(mat.map((x) => x.width[i]).reduce((max, x) => Math.max(max, x), 0));
}
return [maxHeight, maxWidth];
}
function combineCells(mat, maxWidth) {
const newMat = [];
for (const row of mat) {
if (row.height === 0) {
continue;
}
const newCells = [];
for (let i = 0; i < row.cells.length; i++) {
newCells.push(padCell(row.cells[i], row.height, maxWidth[i]));
}
row.cells = newCells;
newMat.push(row);
}
return newMat;
}
function combineRows(mat, maxHeight) {
if (maxHeight === 1) {
return mat
.map((row) => row.lfence + row.cells.join(row.sep) + row.rfence)
.join('\n');
}
const result = [];
for (const row of mat) {
const sep = verticalArrange(row.sep, row.height);
let str = row.cells.shift();
while (row.cells.length) {
str = combineContent(str, sep);
str = combineContent(str, row.cells.shift());
}
str = combineContent(verticalArrange(row.lfence, row.height), str);
str = combineContent(str, verticalArrange(row.rfence, row.height));
result.push(str);
result.push(row.lfence + new Array(strWidth(str) - 3).join(row.sep) + row.rfence);
}
return result.slice(0, -1).join('\n');
}
function verticalArrange(char, height) {
let str = '';
while (height) {
str += char + '\n';
height--;
}
return str.slice(0, -1);
}
function getFence(node) {
if (node.nodeType === DomUtil.NodeType.ELEMENT_NODE &&
DomUtil.tagName(node) === 'FENCE') {
return applyHandler(node);
}
return '';
}
function handleMatrix(matrix) {
let mat = assembleRows(matrix);
const [maxHeight, maxWidth] = getMaxParameters(mat);
mat = combineCells(mat, maxWidth);
return combineRows(mat, maxHeight);
}
function handleTable(table) {
let mat = assembleRows(table);
mat.forEach((row) => {
row.cells = row.cells.slice(1).slice(0, -1);
row.width = row.width.slice(1).slice(0, -1);
});
const [maxHeight, maxWidth] = getMaxParameters(mat);
mat = combineCells(mat, maxWidth);
return combineRows(mat, maxHeight);
}
function handleCases(cases) {
let mat = assembleRows(cases);
mat.forEach((row) => {
row.cells = row.cells.slice(0, -1);
row.width = row.width.slice(0, -1);
});
const [maxHeight, maxWidth] = getMaxParameters(mat);
mat = combineCells(mat, maxWidth);
return combineRows(mat, maxHeight);
}
function handleCayley(cayley) {
let mat = assembleRows(cayley);
mat.forEach((row) => {
row.cells = row.cells.slice(1).slice(0, -1);
row.width = row.width.slice(1).slice(0, -1);
row.sep = row.sep + row.sep;
});
const [maxHeight, maxWidth] = getMaxParameters(mat);
const bar = {
lfence: '',
rfence: '',
cells: maxWidth.map((x) => '⠐' + new Array(x).join('⠒')),
width: maxWidth,
height: 1,
sep: mat[0].sep
};
if (engine_js_1.Engine.getInstance().cayleyshort && mat[0].cells[0] === '') {
bar.cells[0] = '';
}
mat.splice(1, 0, bar);
mat = combineCells(mat, maxWidth);
return combineRows(mat, maxHeight);
}
function handleRow(row) {
const children = Array.from(row.childNodes);
const lfence = getFence(children[0]);
const rfence = getFence(children[children.length - 1]);
if (lfence) {
children.shift();
}
if (rfence) {
children.pop();
}
let sep = '';
const cells = [];
for (const child of children) {
if (child.nodeType === DomUtil.NodeType.TEXT_NODE) {
sep = child.textContent;
continue;
}
const result = applyHandler(child);
cells.push(result);
}
return {
lfence: lfence,
rfence: rfence,
sep: sep,
cells: cells,
height: cells.reduce((max, x) => Math.max(strHeight(x), max), 0),
width: cells.map(strWidth)
};
}
function centerCell(cell, width) {
const cw = strWidth(cell);
const center = (width - cw) / 2;
const [lpad, rpad] = Math.floor(center) === center
? [center, center]
: [Math.floor(center), Math.ceil(center)];
const lines = cell.split(/\r\n|\r|\n/);
const result = [];
const [lstr, rstr] = [
new Array(lpad + 1).join(''),
new Array(rpad + 1).join('')
];
for (const line of lines) {
result.push(lstr + line + rstr);
}
return result.join('\n');
}
function handleFraction(frac) {
const [open, num, , den, close] = Array.from(frac.childNodes);
const numerator = applyHandler(num);
const denominator = applyHandler(den);
const nwidth = strWidth(numerator);
const dwidth = strWidth(denominator);
let maxWidth = Math.max(nwidth, dwidth);
const bar = open + new Array(maxWidth + 1).join('⠒') + close;
maxWidth = bar.length;
return (`${centerCell(numerator, maxWidth)}\n${bar}\n` +
`${centerCell(denominator, maxWidth)}`);
}
function handleFractionPart(prt) {
const fchild = prt.firstChild;
const content = recurseTree(prt);
if (fchild && fchild.nodeType === DomUtil.NodeType.ELEMENT_NODE) {
if (DomUtil.tagName(fchild) === 'ENGLISH') {
return '⠰' + content;
}
if (DomUtil.tagName(fchild) === 'NUMBER') {
return '⠼' + content;
}
}
return content;
}
function handleRelation(rel) {
if (!engine_js_1.Engine.getInstance().linebreaks) {
return recurseTree(rel);
}
const value = relValues.get(parseInt(rel.getAttribute('value')));
return (value ? `<br value="${value}"/>` : '') + recurseTree(rel);
}

View File

@@ -0,0 +1,11 @@
import { AbstractAudioRenderer } from './abstract_audio_renderer.js';
import { Pause } from './audio_util.js';
export declare abstract class MarkupRenderer extends AbstractAudioRenderer {
protected ignoreElements: string[];
private scaleFunction;
abstract pause(pause: Pause): void;
abstract prosodyElement(key: string, value: number): void;
setScaleFunction(a: number, b: number, c: number, d: number, decimals?: number): void;
applyScaleFunction(value: number): number;
protected ignoreElement(key: string): boolean;
}

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MarkupRenderer = void 0;
const EngineConst = require("../common/engine_const.js");
const abstract_audio_renderer_js_1 = require("./abstract_audio_renderer.js");
class MarkupRenderer extends abstract_audio_renderer_js_1.AbstractAudioRenderer {
constructor() {
super(...arguments);
this.ignoreElements = [EngineConst.personalityProps.LAYOUT];
this.scaleFunction = null;
}
setScaleFunction(a, b, c, d, decimals = 0) {
this.scaleFunction = (x) => {
const delta = (x - a) / (b - a);
const num = c * (1 - delta) + d * delta;
return +(Math.round((num + 'e+' + decimals)) +
'e-' +
decimals);
};
}
applyScaleFunction(value) {
return this.scaleFunction ? this.scaleFunction(value) : value;
}
ignoreElement(key) {
return this.ignoreElements.indexOf(key) !== -1;
}
}
exports.MarkupRenderer = MarkupRenderer;

View File

@@ -0,0 +1,8 @@
import { AbstractAudioRenderer } from './abstract_audio_renderer.js';
import * as AudioUtil from './audio_util.js';
import { AuditoryDescription } from './auditory_description.js';
export declare class PunctuationRenderer extends AbstractAudioRenderer {
private static PAUSE_PUNCTUATION;
markup(descrs: AuditoryDescription[]): string;
pause(pause: AudioUtil.PauseValue): string;
}

View File

@@ -0,0 +1,54 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PunctuationRenderer = void 0;
const EngineConst = require("../common/engine_const.js");
const abstract_audio_renderer_js_1 = require("./abstract_audio_renderer.js");
const AudioUtil = require("./audio_util.js");
class PunctuationRenderer extends abstract_audio_renderer_js_1.AbstractAudioRenderer {
markup(descrs) {
const markup = AudioUtil.personalityMarkup(descrs);
let str = '';
let pause = null;
let span = false;
for (let i = 0, descr; (descr = markup[i]); i++) {
if (AudioUtil.isMarkupElement(descr)) {
continue;
}
if (AudioUtil.isPauseElement(descr)) {
pause = descr;
continue;
}
if (pause) {
str += this.pause(pause[EngineConst.personalityProps.PAUSE]);
pause = null;
}
str += (span ? this.separator : '') + this.merge(descr.span);
span = true;
}
return str;
}
pause(pause) {
let newPause;
if (typeof pause === 'number') {
if (pause <= 250) {
newPause = 'short';
}
else if (pause <= 500) {
newPause = 'medium';
}
else {
newPause = 'long';
}
}
else {
newPause = pause;
}
return PunctuationRenderer.PAUSE_PUNCTUATION.get(newPause) || '';
}
}
exports.PunctuationRenderer = PunctuationRenderer;
PunctuationRenderer.PAUSE_PUNCTUATION = new Map([
['short', ','],
['medium', ';'],
['long', '.']
]);

View File

@@ -0,0 +1,9 @@
import * as EngineConst from '../common/engine_const.js';
import { Pause } from './audio_util.js';
import { XmlRenderer } from './xml_renderer.js';
export declare class SableRenderer extends XmlRenderer {
finalize(str: string): string;
pause(pause: Pause): string;
prosodyElement(tag: EngineConst.personalityProps, value: number): string;
closeTag(tag: string): string;
}

View File

@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SableRenderer = void 0;
const EngineConst = require("../common/engine_const.js");
const xml_renderer_js_1 = require("./xml_renderer.js");
class SableRenderer extends xml_renderer_js_1.XmlRenderer {
finalize(str) {
return ('<?xml version="1.0"?>' +
'<!DOCTYPE SABLE PUBLIC "-//SABLE//DTD SABLE speech mark up//EN"' +
' "Sable.v0_2.dtd" []><SABLE>' +
this.separator +
str +
this.separator +
'</SABLE>');
}
pause(pause) {
return ('<BREAK ' +
'MSEC="' +
this.pauseValue(pause[EngineConst.personalityProps.PAUSE]) +
'"/>');
}
prosodyElement(tag, value) {
value = this.applyScaleFunction(value);
switch (tag) {
case EngineConst.personalityProps.PITCH:
return '<PITCH RANGE="' + value + '%">';
case EngineConst.personalityProps.RATE:
return '<RATE SPEED="' + value + '%">';
case EngineConst.personalityProps.VOLUME:
return '<VOLUME LEVEL="' + value + '%">';
default:
return '<' + tag.toUpperCase() + ' VALUE="' + value + '">';
}
}
closeTag(tag) {
return '</' + tag.toUpperCase() + '>';
}
}
exports.SableRenderer = SableRenderer;

15
node_modules/speech-rule-engine/js/audio/span.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
export type SpanAttrs = {
[key: string]: string;
};
export declare class Span {
speech: string;
attributes: SpanAttrs;
constructor(speech: string, attributes: SpanAttrs);
static empty(): Span;
static stringEmpty(str: string): Span;
static stringAttr(str: string, attr: SpanAttrs): Span;
static singleton(str: string, def?: SpanAttrs): Span[];
static node(str: string, node: Element, def?: SpanAttrs): Span;
static attributeList: string[];
static getAttributes(node: Element): SpanAttrs;
}

37
node_modules/speech-rule-engine/js/audio/span.js generated vendored Normal file
View File

@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Span = void 0;
class Span {
constructor(speech, attributes) {
this.speech = speech;
this.attributes = attributes;
}
static empty() {
return new Span('', {});
}
static stringEmpty(str) {
return new Span(str, {});
}
static stringAttr(str, attr) {
return new Span(str, attr);
}
static singleton(str, def = {}) {
return [Span.stringAttr(str, def)];
}
static node(str, node, def = {}) {
const attr = Span.getAttributes(node);
Object.assign(attr, def);
return new Span(str, attr);
}
static getAttributes(node) {
const attrs = {};
for (const attr of Span.attributeList) {
if (node.hasAttribute(attr)) {
attrs[attr] = node.getAttribute(attr);
}
}
return attrs;
}
}
exports.Span = Span;
Span.attributeList = ['id', 'extid'];

View File

@@ -0,0 +1,17 @@
import { Pause } from './audio_util.js';
import { AuditoryDescription } from './auditory_description.js';
import { Span } from './span.js';
import { XmlRenderer } from './xml_renderer.js';
export declare class SsmlRenderer extends XmlRenderer {
finalize(str: string): string;
pause(pause: Pause): string;
prosodyElement(attr: string, value: number): string;
closeTag(_tag: string): string;
static MARK_ONCE: boolean;
static MARK_KIND: boolean;
private static CHARACTER_ATTR;
private static MARKS;
markup(descrs: AuditoryDescription[]): string;
merge(spans: Span[]): string;
private isEmptySpan;
}

View File

@@ -0,0 +1,86 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SsmlRenderer = void 0;
const engine_js_1 = require("../common/engine.js");
const EngineConst = require("../common/engine_const.js");
const xml_renderer_js_1 = require("./xml_renderer.js");
class SsmlRenderer extends xml_renderer_js_1.XmlRenderer {
finalize(str) {
return ('<?xml version="1.0"?><speak version="1.1"' +
' xmlns="http://www.w3.org/2001/10/synthesis"' +
` xml:lang="${engine_js_1.Engine.getInstance().locale}">` +
'<prosody rate="' +
engine_js_1.Engine.getInstance().getRate() +
'%">' +
this.separator +
str +
this.separator +
'</prosody></speak>');
}
pause(pause) {
return ('<break ' +
'time="' +
this.pauseValue(pause[EngineConst.personalityProps.PAUSE]) +
'ms"/>');
}
prosodyElement(attr, value) {
value = Math.floor(this.applyScaleFunction(value));
const valueStr = value < 0 ? value.toString() : '+' + value.toString();
return ('<prosody ' +
attr.toLowerCase() +
'="' +
valueStr +
(attr === EngineConst.personalityProps.VOLUME ? '>' : '%">'));
}
closeTag(_tag) {
return '</prosody>';
}
markup(descrs) {
SsmlRenderer.MARKS = {};
return super.markup(descrs);
}
merge(spans) {
const result = [];
let lastMark = '';
for (let i = 0; i < spans.length; i++) {
const span = spans[i];
if (this.isEmptySpan(span))
continue;
const kind = SsmlRenderer.MARK_KIND ? span.attributes['kind'] : '';
const id = engine_js_1.Engine.getInstance().automark
? span.attributes['id']
: engine_js_1.Engine.getInstance().mark
? span.attributes['extid']
: '';
if (id &&
id !== lastMark &&
!(SsmlRenderer.MARK_ONCE && SsmlRenderer.MARKS[id])) {
result.push(kind ? `<mark name="${id}" kind="${kind}"/>` : `<mark name="${id}"/>`);
lastMark = id;
SsmlRenderer.MARKS[id] = true;
}
if (engine_js_1.Engine.getInstance().character &&
span.speech.length === 1 &&
span.speech.match(/[a-zA-Z]/)) {
result.push('<say-as interpret-as="' +
SsmlRenderer.CHARACTER_ATTR +
'">' +
span.speech +
'</say-as>');
}
else {
result.push(span.speech);
}
}
return result.join(this.separator);
}
isEmptySpan(span) {
const sep = span.attributes['separator'];
return span.speech.match(/^\s*$/) && (!sep || sep.match(/^\s*$/));
}
}
exports.SsmlRenderer = SsmlRenderer;
SsmlRenderer.MARK_ONCE = false;
SsmlRenderer.MARK_KIND = true;
SsmlRenderer.CHARACTER_ATTR = 'character';
SsmlRenderer.MARKS = {};

View File

@@ -0,0 +1,8 @@
import { AbstractAudioRenderer } from './abstract_audio_renderer.js';
import { AuditoryDescription } from './auditory_description.js';
export declare class StringRenderer extends AbstractAudioRenderer {
markup(descrs: AuditoryDescription[]): string;
}
export declare class CountingRenderer extends StringRenderer {
finalize(str: string): string;
}

View File

@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CountingRenderer = exports.StringRenderer = void 0;
const engine_js_1 = require("../common/engine.js");
const abstract_audio_renderer_js_1 = require("./abstract_audio_renderer.js");
const audio_util_js_1 = require("./audio_util.js");
class StringRenderer extends abstract_audio_renderer_js_1.AbstractAudioRenderer {
markup(descrs) {
let str = '';
const markup = (0, audio_util_js_1.personalityMarkup)(descrs);
const clean = markup.filter((x) => x.span);
if (!clean.length) {
return str;
}
const len = clean.length - 1;
for (let i = 0, descr; (descr = clean[i]); i++) {
if (descr.span) {
str += this.merge(descr.span);
}
if (i >= len) {
continue;
}
const join = descr.join;
str += typeof join === 'undefined' ? this.separator : join;
}
return str;
}
}
exports.StringRenderer = StringRenderer;
class CountingRenderer extends StringRenderer {
finalize(str) {
const output = super.finalize(str);
const count = engine_js_1.Engine.getInstance().modality === 'braille' ? '⣿⠀⣿⠀⣿⠀⣿⠀⣿⠀' : '0123456789';
let second = new Array(Math.trunc(output.length / 10) + 1).join(count);
second += count.slice(0, output.length % 10);
return output + '\n' + second;
}
}
exports.CountingRenderer = CountingRenderer;

View File

@@ -0,0 +1,7 @@
import * as EngineConst from '../common/engine_const.js';
import { AuditoryDescription } from './auditory_description.js';
import { MarkupRenderer } from './markup_renderer.js';
export declare abstract class XmlRenderer extends MarkupRenderer {
abstract closeTag(tag: EngineConst.personalityProps): void;
markup(descrs: AuditoryDescription[]): string;
}

View File

@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.XmlRenderer = void 0;
const engine_js_1 = require("../common/engine.js");
const AudioUtil = require("./audio_util.js");
const markup_renderer_js_1 = require("./markup_renderer.js");
class XmlRenderer extends markup_renderer_js_1.MarkupRenderer {
markup(descrs) {
this.setScaleFunction(-2, 2, -100, 100, 2);
const markup = AudioUtil.personalityMarkup(descrs);
const result = [];
const currentOpen = [];
for (let i = 0, descr; (descr = markup[i]); i++) {
if (descr.span) {
result.push(this.merge(descr.span));
continue;
}
if (AudioUtil.isPauseElement(descr)) {
result.push(this.pause(descr));
continue;
}
if (descr.close.length) {
for (let j = 0; j < descr.close.length; j++) {
const last = currentOpen.pop();
if (descr.close.indexOf(last) === -1) {
throw new engine_js_1.SREError('Unknown closing markup element: ' + last);
}
result.push(this.closeTag(last));
}
}
if (descr.open.length) {
const open = AudioUtil.sortClose(descr.open.slice(), markup.slice(i + 1));
open.forEach((o) => {
result.push(this.prosodyElement(o, descr[o]));
currentOpen.push(o);
});
}
}
return result.join(' ');
}
}
exports.XmlRenderer = XmlRenderer;