UNPKG

cxchord

Version:
1,414 lines (1,398 loc) 1.24 MB
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BayesChordCalculator = void 0; var CxChart_1 = require("./CxChart"); var _ = require("lodash"); var BayesChordCalculator = /** @class */function () { function BayesChordCalculator(bayesChordMap) { this.bayesChordMap = bayesChordMap; this.self = this; this.hypothesis = []; this.rules = []; this.likelyhoods = []; this.normalizingConst = []; this.posterior = []; this.chartsCount = 0; this.randomColorFactor = function () { return Math.round(Math.random() * 255); }; this.createHypothesis(); } // // create an even distribution // BayesChordCalculator.prototype.createHypothesis = function () { var idx = 0; var _self = this.self; for (var key in this.bayesChordMap) { for (var inv = 0; inv < this.bayesChordMap[key].length; inv++) { _self.hypothesis.push({ idx: idx++, key: key, inv: inv, group: this.bayesChordMap[key][inv].group, len: this.bayesChordMap[key][inv].notes.length, root: this.bayesChordMap[key][inv].root }); } } }; BayesChordCalculator.prototype.getChordMapNotes = function (idx) { return this.bayesChordMap[this.hypothesis[idx].key][this.hypothesis[idx].inv].notes; }; BayesChordCalculator.prototype.standardDeriviation = function (data) { var sum = _.sum(data); var avg = sum / data.length; var squaredDiffs = _.map(data, function (value) { var diff = value - avg; return diff * diff; }); var avgSquaredDiff = _.sum(squaredDiffs) / squaredDiffs.length; var stdDev = Math.sqrt(avgSquaredDiff); return stdDev; }; // // Apply a Rule to the Hypothesis // BayesChordCalculator.prototype.applyRule = function (rule) { var _self = this.self; var row = this.likelyhoods.length; var firstRow = row == 0; var normalizingConst = 0; this.rules.push(rule); if (_.isUndefined(this.likelyhoods[row])) this.likelyhoods[row] = []; for (var col = 0; col < this.hypothesis.length; col++) { var likelyhood = rule.ruleFx(rule.chord, _self, row, col); this.likelyhoods[row].push(likelyhood); var prior = firstRow ? 1 : this.posterior[row - 1][col].post; normalizingConst += prior * likelyhood; } this.likelyhoods[row].push(normalizingConst); this.calcPosterior(row); }; BayesChordCalculator.prototype.calcPosterior = function (_row) { for (var row = _row < 0 ? 0 : _row; row < this.likelyhoods.length; row++) { var firstRow = row == 0; var colIdx = this.likelyhoods[row].length - 1; var normalizingConst = this.likelyhoods[row][colIdx]; if (_.isUndefined(this.posterior[row])) this.posterior[row] = []; for (var col = 0; col < this.hypothesis.length; col++) { var prior = firstRow ? 1 : this.posterior[row - 1][col].post; var likelyhood = this.likelyhoods[row][col]; var posterior = prior * likelyhood / (firstRow ? 1 : normalizingConst); this.posterior[row].push({ post: posterior, idx: col }); } } }; BayesChordCalculator.prototype.getPosteriorByRow = function (rowIdx) { if (rowIdx < 0 || rowIdx >= this.posterior.length || _.isUndefined(this.posterior[rowIdx])) throw Error("getPosteriorByRow index: " + rowIdx + " is out of range or undefined"); // this.posterior[rowIdx][col].rootName = CxChord.getRootName(this.posterior[rowIdx][col].idx) for (var col = 0; col < this.hypothesis.length; col++) { this.posterior[rowIdx][col].hypo = this.hypothesis[col]; } return _.orderBy(this.posterior[rowIdx], ['post', 'hypo.len', 'hypo.inv'], 'desc'); }; BayesChordCalculator.prototype.getPosterior = function () { var lastRow = this.posterior.length - 1; if (lastRow < 0) return [];else return this.getPosteriorByRow(lastRow); }; BayesChordCalculator.prototype.getHypothesis = function (posterior) { return this.hypothesis[posterior.idx]; }; BayesChordCalculator.prototype.getHypothesisByIdx = function (idx) { if (idx < 0 || idx >= this.hypothesis.length) throw Error("getHypothesisByIdx index: " + idx + " is out of range"); return this.hypothesis[idx]; }; BayesChordCalculator.prototype.getBestPosterior = function (idx) { if (idx === void 0) { idx = 0; } var res = this.getPosterior(); if (idx < 0 || idx >= res.length) throw Error("getBestPosterior index: " + idx + " is out of range"); return res[idx]; }; BayesChordCalculator.prototype.normalize = function (posterior) { var postArr = []; _.forEach(posterior, function (val) { postArr.push(val.post); }); var sum = _.sum(postArr); var checkSum = 0; for (var i = 0; i < postArr.length; i++) { posterior[i].post = postArr[i] / sum; checkSum += posterior[i].post; } // console.log( "checkSum: " + checkSum ) }; BayesChordCalculator.prototype.getTopX = function (topX, row, normalize) { if (topX === void 0) { topX = 10; } if (row === void 0) { row = this.posterior.length - 1; } if (normalize === void 0) { normalize = true; } var posterior = this.getPosteriorByRow(row); var postTopX = _.take(posterior, topX); if (normalize) { this.normalize(postTopX); } return postTopX; }; // Returns a random integer between min (included) and max (included) // Using Math.round() will give you a non-uniform distribution! BayesChordCalculator.prototype.getRandomIntInclusive = function (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }; BayesChordCalculator.prototype.visualizeTopX = function (_title, chord, topX) { if (topX === void 0) { topX = 10; } var labels = []; var posteriorLastRow = this.getTopX(topX); for (var i = 0; i < posteriorLastRow.length; i++) { var hypo = this.getHypothesis(posteriorLastRow[i]); var label = chord.getRootName(hypo) + hypo.key + "_i" + hypo.inv; // + chord.getBassName(hypo) labels.push(label); } var bayesChart = new CxChart_1.BayesChart('visualization', labels); for (var dataSet = 1; dataSet < this.posterior.length; dataSet++) { var data = []; for (var i = 0; i < posteriorLastRow.length; i++) { var idx = posteriorLastRow[i].idx; var post = this.posterior[dataSet][idx].post; data.push(post); } var randomColor = this.randomColorFactor() + ',' + this.randomColorFactor() + ',' + this.randomColorFactor(); bayesChart.addDataSet(this.rules[dataSet].rule, randomColor, data); } bayesChart.showChart(); }; BayesChordCalculator.prototype.visualizeForm = function (form, chord) { // var container = new BayesChart('visualization') // document.getElementById('visualization'); var labels = []; var posteriorLastRow = this.getPosterior(); var lastRow = _.filter(posteriorLastRow, function (p) { return p.hypo.key == form; }); var bestMatch = this.getBestPosterior(); var bestHypo = this.getHypothesis(bestMatch); var bestLabel = chord.getRootName(bestHypo) + bestHypo.key + "_i" + bestHypo.inv; labels.push(bestLabel); for (var i = 0; i < lastRow.length; i++) { var hypo = this.getHypothesis(lastRow[i]); var label = chord.getRootName(hypo) + hypo.key + "_i" + hypo.inv; // + chord.getBassName(hypo) labels.push(label); } var bayesChart = new CxChart_1.BayesChart('visualization', labels); for (var dataSet = 1; dataSet < this.posterior.length; dataSet++) { var data = []; var bestIdx = bestMatch.idx; var bestPost = this.posterior[dataSet][bestIdx].post; data.push(bestPost); for (var i = 0; i < lastRow.length; i++) { var idx = lastRow[i].idx; var post = this.posterior[dataSet][idx].post; data.push(post); } var randomColor = this.randomColorFactor() + ',' + this.randomColorFactor() + ',' + this.randomColorFactor(); bayesChart.addDataSet(this.rules[dataSet].rule, randomColor, data); } bayesChart.showChart(); }; return BayesChordCalculator; }(); exports.BayesChordCalculator = BayesChordCalculator; },{"./CxChart":2,"lodash":10}],2:[function(require,module,exports){ "use strict"; var __extends = this && this.__extends || function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; } || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; }(); Object.defineProperty(exports, "__esModule", { value: true }); exports.BayesChart = exports.BarDataSet = void 0; ///<reference types="../node_modules/@types/chart.js/index.d.ts" /> var chart_js_1 = require("chart.js"); var BarDataSet = /** @class */function () { function BarDataSet(labels) { this.labels = labels; this._options = { scales: { xAxes: [{ // categorySpacing: 1 // barPercentage: 0.5 }], yAxes: [{ type: "linear", display: true, position: "left", id: "y-axis-1" // ticks: { // beginAtZero: true // } }] }, responsive: true, legend: { display: true, position: 'top' }, title: { display: true, text: 'Top Hypothesis' } }; this._options2 = { scaleBeginAtZero: true, scaleShowGridLines: true, scaleGridLineColor: "rgba(0,0,0,.05)", scaleGridLineWidth: 1, barShowStroke: true, barStrokeWidth: 2, barValueSpacing: 5, barDatasetSpacing: 1, legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].lineColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>" }; this.barData = { labels: [], datasets: [] }; this.setLabels(labels); this.barData.labels = labels; } BarDataSet.prototype.componentToHex = function (c) { var num = parseInt(c); var hex = num.toString(16); return hex.length == 1 ? "0" + hex : hex; }; BarDataSet.prototype.rgbToHex = function (rgb) { var _a = rgb.split(','), red = _a[0], green = _a[1], blue = _a[2]; return "#" + this.componentToHex(red) + this.componentToHex(green) + this.componentToHex(blue); }; BarDataSet.prototype.setLabels = function (labels) { this.labels = labels; }; BarDataSet.prototype.addDataSet = function (label, rgb, data) { var len = data.length; var bgColors = []; for (var i = 0; i < len; i++) { bgColors.push(this.rgbToHex(rgb)); } this.barData.datasets.push({ label: label, backgroundColor: bgColors, borderColor: bgColors, // hoverBackgroundColor: bgColors, // fillColor: "rgba(" + rgb + ",0.5)", // strokeColor: "rgba(" + rgb + ",0.8)", // highlightFill: "rgba(" + rgb + ",0.75)", // highlightStroke: "rgba(" + rgb + ",1)", // pointBorderWidth: 1.5, // tension: -1, // yAxisID: "y-axis-1", data: data }); // console.debug(JSON.stringify(this.barData.datasets[this.barData.datasets.length -1])) }; return BarDataSet; }(); exports.BarDataSet = BarDataSet; var BayesChart = /** @class */function (_super) { __extends(BayesChart, _super); function BayesChart(htmlElement, labels) { if (htmlElement === void 0) { htmlElement = 'visualization'; } if (labels === void 0) { labels = []; } var _this = _super.call(this, labels) || this; try { document.getElementById(htmlElement).innerHTML = '&nbsp;'; _this.canvas = document.getElementById(htmlElement); _this.ctx = _this.canvas.getContext('2d'); } catch (e) { console.warn("\nBayesChart: No Visualization HtmlElement " + htmlElement + " found (OK if not in a browser)."); } return _this; } BayesChart.prototype.showChart = function () { try { var conf = {}; this.barChart = new chart_js_1.Chart(this.ctx, { type: 'bar', data: this.barData, options: this._options }); document.getElementById('legend').innerHTML = this.barChart.generateLegend(); } catch (e) { console.warn("\nBayesChart.showChart: Failed to show Chart element (OK if not in a browser)."); } }; return BayesChart; }(BarDataSet); exports.BayesChart = BayesChart; },{"chart.js":9}],3:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChordInstance = void 0; var CxForms_1 = require("./CxForms"); // import * as CxForms from "./CxForms" var _ = require("lodash"); var ChordInstance = /** @class */function () { function ChordInstance(midiChord, normalizeChord) { if (normalizeChord === void 0) { normalizeChord = true; } this.midiChord = midiChord; this.normalizeChord = normalizeChord; this.offset = []; this.chordInv = []; this.matchedNotes = {}; this.favorJazzChords = false; this.validate(midiChord); for (var i = 0; i < midiChord.length; i++) { this.offset.push(midiChord[i]); } this.chordInv = this.invert(midiChord); } ChordInstance.prototype.addOffset = function (chord, offset) { var res = []; for (var i = 0; i < chord.length; i++) { res.push(chord[i] + offset); } return res; }; ChordInstance.prototype.addRootOffset = function (chord, root) { var offset = (root < 0 ? 12 + root : root) % 12; return this.normalize(this.addOffset(chord, offset)); }; ChordInstance.prototype.getOffset = function (inv) { if (inv < 0 || inv >= this.offset.length) throw Error("getRootOffset inversion is out of range");else return this.offset[inv]; }; ChordInstance.prototype.getBassName = function (_hypo, sharpOrFlat) { if (sharpOrFlat === void 0) { sharpOrFlat = 'flat'; } var bass = this.offset[0] % 12; var bassName = CxForms_1.rootNoteNames[sharpOrFlat][bass]; return bassName; }; ChordInstance.prototype.getBassNumber = function () { return this.offset[0]; }; ChordInstance.prototype.getRootName = function (hypo, sharpOrFlat) { if (sharpOrFlat === void 0) { sharpOrFlat = 'flat'; } var _offset = (this.offset[0] + hypo.root) % 12; // var octave = Math.floor( ( this.offset[hypo.inv] + hypo.root ) / 12 ) var root = _offset < 0 ? _offset + 12 : _offset; var rootName = CxForms_1.rootNoteNames[sharpOrFlat][root]; return rootName; }; ChordInstance.prototype.getInversion = function (inv) { return _.isUndefined(this.chordInv[inv]) ? [] : this.chordInv[inv]; }; ChordInstance.prototype.validate = function (notes) { if (notes.length == 0) { throw Error("No notes in notes array"); } for (var i = 0; i < notes.length; i++) { if (notes[i] < 0 || notes[i] > 127) { throw Error("Illegal midi note value:" + notes[i]); } } }; ChordInstance.prototype.normalize = function (notes) { var target = []; try { var offset = notes[0]; for (var i = 0; i < notes.length; i++) { var note = notes[i] - offset; while (note > 21) note -= 12; // if ( note == 16 || note == 19 ) { // note -= 12 // } target[i] = note; } } catch (e) { throw Error(e); } return target; }; ChordInstance.prototype.invert = function (notes) { if (notes.length < 2) throw Error("Cannot invert less than 2 notes"); var target = []; target[0] = this.normalizeChord ? this.normalize(notes) : notes; this.offset[0] = notes[0]; for (var d = 1; d < notes.length; d++) { var currNotes = _.drop(target[d - 1]); var invNote = _.head(target[d - 1]); invNote += 12; currNotes.push(invNote); target[d] = this.normalizeChord ? this.normalize(currNotes) : currNotes; } if (target.length < notes.length) throw Error("Bad invertion"); return target; }; return ChordInstance; }(); exports.ChordInstance = ChordInstance; },{"./CxForms":5,"lodash":10}],4:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var cxchord_1 = require("./cxchord"); var _ = require("lodash"); // jasmine.getEnv().addReporter(new jasmine.ConsoleReporter(console.log)); describe('Testing CxChord', function () { var midiChord = [2, 6, 9, 13]; var chordInst = new cxchord_1.ChordInstance(midiChord); it('ChordInst reads and inverts a chord', function () { expect(chordInst.chordInv.length).toEqual(4); expect(chordInst.chordInv[0][0]).toEqual(0); expect(chordInst.chordInv[0][1]).toEqual(4); expect(chordInst.chordInv[0][2]).toEqual(7); expect(chordInst.chordInv[0][3]).toEqual(11); // expect(chordInst.chordInv[1].length).toEqual(4); expect(chordInst.chordInv[1][0]).toEqual(0); expect(chordInst.chordInv[1][1]).toEqual(3); expect(chordInst.chordInv[1][2]).toEqual(7); expect(chordInst.chordInv[1][3]).toEqual(8); // expect(chordInst.chordInv[2].length).toEqual(4); expect(chordInst.chordInv[2][0]).toEqual(0); expect(chordInst.chordInv[2][1]).toEqual(4); expect(chordInst.chordInv[2][2]).toEqual(5); expect(chordInst.chordInv[2][3]).toEqual(9); midiChord = [60, 67, 74, 78, 81]; chordInst = new cxchord_1.ChordInstance(midiChord); expect(chordInst.chordInv.length).toEqual(5); expect(chordInst.chordInv[0][0]).toEqual(0); expect(chordInst.chordInv[0][1]).toEqual(7); expect(chordInst.chordInv[0][2]).toEqual(14); expect(chordInst.chordInv[0][3]).toEqual(18); expect(chordInst.chordInv[0][4]).toEqual(21); }); it('ChordMatcher.doMatch can do a full match', function () { midiChord = [60, 64, 67, 71]; chordInst = new cxchord_1.ChordInstance(midiChord); expect(chordInst.chordInv.length).toEqual(4); expect(chordInst.chordInv[0][0]).toEqual(0); expect(chordInst.chordInv[0][1]).toEqual(4); expect(chordInst.chordInv[0][2]).toEqual(7); expect(chordInst.chordInv[0][3]).toEqual(11); var cm = new cxchord_1.ChordMatcher(); var chordInst2 = cm.doMatch(chordInst); expect(chordInst2).toBeDefined(); expect(chordInst2.matchedNotes).toBeDefined(); expect(_.keys(chordInst2.matchedNotes).length > 0); _.forIn(chordInst2.matchedNotes, function (value, key) { if (key == "maj,7") { expect(value.invertions[0].length).toEqual(4); } else { expect(value.invertions[0].length > 0).toBeTruthy(); } }); }); it('ChordMatcher.doMatch can do a partial match with chord extensions', function () { midiChord = [60, 67, 71, 74]; chordInst = new cxchord_1.ChordInstance(midiChord); expect(chordInst.chordInv.length).toEqual(4); expect(chordInst.chordInv[0][0]).toEqual(0); expect(chordInst.chordInv[0][1]).toEqual(7); expect(chordInst.chordInv[0][2]).toEqual(11); expect(chordInst.chordInv[0][3]).toEqual(14); var cm = new cxchord_1.ChordMatcher(); var chordInst2 = cm.doMatch(chordInst); expect(chordInst2).toBeDefined(); _.forIn(chordInst2.matchedNotes, function (value, key) { // console.log("Partial Matched:" + key + "(" + value.invertions[0].length + ")") expect(value.invertions[0].length > 0 && value.invertions[0].length < 5).toBeTruthy(); if (key == "maj,7") { expect(value.invertions[0].length).toEqual(3); expect(value.extensions[0].length).toEqual(1); expect(value.extensions[0][0]).toEqual(14); } }); }); it('ChordMatcher.doMatch can do multiple extensions', function () { midiChord = [60, 71, 74, 78, 81]; chordInst = new cxchord_1.ChordInstance(midiChord); var cm = new cxchord_1.ChordMatcher(); var chordInst2 = cm.doMatch(chordInst); expect(chordInst2).toBeDefined(); _.forIn(chordInst2.matchedNotes, function (value, key) { if (key == "maj,7") { expect(value.invertions[0].length).toEqual(2); expect(value.extensions[0].length).toEqual(3); expect(value.extensions[0][0]).toEqual(14); expect(value.extensions[0][1]).toEqual(18); expect(value.extensions[0][2]).toEqual(21); } }); }); it('getChordName can return correct names', function () { expect((0, cxchord_1.getChordName)("Maj,7")).toEqual("CMaj7"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13")).toEqual("CMaj79#1113"); expect((0, cxchord_1.getChordName)("Min,7,9,11,-1")).toEqual("CMin7911-no-root"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", 0, 7)).toEqual("CMaj79#1113/G"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", 0, -5)).toEqual("CMaj79#1113/G"); // expect((0, cxchord_1.getChordName)("Maj,7", 2)).toEqual("DMaj7"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", 2)).toEqual("DMaj79#1113"); expect((0, cxchord_1.getChordName)("Min,7,9,11,-1", 2)).toEqual("DMin7911-no-root"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", 2, 9)).toEqual("DMaj79#1113/A"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", 2, -3)).toEqual("DMaj79#1113/A"); // expect((0, cxchord_1.getChordName)("Maj,7", -1)).toEqual("BMaj7"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", -1)).toEqual("BMaj79#1113"); expect((0, cxchord_1.getChordName)("Min,7,9,11,-1", -1)).toEqual("BMin7911-no-root"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", -1, 6)).toEqual("BMaj79#1113/Gb"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", -1, -6)).toEqual("BMaj79#1113/Gb"); // expect((0, cxchord_1.getChordName)("Maj,7", -13)).toEqual("BMaj7"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", -13)).toEqual("BMaj79#1113"); expect((0, cxchord_1.getChordName)("Min,7,9,11,-1", -13)).toEqual("BMin7911-no-root"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", -13, 6)).toEqual("BMaj79#1113/Gb"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", -13, -6)).toEqual("BMaj79#1113/Gb"); expect((0, cxchord_1.getChordName)("Maj,7", -2, -2, "sharp")).toEqual("A#Maj7"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", -2, -2, "flat")).toEqual("BbMaj79#1113"); expect((0, cxchord_1.getChordName)("Min,7,9,11,-1", -2, -2, "sharp")).toEqual("A#Min7911-no-root"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", -1, 6, "sharp")).toEqual("BMaj79#1113/F#"); expect((0, cxchord_1.getChordName)("Maj,7,9,#11,13", -2, -7, "flat")).toEqual("BbMaj79#1113/F"); }); it('ChordMatcher moves a root correctly', function () { var cm = new cxchord_1.ChordMatcher(); // [0, 4, 5, 9] var inv0 = cm.chordMapWithInv["Min,7,9,-1(B)"][0]; expect(inv0.root).toEqual(-10); // var root = cm.addRootOffset() var inv1 = cm.chordMapWithInv["Min,7,9,-1(B)"][1]; expect(inv1.inv).toEqual(1); expect(inv1.root).toEqual(-2); var inv2 = cm.chordMapWithInv["Min,7,9,-1(B)"][2]; expect(inv2.inv).toEqual(2); expect(inv2.root).toEqual(-3); var inv2 = cm.chordMapWithInv["Min,7,9,-1(B)"][3]; expect(inv2.inv).toEqual(3); expect(inv2.root).toEqual(-7); }); it('ChordMatcher moves a negative root correctly', function () { // midiChord = [60, 64, 67, 70 ] var cm = new cxchord_1.ChordMatcher(); // [0, 4, 5, 9] var inv0 = cm.chordMapWithInv["Maj,6,9,-1(A)"][0]; expect(inv0.inv).toEqual(0); expect(inv0.root).toEqual(-4); var newChord = cm.addRootOffset(inv0.notes, inv0.root); var inv1 = cm.chordMapWithInv["Min,7,9,-1(B)"][1]; expect(inv1.inv).toEqual(1); expect(inv1.root).toEqual(-2); }); it('ChordMatcher can match a C chord', function () { midiChord = [60, 64, 67]; // var chord : ChordInstance = new ChordInstance(midiChord) var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var psr = cm.getPosterior(); expect(psr).toBeDefined(); expect(psr.length).toBeGreaterThan(0); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Maj'); }); it('ChordMatcher can match full major chords', function () { var midiChord = [60, 64, 67, 71, 74, 78, 81]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); // console.log( JSON.stringify( cm.bayes.getTopTeen(), null, 2 ) ) expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj79#1113'); midiChord = [60, 64, 67, 71, 74, 78]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj79#11'); midiChord = [60, 64, 67, 71, 74]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj79'); midiChord = [60, 64, 67, 69, 74]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj69'); midiChord = [60, 64, 67, 69]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); // expect(getExtName(p0.hypo.key)).toEqual('Maj6') // TODO - should be Maj6 }); it('ChordMatcher can match partial major chords', function () { var midiChord = [60, 64, 71, 74, 78, 81]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj79#1113'); midiChord = [60, 64, 71, 74, 78]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj79#11'); midiChord = [60, 64, 71, 74]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj79'); midiChord = [60, 64, 69, 74]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj69'); midiChord = [60, 64, 69]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); // expect(getExtName(p0.hypo.key)).toEqual('Maj6') // TODO - should be Maj6 in the right context // console.log( JSON.stringify( cm.bayes.getTopTeen(2), null, 2 ) ) }); it('ChordMatcher can match inverted major chords', function () { var midiChord = [64, 67, 71, 72, 74, 78, 81]; var cm = new cxchord_1.ChordMatcher(); var chord = cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj79#1113'); midiChord = [67, 71, 72, 74, 76, 78, 81]; cm = new cxchord_1.ChordMatcher(); chord = cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); // var res: Posterior[] = cm.bayes.getTopX() expect((0, cxchord_1.getExtName)(p0.hypo.key)).toEqual('Maj79#1113'); var midiChord = [67, 71, 72, 74, 76, 78, 81]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Maj,7,9,#11,13'); // console.log( JSON.stringify( cm.bayes.getTopTeen(), null, 2 ) ) midiChord = [60, 64, 67, 71, 74, 78]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Maj,7,9,#11'); midiChord = [60, 64, 67, 71, 74]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Maj,7,9'); midiChord = [60, 64, 67, 69, 74]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Maj,6,9'); midiChord = [60, 64, 67, 69]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Maj,6'); }); it('Standard Deriviation Works', function () { var midiChord = [60, 64, 67, 69]; var cm = new cxchord_1.ChordMatcher(); var chord = cm.match(midiChord); // var p0 = cm.bayes.getBestMatch() var stdDev = cm.bayes.standardDeriviation([1, 2, 3, 4, 5, 6, 7, 8, 9, 25]); // Standard Deviation: 6.48074069840786 expect(stdDev).toEqual(6.48074069840786); }); it('CxChord getNoteNumber works as expected', function () { expect((0, cxchord_1.getNoteNumber)("C")).toEqual(60); expect((0, cxchord_1.getNoteNumber)("C6")).toEqual(72); expect((0, cxchord_1.getNoteNumber)("C#7")).toEqual(85); expect((0, cxchord_1.getNoteNumber)("db7")).toEqual(85); expect((0, cxchord_1.getNoteNumber)("g10")).toEqual(127); try { (0, cxchord_1.getNoteNumber)("g11"); } catch (e) { expect(e).toEqual("getNoteNumber: Illegal octave number. Legal octaves are 0-10"); } }); it('ChordMatcher can match Minor chords', function () { midiChord = [60, 63, 67]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Min'); midiChord = [60, 63, 67, 70]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Min,7'); // cm.bayes.visualizeTopX("Match -> Min,7", cm.getChord(), 20) midiChord = [60, 63, 67, 69]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Min,6'); midiChord = [60, 63, 67, 69, 74]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Min,6,9'); }); it('ChordMatcher can match a Dominant Chords chord', function () { midiChord = [60, 64, 67, 70]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7'); midiChord = [64, 67, 70, 72]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7'); midiChord = [67, 70, 72, 76]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7'); midiChord = [60, 64, 67, 70, 74]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,9'); midiChord = [64, 67, 70, 72, 74]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,9'); midiChord = [67, 70, 72, 74, 76]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,9'); // cm.bayes.visualizeTopX("Match", cm.getChord(), 20) }); it('ChordMatcher can match no fifth Dominant Chords chord', function () { midiChord = [60, 64, 70]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7'); midiChord = [64, 70, 72]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7'); midiChord = [70, 72, 76]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7'); midiChord = [60, 64, 70, 74]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,9'); midiChord = [64, 70, 72, 74]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,9'); midiChord = [70, 72, 74, 76]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,9'); }); it('ChordMatcher can match sus chords', function () { midiChord = [60, 65, 67]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Sus4'); midiChord = [60, 62, 67]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Sus2'); midiChord = [60, 65, 67, 71]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Sus4'); midiChord = [60, 62, 67, 71]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Sus2'); midiChord = [60, 65, 70]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Sus2'); midiChord = [67, 72, 74]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Sus4'); midiChord = [60, 65, 67, 70]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,sus4'); midiChord = [60, 62, 67, 70]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,sus2'); }); it('ChordMatcher can match diminished chords', function () { midiChord = [60, 63, 66]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dim'); midiChord = [60, 63, 66, 69]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dim,7'); midiChord = [60, 63, 66, 69, 71]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dim,7(WH)'); }); it('ChordMatcher can match a C5 chord', function () { midiChord = [60, 67]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('5'); midiChord = [55, 60, 67]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('5'); midiChord = [55, 60, 67, 72]; var cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('5'); }); it('ChordMatcher can match major jazz block chords', function () { midiChord = [64, 67, 69, 74]; // Cmaj,7,9,-1 var cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); // cm.bayes.visualizeTopX("Match", cm.getChord(), 20) expect(p0.hypo.key).toEqual("Maj,6,9,-1(A)"); midiChord = [67, 69, 74, 76]; cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual("Maj,6,9,-1(A)"); }); it('ChordMatcher can match minor jazz block chords', function () { var midiChord = [63, 67, 69, 74]; // This one has an invariant dominant chord version var cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual("Min,6,9,-1(A)"); // invariant of "Min,6,9,-1(A)" midiChord = [63, 67, 70, 74]; cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); // cm.bayes.visualizeTopX("Match", cm.getChord(), 10) expect(p0.hypo.key).toEqual("Min,7,9,-1(A)"); midiChord = [60, 64, 65, 69]; var cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual("Min,7,9,-1(B)"); midiChord = [60, 64, 65, 69]; var cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual("Min,7,9,-1(B)"); midiChord = [60, 62, 65, 68]; var cm = new cxchord_1.ChordMatcher(); // cm.favorJazz(true) cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual("Min,6"); p0 = cm.bayes.getBestPosterior(1); expect(p0.hypo.key).toEqual('Min,7,b5'); midiChord = [60, 62, 65, 68]; var cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); // cm.bayes.visualizeForm('Min,7,9,-1(A)', cm.getChord()) // p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual("Min,6"); // p0 = cm.bayes.getBestMatch(1) // expect(p0.hypo.key).toEqual('Min,7,b5' ) }); it('A single ChordMatcher can match Jazz Dominant chords', function () { var midiChord = [17, 21, 23, 28]; var cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(1); // pick the dominant version rather than the min 6,6 invariant // cm.bayes.visualizeTopX("Match", cm.getChord(), 15) // cm.bayes.visualizeForm('Dom,7,9,-1(A)', cm.getChord()) expect(p0.hypo.key).toEqual('Dom,7,9,-1(A)'); midiChord = [21, 23, 28, 29]; cm.match(midiChord); p0 = cm.bayes.getBestPosterior(1); // pick the dominant version rather than the min6 invariant expect(p0.hypo.key == 'Dom,7,9,-1(A)' || p0.hypo.key == 'Min,6,9,-1(A)').toBeTruthy(); midiChord = [23, 28, 29, 33]; cm.favorJazz(true); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,9,-1(B)'); midiChord = [28, 29, 33, 35]; cm.favorJazz(true); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual('Dom,7,9,-1(B)'); }); it('ChordMatcher can deliver a multi-chord result', function () { var midiChord = [21, 23, 28, 29]; var cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); var res = cm.getMatches(); expect(res[0].type).toEqual('Min,6,9,-1(A)'); expect(res[1].type).toEqual('Dom,7,9,-1(A)'); }); it('ChordMatcher can match Reduced -5 chords', function () { var midiChord = [60, 64, 71]; var cm = new cxchord_1.ChordMatcher(); // cm.favorJazz( true ) cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual("Maj,7,-5"); midiChord = [60, 64, 69]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual("Maj,6,-5"); midiChord = [60, 63, 69]; cm = new cxchord_1.ChordMatcher('Min,6,-5'); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); cm.bayes.visualizeTopX("Match", cm.getChord(), 15); // cm.bayes.visualizeForm("Maj,7,-5", cm.getChord()) expect(p0.hypo.key).toEqual("Min,6,-5"); midiChord = [60, 63, 70]; cm = new cxchord_1.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); expect(p0.hypo.key).toEqual("Min,7,-5"); }); it('ChordMatcher can match chords given with tone Names', function () { // var midiChord = [17, 21, 23, 28 ] var midiChord = ["F1", "A1", "b1", "e2"]; var cm = new cxchord_1.ChordMatcher(); cm.favorJazz(true); cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(1); // pick the dominant version rather than the min 6,6 invariant // cm.bayes.visualizeTopX("Match", cm.getChord(), 15) // cm.bayes.visualizeForm('Dom,7,9,-1(A)', cm.getChord()) expect(p0.hypo.key).toEqual('Dom,7,9,-1(A)'); var midiChord = ["F", "A", "b", "e6"]; cm.favorJazz(true); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(1); // pick the dominant version rather than the min 6,6 invariant // cm.bayes.visualizeTopX("Match", cm.getChord(), 15) // cm.bayes.visualizeForm('Dom,7,9,-1(A)', cm.getChord()) expect(p0.hypo.key).toEqual('Dom,7,9,-1(A)'); }); it('ChordMatcher can match multiple chords with a single match instance', function () { var cm = new cxchord_1.ChordMatcher(); var midiChord = [17, 21, 23, 28]; for (var i = 0; i < 400; i++) { for (var d = 0; d < midiChord.length; d++) { midiChord[d] = Math.round(Math.random() * 127); } cm.match(midiChord); var p0 = cm.bayes.getBestPosterior(1); expect(p0.hypo.key).toBeDefined(); } }); }); },{"./cxchord":8,"lodash":10}],5:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChordForms = exports.knockouts = exports.conflicts = exports.mustHave = exports.extensions = exports.chordMap = exports.GR = exports.getKnockouts = exports.isNoRootChord = exports.getChordName = exports.getExtName = exports.getNoteName = exports.getNoteNumber = exports.noteNames = exports.rootNoteNames = void 0; var CxChordInst_1 = require("./CxChordInst"); var _ = require("lodash"); // exports.rootNoteNames = { sharp: ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"], flat: ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"] }; exports.noteNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "c", "c#", "d", "d#", "e", "f", "f#", "g", "g#", "a", "a#", "b", "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B", "c", "db", "d", "eb", "e", "f", "gb", "g", "ab", "a", "bb", "b"]; function getNoteNumber(note) { var octave = 5; var _oct = note.replace(/^[A-Ga-g]+[#b]*/, ''); if (!_.isEmpty(_oct)) { var _octave = _oct.replace(/[^0-9]+/g, ''); if (_octave.match(/^[0-9]0{0,1}/)) octave = parseInt(_octave);else throw Error("getNoteNumber: Illegal octave number. Legal octaves are 0-10"); } var noteName = note.replace(/[0-9]/g, ''); var noteNum = exports.noteNames.indexOf(noteName) % 12; if (noteNum < 0) throw Error("getNoteNumber: Unknown note name");else return noteNum + octave * 12; } exports.getNoteNumber = getNoteNumber; function getNoteName(note, flatOrSharp) { if (note === void 0) { note = 0; } if (flatOrSharp === void 0) { flatOrSharp = "flat"; } // For positive bass notes assume an actual bass has been provided // For negative bass notes assume that a ChorMap type root note has been provided note = note % 12; var noteName = exports.rootNoteNames[flatOrSharp][Math.abs(note < 0 ? note + 12 : note) % 12]; return noteName; } exports.getNoteName = getNoteName; function getExtName(nameWithCommas) { var extName = nameWithCommas.replace(/,/g, "").replace(/-1/g, "-no-root").replace(/-5/g, "-no-fifth"); return extName; } exports.getExtName = getExtName; function getChordName(nameWithCommas, root, bass, flatOrSharp) { if (root === void 0) { root = 0; } if (bass === void 0) { bass = 255; } if (flatOrSharp === void 0) { flatOrSharp = "flat"; } var chordName = getNoteName(root, flatOrSharp); var extName = getExtName(nameWithCommas); chordName += extName; // console.debug("chordName(1):'" + chordName + "'") var group = _.isUndefined(exports.chordMap[nameWithCommas]) ? 2 : exports.chordMap[nameWithCommas].group; bass = bass == 255 ? root : bass; if (bass !== root && group != GR.rootLess) { var bassName = getNoteName(bass, flatOrSharp); chordName += "/" + bassName; } return chordName; } exports.getChordName = getChordName; function isNoRootChord(chordSym) { return _.isUndefined(chordSym) ? false : chordSym.indexOf("-1") > 0; } exports.isNoRootChord = isNoRootChord; function getKnockouts(key) { var _key = key; if (_.isUndefined(exports.knockouts[_key])) { _key = _key.split(',')[0]; } return _.isUndefined(exports.knockouts[_key]) ? [] : exports.knockouts[_key]; } exports.getKnockouts = getKnockouts; var GR; (function (GR) { GR[GR["shell"] = 1] = "shell"; GR[GR["standard"] = 2] = "standard"; GR[GR["altered"] = 4] = "altered"; GR[GR["extented"] = 8] = "extented"; GR[GR["rootLess"] = 16] = "rootLess"; GR[GR["reduced"] = 32] = "reduced"; GR[GR["cluster"] = 64] = "cluster"; GR[GR["passing"] = 128] = "passing"; })(GR || (exports.GR = GR = {})); exports.chordMap = { "Maj": { notes: [0, 4, 7], root: 0, inv: 0, group: GR.standard }, "Maj,7": { notes: [0, 4, 7, 11], root: 0, inv: 0, group: GR.standard }, "Maj,7,9": { notes: [0, 4, 7, 11, 14], root: 0, inv: 0, group: GR.extented }, "Maj,7,9,#11": { notes: [0, 4, 7, 11, 14, 18], root: 0, inv: 0, group: GR.extented }, "Maj,7,9,#11,13": { notes: [0, 4, 7, 11, 14, 18, 21], root: 0, inv: 0, group: GR.extented }, "Maj,6": { notes: [0, 4, 7, 9], root: 0, inv: 0, group: GR.standard }, "Maj,6,9": { notes: [0, 4, 7, 9, 14], root: 0, inv: 0, group: GR.extented }, "Maj,add2": { notes: [0, 2, 4, 7], root: 0, inv: 0, group: GR.cluster }, "Maj,add9": { notes: [0, 4, 7, 14], root: 0, inv: 0, group: GR.extented }, "5": { notes: [0, 7], root: 0, inv: 0, group: GR.shell }, // Minor "Min": { notes: [0, 3, 7], root: 0, inv: 0, group: GR.standard }, "Min,7": { notes: [0, 3, 7, 10], root: 0, inv: 0, group: GR.standard }, "Min,7,9": { notes: [0, 3, 7, 10], root: 0, inv: 0, group: GR.altered }, "Min,7,b5": { notes: [0, 3, 6, 10], root: 0, inv: 0, group: GR.standard }, "Min,6": { notes: [0, 3, 7, 9], root: 0, inv: 0, group: GR.standard }, "Min,6,9": { notes: [0, 3, 7, 9, 14], root: 0, inv: 0, group: GR.extented }, "Min,M7": { notes: [0, 3, 7, 11], root: 0, inv: 0, group: GR.standard }, // Dominant "Dom,7": { notes: [0, 4, 7, 10], root: 0, inv: 0, group: GR.altered }, "Dom,7,9": { notes: [0, 4, 7, 10, 14], root: 0, inv: 0, group: GR.extented }, "Dom,7,#5": { notes: [0, 4, 8, 10], root: 0, inv: 0, group: GR.altered }, "Dom,7,b5": { notes: [0, 4, 6, 10], root: 0, inv: 0, group: GR.altered }, "Dom,7,sus4": { notes: [0, 5, 7, 10], root: 0, inv: 0, group: GR.altered }, "Dom,7,sus2": { notes: [0, 2, 7, 10], root: 0, inv: 0, group: GR.altered }, "Dim": { notes: [0, 3, 6], root: 0, inv: 0, group: GR.passing }, "Dim,7": { notes: [0, 3, 6, 9], root: 0, inv: 0, group: GR.passing }, "Dim,7(HW)": { notes: [0, 3, 6, 9], root: 0, inv: 0, group: GR.passing }, "Dim,7(WH)": { notes: [0, 3, 6, 9], root: 0, inv: 0, group: GR.passing }, // "Dimø" : {notes: [0,3,6,10], root: 0, inv:0, group: 2 }, "Maj,#5": { notes: [0, 4, 8], root: 0, inv: 0, group: GR.altered }, "Sus2": { notes: [0, 2, 7], root: 0, inv: 0, group: GR.altered }, "Sus4": { notes: [0, 5, 7], root: 0, inv: 0, group: GR.altered }, // "Quater" : {notes: [0,5,10], root: 0, inv:0, group: 3 }, // Jazz reduced chords "Maj,7,-5": { notes: [0, 4, 11], root: 0, inv: 0, group: GR.reduced }, "Maj,6,-5": { notes: [0, 4, 9], root: 0, inv: 0, group: GR.reduced }, "Min,6,-5": { notes: [0, 3, 9], root: 0, inv: 0, group: GR.reduced }, "Min,7,-5": { notes: [0, 3, 10], root: 0, inv: 0, group: GR.reduced }, // Jazz block chords // Major A and B Voicings "Maj,6,9,-1(A)": { notes: [0, 3, 5, 10], root: -4, inv: 0, group: GR.rootLess }, "Maj,6,9,-1(B)": { notes: [0, 5, 7, 10], root: -9, inv: 0, group: GR.rootLess }, "Maj,7,9,-1(A)": { notes: [0, 3, 7, 10], root: -4, inv: 0, group: GR.rootLess }, "Maj,7,9,-1(B)": { notes: [0, 3, 5, 8], root: -11, inv: 0, group: GR.rootLess }, // Minor A and B Voicings "Min,6,9,-1(A)": { notes: [0, 4, 6, 11], root: -3, inv: 0, group: GR.rootLess }, // "Min,6,9,-1(B)" : {notes: [0,4,5,9], ro