UNPKG

cxchord

Version:
1,643 lines (1,622 loc) 1.22 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){ const CxChord = require('../lib/CxChord'); var midiChord = [64, 67, 71, 72, 74, 78, 81]; var cm = new CxChord.ChordMatcher(); cm.match(midiChord); p0 = cm.bayes.getBestPosterior(); cm.bayes.visualizeTopX("Match", cm.getChord(), 15); },{"../lib/CxChord":4}],2:[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":3,"lodash":10}],3:[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}],4:[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":2,"./CxChart":3,"./CxChordInst":5,"./CxForms":6,"./CxMatch":7,"./CxRules":8}],5:[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":6,"lodash":10}],6:[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":5,"lodash":10}],7:[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":2,"./CxChordInst":5,"./CxForms":6,"./CxRules":8,"lodash":10}],8:[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);