UNPKG

@tonaljs/chord

Version:

Musical chords and its relations

181 lines 5.33 kB
// 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