cxchord
Version:
Midi Chord Recognizer
1,414 lines (1,398 loc) • 1.24 MB
JavaScript
(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 = ' ';
_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