/abc2pd.js
JavaScript | 5260 lines | 4892 code | 72 blank | 296 comment | 236 complexity | 1c4a52606e3da5f826240f50381b4a2e MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- http://www.JSON.org/json2.js
- 2011-02-23
- Public Domain.
- NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
- See http://www.JSON.org/js.html
- This code should be minified before deployment.
- See http://javascript.crockford.com/jsmin.html
- USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
- NOT CONTROL.
- This file creates a global JSON object containing two methods: stringify
- and parse.
- JSON.stringify(value, replacer, space)
- value any JavaScript value, usually an object or array.
- replacer an optional parameter that determines how object
- values are stringified for objects. It can be a
- function or an array of strings.
- space an optional parameter that specifies the indentation
- of nested structures. If it is omitted, the text will
- be packed without extra whitespace. If it is a number,
- it will specify the number of spaces to indent at each
- level. If it is a string (such as '\t' or ' '),
- it contains the characters used to indent at each level.
- This method produces a JSON text from a JavaScript value.
- When an object value is found, if the object contains a toJSON
- method, its toJSON method will be called and the result will be
- stringified. A toJSON method does not serialize: it returns the
- value represented by the name/value pair that should be serialized,
- or undefined if nothing should be serialized. The toJSON method
- will be passed the key associated with the value, and this will be
- bound to the value
- For example, this would serialize Dates as ISO strings.
- Date.prototype.toJSON = function (key) {
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
- return this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z';
- };
- You can provide an optional replacer method. It will be passed the
- key and value of each member, with this bound to the containing
- object. The value that is returned from your method will be
- serialized. If your method returns undefined, then the member will
- be excluded from the serialization.
- If the replacer parameter is an array of strings, then it will be
- used to select the members to be serialized. It filters the results
- such that only members with keys listed in the replacer array are
- stringified.
- Values that do not have JSON representations, such as undefined or
- functions, will not be serialized. Such values in objects will be
- dropped; in arrays they will be replaced with null. You can use
- a replacer function to replace those with JSON values.
- JSON.stringify(undefined) returns undefined.
- The optional space parameter produces a stringification of the
- value that is filled with line breaks and indentation to make it
- easier to read.
- If the space parameter is a non-empty string, then that string will
- be used for indentation. If the space parameter is a number, then
- the indentation will be that many spaces.
- Example:
- text = JSON.stringify(['e', {pluribus: 'unum'}]);
- // text is '["e",{"pluribus":"unum"}]'
- text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
- // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
- text = JSON.stringify([new Date()], function (key, value) {
- return this[key] instanceof Date ?
- 'Date(' + this[key] + ')' : value;
- });
- // text is '["Date(---current time---)"]'
- JSON.parse(text, reviver)
- This method parses a JSON text to produce an object or array.
- It can throw a SyntaxError exception.
- The optional reviver parameter is a function that can filter and
- transform the results. It receives each of the keys and values,
- and its return value is used instead of the original value.
- If it returns what it received, then the structure is not modified.
- If it returns undefined then the member is deleted.
- Example:
- // Parse the text. Values that look like ISO date strings will
- // be converted to Date objects.
- myData = JSON.parse(text, function (key, value) {
- var a;
- if (typeof value === 'string') {
- a =
- /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
- if (a) {
- return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
- +a[5], +a[6]));
- }
- }
- return value;
- });
- myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
- var d;
- if (typeof value === 'string' &&
- value.slice(0, 5) === 'Date(' &&
- value.slice(-1) === ')') {
- d = new Date(value.slice(5, -1));
- if (d) {
- return d;
- }
- }
- return value;
- });
- This is a reference implementation. You are free to copy, modify, or
- redistribute.
- */
- /*jslint evil: true, strict: false, regexp: false */
- /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
- call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
- getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
- lastIndex, length, parse, prototype, push, replace, slice, stringify,
- test, toJSON, toString, valueOf
- */
- // Create a JSON object only if one does not already exist. We create the
- // methods in a closure to avoid creating global variables.
- var JSON;
- if (!JSON) {
- JSON = {};
- }
- (function () {
- "use strict";
- function f(n) {
- // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
- if (typeof Date.prototype.toJSON !== 'function') {
- Date.prototype.toJSON = function (key) {
- return isFinite(this.valueOf()) ?
- this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z' : null;
- };
- String.prototype.toJSON =
- Number.prototype.toJSON =
- Boolean.prototype.toJSON = function (key) {
- return this.valueOf();
- };
- }
- var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
- gap,
- indent,
- meta = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
- rep;
- function quote(string) {
- // If the string contains no control characters, no quote characters, and no
- // backslash characters, then we can safely slap some quotes around it.
- // Otherwise we must also replace the offending characters with safe escape
- // sequences.
- escapable.lastIndex = 0;
- return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
- var c = meta[a];
- return typeof c === 'string' ? c :
- '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- }) + '"' : '"' + string + '"';
- }
- function str(key, holder) {
- // Produce a string from holder[key].
- var i, // The loop counter.
- k, // The member key.
- v, // The member value.
- length,
- mind = gap,
- partial,
- value = holder[key];
- // If the value has a toJSON method, call it to obtain a replacement value.
- if (value && typeof value === 'object' &&
- typeof value.toJSON === 'function') {
- value = value.toJSON(key);
- }
- // If we were called with a replacer function, then call the replacer to
- // obtain a replacement value.
- if (typeof rep === 'function') {
- value = rep.call(holder, key, value);
- }
- // What happens next depends on the value's type.
- switch (typeof value) {
- case 'string':
- return quote(value);
- case 'number':
- // JSON numbers must be finite. Encode non-finite numbers as null.
- return isFinite(value) ? String(value) : 'null';
- case 'boolean':
- case 'null':
- // If the value is a boolean or null, convert it to a string. Note:
- // typeof null does not produce 'null'. The case is included here in
- // the remote chance that this gets fixed someday.
- return String(value);
- // If the type is 'object', we might be dealing with an object or an array or
- // null.
- case 'object':
- // Due to a specification blunder in ECMAScript, typeof null is 'object',
- // so watch out for that case.
- if (!value) {
- return 'null';
- }
- // Make an array to hold the partial results of stringifying this object value.
- gap += indent;
- partial = [];
- // Is the value an array?
- if (Object.prototype.toString.apply(value) === '[object Array]') {
- // The value is an array. Stringify every element. Use null as a placeholder
- // for non-JSON values.
- length = value.length;
- for (i = 0; i < length; i += 1) {
- partial[i] = str(i, value) || 'null';
- }
- // Join all of the elements together, separated with commas, and wrap them in
- // brackets.
- v = partial.length === 0 ? '[]' : gap ?
- '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
- '[' + partial.join(',') + ']';
- gap = mind;
- return v;
- }
- // If the replacer is an array, use it to select the members to be stringified.
- if (rep && typeof rep === 'object') {
- length = rep.length;
- for (i = 0; i < length; i += 1) {
- if (typeof rep[i] === 'string') {
- k = rep[i];
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- } else {
- // Otherwise, iterate through all of the keys in the object.
- for (k in value) {
- if (Object.prototype.hasOwnProperty.call(value, k)) {
- v = str(k, value);
- if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
- }
- }
- }
- }
- // Join all of the member texts together, separated with commas,
- // and wrap them in braces.
- v = partial.length === 0 ? '{}' : gap ?
- '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
- '{' + partial.join(',') + '}';
- gap = mind;
- return v;
- }
- }
- // If the JSON object does not yet have a stringify method, give it one.
- if (typeof JSON.stringify !== 'function') {
- JSON.stringify = function (value, replacer, space) {
- // The stringify method takes a value and an optional replacer, and an optional
- // space parameter, and returns a JSON text. The replacer can be a function
- // that can replace values, or an array of strings that will select the keys.
- // A default replacer method can be provided. Use of the space parameter can
- // produce text that is more easily readable.
- var i;
- gap = '';
- indent = '';
- // If the space parameter is a number, make an indent string containing that
- // many spaces.
- if (typeof space === 'number') {
- for (i = 0; i < space; i += 1) {
- indent += ' ';
- }
- // If the space parameter is a string, it will be used as the indent string.
- } else if (typeof space === 'string') {
- indent = space;
- }
- // If there is a replacer, it must be a function or an array.
- // Otherwise, throw an error.
- rep = replacer;
- if (replacer && typeof replacer !== 'function' &&
- (typeof replacer !== 'object' ||
- typeof replacer.length !== 'number')) {
- throw new Error('JSON.stringify');
- }
- // Make a fake root object containing our value under the key of ''.
- // Return the result of stringifying the value.
- return str('', {'': value});
- };
- }
- // If the JSON object does not yet have a parse method, give it one.
- if (typeof JSON.parse !== 'function') {
- JSON.parse = function (text, reviver) {
- // The parse method takes a text and an optional reviver function, and returns
- // a JavaScript value if the text is a valid JSON text.
- var j;
- function walk(holder, key) {
- // The walk method is used to recursively walk the resulting structure so
- // that modifications can be made.
- var k, v, value = holder[key];
- if (value && typeof value === 'object') {
- for (k in value) {
- if (Object.prototype.hasOwnProperty.call(value, k)) {
- v = walk(value, k);
- if (v !== undefined) {
- value[k] = v;
- } else {
- delete value[k];
- }
- }
- }
- }
- return reviver.call(holder, key, value);
- }
- // Parsing happens in four stages. In the first stage, we replace certain
- // Unicode characters with escape sequences. JavaScript handles many characters
- // incorrectly, either silently deleting them, or treating them as line endings.
- text = String(text);
- cx.lastIndex = 0;
- if (cx.test(text)) {
- text = text.replace(cx, function (a) {
- return '\\u' +
- ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- });
- }
- // In the second stage, we run the text against regular expressions that look
- // for non-JSON patterns. We are especially concerned with '()' and 'new'
- // because they can cause invocation, and '=' because it can cause mutation.
- // But just to be safe, we want to reject all unexpected forms.
- // We split the second stage into 4 regexp operations in order to work around
- // crippling inefficiencies in IE's and Safari's regexp engines. First we
- // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
- // replace all simple value tokens with ']' characters. Third, we delete all
- // open brackets that follow a colon or comma or that begin the text. Finally,
- // we look to see that the remaining characters are only whitespace or ']' or
- // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
- if (/^[\],:{}\s]*$/
- .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
- .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
- .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
- // In the third stage we use the eval function to compile the text into a
- // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
- // in JavaScript: it can begin a block or an object literal. We wrap the text
- // in parens to eliminate the ambiguity.
- j = eval('(' + text + ')');
- // In the optional fourth stage, we recursively walk the new structure, passing
- // each name/value pair to a reviver function for possible transformation.
- return typeof reviver === 'function' ?
- walk({'': j}, '') : j;
- }
- // If the text is not JSON parseable, then a SyntaxError is thrown.
- throw new SyntaxError('JSON.parse');
- };
- }
- }());
- /*extern document */
- /*global Ajax */
- // A few useful prototype elements so we don't have to load the whole thing.
- Object.clone = function(source) {
- var destination = {};
- for (var property in source)
- destination[property] = source[property];
- return destination;
- };
- Object.keys = function(object) {
- var keys = [];
- for (var property in object)
- if (object.hasOwnProperty(property))
- keys.push(property);
- return keys;
- };
- Array.prototype.clone = function(source) {
- var destination = [];
- for (var i = 0; i < source.length; i++)
- destination.push(source[i]);
- return destination;
- };
- String.prototype.gsub = function(pattern, replacement) {
- return this.split(pattern).join(replacement);
- };
- String.prototype.strip = function() {
- return this.replace(/^\s+/, '').replace(/\s+$/, '');
- };
- String.prototype.startsWith = function(pattern) {
- return this.indexOf(pattern) === 0;
- };
- String.prototype.endsWith = function(pattern) {
- var d = this.length - pattern.length;
- return d >= 0 && this.lastIndexOf(pattern) === d;
- };
- Array.prototype.each = function(iterator, context) {
- for (var i = 0, length = this.length; i < length; i++)
- iterator.apply(context, [this[i],i]);
- };
- Array.prototype.last = function() {
- if (this.length === 0)
- return null;
- return this[this.length-1];
- };
- Array.prototype.compact = function() {
- var output = [];
- for (var i = 0; i < this.length; i++) {
- if (this[i])
- output.push(this[i]);
- }
- return output;
- };
- Array.prototype.detect = function(iterator) {
- for (var i = 0; i < this.length; i++) {
- if (iterator(this[i]))
- return true;
- }
- return false;
- };
- // abc_parse_header.js: parses a the header fields from a string representing ABC Music Notation into a usable internal structure.
- // Copyright (C) 2010 Paul Rosen (paul at paulrosen dot net)
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // This program 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 General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- /*extern AbcParseHeader */
- function AbcParseHeader(tokenizer, warn, multilineVars, tune) {
- var key1sharp = {acc: 'sharp', note: 'f'};
- var key2sharp = {acc: 'sharp', note: 'c'};
- var key3sharp = {acc: 'sharp', note: 'g'};
- var key4sharp = {acc: 'sharp', note: 'd'};
- var key5sharp = {acc: 'sharp', note: 'A'};
- var key6sharp = {acc: 'sharp', note: 'e'};
- var key7sharp = {acc: 'sharp', note: 'B'};
- var key1flat = {acc: 'flat', note: 'B'};
- var key2flat = {acc: 'flat', note: 'e'};
- var key3flat = {acc: 'flat', note: 'A'};
- var key4flat = {acc: 'flat', note: 'd'};
- var key5flat = {acc: 'flat', note: 'G'};
- var key6flat = {acc: 'flat', note: 'c'};
- var key7flat = {acc: 'flat', note: 'f'};
- var keys = {
- 'C#': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
- 'A#m': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
- 'G#Mix': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
- 'D#Dor': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
- 'E#Phr': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
- 'F#Lyd': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
- 'B#Loc': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
- 'F#': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
- 'D#m': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
- 'C#Mix': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
- 'G#Dor': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
- 'A#Phr': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
- 'BLyd': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
- 'E#Loc': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
- 'B': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
- 'G#m': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
- 'F#Mix': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
- 'C#Dor': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
- 'D#Phr': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
- 'ELyd': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
- 'A#Loc': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
- 'E': [ key1sharp, key2sharp, key3sharp, key4sharp ],
- 'C#m': [ key1sharp, key2sharp, key3sharp, key4sharp ],
- 'BMix': [ key1sharp, key2sharp, key3sharp, key4sharp ],
- 'F#Dor': [ key1sharp, key2sharp, key3sharp, key4sharp ],
- 'G#Phr': [ key1sharp, key2sharp, key3sharp, key4sharp ],
- 'ALyd': [ key1sharp, key2sharp, key3sharp, key4sharp ],
- 'D#Loc': [ key1sharp, key2sharp, key3sharp, key4sharp ],
- 'A': [ key1sharp, key2sharp, key3sharp ],
- 'F#m': [ key1sharp, key2sharp, key3sharp ],
- 'EMix': [ key1sharp, key2sharp, key3sharp ],
- 'BDor': [ key1sharp, key2sharp, key3sharp ],
- 'C#Phr': [ key1sharp, key2sharp, key3sharp ],
- 'DLyd': [ key1sharp, key2sharp, key3sharp ],
- 'G#Loc': [ key1sharp, key2sharp, key3sharp ],
- 'D': [ key1sharp, key2sharp ],
- 'Bm': [ key1sharp, key2sharp ],
- 'AMix': [ key1sharp, key2sharp ],
- 'EDor': [ key1sharp, key2sharp ],
- 'F#Phr': [ key1sharp, key2sharp ],
- 'GLyd': [ key1sharp, key2sharp ],
- 'C#Loc': [ key1sharp, key2sharp ],
- 'G': [ key1sharp ],
- 'Em': [ key1sharp ],
- 'DMix': [ key1sharp ],
- 'ADor': [ key1sharp ],
- 'BPhr': [ key1sharp ],
- 'CLyd': [ key1sharp ],
- 'F#Loc': [ key1sharp ],
- 'C': [],
- 'Am': [],
- 'GMix': [],
- 'DDor': [],
- 'EPhr': [],
- 'FLyd': [],
- 'BLoc': [],
- 'F': [ key1flat ],
- 'Dm': [ key1flat ],
- 'CMix': [ key1flat ],
- 'GDor': [ key1flat ],
- 'APhr': [ key1flat ],
- 'BbLyd': [ key1flat ],
- 'ELoc': [ key1flat ],
- 'Bb': [ key1flat, key2flat ],
- 'Gm': [ key1flat, key2flat ],
- 'FMix': [ key1flat, key2flat ],
- 'CDor': [ key1flat, key2flat ],
- 'DPhr': [ key1flat, key2flat ],
- 'EbLyd': [ key1flat, key2flat ],
- 'ALoc': [ key1flat, key2flat ],
- 'Eb': [ key1flat, key2flat, key3flat ],
- 'Cm': [ key1flat, key2flat, key3flat ],
- 'BbMix': [ key1flat, key2flat, key3flat ],
- 'FDor': [ key1flat, key2flat, key3flat ],
- 'GPhr': [ key1flat, key2flat, key3flat ],
- 'AbLyd': [ key1flat, key2flat, key3flat ],
- 'DLoc': [ key1flat, key2flat, key3flat ],
- 'Ab': [ key1flat, key2flat, key3flat, key4flat ],
- 'Fm': [ key1flat, key2flat, key3flat, key4flat ],
- 'EbMix': [ key1flat, key2flat, key3flat, key4flat ],
- 'BbDor': [ key1flat, key2flat, key3flat, key4flat ],
- 'CPhr': [ key1flat, key2flat, key3flat, key4flat ],
- 'DbLyd': [ key1flat, key2flat, key3flat, key4flat ],
- 'GLoc': [ key1flat, key2flat, key3flat, key4flat ],
- 'Db': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
- 'Bbm': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
- 'AbMix': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
- 'EbDor': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
- 'FPhr': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
- 'GbLyd': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
- 'CLoc': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
- 'Gb': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
- 'Ebm': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
- 'DbMix': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
- 'AbDor': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
- 'BbPhr': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
- 'CbLyd': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
- 'FLoc': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
- 'Cb': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
- 'Abm': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
- 'GbMix': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
- 'DbDor': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
- 'EbPhr': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
- 'FbLyd': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
- 'BbLoc': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
- // The following are not in the 2.0 spec, but seem normal enough.
- // TODO-PER: These SOUND the same as what's written, but they aren't right
- 'A#': [ key1flat, key2flat ],
- 'B#': [],
- 'D#': [ key1flat, key2flat, key3flat ],
- 'E#': [ key1flat ],
- 'G#': [ key1flat, key2flat, key3flat, key4flat ],
- 'Gbm': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ]
- };
- var calcMiddle = function(clef, oct) {
- var mid = 0;
- switch(clef) {
- case 'treble':
- case 'perc':
- case 'none':
- case 'treble+8':
- case 'treble-8':
- break;
- case 'bass3':
- case 'bass':
- case 'bass+8':
- case 'bass-8':
- case 'bass+16':
- case 'bass-16':
- mid = -12;
- break;
- case 'tenor':
- mid = -8;
- break;
- case 'alto2':
- case 'alto1':
- case 'alto':
- case 'alto+8':
- case 'alto-8':
- mid = -6;
- break;
- }
- return mid+oct;
- };
- this.parseFontChangeLine = function(textstr) {
- var textParts = textstr.split('$');
- if (textParts.length > 1 && multilineVars.setfont) {
- var textarr = [ { text: textParts[0] }];
- for (var i = 1; i < textParts.length; i++) {
- if (textParts[i].charAt(0) === '0')
- textarr.push({ text: textParts[i].substring(1) });
- else if (textParts[i].charAt(0) === '1' && multilineVars.setfont[1])
- textarr.push({font: multilineVars.setfont[1], text: textParts[i].substring(1) });
- else if (textParts[i].charAt(0) === '2' && multilineVars.setfont[2])
- textarr.push({font: multilineVars.setfont[2], text: textParts[i].substring(1) });
- else if (textParts[i].charAt(0) === '3' && multilineVars.setfont[3])
- textarr.push({font: multilineVars.setfont[3], text: textParts[i].substring(1) });
- else if (textParts[i].charAt(0) === '4' && multilineVars.setfont[4])
- textarr.push({font: multilineVars.setfont[4], text: textParts[i].substring(1) });
- else
- textarr[textarr.length-1].text += '$' + textParts[i];
- }
- if (textarr.length > 1)
- return textarr;
- }
- return textstr;
- }
- this.deepCopyKey = function(key) {
- var ret = { accidentals: [], root: key.root, acc: key.acc, mode: key.mode };
- key.accidentals.each(function(k) {
- ret.accidentals.push(Object.clone(k));
- });
- return ret;
- };
- var pitches = {A: 5, B: 6, C: 0, D: 1, E: 2, F: 3, G: 4, a: 12, b: 13, c: 7, d: 8, e: 9, f: 10, g: 11};
- this.addPosToKey = function(clef, key) {
- // Shift the key signature from the treble positions to whatever position is needed for the clef.
- // This may put the key signature unnaturally high or low, so if it does, then shift it.
- var mid = clef.verticalPos;
- key.accidentals.each(function(acc) {
- var pitch = pitches[acc.note];
- pitch = pitch - mid;
- acc.verticalPos = pitch;
- });
- if (mid < -10) {
- key.accidentals.each(function(acc) {
- acc.verticalPos -= 7;
- if (acc.verticalPos >= 11 || (acc.verticalPos === 10 && acc.acc === 'flat'))
- acc.verticalPos -= 7;
- });
- } else if (mid < -4) {
- key.accidentals.each(function(acc) {
- acc.verticalPos -= 7;
- });
- } else if (mid >= 7) {
- key.accidentals.each(function(acc) {
- acc.verticalPos += 7;
- });
- }
- };
- this.fixKey = function(clef, key) {
- var fixedKey = Object.clone(key);
- this.addPosToKey(clef, fixedKey);
- return fixedKey;
- };
- var parseMiddle = function(str) {
- var mid = pitches[str.charAt(0)];
- for (var i = 1; i < str.length; i++) {
- if (str.charAt(i) === ',') mid -= 7;
- else if (str.charAt(i) === ',') mid += 7;
- else break;
- }
- return { mid: mid - 6, str: str.substring(i) }; // We get the note in the middle of the staff. We want the note that appears as the first ledger line below the staff.
- };
- var normalizeAccidentals = function(accs) {
- for (var i = 0; i < accs.length; i++) {
- if (accs[i].note === 'b')
- accs[i].note = 'B';
- else if (accs[i].note === 'a')
- accs[i].note = 'A';
- else if (accs[i].note === 'F')
- accs[i].note = 'f';
- else if (accs[i].note === 'E')
- accs[i].note = 'e';
- else if (accs[i].note === 'D')
- accs[i].note = 'd';
- else if (accs[i].note === 'C')
- accs[i].note = 'c';
- else if (accs[i].note === 'G' && accs[i].acc === 'sharp')
- accs[i].note = 'g';
- else if (accs[i].note === 'g' && accs[i].acc === 'flat')
- accs[i].note = 'G';
- }
- };
- this.parseKey = function(str) // (and clef)
- {
- // returns:
- // { foundClef: true, foundKey: true }
- // Side effects:
- // calls warn() when there is a syntax error
- // sets these members of multilineVars:
- // clef
- // key
- // style
- //
- // The format is:
- // K: [?key?] [?modifiers?*]
- // modifiers are any of the following in any order:
- // [?clef?] [middle=?pitch?] [transpose=[-]?number?] [stafflines=?number?] [staffscale=?number?][style=?style?]
- // key is none|HP|Hp|?specified_key?
- // clef is [clef=] [?clef type?] [?line number?] [+8|-8]
- // specified_key is ?pitch?[#|b][mode(first three chars are significant)][accidentals*]
- if (str.length === 0) {
- // an empty K: field is the same as K:none
- str = 'none';
- }
- var tokens = tokenizer.tokenize(str, 0, str.length);
- var ret = {};
- // first the key
- switch (tokens[0].token) {
- case 'HP':
- this.addDirective("bagpipes");
- multilineVars.key = { root: "HP", accidentals: [], acc: "", mode: "" };
- ret.foundKey = true;
- tokens.shift();
- break;
- case 'Hp':
- this.addDirective("bagpipes");
- multilineVars.key = { root: "Hp", accidentals: [{acc: 'natural', note: 'g'}, {acc: 'sharp', note: 'f'}, {acc: 'sharp', note: 'c'}], acc: "", mode: "" };
- ret.foundKey = true;
- tokens.shift();
- break;
- case 'none':
- // we got the none key - that's the same as C to us
- multilineVars.key = { root: "none", accidentals: [], acc: "", mode: "" };
- ret.foundKey = true;
- tokens.shift();
- break;
- default:
- var retPitch = tokenizer.getKeyPitch(tokens[0].token);
- if (retPitch.len > 0) {
- ret.foundKey = true;
- var acc = "";
- var mode = "";
- // The accidental and mode might be attached to the pitch, so we might want to just remove the first character.
- if (tokens[0].token.length > 1)
- tokens[0].token = tokens[0].token.substring(1);
- else
- tokens.shift();
- var key = retPitch.token;
- // We got a pitch to start with, so we might also have an accidental and a mode
- if (tokens.length > 0) {
- var retAcc = tokenizer.getSharpFlat(tokens[0].token);
- if (retAcc.len > 0) {
- if (tokens[0].token.length > 1)
- tokens[0].token = tokens[0].token.substring(1);
- else
- tokens.shift();
- key += retAcc.token;
- acc = retAcc.token;
- }
- if (tokens.length > 0) {
- var retMode = tokenizer.getMode(tokens[0].token);
- if (retMode.len > 0) {
- tokens.shift();
- key += retMode.token;
- mode = retMode.token;
- }
- }
- }
- // We need to do a deep copy because we are going to modify it
- multilineVars.key = this.deepCopyKey({accidentals: keys[key]});
- multilineVars.key.root = retPitch.token;
- multilineVars.key.acc = acc;
- multilineVars.key.mode = mode;
- }
- break;
- }
- // There are two special cases of deprecated syntax. Ignore them if they occur
- if (tokens.length === 0) return ret;
- if (tokens[0].token === 'exp') tokens.shift();
- if (tokens.length === 0) return ret;
- if (tokens[0].token === 'oct') tokens.shift();
- // now see if there are extra accidentals
- if (tokens.length === 0) return ret;
- var accs = tokenizer.getKeyAccidentals2(tokens);
- if (accs.warn)
- warn(accs.warn, str, 0);
- // If we have extra accidentals, first replace ones that are of the same pitch before adding them to the end.
- if (accs.accs) {
- if (!ret.foundKey) { // if there are only extra accidentals, make sure this is set.
- ret.foundKey = true;
- multilineVars.key = { root: "none", acc: "", mode: "", accidentals: [] };
- }
- normalizeAccidentals(accs.accs);
- for (var i = 0; i < accs.accs.length; i++) {
- var found = false;
- for (var j = 0; j < multilineVars.key.accidentals.length && !found; j++) {
- if (multilineVars.key.accidentals[j].note === accs.accs[i].note) {
- found = true;
- multilineVars.key.accidentals[j].acc = accs.accs[i].acc;
- }
- }
- if (!found)
- multilineVars.key.accidentals.push(accs.accs[i]);
- }
- }
- // Now see if any optional parameters are present. They have the form "key=value", except that "clef=" is optional
- var token;
- while (tokens.length > 0) {
- switch (tokens[0].token) {
- case "m":
- case "middle":
- tokens.shift();
- if (tokens.length === 0) { warn("Expected = after middle", str, 0); return ret; }
- token = tokens.shift();
- if (token.token !== "=") { warn("Expected = after middle", str, 0); break; }
- if (tokens.length === 0) { warn("Expected parameter after middle=", str, 0); return ret; }
- var pitch = tokenizer.getPitchFromTokens(tokens);
- if (pitch.warn)
- warn(pitch.warn, str, 0);
- if (pitch.position)
- multilineVars.clef.verticalPos = pitch.position - 6; // we get the position from the middle line, but want to offset it to the first ledger line.
- break;
- case "transpose":
- tokens.shift();
- if (tokens.length === 0) { warn("Expected = after transpose", str, 0); return ret; }
- token = tokens.shift();
- if (token.token !== "=") { warn("Expected = after transpose", str, 0); break; }
- if (tokens.length === 0) { warn("Expected parameter after transpose=", str, 0); return ret; }
- if (tokens[0].type !== 'number') { warn("Expected number after transpose", str, 0); break; }
- multilineVars.clef.transpose = parseInt(tokens[0].token);
- tokens.shift();
- break;
- case "stafflines":
- tokens.shift();
- if (tokens.length === 0) { warn("Expected = after stafflines", str, 0); return ret; }
- token = tokens.shift();
- if (token.token !== "=") { warn("Expected = after stafflines", str, 0); break; }
- if (tokens.length === 0) { warn("Expected parameter after stafflines=", str, 0); return ret; }
- if (tokens[0].type !== 'number') { warn("Expected number after stafflines", str, 0); break; }
- multilineVars.clef.stafflines = parseInt(tokens[0].token);
- tokens.shift();
- break;
- case "staffscale":
- tokens.shift();
- if (tokens.length === 0) { warn("Expected = after staffscale", str, 0); return ret; }
- token = tokens.shift();
- if (token.token !== "=") { warn("Expected = after staffscale", str, 0); break; }
- if (tokens.length === 0) { warn("Expected parameter after staffscale=", str, 0); return ret; }
- if (tokens[0].type !== 'number') { warn("Expected number after staffscale", str, 0); break; }
- multilineVars.clef.staffscale = parseInt(tokens[0].token);
- tokens.shift();
- break;
- case "style":
- tokens.shift();
- if (tokens.length === 0) { warn("Expected = after style", str, 0); return ret; }
- token = tokens.shift();
- if (token.token !== "=") { warn("Expected = after style", str, 0); break; }
- if (tokens.length === 0) { warn("Expected parameter after style=", str, 0); return ret; }
- switch (tokens[0].token) {
- case "normal":
- case "harmonic":
- case "rhythm":
- case "x":
- multilineVars.style = tokens[0].token;
- tokens.shift();
- break;
- default:
- warn("error parsing style element: " + tokens[0].token, str, 0);
- break;
- }
- break;
- case "clef":
- tokens.shift();
- if (tokens.length === 0) { warn("Expected = after clef", str, 0); return ret; }
- token = tokens.shift();
- if (token.token !== "=") { warn("Expected = after clef", str, 0); break; }
- if (tokens.length === 0) { warn("Expected parameter after clef=", str, 0); return ret; }
- //break; yes, we want to fall through. That allows "clef=" to be optional.
- case "treble":
- case "bass":
- case "alto":
- case "tenor":
- case "perc":
- // clef is [clef=] [?clef type?] [?line number?] [+8|-8]
- var clef = tokens.shift();
- switch (clef.token) {
- case 'treble':
- case 'tenor':
- case 'alto':
- case 'bass':
- case 'perc':
- case 'none':
- break;
- case 'C': clef.token = 'alto'; break;
- case 'F': clef.token = 'bass'; break;
- case 'G': clef.token = 'treble'; break;
- case 'c': clef.token = 'alto'; break;
- case 'f': clef.token = 'bass'; break;
- case 'g': clef.token = 'treble'; break;
- default:
- warn("Expected clef name. Found " + clef.token, str, 0);
- break;
- }
- if (tokens.length > 0 && tokens[0].type === 'number') {
- clef.token += tokens[0].token;
- tokens.shift();
- }
- if (tokens.length > 1 && (tokens[0].token === '-' || tokens[0].token === '+') && tokens[1].token === '8') {
- clef.token += tokens[0].token + tokens[1].token;
- tokens.shift();
- tokens.shift();
- }
- multilineVars.clef = {type: clef.token, verticalPos: calcMiddle(clef.token, 0)};
- ret.foundClef = true;
- break;
- default:
- warn("Unknown parameter: " + tokens[0].token, str, 0);
- tokens.shift();
- }
- }
- return ret;
- };
- this.parseKeyOld = function(str) // (and clef)
- {
- str = tokenizer.stripComment(str);
- var origStr = str;
- if (str.length === 0) {
- // an empty K: field is the same as K:none
- str = 'none';
- }
- // The format is:
- // [space][tonic[#|b][ ][3-letter-mode][ignored-chars][space]][ accidentals...][ clef=treble|bass|bass3|tenor|alto|alto2|alto1|none [+8|-8] [middle=note] [transpose=num] [stafflines=num] ]
- // K: ?key? [[clef=] [clef type] [line number] [+8|-8]] [middle=?pitch?] [transpose=] [stafflines=?number?] [staffscale=?number?][style=?style?]
- // V: ?voice name? [clef=] [clef type] [name=] [sname=] [merge] [stem=] [up | down | auto] [gstem=] [up | down | auto] [dyn=] [up | down | auto] [lyrics=] [up | down | auto] [gchord=] [up | down | auto] [scale=] [staffscale=] [stafflines=]
- // -- or -- the key can be "none"
- // First get the key letter: turn that into a index into the key array (0-11)
- // Then see if there is a sharp or flat. Increment or decrement.
- // Then see if there is a mode modifier. Add or subtract to the index.
- // Then do a mod 12 on the index and return the key.
- // TODO: This may leave unparsed characters at the end after something reasonable was found.
- // TODO: The above description does not seem to be valid as key names rather than indexes are used -- GD
- var setClefMiddle = function(str) {
- var i = tokenizer.skipWhiteSpace(str);
- str = str.substring(i);
- if (str.startsWith('m=') || str.startsWith('middle=')) {
- str = str.substring(str.indexOf('=')+1);
- var mid = parseMiddle(str);
- multilineVars.clef.verticalPos = mid.mid;
- str = mid.str;
- }
- i = tokenizer.skipWhiteSpace(str);
- str = str.substring(i);
- if (str.startsWith('transpose=')) {
- str = str.substring(str.indexOf('=')+1);
- var num = tokenizer.getInt(str);
- if (num.digits > 0) {
- str = str.substring(num.digits);
- multilineVars.clef.transpose = num.value;
- }
- }
- i = tokenizer.skipWhiteSpace(str);
- str = str.substring(i);
- if (str.startsWith('stafflines=')) {
- str = str.substring(str.indexOf('=')+1);
- var num2 = tokenizer.getInt(str);
- if (num2.digits > 0) {
- str = str.substring(num2.digits);
- multilineVars.clef.stafflines = num2.value;
- }
- }
- };
- // check first to see if there is only a clef. If so, just take that, but ignore an error after that.
- var retClef = tokenizer.getClef(str, true);
- if (retClef.token !== undefined && (retClef.explicit === true || retClef.token !== 'none')) { // none, C, F, and G are the only ambiguous marking. We need to assume that's a key
- multilineVars.clef = {type: retClef.token, verticalPos: calcMiddle(retClef.token, 0)};
- str = str.substring(retClef.len);
- setClefMiddle(str);
- return {foundClef: true};
- //TODO multilinevars.key is not set - is this normal? -- GD
- }
- var ret = { root: 'none', acc: '', mode: '' };
- var retPitch = tokenizer.getKeyPitch(str);
- if (retPitch.len > 0) {
- var key = retPitch.token;
- str = str.substring(retPitch.len);
- // We got a pitch to start with, so we might also have an accidental and a mode
- var retAcc = tokenizer.getSharpFlat(str);
- if (retAcc.len > 0) {
- key += retAcc.token;
- str = str.substring(retAcc.len);
- }
- var retMode = tokenizer.getMode(str);
- if (retMode.len > 0) {
- key += retMode.token;
- str = str.substring(retMode.len);
- }
- // We need to do a deep copy because we are going to modify it
- ret = this.deepCopyKey({accidentals: keys[key]});
- ret.root = retPitch.token;
- ret.acc = retAcc.token || "";
- ret.mode = retMode.token || "";
- } else if (str.startsWith('HP')) {
- this.addDirective("bagpipes");
- ret.accidentals = [];
- ret.root = "HP";
- multilineVars.key = ret;
- return {foundKey: true};
- } else if (str.startsWith('Hp')) {
- ret.accidentals = [ {acc: 'natural', note: 'g'}, {acc: 'sharp', note: 'f'}, {acc: 'sharp', note: 'c'} ];
- this.addDirective("bagpipes");
- ret.root = "Hp";
- multilineVars.key = ret;
- return {foundKey: true};
- } else {
- var retNone = tokenizer.isMatch(str, 'none');
- if (retNone > 0) {
- // we got the none key - that's the same as C to us
- ret.accidentals = [];
- str = str.substring(retNone);
- }
- }
- // There are two special cases of deprecated syntax. Ignore them if they occur
- var j = tokenizer.skipWhiteSpace(str);
- str = str.substring(j);
- if (str.startsWith('exp') || str.startsWith('oct'))
- str = str.substring(3);
- // now see if there are extra accidentals
- var done = false;
- while (!done) {
- var retExtra = tokenizer.getKeyAccidental(str);
- if (retExtra.len === 0)
- done = true;
- else {
- str = str.substring(retExtra.len);
- if (retExtra.warn)
- warn("error parsing extra accidentals:", origStr, 0);
- else {
- if (!ret.accidentals)
- ret.accidentals = [];
- ret.accidentals.push(retExtra.token);
- }
- }
- }
- // now see if there is a clef
- retClef = tokenizer.getClef(str, false);
- if (retClef.len > 0) {
- if (retClef.warn)
- warn("error parsing clef:" + retClef.warn, origStr, 0);
- else {
- //ret.clef = retClef.token;
- multilineVars.clef = {type: retClef.token, verticalPos: calcMiddle(retClef.token, 0)};
- str = str.substring(retClef.len);
- setClefMiddle(str);
- }
- }
- // now see if there is a note style
- i = tokenizer.skipWhiteSpace(str);
- str = str.substring(i);
- if (str.startsWith('style=')) {
- var style = tokenizer.getToken(str, 6, str.length);
- switch (style) {
- case "normal":
- case "harmonic":
- case "rhythm":
- case "x":
- multilineVars.style = style;
- break;
- default:
- warn("error parsing style element of key: ", origStr, 0);
- break;
- }
- str = str.substring(6+style.length);
- }
- // if (ret.accidentals === undefined && retClef.token === undefined) {
- // warn("error parsing key: ", origStr, 0);
- // return {};
- // }
- var result = {};
- if (retClef.token !== undefined)
- result.foundClef = true;
- if (ret.accidentals !== undefined) {
- // Adjust the octave of the accidentals, if necessary
- ret.accidentals.each(function(acc) {
- if (retClef.token === 'bass') {
- //if (acc.note === 'A') acc.note = 'a';
- //if (acc.note === 'B') acc.note = 'b';
- if (acc.note === 'C') acc.note = 'c';
- if (acc.note === 'D' && acc.acc !== 'flat') acc.note = 'd';
- if (acc.note === 'E' && acc.acc !== 'flat') acc.note = 'e';
- if (acc.note === 'F' && acc.acc !== 'flat') acc.note = 'f';
- if (acc.note === 'G' && acc.acc !== 'flat') acc.note = 'g';
- } else {
- if (acc.note === 'a') acc.note = 'A';
- if (acc.note === 'b') acc.note = 'B';
- if (acc.note === 'C') acc.note = 'c';
- }
- });
- multilineVars.key = ret;
- result.foundKey = true;
- }
- return result;
- };
- this.addDirective = function(str) {
- var getRequiredMeasurement = function(cmd, tokens) {
- var points = tokenizer.getMeasurement(tokens);
- if (points.used === 0 || tokens.length !== 0)
- return { error: "Directive \"" + cmd + "\" requires a measurement as a parameter."};
- return points.value;
- };
- var oneParameterMeasurement = function(cmd, tokens) {
- var points = tokenizer.getMeasurement(tokens);
- if (points.used === 0 || tokens.length !== 0)
- return "Directive \"" + cmd + "\" requires a measurement as a parameter.";
- tune.formatting[cmd] = points.value;
- return null;
- };
- var getFontParameter = function(tokens) {
- var font = {};
- var token = tokens.last();
- if (token.type === 'number') {
- font.size = parseInt(token.token);
- tokens.pop();
- }
- if (tokens.length > 0) {
- var scratch = "";
- tokens.each(function(tok) {
- if (tok.token !== '-') {
- if (scratch.length > 0) scratch += ' ';
- scratch += tok.token;
- }
- });
- font.font = scratch;
- }
- return font;
- };
- var getChangingFont = function(cmd, tokens) {
- if (tokens.length === 0)
- return "Directive \"" + cmd + "\" requires a font as a parameter.";
- multilineVars[cmd] = getFontParameter(tokens);
- return null;
- };
- var getGlobalFont = function(cmd, tokens) {
- if (tokens.length === 0)
- return "Directive \"" + cmd + "\" requires a font as a parameter.";
- tune.formatting[cmd] = getFontParameter(tokens);
- return null;
- };
- var tokens = tokenizer.tokenize(str, 0, str.length); // 3 or more % in a row, or just spaces after %% is just a comment
- if (tokens.length === 0 || tokens[0].type !== 'alpha') return null;
- var restOfString = str.substring(str.indexOf(tokens[0].token)+tokens[0].token.length);
- restOfString = tokenizer.stripComment(restOfString);
- var cmd = tokens.shift().token.toLowerCase();
- var num;
- var scratch = "";
- switch (cmd)
- {
- // The following directives were added to abc_parser_lint, but haven't been implemented here.
- // Most of them are direct translations from the directives that will be parsed in. See abcm2ps's format.txt for info on each of these.
- // alignbars: { type: "number", optional: true },
- // aligncomposer: { type: "string", Enum: [ 'left', 'center','right' ], optional: true },
- // annotationfont: fontType,
- // barsperstaff: { type: "number", optional: true },
- // bstemdown: { type: "boolean", optional: true },
- // continueall: { type: "boolean", optional: true },
- // dynalign: { type: "boolean", optional: true },
- // exprabove: { type: "boolean", optional: true },
- // exprbelow: { type: "boolean", optional: true },
- // flatbeams: { type: "boolean", optional: true },
- // footer: { type: "string", optional: true },
- // footerfont: fontType,
- // gchordbox: { type: "boolean", optional: true },
- // graceslurs: { type: "boolean", optional: true },
- // gracespacebefore: { type: "number", optional: true },
- // gracespaceinside: { type: "number", optional: true },
- // gracespaceafter: { type: "number", optional: true },
- // header: { type: "string", optional: true },
- // headerfont: fontType,
- // historyfont: fontType,
- // infofont: fontType,
- // infospace: { type: "number", optional: true },
- // lineskipfac: { type: "number", optional: true },
- // maxshrink: { type: "number", optional: true },
- // maxstaffsep: { type: "number", optional: true },
- // maxsysstaffsep: { type: "number", optional: true },
- // measurebox: { type: "boolean", optional: true },
- // measurefont: fontType,
- // notespacingfactor: { type: "number", optional: true },
- // parskipfac: { type: "number", optional: true },
- // partsbox: { t…
Large files files are truncated, but you can click here to view the full file