fretboard-api
Version:
A kind of API for fretboard diagrams
1,896 lines (1,855 loc) • 66.9 kB
JavaScript
//TODO: move these types into index
/**
*
* @param shape The Shape
*/
function firstPlayedString(shape) {
var n = shape.frets.findIndex(function (string) { return string != null && string.length > 0; });
if (n < 0)
throw new Error("Invalid shape, at least one string must be played.");
return n;
}
/**
* Returns first played fret (non null)
* @param shape The Shape
*/
function firstPlayedFret(shape) {
// const firstString = firstPlayedString(shape);
// if (firstString < 0) throw new Error("Invalid shape, at least a string must be played.");
var fs = shape.frets[firstPlayedString(shape)];
var f = fs ? fs.find(function (fret) { return fret !== null; }) : undefined;
if (f == undefined) {
throw new Error('no played position found');
}
else {
return f;
}
}
/**
* In string definition, use 'X' to denote a non-played string.
* In number[] definition, use 'null' to denote a non-played string.
* "022100" --> [[0], [2], [2], [1], [0], [0]]
* "8 10 10 9 8 8" --> [[8], [10], [10], [9], [8], [8]]
* [8, 10, 10, 9, 8, 8] --> [[8], [10], [10], [9], [8], [8]]
* "24,124,134,134,24,12" --> [[2, 4], [1, 2, 4], [1, 3, 4], [1, 3, 4], [2, 4], [1, 2]]
* "8 10, 7 8 10, 7 9 10, 7 9 10, 8 10, 7 8" --> [[8, 10], [7, 8, 10], [7, 9, 10], [7, 9, 10], [8, 10], [7, 8]]
* @param {?(array|string)} frets - frets.
* @return {array} array of fret numbers.
*/
// export function normalizeInputFormat(frets: string): Fret[][]|undefined;
// export function normalizeInputFormat(frets: number[]): Fret[][]|undefined;
function normalizeInputFormat(frets) {
//TODO: add formats:
//
// "---010" --> [[], [], [], [0], [1], [0]]
//
//
//
if (!frets) {
//TODO: throw an error instead?
return [];
}
if (Array.isArray(frets)) {
return frets.map(function (s) { return s == null ? null : [s]; });
}
// replace multiples blanks with one space:
var fs = frets.toUpperCase().replace(/\s+/g, ' ');
if (fs.indexOf(',') < 0) {
// only one fretted note per string
var a = fs.indexOf(' ') >= 0
? fs.split(' ') // "8 10 ..." --> ["8", "10", ...]
: Array.from(fs); // "022100" --> ["0", "2", "2", "1", "0", "0"]
return a.map(function (s) {
if (s.toUpperCase() === 'X')
return null; // value "null" means non-played string
return [parseInt(s, 10)];
});
}
else {
// more than one fretted note per string
var a = fs.replace(/,\s*/g, ',').split(','); // "8 10, 7 8 10, ..." --> ["8 10", "7 8 10", ...]
return a.map(function (s) {
if (s.toUpperCase() === 'X')
return null; // value "null" means non-played string
return (s.indexOf(' ') >= 0
? s.split(' ') // ["8 10", ...] --> [["8", "10"], ...]
: Array.from(s) // ["24", "124", ...] --> [["2", "4"], ["1", "2", "4"], ...]
).map(function (s) {
if (s.toUpperCase() === 'X')
throw new Error('invalid format');
return parseInt(s, 10);
});
});
}
}
/**
*
* @param fingers
*/
function normalizeFingers(fingers) {
// if (typeof frets !== 'string') return frets;
// if ((frets === undefined) || (frets === null)) { //FIXME: simplify this test
if (!fingers) {
//TODO: throw an error instead?
return [];
}
if (Array.isArray(fingers)) {
return fingers.map(function (s) { return s == null ? null : [s]; });
}
var fs = fingers.toUpperCase().replace(/\s+/g, ' '); // replace multiples blanks with one space
if (fs.indexOf(',') < 0) {
// only one fretted note per string
var a = fs.indexOf(' ') >= 0
? fs.split(' ') // "8 10 ..." --> ["8", "10", ...]
: Array.from(fs); // "022100" --> ["0", "2", "2", "1", "0", "0"]
return a.map(function (s) {
if (s.toUpperCase() === 'X')
return null; // value 0 means non-played string
// if (s === '-') return []; // nothing played on this string
return [parseInt(s, 10)];
});
}
else {
var a = fs.replace(/,\s*/g, ',').split(','); // "8 10, 7 8 10, ..." --> ["8 10", "7 8 10", ...]
return a.map(function (s) {
if (s.toUpperCase() === 'X')
return [0];
// if (s === '' || s === '-') return []; // nothing played on this string
return (s.indexOf(' ') >= 0
? s.split(' ') // ["8 10", ...] --> [["8", "10"], ...]
: Array.from(s) // ["24", "124", ...] --> [["2", "4"], ["1", "2", "4"], ...]
).map(function (s) {
if (s.toUpperCase() === 'X')
throw new Error('invalid format');
// if (s === '-') throw new Error('invalid format');
return parseInt(s, 10);
});
});
}
}
function create(shape) {
var newShape = {
frets: [null],
root: { string: 0, fret: 0 },
position: { string: 0, fret: 0 },
intervals: [],
notes: [],
fromFret: 0,
toFret: 0
};
// if (typeof shape === 'string') { // we use two distinct tests to help Typescript.
//
// o.frets = normalizeInputFormat(shape);
// // o.frets = [[0], [2], [2], [1], [0], [0]];
// // o.fingers = null;
// o.root = {string: 0, fret: 0};
//
// } else if (Array.isArray(shape)) {
if ((typeof shape === 'string') || Array.isArray(shape)) {
newShape.frets = normalizeInputFormat(shape);
// console.log(JSON.stringify(s));
// o.frets = [[0], [2], [2], [1], [0], [0]];
// o.fingers = null;
// o.root = {string: 0, fret: 0};
}
else if (typeof shape === 'object') {
// Assert.hasProperty('frets', shape);
// if (shape.frets) {
// o.frets = normalizeInputFormat(shape.frets);
// }
// o.fingers = normalizeInputFormat(shape.fingers);
newShape = {
// ...s,
frets: normalizeInputFormat(shape.frets),
fingers: normalizeFingers(shape.fingers),
position: shape.position,
root: shape.root,
intervals: [],
notes: [],
fromFret: 0,
toFret: 0
};
// ['frets', 'fingers'].map(p => o[p] = normalizeInputFormat(shape[p]));
// ['position', 'root'].map(p => o[p] = shape[p]);
// } else {
// throw new Error("InvalidArgumentException"); // TODO: return a more helpful message
}
// console.log(o.frets);
if (!newShape.frets || (newShape.frets.length === 0)) { // this allows the creation of empty shapes
return newShape;
}
// if we did not supply the root definition, compute it:
if (!shape.root) {
// by default takes the first fretted note on the first played string
var firstString = firstPlayedString(newShape);
if (firstString < 0)
throw new Error("Invalid shape, at least a string must be played.");
// console.log("firstString", firstString);
newShape.root = {
string: firstString,
// fret: firstPlayedFret(o.frets[firstString])
fret: firstPlayedFret(newShape)
};
// console.log("root", JSON.stringify(s));
}
// if we did not supply the position definition, compute it:
if (!shape.position) {
newShape.position = {
string: newShape.root.string,
fret: newShape.root.fret
};
}
// compute min fret:
newShape.fromFret = newShape.root.fret; // we need to start somewhere
for (var s = 0; s < newShape.frets.length; s++) { // for each string
var f = newShape.frets[s];
if (!f)
continue;
for (var i = 0; i < f.length; i++) { // for each fret
if (f[i] < newShape.fromFret) {
newShape.fromFret = f[i];
}
}
}
// compute max fret:
newShape.toFret = 0;
for (var s = 0; s < newShape.frets.length; s++) { // for each string
var f = newShape.frets[s];
if (!f)
continue;
for (var i = 0; i < f.length; i++) { // for each fret
if (f[i] > newShape.toFret) {
newShape.toFret = f[i];
}
}
}
return newShape;
}
/**
*
* @param shape
* @returns {*}
*/
function getFretPosition(shape) {
if (shape.position === undefined || shape.position === null) {
var s = shape.frets[firstPlayedString(shape)];
// const s0 = s[0];
if (s == null) { // to make typescript happy
return 0;
}
else {
return s[0];
}
// // @ts-ignore
// return s[0];
}
else {
return shape.position.fret;
}
}
var Shape = {
create: create,
normalizeInputFormat: normalizeInputFormat,
// normalizeFingers,
getFretPosition: getFretPosition // used in Fretboard
};
var bass4 = {
standard: ['E1', 'A1', 'D2', 'G2'],
drop_d: ['D1', 'A1', 'D2', 'G2']
};
var guitar6 = {
standard: ['E2', 'A2', 'D3', 'G3', 'B3', 'E4'],
standard_d: ['D2', 'G2', 'C3', 'F3', 'A3', 'D4'],
drop_d: ['D2', 'A2', 'D3', 'G3', 'B3', 'E4'],
drop_c: ['C2', 'G2', 'C3', 'F3', 'A3', 'D4'],
double_drop_d: ['D2', 'A2', 'D3', 'G3', 'B3', 'D4'],
dadgad: ['D2', 'A2', 'D3', 'G3', 'A3', 'D4']
};
var bass = bass4;
var guitar = guitar6;
var Tuning = {
bass: bass,
bass4: bass4,
guitar: guitar,
guitar6: guitar6
};
/*
export const Tunings: { [name: string]: TuningType } = {
bass4: {
standard : ['E1', 'A1', 'D2', 'G2'],
drop_d : ['D1', 'A1', 'D2', 'G2']
},
bass5: {
standard : ['B0', 'E1', 'A1', 'D2', 'G2'],
tenor : ['E1', 'A1', 'D2', 'G2', 'C3']
},
bass6: {
standard : ['B0', 'E1', 'A1', 'D2', 'G2', 'C3']
},
guitar6: {
standard : ['E2', 'A2', 'D3', 'G3', 'B3', 'E4'],
standard_d : ['D2', 'G2', 'C3', 'F3', 'A3', 'D4'],
drop_d : ['D2', 'A2', 'D3', 'G3', 'B3', 'E4'],
drop_c : ['C2', 'G2', 'C3', 'F3', 'A3', 'D4'],
double_drop_d : ['D2', 'A2', 'D3', 'G3', 'B3', 'D4'],
dadgad : ['D2', 'A2', 'D3', 'G3', 'A3', 'D4']
},
guitar7: { // 7 strings guitar
standard : ['B1', 'E2', 'A2', 'D3', 'G3', 'B3', 'E4'],
drop_a : ['A1', 'E2', 'A2', 'D3', 'G3', 'B3', 'E4']
},
guitar8: { // 8 strings guitar
standard : ['F#1', 'B1', 'E2', 'A2', 'D3', 'G3', 'B3', 'E4'],
drop_e : ['E1', 'B1', 'E2', 'A2', 'D3', 'G3', 'B3', 'E4']
}
};
Tunings['bass'] = Tunings.bass4;
Tunings['guitar'] = Tunings.guitar6;
*/
// https://en.wikipedia.org/wiki/List_of_guitar_tunings
// https://en.wikibooks.org/wiki/Guitar/Alternate_Tunings
function n(n){for(var t=arguments.length,r=Array(t>1?t-1:0),e=1;e<t;e++)r[e-1]=arguments[e];if("production"!==process.env.NODE_ENV){var i=H[n],o=i?"function"==typeof i?i.apply(null,r):i:"unknown error nr: "+n;throw Error("[Immer] "+o)}throw Error("[Immer] minified error nr: "+n+(r.length?" "+r.join(","):"")+". Find the full error at: https://bit.ly/3cXEKWf")}function t(n){return !!n&&!!n[B]}function r(n){return !!n&&(function(n){if(!n||"object"!=typeof n)return !1;var t=Object.getPrototypeOf(n);return !t||t===Object.prototype}(n)||Array.isArray(n)||!!n[q]||!!n.constructor[q]||c(n)||s(n))}function i(n,t){0===o(n)?L(n).forEach((function(r){return t(r,n[r],n)})):n.forEach((function(r,e){return t(e,r,n)}));}function o(n){var t=n[B];return t?t.i>3?t.i-4:t.i:Array.isArray(n)?1:c(n)?2:s(n)?3:0}function u(n,t){return 2===o(n)?n.has(t):Object.prototype.hasOwnProperty.call(n,t)}function a(n,t){return 2===o(n)?n.get(t):n[t]}function f(n,t){return n===t?0!==n||1/n==1/t:n!=n&&t!=t}function c(n){return $&&n instanceof Map}function s(n){return U&&n instanceof Set}function v(n){return n.o||n.t}function p(t,r){if(void 0===r&&(r=!1),Array.isArray(t))return t.slice();var e=Object.create(Object.getPrototypeOf(t));return i(t,(function(i){if(i!==B){var o=Object.getOwnPropertyDescriptor(t,i),u=o.value;o.get&&(r||n(1),u=o.get.call(t)),o.enumerable?e[i]=u:Object.defineProperty(e,i,{value:u,writable:!0,configurable:!0});}})),e}function d(n,e){t(n)||Object.isFrozen(n)||!r(n)||(o(n)>1&&(n.set=n.add=n.clear=n.delete=l),Object.freeze(n),e&&i(n,(function(n,t){return d(t,!0)})));}function l(){n(2);}function h(t){var r=Q[t];return r||n("production"!==process.env.NODE_ENV?18:19,t),r}function m(){return "production"===process.env.NODE_ENV||J||n(0),J}function b(n,t){t&&(h("Patches"),n.u=[],n.s=[],n.v=t);}function _(n){j(n),n.p.forEach(g),n.p=null;}function j(n){n===J&&(J=n.l);}function O(n){return J={p:[],l:J,h:n,m:!0,_:0}}function g(n){var t=n[B];0===t.i||1===t.i?t.j():t.O=!0;}function w(t,e){e._=e.p.length;var i=e.p[0],o=void 0!==t&&t!==i;return e.h.g||h("ES5").S(e,t,o),o?(i[B].P&&(_(e),n(4)),r(t)&&(t=S(e,t),e.l||M(e,t)),e.u&&h("Patches").M(i[B],t,e.u,e.s)):t=S(e,i,[]),_(e),e.u&&e.v(e.u,e.s),t!==X?t:void 0}function S(n,t,r){if(Object.isFrozen(t))return t;var e=t[B];if(!e)return i(t,(function(i,o){return P(n,e,t,i,o,r)})),t;if(e.A!==n)return t;if(!e.P)return M(n,e.t,!0),e.t;if(!e.I){e.I=!0,e.A._--;var o=4===e.i||5===e.i?e.o=p(e.k,!0):e.o;i(o,(function(t,i){return P(n,e,o,t,i,r)})),M(n,o,!1),r&&n.u&&h("Patches").R(e,r,n.u,n.s);}return e.o}function P(e,i,c,s,v,p){if("production"!==process.env.NODE_ENV&&v===c&&n(5),t(v)){var d=S(e,v,p&&i&&3!==i.i&&!u(i.D,s)?p.concat(s):void 0);if(h=s,y=d,2===(m=o(l=c))?l.set(h,y):3===m?(l.delete(h),l.add(y)):l[h]=y,!t(d))return;e.m=!1;}var l,h,y,m;if((!i||!f(v,a(i.t,s)))&&r(v)){if(!e.h.N&&e._<1)return;S(e,v),i&&i.A.l||M(e,v);}}function M(n,t,r){void 0===r&&(r=!1),n.h.N&&n.m&&d(t,r);}function A(n,t){var r=n[B],e=Reflect.getOwnPropertyDescriptor(r?v(r):n,t);return e&&e.value}function z(n){if(!n.P){if(n.P=!0,0===n.i||1===n.i){var t=n.o=p(n.t);i(n.p,(function(n,r){t[n]=r;})),n.p=void 0;}n.l&&z(n.l);}}function x(n){n.o||(n.o=p(n.t));}function I(n,t,r){var e=c(t)?h("MapSet").T(t,r):s(t)?h("MapSet").F(t,r):n.g?function(n,t){var r=Array.isArray(n),e={i:r?1:0,A:t?t.A:m(),P:!1,I:!1,D:{},l:t,t:n,k:null,p:{},o:null,j:null,C:!1},i=e,o=V;r&&(i=[e],o=Y);var u=Proxy.revocable(i,o),a=u.revoke,f=u.proxy;return e.k=f,e.j=a,f}(t,r):h("ES5").J(t,r);return (r?r.A:m()).p.push(e),e}var C,J,K="undefined"!=typeof Symbol,$="undefined"!=typeof Map,U="undefined"!=typeof Set,W="undefined"!=typeof Proxy&&void 0!==Proxy.revocable&&"undefined"!=typeof Reflect,X=K?Symbol("immer-nothing"):((C={})["immer-nothing"]=!0,C),q=K?Symbol("immer-draftable"):"__$immer_draftable",B=K?Symbol("immer-state"):"__$immer_state",H={0:"Illegal state",1:"Immer drafts cannot have computed properties",2:"This object has been frozen and should not be mutated",3:function(n){return "Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? "+n},4:"An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.",5:"Immer forbids circular references",6:"The first or second argument to `produce` must be a function",7:"The third argument to `produce` must be a function or undefined",8:"First argument to `createDraft` must be a plain object, an array, or an immerable object",9:"First argument to `finishDraft` must be a draft returned by `createDraft`",10:"The given draft is already finalized",11:"Object.defineProperty() cannot be used on an Immer draft",12:"Object.setPrototypeOf() cannot be used on an Immer draft",13:"Immer only supports deleting array indices",14:"Immer only supports setting array indices and the 'length' property",15:function(n){return "Cannot apply patch, path doesn't resolve: "+n},16:'Sets cannot have "replace" patches.',17:function(n){return "Unsupported patch operation: "+n},18:function(n){return "The plugin for '"+n+"' has not been loaded into Immer. To enable the plugin, import and call `enable"+n+"()` when initializing your application."},19:"plugin not loaded",20:"Cannot use proxies if Proxy, Proxy.revocable or Reflect are not available"},L="undefined"!=typeof Reflect&&Reflect.ownKeys?Reflect.ownKeys:void 0!==Object.getOwnPropertySymbols?function(n){return Object.getOwnPropertyNames(n).concat(Object.getOwnPropertySymbols(n))}:Object.getOwnPropertyNames,Q={},V={get:function(n,t){if(t===B)return n;var e=n.p;if(!n.P&&u(e,t))return e[t];var i=v(n)[t];if(n.I||!r(i))return i;if(n.P){if(i!==A(n.t,t))return i;e=n.o;}return e[t]=I(n.A.h,i,n)},has:function(n,t){return t in v(n)},ownKeys:function(n){return Reflect.ownKeys(v(n))},set:function(n,t,r){if(!n.P){var e=A(n.t,t);if(r?f(e,r)||r===n.p[t]:f(e,r)&&t in n.t)return !0;x(n),z(n);}return n.D[t]=!0,n.o[t]=r,!0},deleteProperty:function(n,t){return void 0!==A(n.t,t)||t in n.t?(n.D[t]=!1,x(n),z(n)):n.D[t]&&delete n.D[t],n.o&&delete n.o[t],!0},getOwnPropertyDescriptor:function(n,t){var r=v(n),e=Reflect.getOwnPropertyDescriptor(r,t);return e&&(e.writable=!0,e.configurable=1!==n.i||"length"!==t),e},defineProperty:function(){n(11);},getPrototypeOf:function(n){return Object.getPrototypeOf(n.t)},setPrototypeOf:function(){n(12);}},Y={};i(V,(function(n,t){Y[n]=function(){return arguments[0]=arguments[0][0],t.apply(this,arguments)};})),Y.deleteProperty=function(t,r){return "production"!==process.env.NODE_ENV&&isNaN(parseInt(r))&&n(13),V.deleteProperty.call(this,t[0],r)},Y.set=function(t,r,e){return "production"!==process.env.NODE_ENV&&"length"!==r&&isNaN(parseInt(r))&&n(14),V.set.call(this,t[0],r,e,t[0])};var Z=function(){function e(n){this.g=W,this.N="production"!==process.env.NODE_ENV,"boolean"==typeof(null==n?void 0:n.useProxies)&&this.setUseProxies(n.useProxies),"boolean"==typeof(null==n?void 0:n.autoFreeze)&&this.setAutoFreeze(n.autoFreeze),this.produce=this.produce.bind(this),this.produceWithPatches=this.produceWithPatches.bind(this);}var i=e.prototype;return i.produce=function(t,e,i){if("function"==typeof t&&"function"!=typeof e){var o=e;e=t;var u=this;return function(n){var t=this;void 0===n&&(n=o);for(var r=arguments.length,i=Array(r>1?r-1:0),a=1;a<r;a++)i[a-1]=arguments[a];return u.produce(n,(function(n){var r;return (r=e).call.apply(r,[t,n].concat(i))}))}}var a;if("function"!=typeof e&&n(6),void 0!==i&&"function"!=typeof i&&n(7),r(t)){var f=O(this),c=I(this,t,void 0),s=!0;try{a=e(c),s=!1;}finally{s?_(f):j(f);}return "undefined"!=typeof Promise&&a instanceof Promise?a.then((function(n){return b(f,i),w(n,f)}),(function(n){throw _(f),n})):(b(f,i),w(a,f))}if((a=e(t))!==X)return void 0===a&&(a=t),this.N&&d(a,!0),a},i.produceWithPatches=function(n,t){var r,e,i=this;return "function"==typeof n?function(t){for(var r=arguments.length,e=Array(r>1?r-1:0),o=1;o<r;o++)e[o-1]=arguments[o];return i.produceWithPatches(t,(function(t){return n.apply(void 0,[t].concat(e))}))}:[this.produce(n,t,(function(n,t){r=n,e=t;})),r,e]},i.createDraft=function(t){r(t)||n(8);var e=O(this),i=I(this,t,void 0);return i[B].C=!0,j(e),i},i.finishDraft=function(t,r){var e=t&&t[B];"production"!==process.env.NODE_ENV&&(e&&e.C||n(9),e.I&&n(10));var i=e.A;return b(i,r),w(void 0,i)},i.setAutoFreeze=function(n){this.N=n;},i.setUseProxies=function(t){W||n(20),this.g=t;},i.applyPatches=function(n,r){var e;for(e=r.length-1;e>=0;e--){var i=r[e];if(0===i.path.length&&"replace"===i.op){n=i.value;break}}var o=h("Patches").U;return t(n)?o(n,r):this.produce(n,(function(n){return o(n,r.slice(e+1))}))},e}(),nn=new Z,tn=nn.produce,rn=nn.produceWithPatches.bind(nn),en=nn.setAutoFreeze.bind(nn),on=nn.setUseProxies.bind(nn),un=nn.applyPatches.bind(nn),an=nn.createDraft.bind(nn),fn=nn.finishDraft.bind(nn);
var NAMES = "C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B".split(" ");
var names = function (accTypes) {
return typeof accTypes !== "string"
? NAMES.slice()
: NAMES.filter(function (n) {
var acc = n[1] || " ";
return accTypes.indexOf(acc) !== -1;
});
};
var SHARPS = names(" #");
var FLATS = names(" b");
var REGEX = /^([a-gA-G]?)(#{1,}|b{1,}|x{1,}|)(-?\d*)\s*(.*)$/;
function tokenize(str) {
if (typeof str !== "string")
str = "";
var m = REGEX.exec(str);
return [m[1].toUpperCase(), m[2].replace(/x/g, "##"), m[3], m[4]];
}
var NO_NOTE = Object.freeze({
pc: null,
name: null,
step: null,
alt: null,
oct: null,
octStr: null,
chroma: null,
midi: null,
freq: null
});
var SEMI = [0, 2, 4, 5, 7, 9, 11];
var properties = function (str) {
var tokens = tokenize(str);
if (tokens[0] === "" || tokens[3] !== "")
return NO_NOTE;
var letter = tokens[0], acc = tokens[1], octStr = tokens[2];
var p = {
letter: letter,
acc: acc,
octStr: octStr,
pc: letter + acc,
name: letter + acc + octStr,
step: (letter.charCodeAt(0) + 3) % 7,
alt: acc[0] === "b" ? -acc.length : acc.length,
oct: octStr.length ? +octStr : null,
chroma: 0,
midi: null,
freq: null
};
p.chroma = (SEMI[p.step] + p.alt + 120) % 12;
p.midi = p.oct !== null ? SEMI[p.step] + p.alt + 12 * (p.oct + 1) : null;
p.freq = midiToFreq(p.midi);
return Object.freeze(p);
};
var memo = function (fn, cache) {
if (cache === void 0) { cache = {}; }
return function (str) { return cache[str] || (cache[str] = fn(str)); };
};
var props = memo(properties);
var pc = function (str) { return props(str).pc; };
var midiToFreq = function (midi, tuning) {
if (tuning === void 0) { tuning = 440; }
return typeof midi === "number" ? Math.pow(2, (midi - 69) / 12) * tuning : null;
};
var chroma = function (str) { return props(str).chroma; };
var LETTERS = "CDEFGAB";
var stepToLetter = function (step) { return LETTERS[step]; };
var fillStr = function (s, n) { return Array(n + 1).join(s); };
var numToStr = function (num, op) {
return typeof num !== "number" ? "" : op(num);
};
var altToAcc = function (alt) {
return numToStr(alt, function (alt) { return (alt < 0 ? fillStr("b", -alt) : fillStr("#", alt)); });
};
var from = function (fromProps, baseNote) {
if (fromProps === void 0) { fromProps = {}; }
if (baseNote === void 0) { baseNote = null; }
var _a = baseNote
? Object.assign({}, props(baseNote), fromProps)
: fromProps, step = _a.step, alt = _a.alt, oct = _a.oct;
if (typeof step !== "number")
return null;
var letter = stepToLetter(step);
if (!letter)
return null;
var pc = letter + altToAcc(alt);
return oct || oct === 0 ? pc + oct : pc;
};
var build = from;
function fromMidi(num, sharps) {
if (sharps === void 0) { sharps = false; }
num = Math.round(num);
var pcs = sharps === true ? SHARPS : FLATS;
var pc = pcs[num % 12];
var o = Math.floor(num / 12) - 1;
return pc + o;
}
var simplify = function (note, sameAcc) {
if (sameAcc === void 0) { sameAcc = true; }
var _a = props(note), alt = _a.alt, chroma = _a.chroma, midi = _a.midi;
if (chroma === null)
return null;
var alteration = alt;
var useSharps = sameAcc === false ? alteration < 0 : alteration > 0;
return midi === null
? pc(fromMidi(chroma, useSharps))
: fromMidi(midi, useSharps);
};
var IVL_TNL = "([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})";
var IVL_STR = "(AA|A|P|M|m|d|dd)([-+]?\\d+)";
var REGEX$1 = new RegExp("^" + IVL_TNL + "|" + IVL_STR + "$");
var SIZES = [0, 2, 4, 5, 7, 9, 11];
var TYPES = "PMMPPMM";
var CLASSES = [0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1];
var tokenize$1 = function (str) {
var m = REGEX$1.exec("" + str);
if (m === null)
return null;
return (m[1] ? [m[1], m[2]] : [m[4], m[3]]);
};
var NO_IVL = Object.freeze({
name: null,
num: null,
q: null,
step: null,
alt: null,
dir: null,
type: null,
simple: null,
semitones: null,
chroma: null,
oct: null
});
var fillStr$1 = function (s, n) { return Array(Math.abs(n) + 1).join(s); };
var qToAlt = function (type, q) {
if (q === "M" && type === "M")
return 0;
if (q === "P" && type === "P")
return 0;
if (q === "m" && type === "M")
return -1;
if (/^A+$/.test(q))
return q.length;
if (/^d+$/.test(q))
return type === "P" ? -q.length : -q.length - 1;
return null;
};
var altToQ = function (type, alt) {
if (alt === 0)
return type === "M" ? "M" : "P";
else if (alt === -1 && type === "M")
return "m";
else if (alt > 0)
return fillStr$1("A", alt);
else if (alt < 0)
return fillStr$1("d", type === "P" ? alt : alt + 1);
else
return null;
};
var numToStep = function (num) { return (Math.abs(num) - 1) % 7; };
var properties$1 = function (str) {
var t = tokenize$1(str);
if (t === null)
return NO_IVL;
var p = {
num: 0,
q: "d",
name: "",
type: "M",
step: 0,
dir: -1,
simple: 1,
alt: 0,
oct: 0,
semitones: 0,
chroma: 0,
ic: 0
};
p.num = +t[0];
p.q = t[1];
p.step = numToStep(p.num);
p.type = TYPES[p.step];
if (p.type === "M" && p.q === "P")
return NO_IVL;
p.name = "" + p.num + p.q;
p.dir = p.num < 0 ? -1 : 1;
p.simple = (p.num === 8 || p.num === -8
? p.num
: p.dir * (p.step + 1));
p.alt = qToAlt(p.type, p.q);
p.oct = Math.floor((Math.abs(p.num) - 1) / 7);
p.semitones = p.dir * (SIZES[p.step] + p.alt + 12 * p.oct);
p.chroma = ((((p.dir * (SIZES[p.step] + p.alt)) % 12) + 12) %
12);
return Object.freeze(p);
};
var cache = {};
function props$1(str) {
if (typeof str !== "string")
return NO_IVL;
return cache[str] || (cache[str] = properties$1(str));
}
var chroma$1 = function (str) { return props$1(str).chroma; };
var ic = function (ivl) {
if (typeof ivl === "string")
ivl = props$1(ivl).chroma;
return typeof ivl === "number" ? CLASSES[ivl % 12] : null;
};
var build$1 = function (_a) {
var _b = _a === void 0 ? {} : _a, num = _b.num, step = _b.step, alt = _b.alt, _c = _b.oct, oct = _c === void 0 ? 1 : _c, dir = _b.dir;
if (step !== undefined)
num = step + 1 + 7 * oct;
if (num === undefined)
return null;
if (typeof alt !== "number")
return null;
var d = typeof dir !== "number" ? "" : dir < 0 ? "-" : "";
var type = TYPES[numToStep(num)];
return (d + num + altToQ(type, alt));
};
var simplify$1 = function (str) {
var p = props$1(str);
if (p === NO_IVL)
return null;
var intervalProps = p;
return intervalProps.simple + intervalProps.q;
};
var IN = [1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7];
var IQ = "P m M m M P d P m M m M".split(" ");
var fromSemitones = function (num) {
var d = num < 0 ? -1 : 1;
var n = Math.abs(num);
var c = n % 12;
var o = Math.floor(n / 12);
return d * (IN[c] + 7 * o) + IQ[c];
};
/**
* [](https://www.npmjs.com/package/tonal-distance)
* [](https://github.com/danigb/tonal/tree/master/packages/tonal/distance)
*
* Transpose notes by intervals and find distances between notes
*
* @example
* // es6
* import * as Distance from "tonal-distance"
* Distance.interval("C3", "C4") // => "1P"
*
* @example
* // es6 import selected functions
* import { interval, semitones, transpose } from "tonal-distance"
*
* semitones("C" ,"D") // => 2
* interval("C4", "G4") // => "5P"
* transpose("C4", "P5") // => "G4"
*
* @example
* // included in tonal facade
* const Tonal = require("tonal");
* Tonal.Distance.transpose("C4", "P5")
* Tonal.Distance.transposeBy("P5", "C4")
*
* @module Distance
*/
// Map from letter step to number of fifths starting from "C":
// { C: 0, D: 2, E: 4, F: -1, G: 1, A: 3, B: 5 }
var FIFTHS = [0, 2, 4, -1, 1, 3, 5];
// Given a number of fifths, return the octaves they span
var fOcts = function (f) { return Math.floor((f * 7) / 12); };
// Get the number of octaves it span each step
var FIFTH_OCTS = FIFTHS.map(fOcts);
var encode = function (ref) {
var step = ref.step;
var alt = ref.alt;
var oct = ref.oct;
var dir = ref.dir; if ( dir === void 0 ) dir = 1;
var f = FIFTHS[step] + 7 * alt;
if (oct === null) { return [dir * f]; }
var o = oct - FIFTH_OCTS[step] - 4 * alt;
return [dir * f, dir * o];
};
// We need to get the steps from fifths
// Fifths for CDEFGAB are [ 0, 2, 4, -1, 1, 3, 5 ]
// We add 1 to fifths to avoid negative numbers, so:
// for ["F", "C", "G", "D", "A", "E", "B"] we have:
var STEPS = [3, 0, 4, 1, 5, 2, 6];
// Return the number of fifths as if it were unaltered
function unaltered(f) {
var i = (f + 1) % 7;
return i < 0 ? 7 + i : i;
}
var decode = function (f, o, dir) {
var step = STEPS[unaltered(f)];
var alt = Math.floor((f + 1) / 7);
if (o === undefined) { return { step: step, alt: alt, dir: dir }; }
var oct = o + 4 * alt + FIFTH_OCTS[step];
return { step: step, alt: alt, oct: oct, dir: dir };
};
var memo$1 = function (fn, cache) {
if ( cache === void 0 ) cache = {};
return function (str) { return cache[str] || (cache[str] = fn(str)); };
};
var encoder = function (props) { return memo$1(function (str) {
var p = props(str);
return p.name === null ? null : encode(p);
}); };
var encodeNote = encoder(props);
var encodeIvl = encoder(props$1);
/**
* Transpose a note by an interval. The note can be a pitch class.
*
* This function can be partially applied.
*
* @param {string} note
* @param {string} interval
* @return {string} the transposed note
* @example
* import { tranpose } from "tonal-distance"
* transpose("d3", "3M") // => "F#3"
* // it works with pitch classes
* transpose("D", "3M") // => "F#"
* // can be partially applied
* ["C", "D", "E", "F", "G"].map(transpose("M3)) // => ["E", "F#", "G#", "A", "B"]
*/
function transpose(note, interval) {
if (arguments.length === 1) { return function (i) { return transpose(note, i); }; }
var n = encodeNote(note);
var i = encodeIvl(interval);
if (n === null || i === null) { return null; }
var tr = n.length === 1 ? [n[0] + i[0]] : [n[0] + i[0], n[1] + i[1]];
return build(decode(tr[0], tr[1]));
}
var isDescending = function (e) { return e[0] * 7 + e[1] * 12 < 0; };
var decodeIvl = function (i) { return isDescending(i) ? decode(-i[0], -i[1], -1) : decode(i[0], i[1], 1); };
/**
* Find the interval between two pitches. It works with pitch classes
* (both must be pitch classes and the interval is always ascending)
*
* Can be partially applied
*
* @param {string} from - distance from
* @param {string} to - distance to
* @return {string} the interval distance
*
* @example
* import { interval } from "tonal-distance"
* interval("C2", "C3") // => "P8"
* interval("G", "B") // => "M3"
*
* @example
* import * as Distance from "tonal-distance"
* Distance.interval("M2", "P5") // => "P4"
*/
function interval(from, to) {
if (arguments.length === 1) { return function (t) { return interval(from, t); }; }
var f = encodeNote(from);
var t = encodeNote(to);
if (f === null || t === null || f.length !== t.length) { return null; }
var d =
f.length === 1
? [t[0] - f[0], -Math.floor(((t[0] - f[0]) * 7) / 12)]
: [t[0] - f[0], t[1] - f[1]];
return build$1(decodeIvl(d));
}
/**
* Get the distance between two notes in semitones
*
* @param {String|Pitch} from - first note
* @param {String|Pitch} to - last note
* @return {Integer} the distance in semitones or null if not valid notes
* @example
* import { semitones } from "tonal-distance"
* semitones("C3", "A2") // => -3
* // or use tonal
* Tonal.Distance.semitones("C3", "G3") // => 7
*/
function semitones(from, to) {
if (arguments.length === 1) { return function (t) { return semitones(from, t); }; }
var f = props(from);
var t = props(to);
return f.midi !== null && t.midi !== null
? t.midi - f.midi
: f.chroma !== null && t.chroma !== null
? (t.chroma - f.chroma + 12) % 12
: null;
}
var chromatic = [
"1P 2m 2M 3m 3M 4P 4A 5P 6m 6M 7m 7M"
];
var lydian = [
"1P 2M 3M 4A 5P 6M 7M"
];
var major = [
"1P 2M 3M 4P 5P 6M 7M",
[
"ionian"
]
];
var mixolydian = [
"1P 2M 3M 4P 5P 6M 7m",
[
"dominant"
]
];
var dorian = [
"1P 2M 3m 4P 5P 6M 7m"
];
var aeolian = [
"1P 2M 3m 4P 5P 6m 7m",
[
"minor"
]
];
var phrygian = [
"1P 2m 3m 4P 5P 6m 7m"
];
var locrian = [
"1P 2m 3m 4P 5d 6m 7m"
];
var altered = [
"1P 2m 3m 3M 5d 6m 7m",
[
"super locrian",
"diminished whole tone",
"pomeroy"
]
];
var diminished = [
"1P 2M 3m 4P 5d 6m 6M 7M",
[
"whole-half diminished"
]
];
var iwato = [
"1P 2m 4P 5d 7m"
];
var hirajoshi = [
"1P 2M 3m 5P 6m"
];
var kumoijoshi = [
"1P 2m 4P 5P 6m"
];
var pelog = [
"1P 2m 3m 5P 6m"
];
var prometheus = [
"1P 2M 3M 4A 6M 7m"
];
var ritusen = [
"1P 2M 4P 5P 6M"
];
var scriabin = [
"1P 2m 3M 5P 6M"
];
var piongio = [
"1P 2M 4P 5P 6M 7m"
];
var augmented = [
"1P 2A 3M 5P 5A 7M"
];
var neopolitan = [
"1P 2m 3m 4P 5P 6m 7M"
];
var egyptian = [
"1P 2M 4P 5P 7m"
];
var oriental = [
"1P 2m 3M 4P 5d 6M 7m"
];
var flamenco = [
"1P 2m 3m 3M 4A 5P 7m"
];
var balinese = [
"1P 2m 3m 4P 5P 6m 7M"
];
var persian = [
"1P 2m 3M 4P 5d 6m 7M"
];
var bebop = [
"1P 2M 3M 4P 5P 6M 7m 7M"
];
var enigmatic = [
"1P 2m 3M 5d 6m 7m 7M"
];
var ichikosucho = [
"1P 2M 3M 4P 5d 5P 6M 7M"
];
var sdata = {
chromatic: chromatic,
lydian: lydian,
major: major,
mixolydian: mixolydian,
dorian: dorian,
aeolian: aeolian,
phrygian: phrygian,
locrian: locrian,
"melodic minor": [
"1P 2M 3m 4P 5P 6M 7M"
],
"melodic minor second mode": [
"1P 2m 3m 4P 5P 6M 7m"
],
"lydian augmented": [
"1P 2M 3M 4A 5A 6M 7M"
],
"lydian dominant": [
"1P 2M 3M 4A 5P 6M 7m",
[
"lydian b7"
]
],
"melodic minor fifth mode": [
"1P 2M 3M 4P 5P 6m 7m",
[
"hindu",
"mixolydian b6M"
]
],
"locrian #2": [
"1P 2M 3m 4P 5d 6m 7m",
[
"half-diminished"
]
],
altered: altered,
"harmonic minor": [
"1P 2M 3m 4P 5P 6m 7M"
],
"phrygian dominant": [
"1P 2m 3M 4P 5P 6m 7m",
[
"spanish",
"phrygian major"
]
],
"half-whole diminished": [
"1P 2m 3m 3M 4A 5P 6M 7m",
[
"dominant diminished"
]
],
diminished: diminished,
"major pentatonic": [
"1P 2M 3M 5P 6M",
[
"pentatonic"
]
],
"lydian pentatonic": [
"1P 3M 4A 5P 7M",
[
"chinese"
]
],
"mixolydian pentatonic": [
"1P 3M 4P 5P 7m",
[
"indian"
]
],
"locrian pentatonic": [
"1P 3m 4P 5d 7m",
[
"minor seven flat five pentatonic"
]
],
"minor pentatonic": [
"1P 3m 4P 5P 7m"
],
"minor six pentatonic": [
"1P 3m 4P 5P 6M"
],
"minor hexatonic": [
"1P 2M 3m 4P 5P 7M"
],
"flat three pentatonic": [
"1P 2M 3m 5P 6M",
[
"kumoi"
]
],
"flat six pentatonic": [
"1P 2M 3M 5P 6m"
],
"major flat two pentatonic": [
"1P 2m 3M 5P 6M"
],
"whole tone pentatonic": [
"1P 3M 5d 6m 7m"
],
"ionian pentatonic": [
"1P 3M 4P 5P 7M"
],
"lydian #5P pentatonic": [
"1P 3M 4A 5A 7M"
],
"lydian dominant pentatonic": [
"1P 3M 4A 5P 7m"
],
"minor #7M pentatonic": [
"1P 3m 4P 5P 7M"
],
"super locrian pentatonic": [
"1P 3m 4d 5d 7m"
],
"in-sen": [
"1P 2m 4P 5P 7m"
],
iwato: iwato,
hirajoshi: hirajoshi,
kumoijoshi: kumoijoshi,
pelog: pelog,
"vietnamese 1": [
"1P 3m 4P 5P 6m"
],
"vietnamese 2": [
"1P 3m 4P 5P 7m"
],
prometheus: prometheus,
"prometheus neopolitan": [
"1P 2m 3M 4A 6M 7m"
],
ritusen: ritusen,
scriabin: scriabin,
piongio: piongio,
"major blues": [
"1P 2M 3m 3M 5P 6M"
],
"minor blues": [
"1P 3m 4P 5d 5P 7m",
[
"blues"
]
],
"composite blues": [
"1P 2M 3m 3M 4P 5d 5P 6M 7m"
],
augmented: augmented,
"augmented heptatonic": [
"1P 2A 3M 4P 5P 5A 7M"
],
"dorian #4": [
"1P 2M 3m 4A 5P 6M 7m"
],
"lydian diminished": [
"1P 2M 3m 4A 5P 6M 7M"
],
"whole tone": [
"1P 2M 3M 4A 5A 7m"
],
"leading whole tone": [
"1P 2M 3M 4A 5A 7m 7M"
],
"lydian minor": [
"1P 2M 3M 4A 5P 6m 7m"
],
"locrian major": [
"1P 2M 3M 4P 5d 6m 7m",
[
"arabian"
]
],
neopolitan: neopolitan,
"neopolitan minor": [
"1P 2m 3m 4P 5P 6m 7M"
],
"neopolitan major": [
"1P 2m 3m 4P 5P 6M 7M",
[
"dorian b2"
]
],
"neopolitan major pentatonic": [
"1P 3M 4P 5d 7m"
],
"romanian minor": [
"1P 2M 3m 5d 5P 6M 7m"
],
"double harmonic lydian": [
"1P 2m 3M 4A 5P 6m 7M"
],
"harmonic major": [
"1P 2M 3M 4P 5P 6m 7M"
],
"double harmonic major": [
"1P 2m 3M 4P 5P 6m 7M",
[
"gypsy"
]
],
egyptian: egyptian,
"hungarian minor": [
"1P 2M 3m 4A 5P 6m 7M"
],
"hungarian major": [
"1P 2A 3M 4A 5P 6M 7m"
],
oriental: oriental,
"spanish heptatonic": [
"1P 2m 3m 3M 4P 5P 6m 7m"
],
flamenco: flamenco,
balinese: balinese,
"todi raga": [
"1P 2m 3m 4A 5P 6m 7M"
],
"malkos raga": [
"1P 3m 4P 6m 7m"
],
"kafi raga": [
"1P 3m 3M 4P 5P 6M 7m 7M"
],
"purvi raga": [
"1P 2m 3M 4P 4A 5P 6m 7M"
],
persian: persian,
bebop: bebop,
"bebop dominant": [
"1P 2M 3M 4P 5P 6M 7m 7M"
],
"bebop minor": [
"1P 2M 3m 3M 4P 5P 6M 7m"
],
"bebop major": [
"1P 2M 3M 4P 5P 5A 6M 7M"
],
"bebop locrian": [
"1P 2m 3m 4P 5d 5P 6m 7m"
],
"minor bebop": [
"1P 2M 3m 4P 5P 6m 7m 7M"
],
"mystery #1": [
"1P 2m 3M 5d 6m 7m"
],
enigmatic: enigmatic,
"minor six diminished": [
"1P 2M 3m 4P 5P 6m 6M 7M"
],
"ionian augmented": [
"1P 2M 3M 4P 5A 6M 7M"
],
"lydian #9": [
"1P 2m 3M 4A 5P 6M 7M"
],
ichikosucho: ichikosucho,
"six tone symmetric": [
"1P 2m 3M 4P 5A 6M"
]
};
var M$1 = [
"1P 3M 5P",
[
"Major",
""
]
];
var M13 = [
"1P 3M 5P 7M 9M 13M",
[
"maj13",
"Maj13"
]
];
var M6 = [
"1P 3M 5P 13M",
[
"6"
]
];
var M69 = [
"1P 3M 5P 6M 9M",
[
"69"
]
];
var M7add13 = [
"1P 3M 5P 6M 7M 9M"
];
var M7b5 = [
"1P 3M 5d 7M"
];
var M7b6 = [
"1P 3M 6m 7M"
];
var M7b9 = [
"1P 3M 5P 7M 9m"
];
var M7sus4 = [
"1P 4P 5P 7M"
];
var M9 = [
"1P 3M 5P 7M 9M",
[
"maj9",
"Maj9"
]
];
var M9b5 = [
"1P 3M 5d 7M 9M"
];
var M9sus4 = [
"1P 4P 5P 7M 9M"
];
var Madd9 = [
"1P 3M 5P 9M",
[
"2",
"add9",
"add2"
]
];
var Maj7 = [
"1P 3M 5P 7M",
[
"maj7",
"M7"
]
];
var Mb5 = [
"1P 3M 5d"
];
var Mb6 = [
"1P 3M 13m"
];
var Msus2 = [
"1P 2M 5P",
[
"add9no3",
"sus2"
]
];
var Msus4 = [
"1P 4P 5P",
[
"sus",
"sus4"
]
];
var Maddb9 = [
"1P 3M 5P 9m"
];
var m$1 = [
"1P 3m 5P"
];
var m11 = [
"1P 3m 5P 7m 9M 11P",
[
"_11"
]
];
var m11b5 = [
"1P 3m 7m 12d 2M 4P",
[
"h11",
"_11b5"
]
];
var m13 = [
"1P 3m 5P 7m 9M 11P 13M",
[
"_13"
]
];
var m6 = [
"1P 3m 4P 5P 13M",
[
"_6"
]
];
var m69 = [
"1P 3m 5P 6M 9M",
[
"_69"
]
];
var m7 = [
"1P 3m 5P 7m",
[
"minor7",
"_",
"_7"
]
];
var m7add11 = [
"1P 3m 5P 7m 11P",
[
"m7add4"
]
];
var m7b5 = [
"1P 3m 5d 7m",
[
"half-diminished",
"h7",
"_7b5"
]
];
var m9 = [
"1P 3m 5P 7m 9M",
[
"_9"
]
];
var m9b5 = [
"1P 3m 7m 12d 2M",
[
"h9",
"-9b5"
]
];
var mMaj7 = [
"1P 3m 5P 7M",
[
"mM7",
"_M7"
]
];
var mMaj7b6 = [
"1P 3m 5P 6m 7M",
[
"mM7b6"
]
];
var mM9 = [
"1P 3m 5P 7M 9M",
[
"mMaj9",
"-M9"
]
];
var mM9b6 = [
"1P 3m 5P 6m 7M 9M",
[
"mMaj9b6"
]
];
var mb6M7 = [
"1P 3m 6m 7M"
];
var mb6b9 = [
"1P 3m 6m 9m"
];
var o$1 = [
"1P 3m 5d",
[
"mb5",
"dim"
]
];
var o7 = [
"1P 3m 5d 13M",
[
"diminished",
"m6b5",
"dim7"
]
];
var o7M7 = [
"1P 3m 5d 6M 7M"
];
var oM7 = [
"1P 3m 5d 7M"
];
var sus24 = [
"1P 2M 4P 5P",
[
"sus4add9"
]
];
var madd4 = [
"1P 3m 4P 5P"
];
var madd9 = [
"1P 3m 5P 9M"
];
var cdata = {
"4": [
"1P 4P 7m 10m",
[
"quartal"
]
],
"5": [
"1P 5P"
],
"7": [
"1P 3M 5P 7m",
[
"Dominant",
"Dom"
]
],
"9": [
"1P 3M 5P 7m 9M",
[
"79"
]
],
"11": [
"1P 5P 7m 9M 11P"
],
"13": [
"1P 3M 5P 7m 9M 13M",
[
"13_"
]
],
"64": [
"5P 8P 10M"
],
M: M$1,
"M#5": [
"1P 3M 5A",
[
"augmented",
"maj#5",
"Maj#5",
"+",
"aug"
]
],
"M#5add9": [
"1P 3M 5A 9M",
[
"+add9"
]
],
M13: M13,
"M13#11": [
"1P 3M 5P 7M 9M 11A 13M",
[
"maj13#11",
"Maj13#11",
"M13+4",
"M13#4"
]
],
M6: M6,
"M6#11": [
"1P 3M 5P 6M 11A",
[
"M6b5",
"6#11",
"6b5"
]
],
M69: M69,
"M69#11": [
"1P 3M 5P 6M 9M 11A"
],
"M7#11": [
"1P 3M 5P 7M 11A",
[
"maj7#11",
"Maj7#11",
"M7+4",
"M7#4"
]
],
"M7#5": [
"1P 3M 5A 7M",
[
"maj7#5",
"Maj7#5",
"maj9#5",
"M7+"
]
],
"M7#5sus4": [
"1P 4P 5A 7M"
],
"M7#9#11": [
"1P 3M 5P 7M 9A 11A"
],
M7add13: M7add13,
M7b5: M7b5,
M7b6: M7b6,
M7b9: M7b9,
M7sus4: M7sus4,
M9: M9,
"M9#11": [
"1P 3M 5P 7M 9M 11A",
[
"maj9#11",
"Maj9#11",
"M9+4",
"M9#4"
]
],
"M9#5": [
"1P 3M 5A 7M 9M",
[
"Maj9#5"
]
],
"M9#5sus4": [
"1P 4P 5A 7M 9M"
],
M9b5: M9b5,
M9sus4: M9sus4,
Madd9: Madd9,
Maj7: Maj7,
Mb5: Mb5,
Mb6: Mb6,
Msus2: Msus2,
Msus4: Msus4,
Maddb9: Maddb9,
"11b9": [
"1P 5P 7m 9m 11P"
],
"13#11": [
"1P 3M 5P 7m 9M 11A 13M",
[
"13+4",
"13#4"
]
],
"13#9": [
"1P 3M 5P 7m 9A 13M",
[
"13#9_"
]
],
"13#9#11": [
"1P 3M 5P 7m 9A 11A 13M"
],
"13b5": [
"1P 3M 5d 6M 7m 9M"
],
"13b9": [
"1P 3M 5P 7m 9m 13M"
],
"13b9#11": [
"1P 3M 5P 7m 9m 11A 13M"
],
"13no5": [
"1P 3M 7m 9M 13M"
],
"13sus4": [
"1P 4P 5P 7m 9M 13M",
[
"13sus"
]
],
"69#11": [
"1P 3M 5P 6M 9M 11A"
],
"7#11": [
"1P 3M 5P 7m 11A",
[
"7+4",
"7#4",
"7#11_",
"7#4_"
]
],
"7#11b13": [
"1P 3M 5P 7m 11A 13m",
[
"7b5b13"
]
],
"7#5": [
"1P 3M 5A 7m",
[
"+7",
"7aug",
"aug7"
]
],
"7#5#9": [
"1P 3M 5A 7m 9A",
[
"7alt",
"7#5#9_",
"7#9b13_"
]
],
"7#5b9": [
"1P 3M 5A 7m 9m"
],
"7#5b9#11": [
"1P 3M 5A 7m 9m 11A"
],
"7#5sus4": [
"1P 4P 5A 7m"
],
"7#9": [
"1P 3M 5P 7m 9A",
[
"7#9_"
]
],
"7#9#11": [
"1P 3M 5P 7m 9A 11A",
[
"7b5#9"
]
],
"7#9#11b13": [
"1P 3M 5P 7m 9A 11A 13m"
],
"7#9b13": [
"1P 3M 5P 7m 9A 13m"
],
"7add6": [
"1P 3M 5P 7m 13M",
[
"67",
"7add13"
]
],
"7b13": [
"1P 3M 7m 13m"
],
"7b5": [
"1P 3M 5d 7m"
],
"7b6": [
"1P 3M 5P 6m 7m"
],
"7b9": [
"1P 3M 5P 7m 9m"
],
"7b9#11": [
"1P 3M 5P 7m 9m 11A",
[
"7b5b9"
]
],
"7b9#9": [
"1P 3M 5P 7m 9m 9A"
],
"7b9b13": [
"1P 3M 5P 7m 9m 13m"
],
"7b9b13#11": [
"1P 3M 5P 7m 9m 11A 13m",
[
"7b9#11b13",
"7b5b9b13"
]
],
"7no5": [
"1P 3M 7m"
],
"7sus4": [
"1P 4P 5P 7m",
[
"7sus"
]
],
"7sus4b9": [
"1P 4P 5P 7m 9m",
[
"susb9",
"7susb9",
"7b9sus",
"7b9sus4",
"phryg"
]
],
"7sus4b9b13": [
"1P 4P 5P 7m 9m 13m",
[
"7b9b13sus4"
]
],
"9#11": [
"1P 3M 5P 7m 9M 11A",
[
"9+4",
"9#4",
"9#11_",
"9#4_"
]
],
"9#11b13": [
"1P 3M 5P 7m 9M 11A 13m",
[
"9b5b13"
]
],
"9#5": [
"1P 3M 5A 7m 9M",
[
"9+"
]
],
"9#5#11": [
"1P 3M 5A 7m 9M 11A"
],
"9b13": [
"1P 3M 7m 9M 13m"
],
"9b5": [
"1P 3M 5d 7m 9M"
],
"9no5": [
"1P 3M 7m 9M"
],
"9sus4": [
"1P 4P 5P 7m 9M",
[
"9sus"
]
],
m: m$1,
"m#5": [
"1P 3m 5A",
[
"m+",
"mb6"
]
],
m11: m11,
"m11A 5": [
"1P 3m 6m 7m 9M 11P"
],
m11b5: m11b5,
m13: m13,
m6: m6,
m69: m69,
m7: m7,
"m7#5": [
"1P 3m 6m 7m"
],
m7add11: m7add11,
m7b5: m7b5,
m9: m9,
"m9#5": [
"1P 3m 6m 7m 9M"
],
m9b5: m9b5,
mMaj7: mMaj7,
mMaj7b6: mMaj7b6,
mM9: mM9,
mM9b6: mM9b6,
mb6M7: mb6M7,
mb6b9: mb6b9,
o: o$1,
o7: o7,
o7M7: o7M7,
oM7: oM7,
sus24: sus24,
"+add#9": [
"1P 3M 5A 9A"
],
madd4: madd4,
madd9: madd9
};
/**
* [](https://www.npmjs.com/package/tonal-pcset)
* [](https://www.npmjs.com/browse/keyword/tonal)
*
* `tonal-pcset` is a collection of functions to work with pitch class sets, oriented
* to make comparations (isEqual, isSubset, isSuperset)
*
* This is part of [tonal](https://www.npmjs.com/package/tonal) music theory library.
*
* You can install via npm: `npm i --save tonal-pcset`
*
* ```js
* // es6
* import PcSet from "tonal-pcset"
* var PcSet = require("tonal-pcset")
*
* PcSet.isEqual("c2 d5 e6", "c6 e3 d1") // => true
* ```
*
* ## API documentation
*
* @module PcSet
*/
var chr = function (str) { return chroma(str) || chroma$1(str) || 0; };
/**
* Get chroma of a pitch class set. A chroma identifies each set uniquely.
* It"s a 12-digit binary each presenting one semitone of the octave.
*
* Note that this function accepts a chroma as parameter and return it
* without modification.
*
* @param {Array|String} set - the pitch class set
* @return {string} a binary representation of the pitch class set
* @example
* PcSet.chroma(["C", "D", "E"]) // => "1010100000000"
*/
function chroma$2(set) {
if (isChroma(set)) { return set; }
if (!Array.isArray(set)) { return ""; }
var b = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
set.map(chr).forEach(function (i) {
b[i] = 1;
});
return b.join("");
}
var REGEX$2 = /^[01]{12}$/;
/**
* Test if the given string is a pitch class set chroma.
* @param {string} chroma - the pitch class set chroma
* @return {Boolean} true if its a valid pcset chroma
* @example
* PcSet.isChroma("101010101010") // => true
* PcSet.isChroma("101001") // => false
*/
function isChroma(set) {
return REGEX$2.test(set);
}
/**
* [](https://www.npmjs.com/package/tonal-dictionary)
*
* `tonal-dictionary` contains a dictionary of musical scales and chords
*
* This is part of [tonal](https://www.npmjs.com/package/tonal) music theory library.
*
* @example
* // es6
* import * as Dictionary from "tonal-dictionary"
* // es5
* const Dictionary = require("tonal-dictionary")
*
* @example
* Dictionary.chord("Maj7") // => ["1P", "3M", "5P", "7M"]
*
* @module Dictionary
*/
var dictionary = function (raw) {
var keys = Object.keys(raw).sort();
var data = [];
var index = [];
var add = function (name, ivls, chroma) {
data[name] = ivls;
index[chroma] = index[chroma] || [];
index[chroma].push(name);
};
keys.forEach(function (key) {
var ivls = raw[key][0].split(" ");
var alias = raw[key][1];
var chr = chroma$2(ivls);
add(key, ivls, chr);
if (alias) { alias.forEach(function (a) { return add(a, ivls, chr); }); }
});
var allKeys = Object.keys(data).sort();
var dict = function (name) { return data[name]; };
dict.names = function (p) {
if (typeof p === "string") { return (index[p] || []).slice(); }
else { return (p === true ? allKeys : keys).slice(); }
};
return dict;
};
/**
* A dictionary of scales: a function that given a scale name (without tonic)
* returns an array of intervals
*
* @function
* @param {string} name
* @return {Array} intervals
* @example
* import { scale } from "tonal-dictionary"
* scale("major") // => ["1P", "2M", ...]
* scale.names(); // => ["major", ...]
*/
var scale = dictionary(sdata);
/**
* A dictionary of chords: a function that given a chord type
* returns an array of intervals
*
* @function
* @param {string} type
* @return {Array} intervals
* @example
* import { chord } from "tonal-dictionary"
* chord("Maj7") // => ["1P", "3M", ...]
* chord.names(); // => ["Maj3", ...]
*/
var chord = dictionary(cdata);
/**
* [](https://www.npmjs.com/package/tonal-scale)
*
* A scale is a collection of pitches in ascending or descending order.
*
* This module provides functions to get and manipulate scales.
*
* @example
* // es6
* import * as Scale from "tonal-scale"
* // es5
* const Scale = require("tonal-scale");
*
* @example
* Scale.notes("Ab bebop") // => [ "Ab", "Bb", "C", "Db", "Eb", "F", "Gb", "G" ]
* Scale.names() => ["major", "minor", ...]
* @module Scale
*/
var NO_SCALE = Object.freeze({
name: null,
intervals: [],
names: [],
chroma: null,
setnum: null
});
/**
* [](https://www.npmjs.com/package/tonal-chord)
* [](https://www.npmjs.com/browse/keyword/tonal)
*
* `tonal-chord` is a collection of functions to manipulate musical chords
*
* This is part of [tonal](https://www.npmjs.com/package/tonal) music theory library.
*
* @example
* // es6
* import * as Chord from "tonal-chord"
* // es5
* const Chord = require("tonal-chord")
*
* @example
* Chord.notes("CMaj7") // => ["C", "E", "G", "B"]
*
* @module Chord
*/
var NO_CHORD = Object.freeze({
name: null,
names: [],
intervals: [],
chroma: null,
setnum: null
});
/**
* [ 'E2', 'A2', 'D3', 'G3', 'B3', 'E4' ] --> [ '1P', '4P', '4P', '4P', '3M', '4P' ]
*
* @param tuning
* @returns {ReadonlyArray<any>}
*/
function computeTuningIntervals(tuning) {
if (tuning === void 0) { tuning = Tuning.guitar.standard; }
var tuningIntervals = Array(tuning.length).fill(null);
for (var i = 0; i < tuning.length; i++) {
// const d = Distance.interval("C2", "C3");
var d = interval(tuning[(i - 1 + tuning.length) % tuning.length], tuning[i]);
// console.log("computeTuningIntervals d", d);
if (typeof d !== "string") { // because Distance.interval can return a function
throw new Error("unexpected error");
}
var simple = simplify$1(d);
tuningIntervals[i] = simple === '-1P' ? '1P' : simple;