UNPKG

satie

Version:

A sheet music renderer for the web

205 lines (204 loc) 7.58 kB
/** * This file is part of Satie music engraver <https://github.com/jnetterf/satie>. * Copyright (C) Joshua Netterfield <joshua.ca> 2015 - present. * * Satie is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Satie is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Satie. If not, see <http://www.gnu.org/licenses/>. */ "use strict"; var musicxml_interfaces_1 = require("musicxml-interfaces"); var lodash_1 = require("lodash"); var private_smufl_1 = require("./private_smufl"); var PADDING = 1.5; function articulationDirectionMatters(model) { return !model.breathMark && !model.caesura; } exports.articulationDirectionMatters = articulationDirectionMatters; function articulationGlyph(model, direction) { if (model.accent) { return "articAccent" + direction; } if (model.breathMark) { return "breathMarkComma"; } if (model.caesura) { return "caesura"; } if (model.detachedLegato) { return "articTenutoStaccato" + direction; } if (model.doit) { return null; } if (model.falloff) { return null; } if (model.plop) { return null; } if (model.scoop) { return null; } if (model.spiccato) { return "articStaccatissimoWedge" + direction; } if (model.staccatissimo) { return "articStaccatissimo" + direction; } if (model.staccato) { return "articStaccato" + direction; } if (model.stress) { return "articStress" + direction; } if (model.strongAccent) { return "articMarcato" + direction; } if (model.tenuto) { return "articTenuto" + direction; } if (model.unstress) { return "articUnstress" + direction; } console.warn("Unknown articulation..."); return null; } exports.articulationGlyph = articulationGlyph; function getBoundingRects(model, note, chord) { var boxes = []; var origModel = model; model = Object.create(model); Object.keys(origModel).forEach(function (m) { model[m] = typeof model[m] === "object" ? Object.create(model[m]) : model; }); lodash_1.forEach(model.accidentalMarks, function (accidentalMark) { // TODO }); lodash_1.forEach(model.arpeggiates, function (arpeggiate) { // TODO }); lodash_1.forEach(model.articulations, function (articulation, idx) { articulation = model.articulations[idx] = Object.create(articulation); lodash_1.forEach(["accent", "breathMark", "caesura", "detachedLegato", "doit", "falloff", "plop", "scoop", "spiccato", "staccatissimo", "staccato", "stress", "strongAccent", "tenuto", "unstress"], function (type) { // TODO: Could this be done any less efficiently? if (model.articulations[idx][type]) { var thisArticulation = Object.create(model.articulations[idx][type]); var placement = thisArticulation.placement; var isBelow = placement === musicxml_interfaces_1.AboveBelow.Below; var glyph = articulationGlyph(articulation, isBelow ? "Below" : "Above"); if (!glyph) { console.warn(Object.keys(articulation)[0], "not implented in chord/notation.ts"); return; } var y = void 0; var noteheadGlyph = chord.model.noteheadGlyph[0]; var center = (private_smufl_1.getLeft(noteheadGlyph) + private_smufl_1.getRight(noteheadGlyph)) / 2 - (private_smufl_1.getLeft(glyph) + private_smufl_1.getRight(glyph)) / 2 - 0.5; if (!chord.satieStem || (note.stem.type === musicxml_interfaces_1.StemType.Up) === isBelow) { y = note.defaultY + (isBelow ? -9 : 9); if (-note.defaultY % 10 === 0) { y += isBelow ? -5 : 5; } } else { y = note.defaultY + chord.satieStem.stemHeight + (isBelow ? -12 : 12); if (-note.defaultY % 10 === 0) { y += isBelow ? -5 : 5; } } model.articulations[idx][type] = push(glyph, thisArticulation, center, y); } }); }); lodash_1.forEach(model.dynamics, function (dynamic) { // TODO }); lodash_1.forEach(model.fermatas, function (fermata, idx) { fermata = model.fermatas[idx] = Object.create(fermata); if (fermata.type === musicxml_interfaces_1.UprightInverted.Inverted) { fermata.placement = musicxml_interfaces_1.AboveBelow.Below; } else { fermata.placement = musicxml_interfaces_1.AboveBelow.Above; } model.fermatas[idx] = push("fermataAbove", fermata); }); lodash_1.forEach(model.glissandos, function (glissando) { // TODO }); lodash_1.forEach(model.nonArpeggiates, function (nonArpeggiate) { // TODO }); lodash_1.forEach(model.ornaments, function (ornament, idx) { ornament = model.ornaments[idx] = Object.create(ornament); if (ornament.tremolo) { chord.satieStem.tremolo = ornament.tremolo; } // TODO }); lodash_1.forEach(model.slides, function (slide) { // TODO }); lodash_1.forEach(model.slurs, function (slur) { // TODO }); lodash_1.forEach(model.technicals, function (technical) { // TODO }); lodash_1.forEach(model.tieds, function (tied) { // TODO }); lodash_1.forEach(model.tuplets, function (tuplet) { // TODO }); function push(glyphName, notation, defaultX, defaultY) { if (defaultX === void 0) { defaultX = 0; } if (defaultY === void 0) { defaultY = NaN; } var box = private_smufl_1.bboxes[glyphName]; if (!box) { console.warn("Unknown glyph", glyphName); return; } if (isNaN(defaultY)) { if (notation.placement === musicxml_interfaces_1.AboveBelow.Below) { defaultY = -30 + box[3] * 10 * PADDING; } else if (notation.placement === musicxml_interfaces_1.AboveBelow.Above) { defaultY = 60 + box[3] * 10 * PADDING; } else { console.warn("TODO: Set default above/below"); // above: "fermata", "breathMark", "caesura", "strings" // below: "dynamic" defaultY = 0; } } var printStyle = Object.create(notation); var boundingRect = printStyle; boundingRect.top = box[3] * 10; boundingRect.bottom = box[1] * 10; boundingRect.left = box[2] * 10; boundingRect.right = box[0] * 10; boundingRect.defaultX = defaultX; boundingRect.defaultY = defaultY; boxes.push(printStyle); return printStyle; } return { bb: boxes, n: model, }; } exports.getBoundingRects = getBoundingRects;