@tonaljs/chord-detect
Version:
Detect chord name based on note names
82 lines • 2.82 kB
JavaScript
// index.ts
import { all } from "@tonaljs/chord-type";
import { modes } from "@tonaljs/pcset";
import { note } from "@tonaljs/pitch-note";
var namedSet = (notes) => {
const pcToName = notes.reduce((record, n) => {
const chroma = note(n).chroma;
if (chroma !== void 0) {
record[chroma] = record[chroma] || note(n).name;
}
return record;
}, {});
return (chroma) => pcToName[chroma];
};
function detect(source, options = {}) {
const notes = source.map((n) => note(n).pc).filter((x) => x);
if (note.length === 0) {
return [];
}
const found = findMatches(notes, 1, options);
return found.filter((chord) => chord.weight).sort((a, b) => b.weight - a.weight).map((chord) => chord.name);
}
var BITMASK = {
// 3m 000100000000
// 3M 000010000000
anyThirds: 384,
// 5P 000000010000
perfectFifth: 16,
// 5d 000000100000
// 5A 000000001000
nonPerfectFifths: 40,
anySeventh: 3
};
var testChromaNumber = (bitmask) => (chromaNumber) => Boolean(chromaNumber & bitmask);
var hasAnyThird = testChromaNumber(BITMASK.anyThirds);
var hasPerfectFifth = testChromaNumber(BITMASK.perfectFifth);
var hasAnySeventh = testChromaNumber(BITMASK.anySeventh);
var hasNonPerfectFifth = testChromaNumber(BITMASK.nonPerfectFifths);
function hasAnyThirdAndPerfectFifthAndAnySeventh(chordType) {
const chromaNumber = parseInt(chordType.chroma, 2);
return hasAnyThird(chromaNumber) && hasPerfectFifth(chromaNumber) && hasAnySeventh(chromaNumber);
}
function withPerfectFifth(chroma) {
const chromaNumber = parseInt(chroma, 2);
return hasNonPerfectFifth(chromaNumber) ? chroma : (chromaNumber | 16).toString(2);
}
function findMatches(notes, weight, options) {
const tonic = notes[0];
const tonicChroma = note(tonic).chroma;
const noteName = namedSet(notes);
const allModes = modes(notes, false);
const found = [];
allModes.forEach((mode, index) => {
const modeWithPerfectFifth = options.assumePerfectFifth && withPerfectFifth(mode);
const chordTypes = all().filter((chordType) => {
if (options.assumePerfectFifth && hasAnyThirdAndPerfectFifthAndAnySeventh(chordType)) {
return chordType.chroma === modeWithPerfectFifth;
}
return chordType.chroma === mode;
});
chordTypes.forEach((chordType) => {
const chordName = chordType.aliases[0];
const baseNote = noteName(index);
const isInversion = index !== tonicChroma;
if (isInversion) {
found.push({
weight: 0.5 * weight,
name: `${baseNote}${chordName}/${tonic}`
});
} else {
found.push({ weight: 1 * weight, name: `${baseNote}${chordName}` });
}
});
});
return found;
}
var chord_detect_default = { detect };
export {
chord_detect_default as default,
detect
};
//# sourceMappingURL=index.mjs.map