@viritura/score-engine 0.1.1-next.27 → 0.1.1-next.28

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 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.27", BUNDLE_WORKER_FILE = "score-engine.worker.js";
2216
+ var PACKAGE_VERSION = "0.1.1-next.28", BUNDLE_WORKER_FILE = "score-engine.worker.js";
1993
2217
  function buildCommit() {
1994
- return "d8a389281839ea20c0cf0bd2b087c1fc253b43f5";
2218
+ return "29a9ddc177a7341276fc760a1004f0dd17bfcbb2";
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,127 @@ 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
+ "fine",
15718
+ "jump",
15719
+ "_x"
15720
+ ]),
15721
+ time: /* @__PURE__ */ new Set(["count", "unit", "display", "_x"]),
15722
+ key: /* @__PURE__ */ new Set(["fifths", "color", "_x"]),
15723
+ barline: /* @__PURE__ */ new Set(["type"]),
15724
+ ending: /* @__PURE__ */ new Set(["duration", "numbers", "open", "color"]),
15725
+ tempo: /* @__PURE__ */ new Set(["bpm", "value", "location", "_x"]),
15726
+ tempoNoteValue: /* @__PURE__ */ new Set(["base", "dots"]),
15727
+ rhythmicPosition: /* @__PURE__ */ new Set(["fraction"]),
15728
+ segno: /* @__PURE__ */ new Set(["location", "glyph", "color"]),
15729
+ fine: /* @__PURE__ */ new Set(["location", "color"]),
15730
+ jump: /* @__PURE__ */ new Set(["type", "location"]),
15731
+ part: /* @__PURE__ */ new Set(["id", "name", "shortName", "staves", "transposition", "measures", "_x"]),
15732
+ transposition: /* @__PURE__ */ new Set(["interval", "keyFifthsFlipAt", "prefersWrittenPitches"]),
15733
+ partMeasure: /* @__PURE__ */ new Set([
15734
+ "sequences",
15735
+ "clefs",
15736
+ "staffConfigs",
15737
+ "arpeggios",
15738
+ "nonArpeggios",
15739
+ "beams",
15740
+ "dynamics",
15741
+ "ottavas",
15742
+ "measureRepeat",
15743
+ "_x"
15744
+ ]),
15745
+ positionedStaffConfig: /* @__PURE__ */ new Set(["config", "position", "staff", "id", "_c", "_x"]),
15746
+ staffConfig: /* @__PURE__ */ new Set(["lines", "id", "_c", "_x"]),
15747
+ measureRepeat: /* @__PURE__ */ new Set(["number", "counter", "displayNumber", "staffPosition", "_c", "_x"]),
15748
+ measureRepeatCounter: /* @__PURE__ */ new Set(["count", "placement", "_c", "_x"]),
15749
+ arpeggio: /* @__PURE__ */ new Set(["id", "position", "span", "direction", "arrow", "_c", "_x"]),
15750
+ nonArpeggio: /* @__PURE__ */ new Set(["id", "position", "span", "_c", "_x"]),
15751
+ idPair: /* @__PURE__ */ new Set(["start", "end"]),
15752
+ positionedClef: /* @__PURE__ */ new Set(["clef", "position", "staff"]),
15753
+ clef: /* @__PURE__ */ new Set(["sign", "staffPosition", "color", "glyph", "octave", "showOctave", "hide"]),
15754
+ beam: /* @__PURE__ */ new Set(["events", "beams", "direction"]),
15755
+ dynamic: /* @__PURE__ */ new Set(["position", "value", "glyph", "staff", "voice"]),
15756
+ ottava: /* @__PURE__ */ new Set(["position", "end", "value", "staff", "voice"]),
15757
+ measureRhythmicPosition: /* @__PURE__ */ new Set(["measure", "position"]),
15758
+ sequence: /* @__PURE__ */ new Set(["content", "fullMeasure", "staff", "voice", "directionHint"]),
15759
+ fullMeasure: /* @__PURE__ */ new Set(["visualDuration", "staffPosition"]),
15760
+ duration: /* @__PURE__ */ new Set(["base", "dots"]),
15761
+ event: /* @__PURE__ */ new Set([
15762
+ "type",
15763
+ "id",
15764
+ "duration",
15765
+ "staff",
15766
+ "rest",
15767
+ "notes",
15768
+ "slurs",
15769
+ "markings",
15770
+ "fermata",
15771
+ "lyrics",
15772
+ "stemDirection",
15773
+ "smufl",
15774
+ "_x"
15775
+ ]),
15776
+ eventLyrics: /* @__PURE__ */ new Set(["lines"]),
15777
+ eventLyricLine: /* @__PURE__ */ new Set(["type", "text", "extender"]),
15778
+ eventLyricLineExtender: /* @__PURE__ */ new Set(["show", "target", "id"]),
15779
+ rest: /* @__PURE__ */ new Set(["staffPosition"]),
15780
+ note: /* @__PURE__ */ new Set(["pitch", "id", "ties", "accidentalDisplay", "written"]),
15781
+ pitch: /* @__PURE__ */ new Set(["step", "octave", "alter"]),
15782
+ tie: /* @__PURE__ */ new Set(["target", "targetType", "side", "lv"]),
15783
+ accidentalDisplay: /* @__PURE__ */ new Set(["show", "force", "enclosure"]),
15784
+ accidentalEnclosure: /* @__PURE__ */ new Set(["symbol"]),
15785
+ written: /* @__PURE__ */ new Set(["diatonicDelta"]),
15786
+ slur: /* @__PURE__ */ new Set(["target", "side", "sideEnd", "lineType", "startNote", "endNote"]),
15787
+ markings: /* @__PURE__ */ new Set([
15788
+ "staccato",
15789
+ "staccatissimo",
15790
+ "spiccato",
15791
+ "staccatissimoWedge",
15792
+ "tenuto",
15793
+ "accent",
15794
+ "strongAccent",
15795
+ "tremolo",
15796
+ "softAccent",
15797
+ "stress",
15798
+ "unstress",
15799
+ "breath",
15800
+ "bowDirection",
15801
+ "_x"
15802
+ ]),
15803
+ tuplet: /* @__PURE__ */ new Set(["type", "inner", "outer", "content", "bracket", "showNumber", "showValue", "placement"]),
15804
+ tupletDuration: /* @__PURE__ */ new Set(["duration", "multiple"]),
15805
+ grace: /* @__PURE__ */ new Set(["type", "content", "graceType", "slash", "color"]),
15806
+ multiTremolo: /* @__PURE__ */ new Set(["type", "content", "marks", "outer"]),
15807
+ space: /* @__PURE__ */ new Set(["type", "duration"]),
15808
+ layoutDefinition: /* @__PURE__ */ new Set(["id", "content"]),
15809
+ layoutGroup: /* @__PURE__ */ new Set(["type", "content", "symbol", "label", "barlineStyle"]),
15810
+ layoutStaff: /* @__PURE__ */ new Set(["type", "sources", "label", "labelref"]),
15811
+ layoutSource: /* @__PURE__ */ new Set(["part", "staff", "stem", "voice", "labelref"]),
15812
+ scoreDefinition: /* @__PURE__ */ new Set(["name", "layout", "multimeasureRests", "pages", "useWritten", "_x"]),
15813
+ multimeasureRest: /* @__PURE__ */ new Set(["start", "duration"]),
15814
+ page: /* @__PURE__ */ new Set(["systems"]),
15815
+ system: /* @__PURE__ */ new Set(["measure", "layout", "layoutChanges"]),
15816
+ layoutChange: /* @__PURE__ */ new Set(["layout", "location"])
15817
+ };
15818
+
15474
15819
  // packages/format/src/mnx/parserCore.ts
15475
15820
  function parseMnxUnvalidated(json) {
15476
15821
  return parseMnxInternal(json, new DiagnosticCollector());
@@ -15478,7 +15823,7 @@ function parseMnxUnvalidated(json) {
15478
15823
  function parseSupport(supportObj) {
15479
15824
  if (!supportObj) return;
15480
15825
  let support = {};
15481
- return typeof supportObj.useAccidentalDisplay == "boolean" && (support.useAccidentalDisplay = supportObj.useAccidentalDisplay), typeof supportObj.useBeams == "boolean" && (support.useBeams = supportObj.useBeams), support;
15826
+ 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
15827
  }
15483
15828
  function parseRootMetadata(rootX) {
15484
15829
  let m = rootX?.viritura?.metadata;
@@ -15646,7 +15991,16 @@ function parseMnxInternal(json, diagnostics) {
15646
15991
  },
15647
15992
  parts: parseParts(partsArr)
15648
15993
  };
15649
- return 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), scanUnknownFields(obj, diagnostics), score;
15994
+ 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);
15995
+ for (let issue of resolveLyricExtenders(score).diagnostics) {
15996
+ 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}"`;
15997
+ diagnostics.warn(
15998
+ ptr("parts", "?", "measures", "?", "sequences", "?", "content", "?", "lyrics", "lines", issue.lineId, "extender"),
15999
+ message,
16000
+ "lyric-extender-reference"
16001
+ );
16002
+ }
16003
+ return scanUnknownFields(obj, diagnostics), score;
15650
16004
  }
15651
16005
  function applyRootExtensions(score, rootX) {
15652
16006
  let metadata = parseRootMetadata(rootX);
@@ -15709,121 +16063,6 @@ function processEventIds(event, usedIds, collectOnly) {
15709
16063
  for (let n of event.notes)
15710
16064
  n.id || (n.id = mintId(usedIds));
15711
16065
  }
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
16066
  function scanUnknownFields(json, dx) {
15828
16067
  if (!json || typeof json != "object") return;
15829
16068
  let root = json;
@@ -15937,6 +16176,19 @@ function scanContentItem(c, p, dx) {
15937
16176
  let type = c.type ?? "event";
15938
16177
  if (type === "event") {
15939
16178
  emitUnknown(c, KEYS.event, p, dx);
16179
+ let lyrics = c.lyrics;
16180
+ if (lyrics) {
16181
+ emitUnknown(lyrics, KEYS.eventLyrics, p + ptr("lyrics"), dx);
16182
+ let lines = lyrics.lines;
16183
+ if (lines && typeof lines == "object")
16184
+ for (let [lineId, line] of Object.entries(lines)) {
16185
+ if (!line || typeof line != "object") continue;
16186
+ let linePath = p + ptr("lyrics", "lines", lineId);
16187
+ emitUnknown(line, KEYS.eventLyricLine, linePath, dx);
16188
+ let extender = line.extender;
16189
+ extender && emitUnknown(extender, KEYS.eventLyricLineExtender, linePath + ptr("extender"), dx);
16190
+ }
16191
+ }
15940
16192
  let notes = c.notes;
15941
16193
  Array.isArray(notes) && notes.forEach((n, i) => {
15942
16194
  n && typeof n == "object" && emitUnknown(n, KEYS.note, p + ptr("notes", i), dx);
@@ -16419,7 +16671,7 @@ function fermataMultiplier(fermata) {
16419
16671
  function caesuraBeats(style) {
16420
16672
  return style === "short" ? CAESURA_SHORT_BEATS : CAESURA_BEATS;
16421
16673
  }
16422
- function durationBeats(d) {
16674
+ function durationBeats2(d) {
16423
16675
  let base = DURATION_BEATS[d.base] ?? 1;
16424
16676
  return d.dots ? base * (2 - Math.pow(2, -d.dots)) : base;
16425
16677
  }
@@ -16437,16 +16689,16 @@ function collectFromContent(content, startBeat, ratio, spans, caesuraByBeat) {
16437
16689
  let cursor = startBeat;
16438
16690
  for (let item of content)
16439
16691
  if (item.type === "event") {
16440
- let dur = durationBeats(item.duration) * ratio, endBeat = cursor + dur;
16692
+ let dur = durationBeats2(item.duration) * ratio, endBeat = cursor + dur;
16441
16693
  if (item.fermata && item.fermata.duration !== "none") {
16442
16694
  let mult = fermataMultiplier(item.fermata);
16443
16695
  dur > 0 && mult > 1 && spans.push({ onset: cursor, end: endBeat, duration: dur, multiplier: mult });
16444
16696
  }
16445
16697
  item.markings?.caesura && mergeMax(caesuraByBeat, endBeat, caesuraBeats(item.markings.caesura.style)), cursor = endBeat;
16446
16698
  } else if (item.type === "tuplet") {
16447
- let outerBeats = durationBeats(item.outer.duration) * item.outer.multiple, innerBeats = durationBeats(item.inner.duration) * item.inner.multiple, childRatio = innerBeats > 0 ? outerBeats / innerBeats * ratio : ratio;
16699
+ 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
16700
  collectFromContent(item.content, cursor, childRatio, spans, caesuraByBeat), cursor += outerBeats * ratio;
16449
- } else item.type === "tremolo" ? cursor += durationBeats(item.outer.duration) * item.outer.multiple * ratio : item.type === "space" && (cursor += item.duration[0] / item.duration[1] * 4 * ratio);
16701
+ } 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
16702
  return cursor - startBeat;
16451
16703
  }
16452
16704
  function collectPartMeasureHolds(partMeasure, originalMeasureIndex, staffMeterTable, spans, caesuraByBeat) {
@@ -16509,21 +16761,21 @@ function contentBeats(content) {
16509
16761
  for (let item of content)
16510
16762
  switch (item.type) {
16511
16763
  case "event":
16512
- beats += durationBeats2(item.duration.base, item.duration.dots);
16764
+ beats += durationBeats3(item.duration.base, item.duration.dots);
16513
16765
  break;
16514
16766
  case "space":
16515
16767
  beats += item.duration[0] / item.duration[1] * 4;
16516
16768
  break;
16517
16769
  case "tuplet":
16518
16770
  case "tremolo":
16519
- beats += durationBeats2(item.outer.duration.base, item.outer.duration.dots) * item.outer.multiple;
16771
+ beats += durationBeats3(item.outer.duration.base, item.outer.duration.dots) * item.outer.multiple;
16520
16772
  break;
16521
16773
  case "grace":
16522
16774
  break;
16523
16775
  }
16524
16776
  return beats;
16525
16777
  }
16526
- function durationBeats2(base, dots) {
16778
+ function durationBeats3(base, dots) {
16527
16779
  let beats = DURATION_BEATS[base];
16528
16780
  return dots ? beats * (2 - Math.pow(2, -dots)) : beats;
16529
16781
  }
@@ -17610,7 +17862,7 @@ function kitNoteToMidi(kn, kitMidiMap) {
17610
17862
  return kitMidiMap.get(kn.kitComponent) ?? -1;
17611
17863
  }
17612
17864
  var GRACE_NOTE_BEATS = 0.125;
17613
- function durationBeats3(d) {
17865
+ function durationBeats4(d) {
17614
17866
  let base = DURATION_BEATS[d.base] ?? 1;
17615
17867
  return d.dots ? base * (2 - Math.pow(2, -d.dots)) : base;
17616
17868
  }
@@ -17927,7 +18179,7 @@ function tryProcessSpecialEvent(ctx, event, measureStartTime, beatOffset, baseVe
17927
18179
  }
17928
18180
  function processNoteEvent(ctx, event, measureStartTime, beatOffset, baseVelocity, tupletRatio) {
17929
18181
  ctx.gmProgram = ctx.instrumentAtBeatOffset?.(beatOffset * ctx.staffMeterRatio).program ?? ctx.gmProgram;
17930
- let { partIndex, channel, tieTargets, out, timeSig, kitMidiMap, kitAltProgramMap } = ctx, beats = durationBeats3(event.duration) * tupletRatio;
18182
+ let { partIndex, channel, tieTargets, out, timeSig, kitMidiMap, kitAltProgramMap } = ctx, beats = durationBeats4(event.duration) * tupletRatio;
17931
18183
  if (isRest(event))
17932
18184
  return flushVoiceLegato(ctx.pendingLegato, ctx.voiceKey, ctx.out), beats;
17933
18185
  resolveVoiceLegato({
@@ -18240,30 +18492,30 @@ function processGrace(ctx, grace, measureStartTime, beatOffset, tupletRatio) {
18240
18492
  if (grace.graceType === "stealFollowing") {
18241
18493
  let cursor2 = beatOffset;
18242
18494
  for (let evt of events) {
18243
- let ratio = graceBeats / durationBeats3(evt.duration);
18495
+ let ratio = graceBeats / durationBeats4(evt.duration);
18244
18496
  processScopedNoteEvent(ctx, evt, measureStartTime, cursor2, ratio), cursor2 += graceBeats;
18245
18497
  }
18246
18498
  return totalGraceBeats;
18247
18499
  }
18248
18500
  let cursor = beatOffset - totalGraceBeats;
18249
18501
  for (let evt of events) {
18250
- let ratio = graceBeats / durationBeats3(evt.duration);
18502
+ let ratio = graceBeats / durationBeats4(evt.duration);
18251
18503
  processScopedNoteEvent(ctx, evt, measureStartTime, cursor, ratio), cursor += graceBeats;
18252
18504
  }
18253
18505
  return 0;
18254
18506
  }
18255
18507
  function processTuplet(ctx, tuplet, measureStartTime, beatOffset, parentTupletRatio) {
18256
- let outerBeats = durationBeats3(tuplet.outer.duration) * tuplet.outer.multiple, innerBeats = durationBeats3(tuplet.inner.duration) * tuplet.inner.multiple, ratio = outerBeats / innerBeats * parentTupletRatio, cursor = beatOffset;
18508
+ let outerBeats = durationBeats4(tuplet.outer.duration) * tuplet.outer.multiple, innerBeats = durationBeats4(tuplet.inner.duration) * tuplet.inner.multiple, ratio = outerBeats / innerBeats * parentTupletRatio, cursor = beatOffset;
18257
18509
  for (let item of tuplet.content)
18258
18510
  cursor += processContentItem(ctx, item, measureStartTime, cursor, ratio);
18259
18511
  return outerBeats * parentTupletRatio;
18260
18512
  }
18261
18513
  function processTremolo(ctx, tremolo, measureStartTime, beatOffset, tupletRatio) {
18262
- let outerBeats = durationBeats3(tremolo.outer.duration) * tremolo.outer.multiple * tupletRatio;
18514
+ let outerBeats = durationBeats4(tremolo.outer.duration) * tremolo.outer.multiple * tupletRatio;
18263
18515
  if (tremolo.content.length < 2) return outerBeats;
18264
18516
  let subdivisions = Math.pow(2, tremolo.marks), subdivBeats = outerBeats / subdivisions;
18265
18517
  for (let s = 0; s < subdivisions; s++) {
18266
- let noteEvent = tremolo.content[s % 2], subBeatOffset = beatOffset + s * subdivBeats, subRatio = subdivBeats / durationBeats3(noteEvent.duration);
18518
+ let noteEvent = tremolo.content[s % 2], subBeatOffset = beatOffset + s * subdivBeats, subRatio = subdivBeats / durationBeats4(noteEvent.duration);
18267
18519
  processScopedNoteEvent(ctx, noteEvent, measureStartTime, subBeatOffset, subRatio);
18268
18520
  }
18269
18521
  return outerBeats;