@tonaljs/chord
Version:
Musical chords and its relations
181 lines • 5.33 kB
JavaScript
// index.ts
import { detect } from "@tonaljs/chord-detect";
import {
all as chordTypes,
get as getChordType
} from "@tonaljs/chord-type";
import { subtract } from "@tonaljs/interval";
import { isSubsetOf, isSupersetOf } from "@tonaljs/pcset";
import {
distance,
tonicIntervalsTransposer,
transpose as transposeNote
} from "@tonaljs/pitch-distance";
import { note, tokenizeNote } from "@tonaljs/pitch-note";
import { all as scaleTypes } from "@tonaljs/scale-type";
import { detect as detect2 } from "@tonaljs/chord-detect";
var NoChord = {
empty: true,
name: "",
symbol: "",
root: "",
bass: "",
rootDegree: 0,
type: "",
tonic: null,
setNum: NaN,
quality: "Unknown",
chroma: "",
normalized: "",
aliases: [],
notes: [],
intervals: []
};
function tokenize(name) {
const [letter, acc, oct, type] = tokenizeNote(name);
if (letter === "") {
return tokenizeBass("", name);
} else if (letter === "A" && type === "ug") {
return tokenizeBass("", "aug");
} else {
return tokenizeBass(letter + acc, oct + type);
}
}
function tokenizeBass(note2, chord2) {
const split = chord2.split("/");
if (split.length === 1) {
return [note2, split[0], ""];
}
const [letter, acc, oct, type] = tokenizeNote(split[1]);
if (letter !== "" && oct === "" && type === "") {
return [note2, split[0], letter + acc];
} else {
return [note2, chord2, ""];
}
}
function get(src) {
if (Array.isArray(src)) {
return getChord(src[1] || "", src[0], src[2]);
} else if (src === "") {
return NoChord;
} else {
const [tonic, type, bass] = tokenize(src);
const chord2 = getChord(type, tonic, bass);
return chord2.empty ? getChord(src) : chord2;
}
}
function getChord(typeName, optionalTonic, optionalBass) {
const type = getChordType(typeName);
const tonic = note(optionalTonic || "");
const bass = note(optionalBass || "");
if (type.empty || optionalTonic && tonic.empty || optionalBass && bass.empty) {
return NoChord;
}
const bassInterval = distance(tonic.pc, bass.pc);
const bassIndex = type.intervals.indexOf(bassInterval);
const hasRoot = bassIndex >= 0;
const root = hasRoot ? bass : note("");
const rootDegree = bassIndex === -1 ? NaN : bassIndex + 1;
const hasBass = bass.pc && bass.pc !== tonic.pc;
const intervals = Array.from(type.intervals);
if (hasRoot) {
for (let i = 1; i < rootDegree; i++) {
const num = intervals[0][0];
const quality = intervals[0][1];
const newNum = parseInt(num, 10) + 7;
intervals.push(`${newNum}${quality}`);
intervals.shift();
}
} else if (hasBass) {
const ivl = subtract(distance(tonic.pc, bass.pc), "8P");
if (ivl) intervals.unshift(ivl);
}
const notes2 = tonic.empty ? [] : intervals.map((i) => transposeNote(tonic.pc, i));
typeName = type.aliases.indexOf(typeName) !== -1 ? typeName : type.aliases[0];
const symbol = `${tonic.empty ? "" : tonic.pc}${typeName}${hasRoot && rootDegree > 1 ? "/" + root.pc : hasBass ? "/" + bass.pc : ""}`;
const name = `${optionalTonic ? tonic.pc + " " : ""}${type.name}${hasRoot && rootDegree > 1 ? " over " + root.pc : hasBass ? " over " + bass.pc : ""}`;
return {
...type,
name,
symbol,
tonic: tonic.pc,
type: type.name,
root: root.pc,
bass: hasBass ? bass.pc : "",
intervals,
rootDegree,
notes: notes2
};
}
var chord = get;
function transpose(chordName, interval) {
const [tonic, type, bass] = tokenize(chordName);
if (!tonic) {
return chordName;
}
const tr = transposeNote(bass, interval);
const slash = tr ? "/" + tr : "";
return transposeNote(tonic, interval) + type + slash;
}
function chordScales(name) {
const s = get(name);
const isChordIncluded = isSupersetOf(s.chroma);
return scaleTypes().filter((scale) => isChordIncluded(scale.chroma)).map((scale) => scale.name);
}
function extended(chordName) {
const s = get(chordName);
const isSuperset = isSupersetOf(s.chroma);
return chordTypes().filter((chord2) => isSuperset(chord2.chroma)).map((chord2) => s.tonic + chord2.aliases[0]);
}
function reduced(chordName) {
const s = get(chordName);
const isSubset = isSubsetOf(s.chroma);
return chordTypes().filter((chord2) => isSubset(chord2.chroma)).map((chord2) => s.tonic + chord2.aliases[0]);
}
function notes(chordName, tonic) {
const chord2 = get(chordName);
const note2 = tonic || chord2.tonic;
if (!note2 || chord2.empty) return [];
return chord2.intervals.map((ivl) => transposeNote(note2, ivl));
}
function degrees(chordName, tonic) {
const chord2 = get(chordName);
const note2 = tonic || chord2.tonic;
const transpose2 = tonicIntervalsTransposer(chord2.intervals, note2);
return (degree) => degree ? transpose2(degree > 0 ? degree - 1 : degree) : "";
}
function steps(chordName, tonic) {
const chord2 = get(chordName);
const note2 = tonic || chord2.tonic;
return tonicIntervalsTransposer(chord2.intervals, note2);
}
var chord_default = {
getChord,
get,
detect,
chordScales,
extended,
reduced,
tokenize,
transpose,
degrees,
steps,
notes,
chord
};
export {
chord,
chordScales,
chord_default as default,
degrees,
detect2 as detect,
extended,
get,
getChord,
notes,
reduced,
steps,
tokenize,
transpose
};
//# sourceMappingURL=index.mjs.map