@viritura/score-engine 0.1.1-next.27 → 0.1.1-next.29
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.
- package/dist/index.js +391 -134
- package/dist/index.js.map +4 -4
- package/dist/wasm/viritura_wasm_bg.wasm +0 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -582,6 +582,230 @@ function parseChordSymbolText(input, position) {
|
|
|
582
582
|
return (!parsedQuality || parsedQuality.modifiers) && (chord.kindText = match[4]), parsedQuality?.extension !== void 0 && (chord.extension = parsedQuality.extension), match[5] && (chord.bass = parseRoot(match[5], match[6] ?? "")), chord;
|
|
583
583
|
}
|
|
584
584
|
|
|
585
|
+
// packages/core/src/operations/lyricExtenders.ts
|
|
586
|
+
init_define_import_meta_env();
|
|
587
|
+
function durationBeats(duration) {
|
|
588
|
+
let base = DURATION_BEATS[duration.base], dots = 1;
|
|
589
|
+
for (let index = 0; index < (duration.dots ?? 0); index++) dots += 0.5 ** (index + 1);
|
|
590
|
+
return base * dots;
|
|
591
|
+
}
|
|
592
|
+
function quantityBeats(quantity) {
|
|
593
|
+
return durationBeats(quantity.duration) * quantity.multiple;
|
|
594
|
+
}
|
|
595
|
+
function walkTimedContent(content, startBeat, scale, partIndex, sequenceIndex, voice, staff, measureIndex, output, ordinal) {
|
|
596
|
+
let cursor = startBeat;
|
|
597
|
+
for (let item of content) {
|
|
598
|
+
if (item.type === "event") {
|
|
599
|
+
let duration = durationBeats(item.duration) * scale;
|
|
600
|
+
output.push({
|
|
601
|
+
event: item,
|
|
602
|
+
partIndex,
|
|
603
|
+
sequenceIndex,
|
|
604
|
+
voice,
|
|
605
|
+
staff,
|
|
606
|
+
measureIndex,
|
|
607
|
+
startBeat: cursor,
|
|
608
|
+
durationBeats: duration,
|
|
609
|
+
rest: isRest(item),
|
|
610
|
+
ordinal: ordinal.value++
|
|
611
|
+
}), cursor += duration;
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
if (item.type === "space") {
|
|
615
|
+
cursor += 4 * item.duration[0] / item.duration[1] * scale;
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
if (item.type === "grace") {
|
|
619
|
+
for (let event of item.content)
|
|
620
|
+
output.push({
|
|
621
|
+
event,
|
|
622
|
+
partIndex,
|
|
623
|
+
sequenceIndex,
|
|
624
|
+
voice,
|
|
625
|
+
staff,
|
|
626
|
+
measureIndex,
|
|
627
|
+
startBeat: cursor,
|
|
628
|
+
durationBeats: 0,
|
|
629
|
+
rest: isRest(event),
|
|
630
|
+
ordinal: ordinal.value++
|
|
631
|
+
});
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
if (item.type === "tuplet") {
|
|
635
|
+
let inner = quantityBeats(item.inner), ratio = inner > 0 ? quantityBeats(item.outer) / inner : 1;
|
|
636
|
+
cursor = walkTimedContent(
|
|
637
|
+
item.content,
|
|
638
|
+
cursor,
|
|
639
|
+
scale * ratio,
|
|
640
|
+
partIndex,
|
|
641
|
+
sequenceIndex,
|
|
642
|
+
voice,
|
|
643
|
+
staff,
|
|
644
|
+
measureIndex,
|
|
645
|
+
output,
|
|
646
|
+
ordinal
|
|
647
|
+
);
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
let subdivision = item.content.length ? quantityBeats(item.outer) * scale / item.content.length : 0;
|
|
651
|
+
for (let event of item.content)
|
|
652
|
+
output.push({
|
|
653
|
+
event,
|
|
654
|
+
partIndex,
|
|
655
|
+
sequenceIndex,
|
|
656
|
+
voice,
|
|
657
|
+
staff,
|
|
658
|
+
measureIndex,
|
|
659
|
+
startBeat: cursor,
|
|
660
|
+
durationBeats: subdivision,
|
|
661
|
+
rest: isRest(event),
|
|
662
|
+
ordinal: ordinal.value++
|
|
663
|
+
}), cursor += subdivision;
|
|
664
|
+
}
|
|
665
|
+
return cursor;
|
|
666
|
+
}
|
|
667
|
+
function collectEvents(score) {
|
|
668
|
+
let offsets = [], measureOffset = 0, measureCount = Math.max(score.global.measures.length, ...score.parts.map((part) => part.measures.length)), activeMeter = { count: 4, unit: 4 }, meters = [];
|
|
669
|
+
for (let index = 0; index < measureCount; index++) {
|
|
670
|
+
let measure = score.global.measures[index];
|
|
671
|
+
measure?.time && (activeMeter = measure.time), meters.push(activeMeter), offsets.push(measureOffset), measureOffset += measureBeats(activeMeter);
|
|
672
|
+
}
|
|
673
|
+
let events = [], writtenSpans = Array(measureCount).fill(0), ordinal = { value: 0 };
|
|
674
|
+
for (let partIndex = 0; partIndex < score.parts.length; partIndex++) {
|
|
675
|
+
let part = score.parts[partIndex], { table } = resolveStaffMeterTimeline(
|
|
676
|
+
part.measures.map((measure) => measure.staffMeters),
|
|
677
|
+
meters
|
|
678
|
+
);
|
|
679
|
+
for (let measureIndex = 0; measureIndex < part.measures.length; measureIndex++) {
|
|
680
|
+
let measure = part.measures[measureIndex], start = offsets[measureIndex] ?? measureIndex * 4;
|
|
681
|
+
measure.sequences.forEach((sequence, sequenceIndex) => {
|
|
682
|
+
if (sequence.fullMeasure) {
|
|
683
|
+
events.push({
|
|
684
|
+
event: { type: "event", duration: sequence.fullMeasure.visualDuration, rest: {} },
|
|
685
|
+
partIndex,
|
|
686
|
+
sequenceIndex,
|
|
687
|
+
voice: sequence.voice,
|
|
688
|
+
staff: sequence.staff ?? 1,
|
|
689
|
+
measureIndex,
|
|
690
|
+
startBeat: start,
|
|
691
|
+
durationBeats: measureBeats(meters[measureIndex]),
|
|
692
|
+
rest: !0,
|
|
693
|
+
ordinal: ordinal.value++
|
|
694
|
+
});
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
let end = walkTimedContent(
|
|
698
|
+
sequence.content,
|
|
699
|
+
start,
|
|
700
|
+
table[measureIndex]?.get(sequence.staff ?? 1) ? ratioToNumber(table[measureIndex].get(sequence.staff ?? 1).ratioToGlobal) : 1,
|
|
701
|
+
partIndex,
|
|
702
|
+
sequenceIndex,
|
|
703
|
+
sequence.voice,
|
|
704
|
+
sequence.staff ?? 1,
|
|
705
|
+
measureIndex,
|
|
706
|
+
events,
|
|
707
|
+
ordinal
|
|
708
|
+
);
|
|
709
|
+
sequence.fullMeasure || (writtenSpans[measureIndex] = Math.max(writtenSpans[measureIndex], end - start));
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
let correction = 0, corrections = [];
|
|
714
|
+
for (let index = 0; index < measureCount; index++) {
|
|
715
|
+
let nominal = measureBeats(meters[index]), measure = score.global.measures[index], written = writtenSpans[index];
|
|
716
|
+
corrections.push(correction), index === 0 && measure?.number === 0 && written > 0 ? correction += written - nominal : measure?.time?.display === "senzaMisura" && (correction += Math.max(nominal, written) - nominal);
|
|
717
|
+
}
|
|
718
|
+
for (let event of events) event.startBeat += corrections[event.measureIndex];
|
|
719
|
+
return events;
|
|
720
|
+
}
|
|
721
|
+
function hasLyrics(event, lineId) {
|
|
722
|
+
return event.event.lyrics?.lines?.[lineId] !== void 0;
|
|
723
|
+
}
|
|
724
|
+
function isEligibleSyllable(line) {
|
|
725
|
+
return line.type !== "start" && line.type !== "middle";
|
|
726
|
+
}
|
|
727
|
+
function sameLyricVoice(source, candidate) {
|
|
728
|
+
return source.partIndex === candidate.partIndex && source.staff === candidate.staff && (source.voice !== void 0 ? source.voice === candidate.voice : candidate.voice === void 0 && source.sequenceIndex === candidate.sequenceIndex);
|
|
729
|
+
}
|
|
730
|
+
function inferredTarget(source, lineId, events) {
|
|
731
|
+
let continuation = events.filter((event) => sameLyricVoice(source, event) && event.ordinal > source.ordinal).sort((left, right) => left.ordinal - right.ordinal), target;
|
|
732
|
+
for (let event of continuation) {
|
|
733
|
+
if (hasLyrics(event, lineId) || event.rest) break;
|
|
734
|
+
target = event;
|
|
735
|
+
}
|
|
736
|
+
return target;
|
|
737
|
+
}
|
|
738
|
+
function crossesLaterSyllable(source, target, lineId, events) {
|
|
739
|
+
return events.some(
|
|
740
|
+
(candidate) => sameLyricVoice(source, candidate) && candidate.ordinal > source.ordinal && candidate.startBeat <= target.startBeat + 1e-9 && candidate.ordinal !== target.ordinal && hasLyrics(candidate, lineId)
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
function resolveLyricExtenders(score) {
|
|
744
|
+
let events = collectEvents(score), byId = /* @__PURE__ */ new Map();
|
|
745
|
+
for (let event of events)
|
|
746
|
+
event.event.id && !byId.has(event.event.id) && byId.set(event.event.id, event);
|
|
747
|
+
let extenders = [], diagnostics = [], explicitPolicy = score.mnx.support?.useLyricExtenders === !0;
|
|
748
|
+
for (let source of events)
|
|
749
|
+
for (let [lineId, line] of Object.entries(source.event.lyrics?.lines ?? {})) {
|
|
750
|
+
let explicit = line.extender !== void 0;
|
|
751
|
+
if (line.extender?.show === !1 || !explicit && explicitPolicy || !explicit && !isEligibleSyllable(line))
|
|
752
|
+
continue;
|
|
753
|
+
let target;
|
|
754
|
+
if (line.extender?.target !== void 0) {
|
|
755
|
+
if (target = byId.get(line.extender.target), !target) {
|
|
756
|
+
diagnostics.push({
|
|
757
|
+
code: "missing-target",
|
|
758
|
+
sourceEventId: source.event.id,
|
|
759
|
+
lineId,
|
|
760
|
+
targetEventId: line.extender.target,
|
|
761
|
+
partIndex: source.partIndex,
|
|
762
|
+
measureIndex: source.measureIndex,
|
|
763
|
+
sequenceIndex: source.sequenceIndex
|
|
764
|
+
});
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
if (target.startBeat < source.startBeat - 1e-9) {
|
|
768
|
+
diagnostics.push({
|
|
769
|
+
code: "backward-target",
|
|
770
|
+
sourceEventId: source.event.id,
|
|
771
|
+
lineId,
|
|
772
|
+
targetEventId: line.extender.target,
|
|
773
|
+
partIndex: source.partIndex,
|
|
774
|
+
measureIndex: source.measureIndex,
|
|
775
|
+
sequenceIndex: source.sequenceIndex
|
|
776
|
+
});
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
if (target.ordinal !== source.ordinal && hasLyrics(target, lineId) || crossesLaterSyllable(source, target, lineId, events)) {
|
|
780
|
+
diagnostics.push({
|
|
781
|
+
code: "conflicting-target",
|
|
782
|
+
sourceEventId: source.event.id,
|
|
783
|
+
lineId,
|
|
784
|
+
targetEventId: line.extender.target,
|
|
785
|
+
partIndex: source.partIndex,
|
|
786
|
+
measureIndex: source.measureIndex,
|
|
787
|
+
sequenceIndex: source.sequenceIndex
|
|
788
|
+
});
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
} else
|
|
792
|
+
target = inferredTarget(source, lineId, events);
|
|
793
|
+
target && extenders.push({
|
|
794
|
+
sourceEventId: source.event.id,
|
|
795
|
+
targetEventId: target.event.id,
|
|
796
|
+
partIndex: source.partIndex,
|
|
797
|
+
sequenceIndex: source.sequenceIndex,
|
|
798
|
+
lineId,
|
|
799
|
+
startMeasure: source.measureIndex,
|
|
800
|
+
endMeasure: target.measureIndex,
|
|
801
|
+
startBeat: source.startBeat,
|
|
802
|
+
endBeat: target.startBeat + target.durationBeats,
|
|
803
|
+
explicit
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
return { extenders, diagnostics };
|
|
807
|
+
}
|
|
808
|
+
|
|
585
809
|
// packages/core/src/diagnostics.ts
|
|
586
810
|
init_define_import_meta_env();
|
|
587
811
|
var DiagnosticCollector = class {
|
|
@@ -1989,9 +2213,9 @@ function interpolateBeatAnchors(bounds, beat, endX) {
|
|
|
1989
2213
|
|
|
1990
2214
|
// packages/score-engine/src/buildInfo.ts
|
|
1991
2215
|
init_define_import_meta_env();
|
|
1992
|
-
var PACKAGE_VERSION = "0.1.1-next.
|
|
2216
|
+
var PACKAGE_VERSION = "0.1.1-next.29", BUNDLE_WORKER_FILE = "score-engine.worker.js";
|
|
1993
2217
|
function buildCommit() {
|
|
1994
|
-
return "
|
|
2218
|
+
return "861ac5447e15b8f748d78775a893a6bda2f11d6d";
|
|
1995
2219
|
}
|
|
1996
2220
|
function bundledAssetBase() {
|
|
1997
2221
|
let moduleUrl = import.meta.url;
|
|
@@ -15105,7 +15329,7 @@ function parseLyrics(raw) {
|
|
|
15105
15329
|
let linesObj = raw.lines, lines = {};
|
|
15106
15330
|
for (let key of Object.keys(linesObj)) {
|
|
15107
15331
|
let lineRaw = linesObj[key], line = { text: lineRaw.text };
|
|
15108
|
-
lineRaw.type !== void 0 && (line.type = lineRaw.type), lines[key] = line;
|
|
15332
|
+
lineRaw.type !== void 0 && (line.type = lineRaw.type), lineRaw.extender !== void 0 && (line.extender = lineRaw.extender), lines[key] = line;
|
|
15109
15333
|
}
|
|
15110
15334
|
lyrics.lines = lines;
|
|
15111
15335
|
}
|
|
@@ -15471,6 +15695,130 @@ function parseSystemDefinition(raw) {
|
|
|
15471
15695
|
// packages/format/src/mnx/diagnostics.ts
|
|
15472
15696
|
init_define_import_meta_env();
|
|
15473
15697
|
|
|
15698
|
+
// packages/format/src/mnx/knownFields.ts
|
|
15699
|
+
init_define_import_meta_env();
|
|
15700
|
+
var KEYS = {
|
|
15701
|
+
root: /* @__PURE__ */ new Set(["mnx", "global", "parts", "layouts", "scores", "_x"]),
|
|
15702
|
+
mnxMeta: /* @__PURE__ */ new Set(["version", "support"]),
|
|
15703
|
+
support: /* @__PURE__ */ new Set(["useAccidentalDisplay", "useBeams", "useLyricExtenders"]),
|
|
15704
|
+
global: /* @__PURE__ */ new Set(["measures", "lyrics"]),
|
|
15705
|
+
globalLyrics: /* @__PURE__ */ new Set(["lineMetadata", "lineOrder"]),
|
|
15706
|
+
globalMeasure: /* @__PURE__ */ new Set([
|
|
15707
|
+
"id",
|
|
15708
|
+
"number",
|
|
15709
|
+
"time",
|
|
15710
|
+
"key",
|
|
15711
|
+
"barline",
|
|
15712
|
+
"repeatStart",
|
|
15713
|
+
"repeatEnd",
|
|
15714
|
+
"ending",
|
|
15715
|
+
"tempos",
|
|
15716
|
+
"segno",
|
|
15717
|
+
"coda",
|
|
15718
|
+
"caesura",
|
|
15719
|
+
"fine",
|
|
15720
|
+
"jump",
|
|
15721
|
+
"_x"
|
|
15722
|
+
]),
|
|
15723
|
+
time: /* @__PURE__ */ new Set(["count", "unit", "display", "_x"]),
|
|
15724
|
+
key: /* @__PURE__ */ new Set(["fifths", "color", "_x"]),
|
|
15725
|
+
barline: /* @__PURE__ */ new Set(["type"]),
|
|
15726
|
+
ending: /* @__PURE__ */ new Set(["duration", "numbers", "open", "color"]),
|
|
15727
|
+
tempo: /* @__PURE__ */ new Set(["bpm", "value", "location", "_x"]),
|
|
15728
|
+
tempoNoteValue: /* @__PURE__ */ new Set(["base", "dots"]),
|
|
15729
|
+
rhythmicPosition: /* @__PURE__ */ new Set(["fraction"]),
|
|
15730
|
+
segno: /* @__PURE__ */ new Set(["location", "glyph", "color"]),
|
|
15731
|
+
fine: /* @__PURE__ */ new Set(["location", "color"]),
|
|
15732
|
+
jump: /* @__PURE__ */ new Set(["type", "location"]),
|
|
15733
|
+
part: /* @__PURE__ */ new Set(["id", "name", "shortName", "staves", "transposition", "measures", "_x"]),
|
|
15734
|
+
transposition: /* @__PURE__ */ new Set(["interval", "keyFifthsFlipAt", "prefersWrittenPitches"]),
|
|
15735
|
+
partMeasure: /* @__PURE__ */ new Set([
|
|
15736
|
+
"sequences",
|
|
15737
|
+
"clefs",
|
|
15738
|
+
"staffConfigs",
|
|
15739
|
+
"arpeggios",
|
|
15740
|
+
"nonArpeggios",
|
|
15741
|
+
"beams",
|
|
15742
|
+
"dynamics",
|
|
15743
|
+
"ottavas",
|
|
15744
|
+
"measureRepeat",
|
|
15745
|
+
"_x"
|
|
15746
|
+
]),
|
|
15747
|
+
positionedStaffConfig: /* @__PURE__ */ new Set(["config", "position", "staff", "id", "_c", "_x"]),
|
|
15748
|
+
staffConfig: /* @__PURE__ */ new Set(["lines", "id", "_c", "_x"]),
|
|
15749
|
+
measureRepeat: /* @__PURE__ */ new Set(["number", "counter", "displayNumber", "staffPosition", "_c", "_x"]),
|
|
15750
|
+
measureRepeatCounter: /* @__PURE__ */ new Set(["count", "placement", "_c", "_x"]),
|
|
15751
|
+
arpeggio: /* @__PURE__ */ new Set(["id", "position", "span", "direction", "arrow", "_c", "_x"]),
|
|
15752
|
+
nonArpeggio: /* @__PURE__ */ new Set(["id", "position", "span", "_c", "_x"]),
|
|
15753
|
+
idPair: /* @__PURE__ */ new Set(["start", "end"]),
|
|
15754
|
+
positionedClef: /* @__PURE__ */ new Set(["clef", "position", "staff"]),
|
|
15755
|
+
clef: /* @__PURE__ */ new Set(["sign", "staffPosition", "color", "glyph", "octave", "showOctave", "hide"]),
|
|
15756
|
+
beam: /* @__PURE__ */ new Set(["events", "beams", "direction"]),
|
|
15757
|
+
dynamic: /* @__PURE__ */ new Set(["position", "value", "glyph", "staff", "voice"]),
|
|
15758
|
+
ottava: /* @__PURE__ */ new Set(["position", "end", "value", "staff", "voice"]),
|
|
15759
|
+
measureRhythmicPosition: /* @__PURE__ */ new Set(["measure", "position"]),
|
|
15760
|
+
sequence: /* @__PURE__ */ new Set(["content", "fullMeasure", "staff", "voice", "directionHint"]),
|
|
15761
|
+
fullMeasure: /* @__PURE__ */ new Set(["visualDuration", "staffPosition"]),
|
|
15762
|
+
duration: /* @__PURE__ */ new Set(["base", "dots"]),
|
|
15763
|
+
event: /* @__PURE__ */ new Set([
|
|
15764
|
+
"type",
|
|
15765
|
+
"id",
|
|
15766
|
+
"duration",
|
|
15767
|
+
"staff",
|
|
15768
|
+
"rest",
|
|
15769
|
+
"notes",
|
|
15770
|
+
"slurs",
|
|
15771
|
+
"markings",
|
|
15772
|
+
"fermata",
|
|
15773
|
+
"lyrics",
|
|
15774
|
+
"stemDirection",
|
|
15775
|
+
"smufl",
|
|
15776
|
+
"_x"
|
|
15777
|
+
]),
|
|
15778
|
+
eventLyrics: /* @__PURE__ */ new Set(["lines"]),
|
|
15779
|
+
eventLyricLine: /* @__PURE__ */ new Set(["type", "text", "extender"]),
|
|
15780
|
+
eventLyricLineExtender: /* @__PURE__ */ new Set(["show", "target", "id"]),
|
|
15781
|
+
rest: /* @__PURE__ */ new Set(["staffPosition"]),
|
|
15782
|
+
note: /* @__PURE__ */ new Set(["pitch", "id", "ties", "accidentalDisplay", "written", "markings"]),
|
|
15783
|
+
pitch: /* @__PURE__ */ new Set(["step", "octave", "alter"]),
|
|
15784
|
+
tie: /* @__PURE__ */ new Set(["target", "targetType", "side", "lv"]),
|
|
15785
|
+
accidentalDisplay: /* @__PURE__ */ new Set(["show", "force", "enclosure"]),
|
|
15786
|
+
accidentalEnclosure: /* @__PURE__ */ new Set(["symbol"]),
|
|
15787
|
+
written: /* @__PURE__ */ new Set(["diatonicDelta"]),
|
|
15788
|
+
slur: /* @__PURE__ */ new Set(["target", "side", "sideEnd", "lineType", "startNote", "endNote"]),
|
|
15789
|
+
markings: /* @__PURE__ */ new Set([
|
|
15790
|
+
"staccato",
|
|
15791
|
+
"staccatissimo",
|
|
15792
|
+
"spiccato",
|
|
15793
|
+
"staccatissimoWedge",
|
|
15794
|
+
"tenuto",
|
|
15795
|
+
"accent",
|
|
15796
|
+
"strongAccent",
|
|
15797
|
+
"tremolo",
|
|
15798
|
+
"softAccent",
|
|
15799
|
+
"stress",
|
|
15800
|
+
"unstress",
|
|
15801
|
+
"breath",
|
|
15802
|
+
"caesura",
|
|
15803
|
+
"bowDirection",
|
|
15804
|
+
"_x"
|
|
15805
|
+
]),
|
|
15806
|
+
tuplet: /* @__PURE__ */ new Set(["type", "inner", "outer", "content", "bracket", "showNumber", "showValue", "placement"]),
|
|
15807
|
+
tupletDuration: /* @__PURE__ */ new Set(["duration", "multiple"]),
|
|
15808
|
+
grace: /* @__PURE__ */ new Set(["type", "content", "graceType", "slash", "color"]),
|
|
15809
|
+
multiTremolo: /* @__PURE__ */ new Set(["type", "content", "marks", "outer"]),
|
|
15810
|
+
space: /* @__PURE__ */ new Set(["type", "duration"]),
|
|
15811
|
+
layoutDefinition: /* @__PURE__ */ new Set(["id", "content"]),
|
|
15812
|
+
layoutGroup: /* @__PURE__ */ new Set(["type", "content", "symbol", "label", "barlineStyle"]),
|
|
15813
|
+
layoutStaff: /* @__PURE__ */ new Set(["type", "sources", "label", "labelref"]),
|
|
15814
|
+
layoutSource: /* @__PURE__ */ new Set(["part", "staff", "stem", "voice", "labelref"]),
|
|
15815
|
+
scoreDefinition: /* @__PURE__ */ new Set(["name", "layout", "multimeasureRests", "pages", "useWritten", "_x"]),
|
|
15816
|
+
multimeasureRest: /* @__PURE__ */ new Set(["start", "duration"]),
|
|
15817
|
+
page: /* @__PURE__ */ new Set(["systems"]),
|
|
15818
|
+
system: /* @__PURE__ */ new Set(["measure", "layout", "layoutChanges"]),
|
|
15819
|
+
layoutChange: /* @__PURE__ */ new Set(["layout", "location"])
|
|
15820
|
+
};
|
|
15821
|
+
|
|
15474
15822
|
// packages/format/src/mnx/parserCore.ts
|
|
15475
15823
|
function parseMnxUnvalidated(json) {
|
|
15476
15824
|
return parseMnxInternal(json, new DiagnosticCollector());
|
|
@@ -15478,7 +15826,7 @@ function parseMnxUnvalidated(json) {
|
|
|
15478
15826
|
function parseSupport(supportObj) {
|
|
15479
15827
|
if (!supportObj) return;
|
|
15480
15828
|
let support = {};
|
|
15481
|
-
return typeof supportObj.useAccidentalDisplay == "boolean" && (support.useAccidentalDisplay = supportObj.useAccidentalDisplay), typeof supportObj.useBeams == "boolean" && (support.useBeams = supportObj.useBeams), support;
|
|
15829
|
+
return typeof supportObj.useAccidentalDisplay == "boolean" && (support.useAccidentalDisplay = supportObj.useAccidentalDisplay), typeof supportObj.useBeams == "boolean" && (support.useBeams = supportObj.useBeams), typeof supportObj.useLyricExtenders == "boolean" && (support.useLyricExtenders = supportObj.useLyricExtenders), support;
|
|
15482
15830
|
}
|
|
15483
15831
|
function parseRootMetadata(rootX) {
|
|
15484
15832
|
let m = rootX?.viritura?.metadata;
|
|
@@ -15646,7 +15994,16 @@ function parseMnxInternal(json, diagnostics) {
|
|
|
15646
15994
|
},
|
|
15647
15995
|
parts: parseParts(partsArr)
|
|
15648
15996
|
};
|
|
15649
|
-
|
|
15997
|
+
globalObj?.lyrics && (score.global.lyrics = parseGlobalLyrics(globalObj.lyrics)), globalObj?.sounds && (score.global.sounds = parseGlobalSounds(globalObj.sounds)), layoutsArr && layoutsArr.length > 0 && (score.layouts = layoutsArr.map((l) => parseLayoutDefinition(l))), scoresArr && scoresArr.length > 0 && (score.scores = scoresArr.map((s) => parseScoreDefinition(s))), applyRootExtensions(score, obj._x), assignMissingIds(score), validateSupportConsistency(score, support, diagnostics);
|
|
15998
|
+
for (let issue of resolveLyricExtenders(score).diagnostics) {
|
|
15999
|
+
let source = issue.sourceEventId ? ` on event "${issue.sourceEventId}"` : "", message = issue.code === "missing-target" ? `Lyric extender${source} targets missing event "${issue.targetEventId}"` : issue.code === "backward-target" ? `Lyric extender${source} targets earlier event "${issue.targetEventId}"` : `Lyric extender${source} ends on an event with another syllable in lyric line "${issue.lineId}"`;
|
|
16000
|
+
diagnostics.warn(
|
|
16001
|
+
ptr("parts", "?", "measures", "?", "sequences", "?", "content", "?", "lyrics", "lines", issue.lineId, "extender"),
|
|
16002
|
+
message,
|
|
16003
|
+
"lyric-extender-reference"
|
|
16004
|
+
);
|
|
16005
|
+
}
|
|
16006
|
+
return scanUnknownFields(obj, diagnostics), score;
|
|
15650
16007
|
}
|
|
15651
16008
|
function applyRootExtensions(score, rootX) {
|
|
15652
16009
|
let metadata = parseRootMetadata(rootX);
|
|
@@ -15709,121 +16066,6 @@ function processEventIds(event, usedIds, collectOnly) {
|
|
|
15709
16066
|
for (let n of event.notes)
|
|
15710
16067
|
n.id || (n.id = mintId(usedIds));
|
|
15711
16068
|
}
|
|
15712
|
-
var KEYS = {
|
|
15713
|
-
root: /* @__PURE__ */ new Set(["mnx", "global", "parts", "layouts", "scores", "_x"]),
|
|
15714
|
-
mnxMeta: /* @__PURE__ */ new Set(["version", "support"]),
|
|
15715
|
-
support: /* @__PURE__ */ new Set(["useAccidentalDisplay", "useBeams"]),
|
|
15716
|
-
global: /* @__PURE__ */ new Set(["measures", "lyrics"]),
|
|
15717
|
-
globalLyrics: /* @__PURE__ */ new Set(["lineMetadata", "lineOrder"]),
|
|
15718
|
-
globalMeasure: /* @__PURE__ */ new Set([
|
|
15719
|
-
"id",
|
|
15720
|
-
"number",
|
|
15721
|
-
"time",
|
|
15722
|
-
"key",
|
|
15723
|
-
"barline",
|
|
15724
|
-
"repeatStart",
|
|
15725
|
-
"repeatEnd",
|
|
15726
|
-
"ending",
|
|
15727
|
-
"tempos",
|
|
15728
|
-
"segno",
|
|
15729
|
-
"fine",
|
|
15730
|
-
"jump",
|
|
15731
|
-
"_x"
|
|
15732
|
-
]),
|
|
15733
|
-
time: /* @__PURE__ */ new Set(["count", "unit", "display", "_x"]),
|
|
15734
|
-
key: /* @__PURE__ */ new Set(["fifths", "color", "_x"]),
|
|
15735
|
-
barline: /* @__PURE__ */ new Set(["type"]),
|
|
15736
|
-
ending: /* @__PURE__ */ new Set(["duration", "numbers", "open", "color"]),
|
|
15737
|
-
tempo: /* @__PURE__ */ new Set(["bpm", "value", "location", "_x"]),
|
|
15738
|
-
tempoNoteValue: /* @__PURE__ */ new Set(["base", "dots"]),
|
|
15739
|
-
rhythmicPosition: /* @__PURE__ */ new Set(["fraction"]),
|
|
15740
|
-
segno: /* @__PURE__ */ new Set(["location", "glyph", "color"]),
|
|
15741
|
-
fine: /* @__PURE__ */ new Set(["location", "color"]),
|
|
15742
|
-
jump: /* @__PURE__ */ new Set(["type", "location"]),
|
|
15743
|
-
part: /* @__PURE__ */ new Set(["id", "name", "shortName", "staves", "transposition", "measures", "_x"]),
|
|
15744
|
-
transposition: /* @__PURE__ */ new Set(["interval", "keyFifthsFlipAt", "prefersWrittenPitches"]),
|
|
15745
|
-
partMeasure: /* @__PURE__ */ new Set([
|
|
15746
|
-
"sequences",
|
|
15747
|
-
"clefs",
|
|
15748
|
-
"staffConfigs",
|
|
15749
|
-
"arpeggios",
|
|
15750
|
-
"nonArpeggios",
|
|
15751
|
-
"beams",
|
|
15752
|
-
"dynamics",
|
|
15753
|
-
"ottavas",
|
|
15754
|
-
"measureRepeat",
|
|
15755
|
-
"_x"
|
|
15756
|
-
]),
|
|
15757
|
-
positionedStaffConfig: /* @__PURE__ */ new Set(["config", "position", "staff", "id", "_c", "_x"]),
|
|
15758
|
-
staffConfig: /* @__PURE__ */ new Set(["lines", "id", "_c", "_x"]),
|
|
15759
|
-
measureRepeat: /* @__PURE__ */ new Set(["number", "counter", "displayNumber", "staffPosition", "_c", "_x"]),
|
|
15760
|
-
measureRepeatCounter: /* @__PURE__ */ new Set(["count", "placement", "_c", "_x"]),
|
|
15761
|
-
arpeggio: /* @__PURE__ */ new Set(["id", "position", "span", "direction", "arrow", "_c", "_x"]),
|
|
15762
|
-
nonArpeggio: /* @__PURE__ */ new Set(["id", "position", "span", "_c", "_x"]),
|
|
15763
|
-
idPair: /* @__PURE__ */ new Set(["start", "end"]),
|
|
15764
|
-
positionedClef: /* @__PURE__ */ new Set(["clef", "position", "staff"]),
|
|
15765
|
-
clef: /* @__PURE__ */ new Set(["sign", "staffPosition", "color", "glyph", "octave", "showOctave", "hide"]),
|
|
15766
|
-
beam: /* @__PURE__ */ new Set(["events", "beams", "direction"]),
|
|
15767
|
-
dynamic: /* @__PURE__ */ new Set(["position", "value", "glyph", "staff", "voice"]),
|
|
15768
|
-
ottava: /* @__PURE__ */ new Set(["position", "end", "value", "staff", "voice"]),
|
|
15769
|
-
measureRhythmicPosition: /* @__PURE__ */ new Set(["measure", "position"]),
|
|
15770
|
-
sequence: /* @__PURE__ */ new Set(["content", "fullMeasure", "staff", "voice", "directionHint"]),
|
|
15771
|
-
fullMeasure: /* @__PURE__ */ new Set(["visualDuration", "staffPosition"]),
|
|
15772
|
-
duration: /* @__PURE__ */ new Set(["base", "dots"]),
|
|
15773
|
-
event: /* @__PURE__ */ new Set([
|
|
15774
|
-
"type",
|
|
15775
|
-
"id",
|
|
15776
|
-
"duration",
|
|
15777
|
-
"staff",
|
|
15778
|
-
"rest",
|
|
15779
|
-
"notes",
|
|
15780
|
-
"slurs",
|
|
15781
|
-
"markings",
|
|
15782
|
-
"fermata",
|
|
15783
|
-
"lyrics",
|
|
15784
|
-
"stemDirection",
|
|
15785
|
-
"smufl",
|
|
15786
|
-
"_x"
|
|
15787
|
-
]),
|
|
15788
|
-
rest: /* @__PURE__ */ new Set(["staffPosition"]),
|
|
15789
|
-
note: /* @__PURE__ */ new Set(["pitch", "id", "ties", "accidentalDisplay", "written"]),
|
|
15790
|
-
pitch: /* @__PURE__ */ new Set(["step", "octave", "alter"]),
|
|
15791
|
-
tie: /* @__PURE__ */ new Set(["target", "targetType", "side", "lv"]),
|
|
15792
|
-
accidentalDisplay: /* @__PURE__ */ new Set(["show", "force", "enclosure"]),
|
|
15793
|
-
accidentalEnclosure: /* @__PURE__ */ new Set(["symbol"]),
|
|
15794
|
-
written: /* @__PURE__ */ new Set(["diatonicDelta"]),
|
|
15795
|
-
slur: /* @__PURE__ */ new Set(["target", "side", "sideEnd", "lineType", "startNote", "endNote"]),
|
|
15796
|
-
markings: /* @__PURE__ */ new Set([
|
|
15797
|
-
"staccato",
|
|
15798
|
-
"staccatissimo",
|
|
15799
|
-
"spiccato",
|
|
15800
|
-
"staccatissimoWedge",
|
|
15801
|
-
"tenuto",
|
|
15802
|
-
"accent",
|
|
15803
|
-
"strongAccent",
|
|
15804
|
-
"tremolo",
|
|
15805
|
-
"softAccent",
|
|
15806
|
-
"stress",
|
|
15807
|
-
"unstress",
|
|
15808
|
-
"breath",
|
|
15809
|
-
"bowDirection",
|
|
15810
|
-
"_x"
|
|
15811
|
-
]),
|
|
15812
|
-
tuplet: /* @__PURE__ */ new Set(["type", "inner", "outer", "content", "bracket", "showNumber", "showValue", "placement"]),
|
|
15813
|
-
tupletDuration: /* @__PURE__ */ new Set(["duration", "multiple"]),
|
|
15814
|
-
grace: /* @__PURE__ */ new Set(["type", "content", "graceType", "slash", "color"]),
|
|
15815
|
-
multiTremolo: /* @__PURE__ */ new Set(["type", "content", "marks", "outer"]),
|
|
15816
|
-
space: /* @__PURE__ */ new Set(["type", "duration"]),
|
|
15817
|
-
layoutDefinition: /* @__PURE__ */ new Set(["id", "content"]),
|
|
15818
|
-
layoutGroup: /* @__PURE__ */ new Set(["type", "content", "symbol", "label", "barlineStyle"]),
|
|
15819
|
-
layoutStaff: /* @__PURE__ */ new Set(["type", "sources", "label", "labelref"]),
|
|
15820
|
-
layoutSource: /* @__PURE__ */ new Set(["part", "staff", "stem", "voice", "labelref"]),
|
|
15821
|
-
scoreDefinition: /* @__PURE__ */ new Set(["name", "layout", "multimeasureRests", "pages", "useWritten", "_x"]),
|
|
15822
|
-
multimeasureRest: /* @__PURE__ */ new Set(["start", "duration"]),
|
|
15823
|
-
page: /* @__PURE__ */ new Set(["systems"]),
|
|
15824
|
-
system: /* @__PURE__ */ new Set(["measure", "layout", "layoutChanges"]),
|
|
15825
|
-
layoutChange: /* @__PURE__ */ new Set(["layout", "location"])
|
|
15826
|
-
};
|
|
15827
16069
|
function scanUnknownFields(json, dx) {
|
|
15828
16070
|
if (!json || typeof json != "object") return;
|
|
15829
16071
|
let root = json;
|
|
@@ -15870,6 +16112,8 @@ function scanGlobalMeasure(gm, p, dx) {
|
|
|
15870
16112
|
});
|
|
15871
16113
|
let segno = gm.segno;
|
|
15872
16114
|
segno && emitUnknown(segno, KEYS.segno, p + ptr("segno"), dx);
|
|
16115
|
+
let coda = gm.coda;
|
|
16116
|
+
coda && emitUnknown(coda, KEYS.segno, p + ptr("coda"), dx);
|
|
15873
16117
|
let fine = gm.fine;
|
|
15874
16118
|
fine && emitUnknown(fine, KEYS.fine, p + ptr("fine"), dx);
|
|
15875
16119
|
let jump = gm.jump;
|
|
@@ -15937,6 +16181,19 @@ function scanContentItem(c, p, dx) {
|
|
|
15937
16181
|
let type = c.type ?? "event";
|
|
15938
16182
|
if (type === "event") {
|
|
15939
16183
|
emitUnknown(c, KEYS.event, p, dx);
|
|
16184
|
+
let lyrics = c.lyrics;
|
|
16185
|
+
if (lyrics) {
|
|
16186
|
+
emitUnknown(lyrics, KEYS.eventLyrics, p + ptr("lyrics"), dx);
|
|
16187
|
+
let lines = lyrics.lines;
|
|
16188
|
+
if (lines && typeof lines == "object")
|
|
16189
|
+
for (let [lineId, line] of Object.entries(lines)) {
|
|
16190
|
+
if (!line || typeof line != "object") continue;
|
|
16191
|
+
let linePath = p + ptr("lyrics", "lines", lineId);
|
|
16192
|
+
emitUnknown(line, KEYS.eventLyricLine, linePath, dx);
|
|
16193
|
+
let extender = line.extender;
|
|
16194
|
+
extender && emitUnknown(extender, KEYS.eventLyricLineExtender, linePath + ptr("extender"), dx);
|
|
16195
|
+
}
|
|
16196
|
+
}
|
|
15940
16197
|
let notes = c.notes;
|
|
15941
16198
|
Array.isArray(notes) && notes.forEach((n, i) => {
|
|
15942
16199
|
n && typeof n == "object" && emitUnknown(n, KEYS.note, p + ptr("notes", i), dx);
|
|
@@ -16419,7 +16676,7 @@ function fermataMultiplier(fermata) {
|
|
|
16419
16676
|
function caesuraBeats(style) {
|
|
16420
16677
|
return style === "short" ? CAESURA_SHORT_BEATS : CAESURA_BEATS;
|
|
16421
16678
|
}
|
|
16422
|
-
function
|
|
16679
|
+
function durationBeats2(d) {
|
|
16423
16680
|
let base = DURATION_BEATS[d.base] ?? 1;
|
|
16424
16681
|
return d.dots ? base * (2 - Math.pow(2, -d.dots)) : base;
|
|
16425
16682
|
}
|
|
@@ -16437,16 +16694,16 @@ function collectFromContent(content, startBeat, ratio, spans, caesuraByBeat) {
|
|
|
16437
16694
|
let cursor = startBeat;
|
|
16438
16695
|
for (let item of content)
|
|
16439
16696
|
if (item.type === "event") {
|
|
16440
|
-
let dur =
|
|
16697
|
+
let dur = durationBeats2(item.duration) * ratio, endBeat = cursor + dur;
|
|
16441
16698
|
if (item.fermata && item.fermata.duration !== "none") {
|
|
16442
16699
|
let mult = fermataMultiplier(item.fermata);
|
|
16443
16700
|
dur > 0 && mult > 1 && spans.push({ onset: cursor, end: endBeat, duration: dur, multiplier: mult });
|
|
16444
16701
|
}
|
|
16445
16702
|
item.markings?.caesura && mergeMax(caesuraByBeat, endBeat, caesuraBeats(item.markings.caesura.style)), cursor = endBeat;
|
|
16446
16703
|
} else if (item.type === "tuplet") {
|
|
16447
|
-
let outerBeats =
|
|
16704
|
+
let outerBeats = durationBeats2(item.outer.duration) * item.outer.multiple, innerBeats = durationBeats2(item.inner.duration) * item.inner.multiple, childRatio = innerBeats > 0 ? outerBeats / innerBeats * ratio : ratio;
|
|
16448
16705
|
collectFromContent(item.content, cursor, childRatio, spans, caesuraByBeat), cursor += outerBeats * ratio;
|
|
16449
|
-
} else item.type === "tremolo" ? cursor +=
|
|
16706
|
+
} else item.type === "tremolo" ? cursor += durationBeats2(item.outer.duration) * item.outer.multiple * ratio : item.type === "space" && (cursor += item.duration[0] / item.duration[1] * 4 * ratio);
|
|
16450
16707
|
return cursor - startBeat;
|
|
16451
16708
|
}
|
|
16452
16709
|
function collectPartMeasureHolds(partMeasure, originalMeasureIndex, staffMeterTable, spans, caesuraByBeat) {
|
|
@@ -16509,21 +16766,21 @@ function contentBeats(content) {
|
|
|
16509
16766
|
for (let item of content)
|
|
16510
16767
|
switch (item.type) {
|
|
16511
16768
|
case "event":
|
|
16512
|
-
beats +=
|
|
16769
|
+
beats += durationBeats3(item.duration.base, item.duration.dots);
|
|
16513
16770
|
break;
|
|
16514
16771
|
case "space":
|
|
16515
16772
|
beats += item.duration[0] / item.duration[1] * 4;
|
|
16516
16773
|
break;
|
|
16517
16774
|
case "tuplet":
|
|
16518
16775
|
case "tremolo":
|
|
16519
|
-
beats +=
|
|
16776
|
+
beats += durationBeats3(item.outer.duration.base, item.outer.duration.dots) * item.outer.multiple;
|
|
16520
16777
|
break;
|
|
16521
16778
|
case "grace":
|
|
16522
16779
|
break;
|
|
16523
16780
|
}
|
|
16524
16781
|
return beats;
|
|
16525
16782
|
}
|
|
16526
|
-
function
|
|
16783
|
+
function durationBeats3(base, dots) {
|
|
16527
16784
|
let beats = DURATION_BEATS[base];
|
|
16528
16785
|
return dots ? beats * (2 - Math.pow(2, -dots)) : beats;
|
|
16529
16786
|
}
|
|
@@ -17610,7 +17867,7 @@ function kitNoteToMidi(kn, kitMidiMap) {
|
|
|
17610
17867
|
return kitMidiMap.get(kn.kitComponent) ?? -1;
|
|
17611
17868
|
}
|
|
17612
17869
|
var GRACE_NOTE_BEATS = 0.125;
|
|
17613
|
-
function
|
|
17870
|
+
function durationBeats4(d) {
|
|
17614
17871
|
let base = DURATION_BEATS[d.base] ?? 1;
|
|
17615
17872
|
return d.dots ? base * (2 - Math.pow(2, -d.dots)) : base;
|
|
17616
17873
|
}
|
|
@@ -17927,7 +18184,7 @@ function tryProcessSpecialEvent(ctx, event, measureStartTime, beatOffset, baseVe
|
|
|
17927
18184
|
}
|
|
17928
18185
|
function processNoteEvent(ctx, event, measureStartTime, beatOffset, baseVelocity, tupletRatio) {
|
|
17929
18186
|
ctx.gmProgram = ctx.instrumentAtBeatOffset?.(beatOffset * ctx.staffMeterRatio).program ?? ctx.gmProgram;
|
|
17930
|
-
let { partIndex, channel, tieTargets, out, timeSig, kitMidiMap, kitAltProgramMap } = ctx, beats =
|
|
18187
|
+
let { partIndex, channel, tieTargets, out, timeSig, kitMidiMap, kitAltProgramMap } = ctx, beats = durationBeats4(event.duration) * tupletRatio;
|
|
17931
18188
|
if (isRest(event))
|
|
17932
18189
|
return flushVoiceLegato(ctx.pendingLegato, ctx.voiceKey, ctx.out), beats;
|
|
17933
18190
|
resolveVoiceLegato({
|
|
@@ -18240,30 +18497,30 @@ function processGrace(ctx, grace, measureStartTime, beatOffset, tupletRatio) {
|
|
|
18240
18497
|
if (grace.graceType === "stealFollowing") {
|
|
18241
18498
|
let cursor2 = beatOffset;
|
|
18242
18499
|
for (let evt of events) {
|
|
18243
|
-
let ratio = graceBeats /
|
|
18500
|
+
let ratio = graceBeats / durationBeats4(evt.duration);
|
|
18244
18501
|
processScopedNoteEvent(ctx, evt, measureStartTime, cursor2, ratio), cursor2 += graceBeats;
|
|
18245
18502
|
}
|
|
18246
18503
|
return totalGraceBeats;
|
|
18247
18504
|
}
|
|
18248
18505
|
let cursor = beatOffset - totalGraceBeats;
|
|
18249
18506
|
for (let evt of events) {
|
|
18250
|
-
let ratio = graceBeats /
|
|
18507
|
+
let ratio = graceBeats / durationBeats4(evt.duration);
|
|
18251
18508
|
processScopedNoteEvent(ctx, evt, measureStartTime, cursor, ratio), cursor += graceBeats;
|
|
18252
18509
|
}
|
|
18253
18510
|
return 0;
|
|
18254
18511
|
}
|
|
18255
18512
|
function processTuplet(ctx, tuplet, measureStartTime, beatOffset, parentTupletRatio) {
|
|
18256
|
-
let outerBeats =
|
|
18513
|
+
let outerBeats = durationBeats4(tuplet.outer.duration) * tuplet.outer.multiple, innerBeats = durationBeats4(tuplet.inner.duration) * tuplet.inner.multiple, ratio = outerBeats / innerBeats * parentTupletRatio, cursor = beatOffset;
|
|
18257
18514
|
for (let item of tuplet.content)
|
|
18258
18515
|
cursor += processContentItem(ctx, item, measureStartTime, cursor, ratio);
|
|
18259
18516
|
return outerBeats * parentTupletRatio;
|
|
18260
18517
|
}
|
|
18261
18518
|
function processTremolo(ctx, tremolo, measureStartTime, beatOffset, tupletRatio) {
|
|
18262
|
-
let outerBeats =
|
|
18519
|
+
let outerBeats = durationBeats4(tremolo.outer.duration) * tremolo.outer.multiple * tupletRatio;
|
|
18263
18520
|
if (tremolo.content.length < 2) return outerBeats;
|
|
18264
18521
|
let subdivisions = Math.pow(2, tremolo.marks), subdivBeats = outerBeats / subdivisions;
|
|
18265
18522
|
for (let s = 0; s < subdivisions; s++) {
|
|
18266
|
-
let noteEvent = tremolo.content[s % 2], subBeatOffset = beatOffset + s * subdivBeats, subRatio = subdivBeats /
|
|
18523
|
+
let noteEvent = tremolo.content[s % 2], subBeatOffset = beatOffset + s * subdivBeats, subRatio = subdivBeats / durationBeats4(noteEvent.duration);
|
|
18267
18524
|
processScopedNoteEvent(ctx, noteEvent, measureStartTime, subBeatOffset, subRatio);
|
|
18268
18525
|
}
|
|
18269
18526
|
return outerBeats;
|