cxchord
Version:
Midi Chord Recognizer
1,647 lines (1,627 loc) • 1.22 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":9}],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":8}],3:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Rules = exports.ChordMatcher = exports.ChordMatch = exports.ChordForms = exports.knockouts = exports.conflicts = exports.extensions = exports.chordMap = exports.GR = exports.getKnockouts = exports.isNoRootChord = exports.getChordName = exports.getExtName = exports.getNoteName = exports.getNoteNumber = exports.noteNames = exports.rootNoteNames = exports.ChordInstance = exports.BarDataSet = exports.BayesChordCalculator = void 0;
var CxBayes_1 = require("./CxBayes");
Object.defineProperty(exports, "BayesChordCalculator", {
enumerable: true,
get: function () {
return CxBayes_1.BayesChordCalculator;
}
});
var CxChart_1 = require("./CxChart");
Object.defineProperty(exports, "BarDataSet", {
enumerable: true,
get: function () {
return CxChart_1.BarDataSet;
}
});
var CxChordInst_1 = require("./CxChordInst");
Object.defineProperty(exports, "ChordInstance", {
enumerable: true,
get: function () {
return CxChordInst_1.ChordInstance;
}
});
var CxForms_1 = require("./CxForms");
Object.defineProperty(exports, "rootNoteNames", {
enumerable: true,
get: function () {
return CxForms_1.rootNoteNames;
}
});
Object.defineProperty(exports, "noteNames", {
enumerable: true,
get: function () {
return CxForms_1.noteNames;
}
});
Object.defineProperty(exports, "getNoteNumber", {
enumerable: true,
get: function () {
return CxForms_1.getNoteNumber;
}
});
Object.defineProperty(exports, "getNoteName", {
enumerable: true,
get: function () {
return CxForms_1.getNoteName;
}
});
Object.defineProperty(exports, "getExtName", {
enumerable: true,
get: function () {
return CxForms_1.getExtName;
}
});
Object.defineProperty(exports, "getChordName", {
enumerable: true,
get: function () {
return CxForms_1.getChordName;
}
});
Object.defineProperty(exports, "isNoRootChord", {
enumerable: true,
get: function () {
return CxForms_1.isNoRootChord;
}
});
Object.defineProperty(exports, "getKnockouts", {
enumerable: true,
get: function () {
return CxForms_1.getKnockouts;
}
});
Object.defineProperty(exports, "GR", {
enumerable: true,
get: function () {
return CxForms_1.GR;
}
});
Object.defineProperty(exports, "chordMap", {
enumerable: true,
get: function () {
return CxForms_1.chordMap;
}
});
Object.defineProperty(exports, "extensions", {
enumerable: true,
get: function () {
return CxForms_1.extensions;
}
});
Object.defineProperty(exports, "conflicts", {
enumerable: true,
get: function () {
return CxForms_1.conflicts;
}
});
Object.defineProperty(exports, "knockouts", {
enumerable: true,
get: function () {
return CxForms_1.knockouts;
}
});
Object.defineProperty(exports, "ChordForms", {
enumerable: true,
get: function () {
return CxForms_1.ChordForms;
}
});
var CxMatch_1 = require("./CxMatch");
Object.defineProperty(exports, "ChordMatch", {
enumerable: true,
get: function () {
return CxMatch_1.ChordMatch;
}
});
Object.defineProperty(exports, "ChordMatcher", {
enumerable: true,
get: function () {
return CxMatch_1.ChordMatcher;
}
});
var CxRules_1 = require("./CxRules");
Object.defineProperty(exports, "Rules", {
enumerable: true,
get: function () {
return CxRules_1.Rules;
}
});
},{"./CxBayes":1,"./CxChart":2,"./CxChordInst":4,"./CxForms":5,"./CxMatch":6,"./CxRules":7}],4:[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":9}],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], root: -10, inv:0, group: GR.rootLess }, // TODO - Check this one
"Min,7,9,-1(A)": {
notes: [0, 4, 7, 11],
root: -3,
inv: 0,
group: GR.rootLess
},
"Min,7,9,-1(B)": {
notes: [0, 4, 5, 9],
root: -10,
inv: 0,
group: GR.rootLess
},
// "Min,7,b5(A)" : {notes: [0,3,7,9], root: -3, inv:0, group: GR.standard },
// "Min,7,b5(B)" : {notes: [0,2,5,8], root: -10, inv:0, group: GR.standard },
// "MinCluster,7,9,-1" : {notes: [0,4,5,9], root: -10, inv:0, group: GR.rootLess },
// Dominant A and B Voicings
"Dom,7,9,-1(A)": {
notes: [0, 4, 6, 11],
root: -10,
inv: 0,
group: GR.rootLess
},
"Dom,7,9,-1(B)": {
notes: [0, 5, 6, 10],
root: -4,
inv: 0,
group: GR.rootLess
},
// "Dom,7,b9,-1(A)" : {notes: [0,3,6,10], root: -10, inv:0, group: GR.rootLess },
"Dom,7,b9,b13,-1(A)": {
notes: [0, 5, 6, 10],
root: -4,
inv: 0,
group: GR.rootLess
},
"Dom,7,b9,b13,-1(B)": {
notes: [0, 4, 6, 9],
root: -4,
inv: 0,
group: GR.rootLess
},
"Dom,7,b9,-1": {
notes: [0, 3, 6, 9],
root: -4,
inv: 0,
group: GR.rootLess
},
"Dom,7,#9,-1": {
notes: [0, 3, 6, 11],
root: -4,
inv: 0,
group: GR.rootLess
}
// "MinCluster" : {notes: [0,2,3,7], root: 0, inv:0, group: 3 },
// "MajCluster" : {notes: [0,2,4,7], root: 0, inv:0, group: 3 },
// "Dom7Cluster,-1" : {notes: [0,4,6,9], root: -4, inv:0, group: GR.rootLess }
};
// Note: Extension don't live with a half or whole step between each other
// except for (mostly altered) dominant chords
exports.extensions = {
"Maj": [14, 18, 21],
"Maj,7": [14, 18, 21],
"Min": [14, 17, 21, 13, 18],
"Min,M7": [14, 17, 21, 18],
// "Dim7HW" : [14,17,20,23],
// "Dim7WH" : [14,17,20,23],
// "Half-Dim7": [14,17,20,21],
"Maj,#5": [14, 18],
"Dom,7": [13, 14, 18, 21],
"Dom,7,#5": [13, 14, 15, 18, 19],
"Dom,7,b5": [13, 14, 15, 19, 20, 21]
// TODO: Add the rest later
};
exports.mustHave = {
// Major
"Maj": [4],
"Maj,7": [4, 11],
"Maj,7,9": [4, 11],
"Maj,7,9,#11": [4, 11],
"Maj,7,9,#11,13": [4, 11],
"Maj,6": [4, 9],
"Maj,6,9": [4, 9],
"Maj,6,9,-1": [4, 9],
// "Maj,7,b5" : [0,4,6,11],
"Maj,add2": [2, 4],
"Maj,add9": [4, 14],
// "Maj-add9no5":[4,14],
"Maj,#5": [0, 4, 8],
// Sus Types
"Sus2": [0, 2, 7],
"Sus4": [0, 5, 7],
// Minor
"Min": [3],
"Min,6": [3, 9],
"Min,6,9": [3, 9],
"Min,6,9,-1": [3, 9],
"Min,7": [3, 10],
"Min,7,9": [3, 10],
"Min,7,9,-1": [3, 10],
"Min,7,b5": [3, 6, 10],
"Min,M7": [3, 11],
// Dominant
"Dom,7": [4, 10],
"Dom,7,9": [4, 10],
"Dom,7,#5": [4, 8, 10],
"Dom,7,b5": [4, 6, 10],
"Dom,7,sus4": [5, 10],
"Dom,7,sus2": [2, 10],
"Dim": [0, 3, 6],
"Dim,7(WH)": [0, 3, 6, 9],
"Dim,7(HW)": [0, 3, 6, 9],
// Jazz type no-root chords
"Dom,7,9,-1": [4, 10],
"Dom,7,b9,-1": [4, 10],
"Dom,7,#9,-1": [4, 10],
"Dom,7,9,13,-1,-5": [4, 10, 21]
};
exports.conflicts = {
// Major
/*
"Maj" : [[4,5],[10,11]],
"Maj7" : [],
"Maj79" : [],
"Maj79#11" : [],
"Maj79#1113": [],
"Maj6" : [],
"Maj69" : [],
*/
// "Maj,7,b5" : [[6,7]],
/*
"Maj-add2" : [],
"Maj-add9" : [],
"Maj-add9no5":[],
*/
"Maj,#5": [[7, 8]],
// Minor
"Min": [[5, 6], [7, 8]],
"Min,6": [[5, 6], [7, 8]],
"Min,6,9": [[5, 6], [7, 8]],
"Min,6,9,-1": [[5, 6], [7, 8]],
"Min,7": [[5, 6], [7, 8]],
"Min,7,9": [[5, 6], [7, 8]],
"Min,7,9,-1": [[5, 6], [7, 8]],
"Min,7,b5": [[5, 6], [7, 8]],
"Min,M7": [[5, 6], [7, 8]]
// "MinCluster,7,9,-1": [[5,6], [7,8]]
// Dominant
/*
"Dom7" : [],
"Dom7#5" : [],
"Dom7b5" : [],
"Dom7sus4" : [],
"Dom7sus2" : [],
// Jazz type no-root chords
"Dom79-no root" : [],
"Dom7b9-no root" : [],
"Dom7#9-no root" : [],
"Dim" : [],
"Dim7WH" : [],
"Dim7HW" : []
*/
};
exports.knockouts = {
// Major
"Maj": [1, 3, 5, 8, 10],
"Maj,7": [1, 3, 5, 8, 10],
"Maj,7,9": [1, 3, 5, 8, 10],
"Maj,7,9,#11": [1, 3, 5, 8, 10],
"Maj,7,9,#11,13": [1, 3, 5, 8, 10],
"Maj,6": [1, 3, 5, 8, 10],
"Maj,6,9": [1, 3, 5, 8, 10],
"Maj,7,b5": [1, 3, 5, 7, 8, 10],
"Maj,add2": [1, 3, 5, 8, 10, 11, 14],
"Maj,add9": [1, 3, 5, 8, 9, 10, 11],
// "Maj,add9no5": [1,3,5,8,10],
"Maj,#5": [1, 3, 5, 7, 10],
"5": [1, 2, 3, 4, 5, 6, 8, 9, 10, 11],
// Minor
"Min": [1, 4, 6, 8, 11],
"Min,6": [1, 4, 6, 8],
"Min,6,9": [1, 4, 6, 8],
"Min,7": [1, 4, 6, 8, 11],
"Min,7,9": [1, 4, 6, 8, 11],
"Min,7,b5": [4, 7, 8, 11],
"Min,M7": [1, 4, 6, 8, 10],
"MinCluster,7,9,-1": [1, 4, 8],
// Diminished
"Dim": [4, 7, 9, 10, 11],
"Dim,7": [1, 2, 4, 5, 7, 8, 10, 11],
"Dim,7(HW)": [2, 5, 8, 11],
"Dim,7(WH)": [1, 4, 7, 10],
// "Half-Dim7" : [4,7,11],
// Dominant
"Dom,7": [5, 11],
"Dom,7,#5": [5, 11],
"Dom,7,sus4": [4, 11],
// "Dom7sus4#5": [4,11],
"Dom,7,b5": [5, 7, 11],
// Quater types
"Sus2": [1, 3, 4, 5, 8],
"Sus4": [1, 3, 4, 6, 8],
// "Quater" : [1,3,4,5,8,],
// Jazz reduced chords
"Maj,7,-5": [1, 3, 5, 6, 7, 8, 10],
"Maj,6,-5": [1, 3, 5, 6, 7, 8, 10],
"Min,6,-5": [1, 4, 6, 7, 8],
"Min,7,-5": [1, 4, 6, 7, 8, 11],
// Jazz type no-root chords
"Maj,6,9,-1(A)": [0, 1, 3, 5, 6, 8, 10],
"Maj,6,9,-1(B)": [0, 1, 3, 5, 6, 8, 10],
"Maj,7,9,-1(A)": [0, 1, 3, 5, 6, 8, 10],
"Maj,7,9,-1(B)": [0, 1, 3, 5, 6, 8, 10],
"Maj,7,9,-1": [0, 1, 3, 5, 6, 8, 10],
"Min,6,9,-1(A)": [0, 4, 6, 8, 10, 11],
"Min,6,9,-1(B)": [0, 4, 6, 8, 10, 11],
"Min,7,9,-1(A)": [0, 4, 6, 8, 11],
"Min,7,9,-1(B)": [0, 4, 6, 8, 11],
// "Min,7,b5(A)" : [0,4,7,8,11],
// "Min,7,b5(B)" : [0,4,7,8,11],
"Min,6,9,-1": [1, 4, 8],
"Min,7,9,-1": [1, 4, 8],
"Dom,7,9,-1(A)": [0, 1, 3, 5, 8, 11],
"Dom,7,9,-1(B)": [0, 1, 3, 5, 8, 11],
"Dom,7,b9,b13,-1(A)": [0, 2, 5, 8, 11],
"Dom,7,b9,b13,-1(B)": [0, 2, 5, 8, 11],
"Dom,7,9,13,-1,-5": [0, 5, 7, 11],
"Dom,7,9,-1": [0, 5, 7, 11],
"Dom,7,b9,-1": [0, 5, 7, 11],
"Dom,7,#9,-1": [0, 5, 7, 11]
// "Dom7Cluster,-1": [0,5,7,11]
};
var ChordForms = /** @class */function () {
function ChordForms() {
this.chordMapWithInv = {};
this.buildInversions();
}
ChordForms.prototype.getInvariants = function (chordName) {
var invariants = [];
if (_.has(exports.chordMap, chordName)) {
var chord_1 = exports.chordMap[chordName];
_.forIn(exports.chordMap, function (value, key) {
if (key !== chordName && _.isEqual(value.notes, chord_1.notes)) {
invariants.push(key);
}
});
}
return invariants;
};
ChordForms.prototype.buildInversions = function () {
var mapWithInv = this.chordMapWithInv;
//
// Loop through the Chord hypothesis
//
_.forIn(exports.chordMap, function (value, key) {
mapWithInv[key] = [];
//
// Loop through the inversions
//
var chord = new CxChordInst_1.ChordInstance(value.notes);
var interval = chord.getInversion(0);
for (var i = 0; i < value.notes.length; i++) {
var _notes = chord.getInversion(i);
//
// Calculate the new inverted root note
//
var rootNote = -(Math.abs(value.root) + interval[i]) % 12;
// mapWithInv[key].push( { notes: _notes, root: ( rootNote <= 0 ? 0 : rootNote ) , inv: i, group: value.group } )
mapWithInv[key].push({
notes: _notes,
root: rootNote,
inv: i,
group: value.group
});
}
});
};
return ChordForms;
}();
exports.ChordForms = ChordForms;
},{"./CxChordInst":4,"lodash":9}],6:[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.ChordMatcher = exports.ChordMatch = void 0;
var CxBayes_1 = require("./CxBayes");
var CxChordInst_1 = require("./CxChordInst");
var CxForms_1 = require("./CxForms");
var CxRules_1 = require("./CxRules");
var _ = require("lodash");
var ChordMatch = /** @class */function () {
function ChordMatch(hypo, chordEntry, _mapEntry, sharpOrFlat) {
if (sharpOrFlat === void 0) {
sharpOrFlat = 'flat';
}
this.hypo = hypo;
this.notes = [];
this.inv = hypo.inv;
this.type = hypo.key;
for (var i = 0; i < chordEntry.chordInv[0].length; i++) {
var note = chordEntry.chordInv[0][i] + chordEntry.offset[0];
this.notes.push(note);
}
this.bass = chordEntry.getBassName(hypo, sharpOrFlat);
this.root = chordEntry.getRootName(hypo, sharpOrFlat);
this.list = this.root + "," + this.hypo.key;
if (this.bass !== this.root) {
this.list += ",/" + this.bass;
}
this.chord = (0, CxForms_1.getExtName)(this.list);
}
return ChordMatch;
}();
exports.ChordMatch = ChordMatch;
var ChordMatcher = /** @class */function (_super) {
__extends(ChordMatcher, _super);
function ChordMatcher(debugKey) {
if (debugKey === void 0) {
debugKey = "Maj";
}
var _this = _super.call(this) || this;
_this.debugKey = debugKey;
_this.chord = null;
_this.bayes = null;
_this.rules = null;
_this.favorJazzChords = false;
_this.priorChords = [];
return _this;
}
ChordMatcher.prototype.getMatches = function (sharpOrFlat) {
if (sharpOrFlat === void 0) {
sharpOrFlat = 'flat';
}
var post = this.bayes.getPosterior();
var res = [];
for (var i = 0; i < post.length; i++) if (i == 0 || post[i].post == post[i - 1].post) {
var chordEntry = this.chord;
var chordMapEntry = this.chordMapWithInv[post[i].hypo.key][post[i].hypo.inv];
var entry = new ChordMatch(post[i].hypo, chordEntry, chordMapEntry, sharpOrFlat);
res.push(entry);
} else {
break;
}
return res;
};
ChordMatcher.prototype.getMatch = function (idx, sharpOrFlat) {
if (idx === void 0) {
idx = 0;
}
if (sharpOrFlat === void 0) {
sharpOrFlat = 'flat';
}
var res = this.getMatches(sharpOrFlat);
if (idx < 0 || idx >= res.length) throw Error("getMatch index: " + idx + " is out of range");else return res[idx];
};
ChordMatcher.prototype.getPosterior = function () {
return this.bayes.getPosterior();
};
ChordMatcher.prototype.getChord = function () {
return this.chord;
};
ChordMatcher.prototype.favorJazz = function (favor) {
if (favor === void 0) {
favor = true;
}
this.favorJazzChords = favor;
if (this.chord !== null) {
this.chord.favorJazzChords = favor;
}
};
ChordMatcher.prototype.addRootOffset = function (_arr, root, _addOctave) {
if (_arr === void 0) {
_arr = [];
}
if (_addOctave === void 0) {
_addOctave = true;
}
var arr = [];
if (root == 0) {
arr = _arr;
} else {
for (var i = 0; i < _arr.length; i++) {
var note = _arr[i] + root % 12;
note = note < 0 ? note + 12 : note;
arr.push(note);
}
}
return _.sortedUniq(arr);
};
ChordMatcher.prototype.addToArray = function (_arr, value) {
var arr = [];
for (var i = 0; i < _arr.length; i++) {
arr.push(_arr[i] + value);
}
return arr;
};
ChordMatcher.prototype.doMatch = function (chord, _limit) {
if (_limit === void 0) {
_limit = chord.chordInv[0].length;
}
// deno-lint-ignore no-this-alias
var self = this;
var idx = 0;
_.forIn(this.chordMapWithInv, function (hypothesis, key) {
var _a;
idx++;
for (var inv = 0; inv < hypothesis.length; inv++) {
idx += inv;
if (!_.has(chord.matchedNotes, key)) {
chord.matchedNotes[key] = {
invertions: [],
extensions: [],
knockouts: [],
mustHave: [],
rootNotes: [],
conflicts: [],
roots: [],
group: hypothesis[inv].group
};
}
// Save the root note for the inversion
chord.matchedNotes[key].rootNotes.push(hypothesis[inv].root);
//
// Check for matching notes
//
var intersection = _.intersection(chord.chordInv[0], hypothesis[inv].notes);
if (!_.isArray(intersection)) throw Error('inversion Intersection is not an array');
chord.matchedNotes[key].invertions.push(intersection);
// if ( chord.chordInv[0].length == intersection.length ) this.fullMatches = true
//
// The following checks should also check against the the root of no-root chords
//
var _hypoToMatch = [];
var chordToMatch = [];
var invRoot = (hypothesis[inv].root < 0 ? 12 + hypothesis[inv].root : hypothesis[inv].root) % 12;
if ((0, CxForms_1.isNoRootChord)(key) && hypothesis[inv].root < 0) {
var tmpArr = [];
tmpArr.push(invRoot);
_hypoToMatch = tmpArr.concat(hypothesis[inv].notes).sort();
chordToMatch = chord.addRootOffset(chord.chordInv[0], hypothesis[inv].root);
} else {
_hypoToMatch = hypothesis[inv].notes;
chordToMatch = chord.chordInv[0];
}
//
// Check for the root notes
// For chord without the root it should not be present
// For chord with roots it should score higher if present
//
var indexOfRoot = chordToMatch.indexOf(invRoot) >= 0 ? chordToMatch.indexOf(invRoot) : chordToMatch.indexOf(invRoot + 12);
chord.matchedNotes[key].roots.push(indexOfRoot);
//
// Check for must Have notes
//
var mustHaveTrans = void 0;
var mustHaveMatch = void 0;
if (!_.isUndefined(CxForms_1.mustHave[key])) {
mustHaveTrans = self.addRootOffset(CxForms_1.mustHave[key], hypothesis[inv].root, false);
mustHaveMatch = _.intersection(chordToMatch, mustHaveTrans);
chord.matchedNotes[key].mustHave.push(mustHaveMatch.length - mustHaveTrans.length);
} else chord.matchedNotes[key].mustHave.push(0);
//
// Now check the extensions
//
var extensionNotes = CxForms_1.extensions[key];
var remainingNotes = _.difference(chord.chordInv[0], intersection);
var extensionMatch = _.intersection(remainingNotes, extensionNotes);
chord.matchedNotes[key].extensions.push(extensionMatch);
//
// Now check the knockouts
//
var knockoutTrans = void 0;
var knockoutMatch = void 0;
var KOs = (0, CxForms_1.getKnockouts)(key);
if (KOs.length > 0) {
knockoutTrans = self.addRootOffset(CxForms_1.knockouts[key], hypothesis[inv].root);
knockoutMatch = _.intersection(chord.chordInv[0], knockoutTrans);
}
chord.matchedNotes[key].knockouts.push((_a = knockoutMatch) !== null && _a !== void 0 ? _a : []);
//
// Check for Conflicting notes
//
var conflictCount = 0;
var conflictTrans = void 0;
if (!_.isUndefined(CxForms_1.conflicts[key])) {
for (var i = 0; i < CxForms_1.conflicts[key].length; i++) {
conflictTrans = self.addRootOffset(CxForms_1.conflicts[key][i], hypothesis[inv].root);
var conflictMatch = _.intersection(chordToMatch, conflictTrans);
if (conflictMatch.length == conflictTrans.length) {
conflictCount += 1;
}
// Check in 2 octaves
conflictTrans = self.addToArray(conflictTrans, 12);
conflictMatch = _.intersection(chord.chordInv[0], conflictTrans);
if (conflictMatch.length == conflictTrans.length) {
conflictCount += 1;
}
}
}
chord.matchedNotes[key].conflicts.push(conflictCount);
}
});
return chord;
};
//
// Tone number and name support
//
ChordMatcher.prototype.match = function (midiChord) {
if (_.isUndefined(midiChord) || _.isEmpty(midiChord)) throw "match: supplied Chord is empty";
if (_.isNumber(midiChord[0])) return this.matchNotes(midiChord);
// else
return this.matchNoteNames(midiChord);
};
ChordMatcher.prototype.matchNoteNames = function (midiNames) {
var midiChord = [];
for (var i = 0; i < midiNames.length; i++) try {
var noteNo = (0, CxForms_1.getNoteNumber)(midiNames[i]);
midiChord.push(noteNo);
} catch (e) {
throw e;
}
return this.matchNotes(midiChord);
};
ChordMatcher.prototype.matchNotes = function (midiChord) {
this.bayes = new CxBayes_1.BayesChordCalculator(this.chordMapWithInv);
this.chord = new CxChordInst_1.ChordInstance(midiChord);
this.chord.favorJazzChords = this.favorJazzChords;
//
// TODO: Application of rules should be configurable or even dynamic for best matching capabilities
//
// Do chord tone matches
//
this.doMatch(this.chord);
this.rules = new CxRules_1.Rules(this.chord, this.debugKey);
//
// Apply the Bayes Rules
//
// Even distribution
//
var ruleE = this.rules.get('EvenDistribution');
this.bayes.applyRule(ruleE);
//
// Count Notes Rule
//
// var ruleN: Rule = this.rules.get('CountNotes')
// this.bayes.applyRule(ruleN)
//
// Knockout Rule
//
var ruleK = this.rules.get('Knockouts');
this.bayes.applyRule(ruleK);
//
// Matched Notes rule
//
var ruleM = this.rules.get('MatchedNotes');
this.bayes.applyRule(ruleM);
//
// MustHave Notes rule
//
var ruleH = this.rules.get('MustHave');
this.bayes.applyRule(ruleH);
//
// Favor Jazz Chords
//
// if ( this.favorJazzChords ) {
// var ruleJ: Rule = this.rules.get('FavorJazz')
// this.bayes.applyRule(ruleJ)
// }
//
// Conflict Notes rule
//
// var ruleX: Rule = this.rules.get('Conflicts')
// this.bayes.applyRule(ruleX)
//
// Root is present Rule
//
var ruleR = this.rules.get('RootFound');
this.bayes.applyRule(ruleR);
//
// Group Rule
//
// var ruleG: Rule = this.rules.get('ChordGroup')
// this.bayes.applyRule(ruleG)
// this.priorChords.push(this.chord)
//
return this.chord;
};
return ChordMatcher;
}(CxForms_1.ChordForms);
exports.ChordMatcher = ChordMatcher;
},{"./CxBayes":1,"./CxChordInst":4,"./CxForms":5,"./CxRules":7,"lodash":9}],7:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Rules = void 0;
var CxForms_1 = require("./CxForms");
/*
export interface RuleMap<K, V> {
// clear(): void;
// delete(key: K): boolean;
// forEach(callbackfn: (value: V, index: K, map: Map<K, V>) => void, thisArg?: any): void;
get(key: K): V;
has(key: K): boolean;
set(key: K, value: V): Map<K, V>;
size: number;
}
*/
var Rules = /** @class */function () {
function Rules(_chord, debugKey) {
if (debugKey === void 0) {
debugKey = 'Maj';
}
this.debugKey = debugKey;
// size = 0
this.ruleMap = new Map();
//
// TODO: Scores and Penalties (tax) should be configurable or even dynamic and trained for best matching capability
//
//
// Even Distribution Rule
//
this.set('EvenDistribution', {
chord: _chord,
// deno-lint-ignore no-unused-vars
ruleFx: function (chord, bayes, row, col) {
var _a;
var evenDistibution = (_a = 1 / bayes.hypothesis.length) !== null && _a !== void 0 ? _a : 0;
return evenDistibution;
}
});
//
// Count the number of notes and see iof they match with the Hypothesis chord
//
this.set('CountNotes', {
chord: _chord,
// deno-lint-ignore no-unused-vars
ruleFx: function (chord, bayes, row, col) {
var hypoLen = bayes.hypothesis[col].len;
var chordLen = chord.chordInv[0].length;
var score = 0.1;
if (hypoLen == chordLen) score = 1;else if (hypoLen > chordLen) score = 1 / (hypoLen - chordLen) * 2;else if (hypoLen < chordLen) score = 1 / (chordLen - hypoLen) * 2;
return score;
}
});
//
// MustHave Rule
//
this.set('MustHave', {
chord: _chord,
// deno-lint-ignore no-unused-vars
ruleFx: function (chord, bayes, row, col) {
var key = bayes.hypothesis[col].key;
var inv = bayes.hypothesis[col].inv;
var mustHave = chord.matchedNotes[key].mustHave[inv];
var score = 1 / (mustHave == 0 ? 1 : Math.abs(mustHave) * 2);
return score;
}
});
//
// Knockout Rule
//
this.set('Knockouts', {
chord: _chord,
// deno-lint-ignore no-unused-vars
ruleFx: function (chord, bayes, row, col) {
var key = bayes.hypothesis[col].key;
var inv = bayes.hypothesis[col].inv;