@stringsync/vexml
Version:
MusicXML to Vexflow
152 lines (151 loc) • 6.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Measure = void 0;
const util = __importStar(require("../../util"));
const fragment_1 = require("./fragment");
const signature_1 = require("./signature");
const contexts_1 = require("./contexts");
class Measure {
config;
log;
initialSignature;
index;
label;
events;
jumpGroup;
startBarlineStyle;
endBarlineStyle;
fragments;
repetitionSymbols;
constructor(config, log, initialSignature, index, label, events, jumpGroup, startBarlineStyle, endBarlineStyle, fragments, repetitionSymbols) {
this.config = config;
this.log = log;
this.initialSignature = initialSignature;
this.index = index;
this.label = label;
this.events = events;
this.jumpGroup = jumpGroup;
this.startBarlineStyle = startBarlineStyle;
this.endBarlineStyle = endBarlineStyle;
this.fragments = fragments;
this.repetitionSymbols = repetitionSymbols;
util.assert(events.every((e) => e.measureIndex === index), 'Expected all events to belong to the current measure');
}
static create(config, log, initialSignature, index, label, events, partIds, jumpGroup, startBarlineStyle, endBarlineStyle) {
const fragments = Measure.fragmentize(config, log, events, initialSignature, partIds);
// TODO: Incoporate this when calculating jumps.
const repetitionSymbols = new Array();
if (events.some((e) => e.type === 'coda')) {
repetitionSymbols.push('coda');
}
if (events.some((e) => e.type === 'segno')) {
repetitionSymbols.push('segno');
}
return new Measure(config, log, initialSignature, index, label, events, jumpGroup, startBarlineStyle, endBarlineStyle, fragments, repetitionSymbols);
}
static fragmentize(config, log, measureEvents, initialSignature, partIds) {
const fragments = new Array();
const sortedEvents = measureEvents.toSorted((a, b) => a.measureBeat.toDecimal() - b.measureBeat.toDecimal());
// First, get all the unique measure beats that events happen on. When we come across a measure beat, we have to
// process all the events that happen on that beat before making a decision.
const measureBeats = util.uniqueBy(sortedEvents, (e) => e.measureBeat.toDecimal()).map((e) => e.measureBeat);
// Next, we calculate the fragment boundaries by maintaining a buffer of the next fragment events. When the
// signature changes, we'll materialize the buffer into a Fragment, then start a new buffer. We'll also do
// this if the buffer has items after going over all the measure beats.
let signature = initialSignature;
let buffer = new Array();
for (const measureBeat of measureBeats) {
const measureBeatEvents = sortedEvents.filter((e) => measureBeat.toDecimal() === e.measureBeat.toDecimal());
const builder = signature_1.Signature.builder(config, log).setPreviousSignature(signature);
// Apply all the signature-changing events.
for (const event of measureBeatEvents) {
switch (event.type) {
case 'metronome':
builder.setMetronome(event.metronome);
break;
case 'stavecount':
builder.addStaveCount(event.staveCount);
break;
case 'stavelinecount':
builder.addStaveLineCount(event.staveLineCount);
break;
case 'clef':
builder.addClef(event.clef);
break;
case 'key':
builder.addKey(event.key);
break;
case 'time':
builder.addTime(event.time);
break;
}
}
// If the signature changed and there are events in the buffer, materialize a fragment with the **old** signature.
const nextSignature = builder.build();
if (nextSignature.hasChanges() && buffer.length > 0) {
fragments.push(fragment_1.Fragment.create(config, log, signature, buffer, partIds));
buffer = [];
}
signature = nextSignature;
// Process all the stave events that happen on this measure beat.
const staveEvents = measureBeatEvents.filter((e) => typeof e.staveNumber === 'number');
buffer.push(...staveEvents);
}
if (buffer.length > 0) {
fragments.push(fragment_1.Fragment.create(config, log, signature, buffer, partIds));
}
return fragments;
}
getEvents() {
return this.events;
}
getLastSignature() {
return this.fragments.at(-1)?.getSignature() ?? this.initialSignature;
}
parse(systemCtx) {
const measureCtx = new contexts_1.MeasureContext(systemCtx, this.index);
return {
type: 'measure',
label: this.label,
fragments: this.fragments.map((fragment) => fragment.parse(measureCtx)),
jumps: this.jumpGroup.parse(),
startBarlineStyle: this.startBarlineStyle,
endBarlineStyle: this.endBarlineStyle,
repetitionSymbols: this.repetitionSymbols,
};
}
}
exports.Measure = Measure;