@stringsync/vexml
Version:
MusicXML to Vexflow
112 lines (111 loc) • 4.59 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.Document = void 0;
const util = __importStar(require("../util"));
const errors = __importStar(require("../errors"));
const DEFAULT_FRAGMENT_WIDTH = 300;
/** Document is an interface for mutating a {@link Score}. */
class Document {
score;
constructor(score) {
this.score = score;
}
/** Returns a valid empty Document. */
static empty() {
return new Document({
type: 'score',
title: null,
systems: [],
partLabels: [],
curves: [],
wedges: [],
pedals: [],
octaveShifts: [],
vibratos: [],
});
}
/**
* Mutates the score by inserting a gap measure with the given message. It will cause the measure indexes to shift,
* but not the measure labels.
*/
insertGapMeasureBefore(opts) {
// Inserting gaps requires us to know about the part and stave signatures, so we can visually extend the measure
// that precedes it.
const measures = this.score.systems.flatMap((system) => system.measures);
if (measures.length === 0) {
throw new errors.DocumentError('cannot insert gap into empty score');
}
if (opts.absoluteMeasureIndex > measures.length) {
throw new errors.DocumentError('cannot insert gap after non-existent measure');
}
// First, find a template that we'll copy to create the gap.
const templateMeasure = measures[opts.absoluteMeasureIndex];
// Clone the template. We'll mutate the clone and insert it into the score.
const cloneMeasure = util.deepClone(templateMeasure);
if (cloneMeasure.fragments.length === 0) {
throw new errors.DocumentError('cannot insert gap into empty measure');
}
// Update the measure properties we don't care about.
cloneMeasure.label = null;
cloneMeasure.fragments.splice(0, cloneMeasure.fragments.length - 1);
// Transform the fragment into a non-musical gap.
cloneMeasure.fragments[0].kind = 'nonmusical';
const gapFragment = cloneMeasure.fragments[0];
gapFragment.durationMs = opts.durationMs;
gapFragment.label = opts.label ?? null;
gapFragment.minWidth = opts.minWidth ?? DEFAULT_FRAGMENT_WIDTH;
gapFragment.style = opts.style;
// Get rid of all the voices in the parts, since we're potentially just rendering a label.
gapFragment.parts
.flatMap((part) => part.staves)
.forEach((stave) => {
stave.voices = [];
});
// Insert the gap into the score into the same system as the template.
const systemIndex = this.score.systems.findIndex((system) => system.measures.includes(templateMeasure));
this.score.systems[systemIndex].measures.splice(opts.absoluteMeasureIndex, 0, cloneMeasure);
return this;
}
removePartLabels() {
this.score.partLabels = [];
return this;
}
clone() {
const score = util.deepClone(this.score);
return new Document(score);
}
}
exports.Document = Document;