@stringsync/vexml
Version:
MusicXML to Vexflow
96 lines (95 loc) • 3.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Metronome = void 0;
const enums_1 = require("./enums");
/**
* Represents metronome marks and other metric relationships.
*
* Only supports simple meters in the form of [beat-unit symbol] = [bpm].
*
* See https://www.w3.org/2021/06/musicxml40/musicxml-reference/elements/metronome/.
*/
class Metronome {
element;
constructor(element) {
this.element = element;
}
/** Returns whether the metronome mark is in parentheses. */
parentheses() {
return this.element.attr('parentheses').withDefault('no').str() === 'yes';
}
/** Returns the metronome mark details. Defaults to a quarter note = 120 bpm. */
getMark() {
const leftElements = new Array();
const rightElements = new Array();
for (const child of this.element.children()) {
const hasLeftElements = leftElements.length > 0;
const hasRightElements = rightElements.length > 0;
if (child.isNamed('beat-unit')) {
if (hasLeftElements) {
rightElements.push(child);
}
else {
leftElements.push(child);
}
}
if (child.isNamed('beat-unit-dot')) {
if (hasRightElements) {
rightElements.push(child);
}
else {
leftElements.push(child);
}
}
if (child.isNamed('per-minute')) {
rightElements.push(child);
}
}
if (!this.isWellFormedNote(leftElements)) {
return null;
}
const rightOperandType = this.isWellFormedNote(rightElements)
? 'note'
: this.isWellFormedBpm(rightElements)
? 'bpm'
: 'invalid';
if (rightOperandType === 'invalid') {
return null;
}
return {
left: this.noteOperand(leftElements),
right: rightOperandType === 'note' ? this.noteOperand(rightElements) : this.bpmOperand(rightElements),
};
}
noteOperand(elements) {
const unit = elements[0].content().enum(enums_1.NOTE_TYPES) ?? 'quarter';
const dotCount = elements.slice(1).filter((child) => child.isNamed('beat-unit-dot')).length;
return { type: 'note', unit, dotCount };
}
bpmOperand(elements) {
const bpm = elements[0].content().int() ?? 120;
return { type: 'bpm', bpm };
}
isWellFormedNote(elements) {
if (elements.length === 0) {
return false;
}
if (!elements[0].isNamed('beat-unit')) {
return false;
}
if (elements.slice(1).some((child) => !child.isNamed('beat-unit-dot'))) {
return false;
}
return true;
}
isWellFormedBpm(elements) {
if (elements.length > 1) {
return false;
}
if (!elements[0].isNamed('per-minute')) {
return false;
}
return true;
}
}
exports.Metronome = Metronome;