UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature

1,195 lines (964 loc) 1.39 MB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["Vex"] = factory(); else root["Vex"] = factory(); })(window, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "./src/index.js"); /******/ }) /************************************************************************/ /******/ ({ /***/ "./src/accidental.js": /*!***************************!*\ !*** ./src/accidental.js ***! \***************************/ /*! exports provided: Accidental */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Accidental", function() { return Accidental; }); /* harmony import */ var _vex__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./vex */ "./src/vex.js"); /* harmony import */ var _fraction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./fraction */ "./src/fraction.js"); /* harmony import */ var _tables__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./tables */ "./src/tables.js"); /* harmony import */ var _music__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./music */ "./src/music.js"); /* harmony import */ var _modifier__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./modifier */ "./src/modifier.js"); /* harmony import */ var _glyph__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./glyph */ "./src/glyph.js"); function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010. // @author Mohit Cheppudira // @author Greg Ristow (modifications) // // ## Description // // This file implements accidentals as modifiers that can be attached to // notes. Support is included for both western and microtonal accidentals. // // See `tests/accidental_tests.js` for usage examples. // To enable logging for this class. Set `Vex.Flow.Accidental.DEBUG` to `true`. function L() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } if (Accidental.DEBUG) _vex__WEBPACK_IMPORTED_MODULE_0__["Vex"].L('Vex.Flow.Accidental', args); } var getGlyphWidth = function getGlyphWidth(glyph) { return glyph.getMetrics().width; }; // An `Accidental` inherits from `Modifier`, and is formatted within a // `ModifierContext`. var Accidental = /*#__PURE__*/ function (_Modifier) { _inherits(Accidental, _Modifier); _createClass(Accidental, null, [{ key: "format", // Arrange accidentals inside a ModifierContext. value: function format(accidentals, state) { var _this2 = this; var noteheadAccidentalPadding = 1; var leftShift = state.left_shift + noteheadAccidentalPadding; var accidentalSpacing = 3; // If there are no accidentals, we needn't format their positions if (!accidentals || accidentals.length === 0) return; var accList = []; var prevNote = null; var shiftL = 0; // First determine the accidentals' Y positions from the note.keys for (var i = 0; i < accidentals.length; ++i) { var acc = accidentals[i]; var note = acc.getNote(); var stave = note.getStave(); var props = note.getKeyProps()[acc.getIndex()]; if (note !== prevNote) { // Iterate through all notes to get the displaced pixels for (var n = 0; n < note.keys.length; ++n) { shiftL = Math.max(note.getLeftDisplacedHeadPx(), shiftL); } prevNote = note; } if (stave !== null) { var lineSpace = stave.options.spacing_between_lines_px; var y = stave.getYForLine(props.line); var accLine = Math.round(y / lineSpace * 2) / 2; accList.push({ y: y, line: accLine, shift: shiftL, acc: acc, lineSpace: lineSpace }); } else { accList.push({ line: props.line, shift: shiftL, acc: acc }); } } // Sort accidentals by line number. accList.sort(function (a, b) { return b.line - a.line; }); // FIXME: Confusing name. Each object in this array has a property called `line`. // So if this is a list of lines, you end up with: `line.line` which is very awkward. var lineList = []; // amount by which all accidentals must be shifted right or left for // stem flipping, notehead shifting concerns. var accShift = 0; var previousLine = null; // Create an array of unique line numbers (lineList) from accList for (var _i = 0; _i < accList.length; _i++) { var _acc = accList[_i]; // if this is the first line, or a new line, add a lineList if (previousLine === null || previousLine !== _acc.line) { lineList.push({ line: _acc.line, flatLine: true, dblSharpLine: true, numAcc: 0, width: 0 }); } // if this accidental is not a flat, the accidental needs 3.0 lines lower // clearance instead of 2.5 lines for b or bb. // FIXME: Naming could use work. acc.acc is very awkward if (_acc.acc.type !== 'b' && _acc.acc.type !== 'bb') { lineList[lineList.length - 1].flatLine = false; } // if this accidental is not a double sharp, the accidental needs 3.0 lines above if (_acc.acc.type !== '##') { lineList[lineList.length - 1].dblSharpLine = false; } // Track how many accidentals are on this line: lineList[lineList.length - 1].numAcc++; // Track the total x_offset needed for this line which will be needed // for formatting lines w/ multiple accidentals: // width = accidental width + universal spacing between accidentals lineList[lineList.length - 1].width += _acc.acc.getWidth() + accidentalSpacing; // if this accShift is larger, use it to keep first column accidentals in the same line accShift = _acc.shift > accShift ? _acc.shift : accShift; previousLine = _acc.line; } // ### Place Accidentals in Columns // // Default to a classic triangular layout (middle accidental farthest left), // but follow exceptions as outlined in G. Read's _Music Notation_ and // Elaine Gould's _Behind Bars_. // // Additionally, this implements different vertical collision rules for // flats (only need 2.5 lines clearance below) and double sharps (only // need 2.5 lines of clearance above or below). // // Classic layouts and exception patterns are found in the 'tables.js' // in 'Vex.Flow.accidentalColumnsTable' // // Beyond 6 vertical accidentals, default to the parallel ascending lines approach, // using as few columns as possible for the verticle structure. // // TODO (?): Allow column to be specified for an accidental at run-time? var totalColumns = 0; // establish the boundaries for a group of notes with clashing accidentals: var _loop = function _loop(_i3) { var noFurtherConflicts = false; var groupStart = _i3; var groupEnd = _i3; while (groupEnd + 1 < lineList.length && !noFurtherConflicts) { // if this note conflicts with the next: if (_this2.checkCollision(lineList[groupEnd], lineList[groupEnd + 1])) { // include the next note in the group: groupEnd++; } else { noFurtherConflicts = true; } } // Gets an a line from the `lineList`, relative to the current group var getGroupLine = function getGroupLine(index) { return lineList[groupStart + index]; }; var getGroupLines = function getGroupLines(indexes) { return indexes.map(getGroupLine); }; var lineDifference = function lineDifference(indexA, indexB) { var _getGroupLines$map = getGroupLines([indexA, indexB]).map(function (item) { return item.line; }), _getGroupLines$map2 = _slicedToArray(_getGroupLines$map, 2), a = _getGroupLines$map2[0], b = _getGroupLines$map2[1]; _i2 = _i3; return a - b; }; var notColliding = function notColliding() { for (var _len2 = arguments.length, indexPairs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { indexPairs[_key2] = arguments[_key2]; } return indexPairs.map(getGroupLines).every(function (lines) { return !_this2.checkCollision.apply(_this2, _toConsumableArray(lines)); }); }; // Set columns for the lines in this group: var groupLength = groupEnd - groupStart + 1; // Set the accidental column for each line of the group var endCase = _this2.checkCollision(lineList[groupStart], lineList[groupEnd]) ? 'a' : 'b'; switch (groupLength) { case 3: if (endCase === 'a' && lineDifference(1, 2) === 0.5 && lineDifference(0, 1) !== 0.5) { endCase = 'second_on_bottom'; } break; case 4: if (notColliding([0, 2], [1, 3])) { endCase = 'spaced_out_tetrachord'; } break; case 5: if (endCase === 'b' && notColliding([1, 3])) { endCase = 'spaced_out_pentachord'; if (notColliding([0, 2], [2, 4])) { endCase = 'very_spaced_out_pentachord'; } } break; case 6: if (notColliding([0, 3], [1, 4], [2, 5])) { endCase = 'spaced_out_hexachord'; } if (notColliding([0, 2], [2, 4], [1, 3], [3, 5])) { endCase = 'very_spaced_out_hexachord'; } break; default: break; } var groupMember = void 0; var column = void 0; // If the group contains more than seven members, use ascending parallel lines // of accidentals, using as few columns as possible while avoiding collisions. if (groupLength >= 7) { // First, determine how many columns to use: var patternLength = 2; var collisionDetected = true; while (collisionDetected === true) { collisionDetected = false; for (var line = 0; line + patternLength < lineList.length; line++) { if (_this2.checkCollision(lineList[line], lineList[line + patternLength])) { collisionDetected = true; patternLength++; break; } } } // Then, assign a column to each line of accidentals for (groupMember = _i3; groupMember <= groupEnd; groupMember++) { column = (groupMember - _i3) % patternLength + 1; lineList[groupMember].column = column; totalColumns = totalColumns > column ? totalColumns : column; } // Otherwise, if the group contains fewer than seven members, use the layouts from // the accidentalsColumnsTable housed in tables.js. } else { for (groupMember = _i3; groupMember <= groupEnd; groupMember++) { column = _tables__WEBPACK_IMPORTED_MODULE_2__["Flow"].accidentalColumnsTable[groupLength][endCase][groupMember - _i3]; lineList[groupMember].column = column; totalColumns = totalColumns > column ? totalColumns : column; } } // Increment i to the last note that was set, so that if a lower set of notes // does not conflict at all with this group, it can have its own classic shape. _i3 = groupEnd; _i2 = _i3; }; for (var _i2 = 0; _i2 < lineList.length; _i2++) { _loop(_i2); } // ### Convert Columns to x_offsets // // This keeps columns aligned, even if they have different accidentals within them // which sometimes results in a larger x_offset than is an accidental might need // to preserve the symmetry of the accidental shape. // // Neither A.C. Vinci nor G. Read address this, and it typically only happens in // music with complex chord clusters. // // TODO (?): Optionally allow closer compression of accidentals, instead of forcing // parallel columns. // track each column's max width, which will be used as initial shift of later columns: var columnWidths = []; var columnXOffsets = []; for (var _i4 = 0; _i4 <= totalColumns; _i4++) { columnWidths[_i4] = 0; columnXOffsets[_i4] = 0; } columnWidths[0] = accShift + leftShift; columnXOffsets[0] = accShift + leftShift; // Fill columnWidths with widest needed x-space; // this is what keeps the columns parallel. lineList.forEach(function (line) { if (line.width > columnWidths[line.column]) columnWidths[line.column] = line.width; }); for (var _i5 = 1; _i5 < columnWidths.length; _i5++) { // this column's offset = this column's width + previous column's offset columnXOffsets[_i5] = columnWidths[_i5] + columnXOffsets[_i5 - 1]; } var totalShift = columnXOffsets[columnXOffsets.length - 1]; // Set the xShift for each accidental according to column offsets: var accCount = 0; lineList.forEach(function (line) { var lineWidth = 0; var lastAccOnLine = accCount + line.numAcc; // handle all of the accidentals on a given line: for (accCount; accCount < lastAccOnLine; accCount++) { var xShift = columnXOffsets[line.column - 1] + lineWidth; accList[accCount].acc.setXShift(xShift); // keep track of the width of accidentals we've added so far, so that when // we loop, we add space for them. lineWidth += accList[accCount].acc.getWidth() + accidentalSpacing; L('Line, accCount, shift: ', line.line, accCount, xShift); } }); // update the overall layout with the full width of the accidental shapes: state.left_shift += totalShift; } // Helper function to determine whether two lines of accidentals collide vertically }, { key: "checkCollision", value: function checkCollision(line1, line2) { var clearance = line2.line - line1.line; var clearanceRequired = 3; // But less clearance is required for certain accidentals: b, bb and ##. if (clearance > 0) { // then line 2 is on top clearanceRequired = line2.flatLine || line2.dblSharpLine ? 2.5 : 3.0; if (line1.dblSharpLine) clearance -= 0.5; } else { // line 1 is on top clearanceRequired = line1.flatLine || line1.dblSharpLine ? 2.5 : 3.0; if (line2.dblSharpLine) clearance -= 0.5; } var collision = Math.abs(clearance) < clearanceRequired; L('Line_1, Line_2, Collision: ', line1.line, line2.line, collision); return collision; } // Use this method to automatically apply accidentals to a set of `voices`. // The accidentals will be remembered between all the voices provided. // Optionally, you can also provide an initial `keySignature`. }, { key: "applyAccidentals", value: function applyAccidentals(voices, keySignature) { var tickPositions = []; var tickNoteMap = {}; // Sort the tickables in each voice by their tick position in the voice voices.forEach(function (voice) { var tickPosition = new _fraction__WEBPACK_IMPORTED_MODULE_1__["Fraction"](0, 1); var notes = voice.getTickables(); notes.forEach(function (note) { if (note.shouldIgnoreTicks()) return; var notesAtPosition = tickNoteMap[tickPosition.value()]; if (!notesAtPosition) { tickPositions.push(tickPosition.value()); tickNoteMap[tickPosition.value()] = [note]; } else { notesAtPosition.push(note); } tickPosition.add(note.getTicks()); }); }); var music = new _music__WEBPACK_IMPORTED_MODULE_3__["Music"](); // Default key signature is C major if (!keySignature) keySignature = 'C'; // Get the scale map, which represents the current state of each pitch var scaleMap = music.createScaleMap(keySignature); tickPositions.forEach(function (tick) { var notes = tickNoteMap[tick]; // Array to store all pitches that modified accidental states // at this tick position var modifiedPitches = []; var processNote = function processNote(note) { if (note.isRest() || note.shouldIgnoreTicks()) return; // Go through each key and determine if an accidental should be // applied note.keys.forEach(function (keyString, keyIndex) { var key = music.getNoteParts(keyString.split('/')[0]); // Force a natural for every key without an accidental var accidentalString = key.accidental || 'n'; var pitch = key.root + accidentalString; // Determine if the current pitch has the same accidental // as the scale state var sameAccidental = scaleMap[key.root] === pitch; // Determine if an identical pitch in the chord already // modified the accidental state var previouslyModified = modifiedPitches.indexOf(pitch) > -1; // Add the accidental to the StaveNote if (!sameAccidental || sameAccidental && previouslyModified) { // Modify the scale map so that the root pitch has an // updated state scaleMap[key.root] = pitch; // Create the accidental var accidental = new Accidental(accidentalString); // Attach the accidental to the StaveNote note.addAccidental(keyIndex, accidental); // Add the pitch to list of pitches that modified accidentals modifiedPitches.push(pitch); } }); // process grace notes note.getModifiers().forEach(function (modifier) { if (modifier.getCategory() === 'gracenotegroups') { modifier.getGraceNotes().forEach(processNote); } }); }; notes.forEach(processNote); }); } // Create accidental. `type` can be a value from the // `Vex.Flow.accidentalCodes.accidentals` table in `tables.js`. For // example: `#`, `##`, `b`, `n`, etc. }, { key: "CATEGORY", get: function get() { return 'accidentals'; } }]); function Accidental() { var _this; var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; _classCallCheck(this, Accidental); _this = _possibleConstructorReturn(this, _getPrototypeOf(Accidental).call(this)); _this.setAttribute('type', 'Accidental'); L('New accidental: ', type); _this.note = null; // The `index` points to a specific note in a chord. _this.index = null; _this.type = type; _this.position = _modifier__WEBPACK_IMPORTED_MODULE_4__["Modifier"].Position.LEFT; _this.render_options = { // Font size for glyphs font_scale: 38, // Length of stroke across heads above or below the stave. stroke_px: 3, // Padding between accidental and parentheses on each side parenLeftPadding: 2, parenRightPadding: 2 }; _this.accidental = _tables__WEBPACK_IMPORTED_MODULE_2__["Flow"].accidentalCodes(_this.type); if (!_this.accidental) { throw new _vex__WEBPACK_IMPORTED_MODULE_0__["Vex"].RERR('ArgumentError', "Unknown accidental type: ".concat(type)); } // Cautionary accidentals have parentheses around them _this.cautionary = false; _this.parenLeft = null; _this.parenRight = null; _this.reset(); return _this; } _createClass(Accidental, [{ key: "reset", value: function reset() { var fontScale = this.render_options.font_scale; this.glyph = new _glyph__WEBPACK_IMPORTED_MODULE_5__["Glyph"](this.accidental.code, fontScale); this.glyph.setOriginX(1.0); if (this.cautionary) { this.parenLeft = new _glyph__WEBPACK_IMPORTED_MODULE_5__["Glyph"](_tables__WEBPACK_IMPORTED_MODULE_2__["Flow"].accidentalCodes('{').code, fontScale); this.parenRight = new _glyph__WEBPACK_IMPORTED_MODULE_5__["Glyph"](_tables__WEBPACK_IMPORTED_MODULE_2__["Flow"].accidentalCodes('}').code, fontScale); this.parenLeft.setOriginX(1.0); this.parenRight.setOriginX(1.0); } } }, { key: "getCategory", value: function getCategory() { return Accidental.CATEGORY; } }, { key: "getWidth", value: function getWidth() { var parenWidth = this.cautionary ? getGlyphWidth(this.parenLeft) + getGlyphWidth(this.parenRight) + this.render_options.parenLeftPadding + this.render_options.parenRightPadding : 0; return getGlyphWidth(this.glyph) + parenWidth; } // Attach this accidental to `note`, which must be a `StaveNote`. }, { key: "setNote", value: function setNote(note) { if (!note) { throw new _vex__WEBPACK_IMPORTED_MODULE_0__["Vex"].RERR('ArgumentError', "Bad note value: ".concat(note)); } this.note = note; // Accidentals attached to grace notes are rendered smaller. if (this.note.getCategory() === 'gracenotes') { this.render_options.font_scale = 25; this.reset(); } } // If called, draws parenthesis around accidental. }, { key: "setAsCautionary", value: function setAsCautionary() { this.cautionary = true; this.render_options.font_scale = 28; this.reset(); return this; } // Render accidental onto canvas. }, { key: "draw", value: function draw() { var context = this.context, type = this.type, position = this.position, note = this.note, index = this.index, cautionary = this.cautionary, x_shift = this.x_shift, y_shift = this.y_shift, glyph = this.glyph, parenLeft = this.parenLeft, parenRight = this.parenRight, _this$render_options = this.render_options, parenLeftPadding = _this$render_options.parenLeftPadding, parenRightPadding = _this$render_options.parenRightPadding; this.checkContext(); if (!(note && index != null)) { throw new _vex__WEBPACK_IMPORTED_MODULE_0__["Vex"].RERR('NoAttachedNote', "Can't draw accidental without a note and index."); } // Figure out the start `x` and `y` coordinates for note and index. var start = note.getModifierStartXY(position, index); var accX = start.x + x_shift; var accY = start.y + y_shift; L('Rendering: ', type, accX, accY); if (!cautionary) { glyph.render(context, accX, accY); } else { // Render the accidental in parentheses. parenRight.render(context, accX, accY); accX -= getGlyphWidth(parenRight); accX -= parenRightPadding; accX -= this.accidental.parenRightPaddingAdjustment; glyph.render(context, accX, accY); accX -= getGlyphWidth(glyph); accX -= parenLeftPadding; parenLeft.render(context, accX, accY); } this.setRendered(); } }]); return Accidental; }(_modifier__WEBPACK_IMPORTED_MODULE_4__["Modifier"]); /***/ }), /***/ "./src/annotation.js": /*!***************************!*\ !*** ./src/annotation.js ***! \***************************/ /*! exports provided: Annotation */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Annotation", function() { return Annotation; }); /* harmony import */ var _vex__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./vex */ "./src/vex.js"); /* harmony import */ var _tables__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tables */ "./src/tables.js"); /* harmony import */ var _modifier__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./modifier */ "./src/modifier.js"); function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010. // // ## Description // // This file implements text annotations as modifiers that can be attached to // notes. // // See `tests/annotation_tests.js` for usage examples. // To enable logging for this class. Set `Vex.Flow.Annotation.DEBUG` to `true`. function L() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } if (Annotation.DEBUG) _vex__WEBPACK_IMPORTED_MODULE_0__["Vex"].L('Vex.Flow.Annotation', args); } var Annotation = /*#__PURE__*/ function (_Modifier) { _inherits(Annotation, _Modifier); _createClass(Annotation, null, [{ key: "format", // Arrange annotations within a `ModifierContext` value: function format(annotations, state) { if (!annotations || annotations.length === 0) return false; var width = 0; for (var i = 0; i < annotations.length; ++i) { var annotation = annotations[i]; width = Math.max(annotation.getWidth(), width); if (annotation.getPosition() === _modifier__WEBPACK_IMPORTED_MODULE_2__["Modifier"].Position.ABOVE) { annotation.setTextLine(state.top_text_line); state.top_text_line++; } else { annotation.setTextLine(state.text_line); state.text_line++; } } state.left_shift += width / 2; state.right_shift += width / 2; return true; } // ## Prototype Methods // // Annotations inherit from `Modifier` and is positioned correctly when // in a `ModifierContext`. // Create a new `Annotation` with the string `text`. }, { key: "CATEGORY", get: function get() { return 'annotations'; } // Text annotations can be positioned and justified relative to the note. }, { key: "Justify", get: function get() { return { LEFT: 1, CENTER: 2, RIGHT: 3, CENTER_STEM: 4 }; } }, { key: "JustifyString", get: function get() { return { left: Annotation.Justify.LEFT, right: Annotation.Justify.RIGHT, center: Annotation.Justify.CENTER, centerStem: Annotation.Justify.CENTER_STEM }; } }, { key: "VerticalJustify", get: function get() { return { TOP: 1, CENTER: 2, BOTTOM: 3, CENTER_STEM: 4 }; } }, { key: "VerticalJustifyString", get: function get() { return { above: Annotation.VerticalJustify.TOP, top: Annotation.VerticalJustify.TOP, below: Annotation.VerticalJustify.BOTTOM, bottom: Annotation.VerticalJustify.BOTTOM, center: Annotation.VerticalJustify.CENTER, centerStem: Annotation.VerticalJustify.CENTER_STEM }; } }]); function Annotation(text) { var _this; _classCallCheck(this, Annotation); _this = _possibleConstructorReturn(this, _getPrototypeOf(Annotation).call(this)); _this.setAttribute('type', 'Annotation'); _this.note = null; _this.index = null; _this.text = text; _this.justification = Annotation.Justify.CENTER; _this.vert_justification = Annotation.VerticalJustify.TOP; _this.font = { family: 'Arial', size: 10, weight: '' }; // The default width is calculated from the text. _this.setWidth(_tables__WEBPACK_IMPORTED_MODULE_1__["Flow"].textWidth(text)); return _this; } _createClass(Annotation, [{ key: "getCategory", value: function getCategory() { return Annotation.CATEGORY; } // Set font family, size, and weight. E.g., `Arial`, `10pt`, `Bold`. }, { key: "setFont", value: function setFont(family, size, weight) { this.font = { family: family, size: size, weight: weight }; return this; } // Set vertical position of text (above or below stave). `just` must be // a value in `Annotation.VerticalJustify`. }, { key: "setVerticalJustification", value: function setVerticalJustification(just) { this.vert_justification = typeof just === 'string' ? Annotation.VerticalJustifyString[just] : just; return this; } // Get and set horizontal justification. `justification` is a value in // `Annotation.Justify`. }, { key: "getJustification", value: function getJustification() { return this.justification; } }, { key: "setJustification", value: function setJustification(just) { this.justification = typeof just === 'string' ? Annotation.JustifyString[just] : just; return this; } // Render text beside the note. }, { key: "draw", value: function draw() { this.checkContext(); if (!this.note) { throw new _vex__WEBPACK_IMPORTED_MODULE_0__["Vex"].RERR('NoNoteForAnnotation', "Can't draw text annotation without an attached note."); } this.setRendered(); var start = this.note.getModifierStartXY(_modifier__WEBPACK_IMPORTED_MODULE_2__["Modifier"].Position.ABOVE, this.index); // We're changing context parameters. Save current state. this.context.save(); this.context.setFont(this.font.family, this.font.size, this.font.weight); var text_width = this.context.measureText(this.text).width; // Estimate text height to be the same as the width of an 'm'. // // This is a hack to work around the inability to measure text height // in HTML5 Canvas (and SVG). var text_height = this.context.measureText('m').width; var x; var y; if (this.justification === Annotation.Justify.LEFT) { x = start.x; } else if (this.justification === Annotation.Justify.RIGHT) { x = start.x - text_width; } else if (this.justification === Annotation.Justify.CENTER) { x = start.x - text_width / 2; } else /* CENTER_STEM */ { x = this.note.getStemX() - text_width / 2; } var stem_ext; var spacing; var has_stem = this.note.hasStem(); var stave = this.note.getStave(); // The position of the text varies based on whether or not the note // has a stem. if (has_stem) { stem_ext = this.note.getStem().getExtents(); spacing = stave.getSpacingBetweenLines(); } if (this.vert_justification === Annotation.VerticalJustify.BOTTOM) { // HACK: We need to compensate for the text's height since its origin // is bottom-right. y = stave.getYForBottomText(this.text_line + _tables__WEBPACK_IMPORTED_MODULE_1__["Flow"].TEXT_HEIGHT_OFFSET_HACK); if (has_stem) { var stem_base = this.note.getStemDirection() === 1 ? stem_ext.baseY : stem_ext.topY; y = Math.max(y, stem_base + spacing * (this.text_line + 2)); } } else if (this.vert_justification === Annotation.VerticalJustify.CENTER) { var yt = this.note.getYForTopText(this.text_line) - 1; var yb = stave.getYForBottomText(this.text_line); y = yt + (yb - yt) / 2 + text_height / 2; } else if (this.vert_justification === Annotation.VerticalJustify.TOP) { y = Math.min(stave.getYForTopText(this.text_line), this.note.getYs()[0] - 10); if (has_stem) { y = Math.min(y, stem_ext.topY - 5 - spacing * this.text_line); } } else /* CENTER_STEM */ { var extents = this.note.getStemExtents(); y = extents.topY + (extents.baseY - extents.topY) / 2 + text_height / 2; } L('Rendering annotation: ', this.text, x, y); this.context.fillText(this.text, x, y); this.context.restore(); } }]); return Annotation; }(_modifier__WEBPACK_IMPORTED_MODULE_2__["Modifier"]); /***/ }), /***/ "./src/articulation.js": /*!*****************************!*\ !*** ./src/articulation.js ***! \*****************************/ /*! exports provided: Articulation */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Articulation", function() { return Articulation; }); /* harmony import */ var _vex__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./vex */ "./src/vex.js"); /* harmony import */ var _tables__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tables */ "./src/tables.js"); /* harmony import */ var _modifier__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./modifier */ "./src/modifier.js"); /* harmony import */ var _glyph__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./glyph */ "./src/glyph.js"); /* harmony import */ var _stem__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./stem */ "./src/stem.js"); function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010. // Author: Larry Kuhns. // // ## Description // // This file implements articulations and accents as modifiers that can be // attached to notes. The complete list of articulations is available in // `tables.js` under `Vex.Flow.articulationCodes`. // // See `tests/articulation_tests.js` for usage examples. // To enable logging for this class. Set `Vex.Flow.Articulation.DEBUG` to `true`. function L() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } if (Articulation.DEBUG) _vex__WEBPACK_IMPORTED_MODULE_0__["Vex"].L('Vex.Flow.Articulation', args); } var _Modifier$Position = _modifier__WEBPACK_IMPORTED_MODULE_2__["Modifier"].Position, ABOVE = _Modifier$Position.ABOVE, BELOW = _Modifier$Position.BELOW; var roundToNearestHalf = function roundToNearestHalf(mathFn, value) { return mathFn(value / 0.5) * 0.5; }; // This includes both staff and ledger lines var isWithinLines = function isWithinLines(line, position) { return position === ABOVE ? line <= 5 : line >= 1; }; var getRoundingFunction = function getRoundingFunction(line, position) { if (isWithinLines(line, position)) { if (position === ABOVE) { return Math.ceil; } else { return Math.floor; } } else { return Math.round; } }; var snapLineToStaff = function snapLineToStaff(canSitBetweenLines, line, position, offsetDirection) { // Initially, snap to nearest staff line or space var snappedLine = roundToNearestHalf(getRoundingFunction(line, position), line); var canSnapToStaffSpace = canSitBetweenLines && isWithinLines(snappedLine, position); var onStaffLine = snappedLine % 1 === 0; if (canSnapToStaffSpace && onStaffLine) { var HALF_STAFF_SPACE = 0.5; return snappedLine + HALF_STAFF_SPACE * -offsetDirection; } else { return snappedLine; } }; var isStaveNote = function isStaveNote(note) { var noteCategory = note.getCategory(); return noteCategory === 'stavenotes' || noteCategory === 'gracenotes'; }; var getTopY = function getTopY(note, textLine) { var stave = note.getStave(); var stemDirection = note.getStemDirection(); var _note$getStemExtents = note.getStemExtents(), stemTipY = _note$getStemExtents.topY, stemBaseY = _note$getStemExtents.baseY; if (isStaveNote(note)) { if (note.hasStem()) { if (stemDirection === _stem__WEBPACK_IMPORTED_MODULE_4__["Stem"].UP) { return stemTipY; } else { return stemBaseY; } } else { return Math.min.apply(Math, _toConsumableArray(note.getYs())); } } else if (note.getCategory() === 'tabnotes') { if (note.hasStem()) { if (stemDirection === _stem__WEBPACK_IMPORTED_MODULE_4__["Stem"].UP) { return stemTipY; } else { return stave.getYForTopText(textLine); } } else { return stave.getYForTopText(textLine); } } else { throw new _vex__WEBPACK_IMPORTED_MODULE_0__["Vex"].RERR('UnknownCategory', 'Only can get the top and bottom ys of stavenotes and tabnotes'); } }; var getBottomY = function getBottomY(note, textLine) { var stave = note.getStave(); var stemDirection = note.getStemDirection(); var _note$getStemExtents2 = note.getStemExtents(), stemTipY = _note$getStemExtents2.topY, stemBaseY = _note$getStemExtents2.baseY; if (isStaveNote(note)) { if (note.hasStem()) { if (stemDirection === _stem__WEBPACK_IMPORTED_MODULE_4__["Stem"].UP) { return stemBaseY; } else { return stemTipY; } } else { return Math.max.apply(Math, _toConsumableArray(note.getYs())); } } else if (note.getCategory() ===