@stringsync/vexml
Version:
MusicXML to Vexflow
717 lines (716 loc) • 23.6 kB
JavaScript
"use strict";
/**
* @file This file contains **mutable** context objects that are used during parsing.
*
* When parsing, parent contexts may need to drill state to a distant descendant. Conversely, a child context may need
* to communicate state to a distant ancestor. Separate context objects are used to avoid passing state through many
* layers and to avoid tight coupling between the main parsing classes.
*
* NOTE: This code must **not** depend on any other parsing code because it will create an undesireble dependency graph.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.VoiceEntryContext = exports.VoiceContext = exports.StaveContext = exports.PartContext = exports.FragmentContext = exports.MeasureContext = exports.SystemContext = exports.ScoreContext = void 0;
class ScoreContext {
idProvider;
// part ID -> nullable stave number -> multi rest count
// When the stave number is null, the multi rest count applies to all staves in the part.
multiRestCounts = new Map();
curves = new Array();
// curve number -> curve ID
// See https://www.w3.org/2021/06/musicxml40/musicxml-reference/elements/slur/#:~:text=dotted%2C%20or%20wavy.-,number,-number%2Dlevel
curveIds = new Map();
wedges = new Array();
// part ID -> stave number -> wedge status
wedgeStatuses = new Map();
pedals = new Array();
// part ID -> pedal status
pedalStatuses = new Map();
octaveShifts = new Array();
// part ID -> stave number -> octave shift status
octaveShiftStatuses = new Map();
vibratos = new Array();
// vibrato number -> vibrato ID
vibratoStatuses = new Map();
constructor(idProvider) {
this.idProvider = idProvider;
}
nextId() {
return this.idProvider.next();
}
getMultiRestCount(partId, staveNumber) {
return this.multiRestCounts.get(partId)?.get(null) ?? this.multiRestCounts.get(partId)?.get(staveNumber) ?? 0;
}
incrementMultiRestCount(partId, staveNumber, count) {
if (!this.multiRestCounts.has(partId)) {
this.multiRestCounts.set(partId, new Map());
}
this.multiRestCounts.get(partId).set(staveNumber, count + this.getMultiRestCount(partId, staveNumber));
}
decrementMultiRestCounts() {
for (const partId of this.multiRestCounts.keys()) {
const staveNumbers = this.multiRestCounts.get(partId).keys();
for (const staveNumber of staveNumbers) {
const count = this.getMultiRestCount(partId, staveNumber);
if (count > 0) {
this.multiRestCounts.get(partId).set(staveNumber, count - 1);
}
}
}
}
getCurves() {
return this.curves;
}
beginCurve(curveNumber, placement, opening, articulation) {
const id = this.nextId();
this.curves.push({ type: 'curve', id, placement, opening, articulation });
this.curveIds.set(curveNumber, id);
return id;
}
continueCurve(curveNumber) {
return this.curveIds.get(curveNumber) ?? null;
}
getWedges() {
return this.wedges;
}
beginWedge(partId, staveNumber, wedgeType, placement) {
const id = this.nextId();
this.wedges.push({ type: 'wedge', wedgeType, id, placement });
if (!this.wedgeStatuses.has(partId)) {
this.wedgeStatuses.set(partId, new Map());
}
this.wedgeStatuses.get(partId).set(staveNumber, { id, count: 0, delete: false });
return id;
}
continueOpenWedge(partId, staveNumber) {
const status = this.wedgeStatuses.get(partId)?.get(staveNumber);
if (!status) {
return null;
}
if (status.delete) {
this.wedgeStatuses.get(partId)?.delete(staveNumber);
}
status.count++;
return status.id;
}
closeWedge(partId, staveNumber) {
const status = this.wedgeStatuses.get(partId)?.get(staveNumber);
if (!status) {
return;
}
if (status.count > 1) {
this.wedgeStatuses.get(partId)?.delete(staveNumber);
}
else {
// We don't meet the criteria to be fully specified, so we'll mark for delete later.
status.delete = true;
}
}
getPedals() {
return this.pedals;
}
beginPedal(partId, pedalType) {
const id = this.nextId();
this.pedals.push({ type: 'pedal', id, pedalType });
this.pedalStatuses.set(partId, { id, next: 'default', count: 0, delete: false });
return id;
}
continueOpenPedal(partId) {
const status = this.pedalStatuses.get(partId);
if (!status) {
return null;
}
const pedalMarkType = status.next;
status.next = 'default'; // consume the next pedal mark type
if (status.delete && status.count > 1) {
this.pedalStatuses.delete(partId);
}
status.count++;
return { type: 'pedalmark', pedalMarkType, pedalId: status.id };
}
primeNextPedalMark(partId, pedalMarkType) {
const status = this.pedalStatuses.get(partId);
if (!status) {
return;
}
status.next = pedalMarkType;
if (pedalMarkType === 'change') {
// We want to avoid ending the pedal on a change, so we'll reset the count.
status.count = 0;
}
}
closePedal(partId) {
const status = this.pedalStatuses.get(partId);
if (!status) {
return;
}
if (status.count > 1) {
this.pedalStatuses.delete(partId);
}
else {
// We don't meet the criteria to be fully specified, so we'll mark for delete later.
status.delete = true;
}
}
getOctaveShifts() {
return this.octaveShifts;
}
beginOctaveShift(partId, staveNumber, size) {
const id = this.nextId();
this.octaveShifts.push({ type: 'octaveshift', id, size });
if (!this.octaveShiftStatuses.has(partId)) {
this.octaveShiftStatuses.set(partId, new Map());
}
this.octaveShiftStatuses.get(partId).set(staveNumber, { id, count: 0, delete: false });
return id;
}
continueOpenOctaveShift(partId, staveNumber) {
const status = this.octaveShiftStatuses.get(partId)?.get(staveNumber);
if (!status) {
return null;
}
if (status.delete && status.count > 1) {
this.octaveShiftStatuses.get(partId)?.delete(staveNumber);
}
status.count++;
return status.id;
}
closeOctaveShift(partId, staveNumber) {
const status = this.octaveShiftStatuses.get(partId)?.get(staveNumber);
if (!status) {
return;
}
if (status.count > 1) {
this.octaveShiftStatuses.get(partId)?.delete(staveNumber);
}
else {
// We don't meet the criteria to be fully specified, so we'll mark for delete later.
status.delete = true;
}
}
getVibratos() {
return this.vibratos;
}
beginVibrato(vibratoNumber) {
const id = this.nextId();
this.vibratos.push({ type: 'vibrato', id });
this.vibratoStatuses.set(vibratoNumber, id);
return id;
}
continueVibrato(vibratoNumber) {
return this.vibratoStatuses.get(vibratoNumber) ?? null;
}
}
exports.ScoreContext = ScoreContext;
class SystemContext {
score;
constructor(score) {
this.score = score;
}
nextId() {
return this.score.nextId();
}
getMultiRestCount(partId, staveNumber) {
return this.score.getMultiRestCount(partId, staveNumber);
}
incrementMultiRestCount(partId, staveNumber, count) {
return this.score.incrementMultiRestCount(partId, staveNumber, count);
}
decrementMultiRestCounts() {
return this.score.decrementMultiRestCounts();
}
beginCurve(curveNumber, placement, opening, articulation) {
return this.score.beginCurve(curveNumber, placement, opening, articulation);
}
continueCurve(curveNumber) {
return this.score.continueCurve(curveNumber);
}
beginWedge(partId, staveNumber, wedgeType, placement) {
return this.score.beginWedge(partId, staveNumber, wedgeType, placement);
}
continueOpenWedge(partId, staveNumber) {
return this.score.continueOpenWedge(partId, staveNumber);
}
closeWedge(partId, staveNumber) {
this.score.closeWedge(partId, staveNumber);
}
beginPedal(partId, pedalType) {
return this.score.beginPedal(partId, pedalType);
}
continueOpenPedal(partId) {
return this.score.continueOpenPedal(partId);
}
primeNextPedalMark(partId, pedalMarkType) {
this.score.primeNextPedalMark(partId, pedalMarkType);
}
closePedal(partId) {
this.score.closePedal(partId);
}
beginOctaveShift(partId, staveNumber, size) {
return this.score.beginOctaveShift(partId, staveNumber, size);
}
continueOpenOctaveShift(partId, staveNumber) {
return this.score.continueOpenOctaveShift(partId, staveNumber);
}
closeOctaveShift(partId, staveNumber) {
this.score.closeOctaveShift(partId, staveNumber);
}
beginVibrato(vibratoNumber) {
return this.score.beginVibrato(vibratoNumber);
}
continueVibrato(vibratoNumber) {
return this.score.continueVibrato(vibratoNumber);
}
}
exports.SystemContext = SystemContext;
class MeasureContext {
system;
index;
// part ID -> pitch -> octave -> accidental code
accidentals = {};
constructor(system, index) {
this.system = system;
this.index = index;
}
nextId() {
return this.system.nextId();
}
getIndex() {
return this.index;
}
getActiveAccidental(partId, pitch, octave) {
return this.accidentals[partId]?.[pitch]?.[octave] ?? null;
}
setActiveAccidental(partId, pitch, octave, accidental) {
this.accidentals[partId] ??= {};
this.accidentals[partId][pitch] ??= {};
this.accidentals[partId][pitch][octave] = accidental;
}
getMultiRestCount(partId, staveNumber) {
return this.system.getMultiRestCount(partId, staveNumber);
}
beginCurve(curveNumber, placement, opening, articulation) {
return this.system.beginCurve(curveNumber, placement, opening, articulation);
}
continueCurve(curveNumber) {
return this.system.continueCurve(curveNumber);
}
beginWedge(partId, staveNumber, wedgeType, placement) {
return this.system.beginWedge(partId, staveNumber, wedgeType, placement);
}
continueOpenWedge(partId, staveNumber) {
return this.system.continueOpenWedge(partId, staveNumber);
}
closeWedge(partId, staveNumber) {
this.system.closeWedge(partId, staveNumber);
}
beginPedal(partId, pedalType) {
return this.system.beginPedal(partId, pedalType);
}
continueOpenPedal(partId) {
return this.system.continueOpenPedal(partId);
}
primeNextPedalMark(partId, pedalMarkType) {
this.system.primeNextPedalMark(partId, pedalMarkType);
}
closePedal(partId) {
this.system.closePedal(partId);
}
beginOctaveShift(partId, staveNumber, size) {
return this.system.beginOctaveShift(partId, staveNumber, size);
}
continueOpenOctaveShift(partId, staveNumber) {
return this.system.continueOpenOctaveShift(partId, staveNumber);
}
closeOctaveShift(partId, staveNumber) {
this.system.closeOctaveShift(partId, staveNumber);
}
beginVibrato(vibratoNumber) {
return this.system.beginVibrato(vibratoNumber);
}
continueVibrato(vibratoNumber) {
return this.system.continueVibrato(vibratoNumber);
}
}
exports.MeasureContext = MeasureContext;
class FragmentContext {
measure;
signature;
constructor(measure, signature) {
this.measure = measure;
this.signature = signature;
}
nextId() {
return this.measure.nextId();
}
getSignature() {
return this.signature;
}
getActiveAccidental(partId, pitch, octave) {
return this.measure.getActiveAccidental(partId, pitch, octave);
}
setActiveAccidental(partId, pitch, octave, accidental) {
this.measure.setActiveAccidental(partId, pitch, octave, accidental);
}
getMultiRestCount(partId, staveNumber) {
return this.measure.getMultiRestCount(partId, staveNumber);
}
beginCurve(curveNumber, placement, opening, articulation) {
return this.measure.beginCurve(curveNumber, placement, opening, articulation);
}
continueCurve(curveNumber) {
return this.measure.continueCurve(curveNumber);
}
beginWedge(partId, staveNumber, wedgeType, placement) {
return this.measure.beginWedge(partId, staveNumber, wedgeType, placement);
}
continueOpenWedge(partId, staveNumber) {
return this.measure.continueOpenWedge(partId, staveNumber);
}
closeWedge(partId, staveNumber) {
this.measure.closeWedge(partId, staveNumber);
}
beginPedal(partId, pedalType) {
return this.measure.beginPedal(partId, pedalType);
}
continueOpenPedal(partId) {
return this.measure.continueOpenPedal(partId);
}
primeNextPedalMark(partId, pedalMarkType) {
this.measure.primeNextPedalMark(partId, pedalMarkType);
}
closePedal(partId) {
this.measure.closePedal(partId);
}
beginOctaveShift(partId, staveNumber, size) {
return this.measure.beginOctaveShift(partId, staveNumber, size);
}
continueOpenOctaveShift(partId, staveNumber) {
return this.measure.continueOpenOctaveShift(partId, staveNumber);
}
closeOctaveShift(partId, staveNumber) {
this.measure.closeOctaveShift(partId, staveNumber);
}
beginVibrato(vibratoNumber) {
return this.measure.beginVibrato(vibratoNumber);
}
continueVibrato(vibratoNumber) {
return this.measure.continueVibrato(vibratoNumber);
}
}
exports.FragmentContext = FragmentContext;
class PartContext {
fragment;
id;
constructor(fragment, id) {
this.fragment = fragment;
this.id = id;
}
nextId() {
return this.fragment.nextId();
}
getId() {
return this.id;
}
getKey(staveNumber) {
return this.fragment.getSignature().getKey(this.id, staveNumber);
}
getTime(staveNumber) {
return this.fragment.getSignature().getTime(this.id, staveNumber);
}
getActiveAccidental(pitch, octave) {
return this.fragment.getActiveAccidental(this.id, pitch, octave);
}
setActiveAccidental(pitch, octave, accidental) {
this.fragment.setActiveAccidental(this.id, pitch, octave, accidental);
}
getMultiRestCount(staveNumber) {
return this.fragment.getMultiRestCount(this.id, staveNumber);
}
beginCurve(curveNumber, placement, opening, articulation) {
return this.fragment.beginCurve(curveNumber, placement, opening, articulation);
}
continueCurve(curveNumber) {
return this.fragment.continueCurve(curveNumber);
}
beginWedge(placement, wedgeType, staveNumber) {
return this.fragment.beginWedge(this.id, staveNumber, wedgeType, placement);
}
continueOpenWedge(staveNumber) {
return this.fragment.continueOpenWedge(this.id, staveNumber);
}
closeWedge(staveNumber) {
this.fragment.closeWedge(this.id, staveNumber);
}
beginPedal(pedalType) {
return this.fragment.beginPedal(this.id, pedalType);
}
continueOpenPedal() {
return this.fragment.continueOpenPedal(this.id);
}
primeNextPedalMark(pedalMarkType) {
this.fragment.primeNextPedalMark(this.id, pedalMarkType);
}
closePedal() {
this.fragment.closePedal(this.id);
}
beginOctaveShift(staveNumber, size) {
return this.fragment.beginOctaveShift(this.id, staveNumber, size);
}
continueOpenOctaveShift(staveNumber) {
return this.fragment.continueOpenOctaveShift(this.id, staveNumber);
}
closeOctaveShift(staveNumber) {
this.fragment.closeOctaveShift(this.id, staveNumber);
}
beginVibrato(vibratoNumber) {
return this.fragment.beginVibrato(vibratoNumber);
}
continueVibrato(vibratoNumber) {
return this.fragment.continueVibrato(vibratoNumber);
}
}
exports.PartContext = PartContext;
class StaveContext {
part;
number;
constructor(part, number) {
this.part = part;
this.number = number;
}
nextId() {
return this.part.nextId();
}
getNumber() {
return this.number;
}
getKey() {
return this.part.getKey(this.number);
}
getTime() {
return this.part.getTime(this.number);
}
getActiveAccidental(pitch, octave) {
return this.part.getActiveAccidental(pitch, octave);
}
setActiveAccidental(pitch, octave, accidental) {
this.part.setActiveAccidental(pitch, octave, accidental);
}
getMultiRestCount() {
return this.part.getMultiRestCount(this.number);
}
beginCurve(curveNumber, placement, opening, articulation) {
return this.part.beginCurve(curveNumber, placement, opening, articulation);
}
continueCurve(curveNumber) {
return this.part.continueCurve(curveNumber);
}
beginWedge(placement, wedgeType) {
return this.part.beginWedge(placement, wedgeType, this.number);
}
continueOpenWedge() {
return this.part.continueOpenWedge(this.number);
}
closeWedge() {
this.part.closeWedge(this.number);
}
beginPedal(pedalType) {
return this.part.beginPedal(pedalType);
}
continueOpenPedal() {
return this.part.continueOpenPedal();
}
primeNextPedalMark(pedalMarkType) {
this.part.primeNextPedalMark(pedalMarkType);
}
closePedal() {
this.part.closePedal();
}
beginOctaveShift(size) {
return this.part.beginOctaveShift(this.number, size);
}
continueOpenOctaveShift() {
return this.part.continueOpenOctaveShift(this.number);
}
closeOctaveShift() {
this.part.closeOctaveShift(this.number);
}
beginVibrato(vibratoNumber) {
return this.part.beginVibrato(vibratoNumber);
}
continueVibrato(vibratoNumber) {
return this.part.continueVibrato(vibratoNumber);
}
}
exports.StaveContext = StaveContext;
class VoiceContext {
stave;
id;
beams = new Array();
// tuplet number -> tuplet
openTuplets = new Map();
closedTuplets = new Array();
constructor(stave, id) {
this.stave = stave;
this.id = id;
}
nextId() {
return this.stave.nextId();
}
getId() {
return this.id;
}
getKey() {
return this.stave.getKey();
}
getTime() {
return this.stave.getTime();
}
getActiveAccidental(pitch, octave) {
return this.stave.getActiveAccidental(pitch, octave);
}
setActiveAccidental(pitch, octave, accidental) {
this.stave.setActiveAccidental(pitch, octave, accidental);
}
getMultiRestCount() {
return this.stave.getMultiRestCount();
}
beginCurve(curveNumber, placement, opening, articulation) {
return this.stave.beginCurve(curveNumber, placement, opening, articulation);
}
continueCurve(curveNumber) {
return this.stave.continueCurve(curveNumber);
}
getBeams() {
return this.beams;
}
beginBeam() {
const id = this.nextId();
this.beams.push({ type: 'beam', id });
return id;
}
continueBeam() {
return this.beams.at(-1)?.id ?? null;
}
getTuplets() {
return this.closedTuplets;
}
beginTuplet(number, showNumber, placement) {
const id = this.nextId();
this.openTuplets.set(number, { type: 'tuplet', id, showNumber, placement });
return id;
}
continueOpenTuplets() {
return [...this.openTuplets.values()].map((tuplet) => tuplet.id);
}
closeTuplet(number) {
if (!this.openTuplets.has(number)) {
return null;
}
const tuplet = this.openTuplets.get(number);
this.closedTuplets.push(tuplet);
this.openTuplets.delete(number);
return tuplet.id;
}
beginWedge(placement, wedgeType) {
return this.stave.beginWedge(placement, wedgeType);
}
continueOpenWedge() {
return this.stave.continueOpenWedge();
}
closeWedge() {
this.stave.closeWedge();
}
beginPedal(pedalType) {
return this.stave.beginPedal(pedalType);
}
continueOpenPedal() {
return this.stave.continueOpenPedal();
}
primeNextPedalMark(pedalMarkType) {
this.stave.primeNextPedalMark(pedalMarkType);
}
closePedal() {
this.stave.closePedal();
}
beginOctaveShift(size) {
return this.stave.beginOctaveShift(size);
}
continueOpenOctaveShift() {
return this.stave.continueOpenOctaveShift();
}
closeOctaveShift() {
this.stave.closeOctaveShift();
}
beginVibrato(vibratoNumber) {
return this.stave.beginVibrato(vibratoNumber);
}
continueVibrato(vibratoNumber) {
return this.stave.continueVibrato(vibratoNumber);
}
}
exports.VoiceContext = VoiceContext;
class VoiceEntryContext {
voice;
pitch;
octave;
constructor(voice, pitch, octave) {
this.voice = voice;
this.pitch = pitch;
this.octave = octave;
}
static note(voice, pitch, octave) {
return new VoiceEntryContext(voice, pitch, octave);
}
static rest(voice) {
return new VoiceEntryContext(voice, '', 0);
}
nextId() {
return this.voice.nextId();
}
getKeyAccidental() {
return this.voice.getKey().getAccidentalCode(this.pitch);
}
getActiveAccidental() {
return this.voice.getActiveAccidental(this.pitch, this.octave);
}
setActiveAccidental(accidental) {
this.voice.setActiveAccidental(this.pitch, this.octave, accidental);
}
beginCurve(curveNumber, placement, opening, articulation) {
return this.voice.beginCurve(curveNumber, placement, opening, articulation);
}
continueCurve(curveNumber) {
return this.voice.continueCurve(curveNumber);
}
beginBeam() {
return this.voice.beginBeam();
}
continueBeam() {
return this.voice.continueBeam();
}
beginTuplet(number, showNumber, placement) {
return this.voice.beginTuplet(number, showNumber, placement);
}
continueOpenTuplets() {
return this.voice.continueOpenTuplets();
}
closeTuplet(number) {
return this.voice.closeTuplet(number);
}
continueOpenWedge() {
return this.voice.continueOpenWedge();
}
continueOpenPedal() {
return this.voice.continueOpenPedal();
}
continueOpenOctaveShift() {
return this.voice.continueOpenOctaveShift();
}
beginVibrato(vibratoNumber) {
return this.voice.beginVibrato(vibratoNumber);
}
continueVibrato(vibratoNumber) {
return this.voice.continueVibrato(vibratoNumber);
}
}
exports.VoiceEntryContext = VoiceEntryContext;