UNPKG

@tonaljs/key

Version:

Functions to work with musical keys

257 lines (256 loc) 8.4 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // index.ts var index_exports = {}; __export(index_exports, { default: () => index_default, majorKey: () => majorKey, majorKeyChords: () => majorKeyChords, majorTonicFromKeySignature: () => majorTonicFromKeySignature, minorKey: () => minorKey, minorKeyChords: () => minorKeyChords }); module.exports = __toCommonJS(index_exports); var import_note = require("@tonaljs/note"); var import_pitch_note = require("@tonaljs/pitch-note"); var import_roman_numeral = require("@tonaljs/roman-numeral"); var Empty = Object.freeze([]); var NoKey = { type: "major", tonic: "", alteration: 0, keySignature: "" }; var NoKeyScale = { tonic: "", grades: Empty, intervals: Empty, scale: Empty, triads: Empty, chords: Empty, chordsHarmonicFunction: Empty, chordScales: Empty, secondaryDominants: Empty, secondaryDominantSupertonics: Empty, substituteDominantsMinorRelative: Empty, substituteDominants: Empty, substituteDominantSupertonics: Empty, secondaryDominantsMinorRelative: Empty }; var NoMajorKey = { ...NoKey, ...NoKeyScale, type: "major", minorRelative: "", scale: Empty, substituteDominants: Empty, secondaryDominantSupertonics: Empty, substituteDominantsMinorRelative: Empty }; var NoMinorKey = { ...NoKey, type: "minor", relativeMajor: "", natural: NoKeyScale, harmonic: NoKeyScale, melodic: NoKeyScale }; var mapScaleToType = (scale, list, sep = "") => list.map((type, i) => `${scale[i]}${sep}${type}`); function keyScale(grades, triads, chordTypes, harmonicFunctions, chordScales) { return (tonic) => { const intervals = grades.map((gr) => (0, import_roman_numeral.get)(gr).interval || ""); const scale = intervals.map((interval) => (0, import_note.transpose)(tonic, interval)); const chords = mapScaleToType(scale, chordTypes); const secondaryDominants = scale.map((note2) => (0, import_note.transpose)(note2, "5P")).map( (note2) => ( // A secondary dominant is a V chord which: // 1. is not diatonic to the key, // 2. it must have a diatonic root. scale.includes(note2) && !chords.includes(note2 + "7") ? note2 + "7" : "" ) ); const secondaryDominantSupertonics = supertonics( secondaryDominants, triads ); const substituteDominants = secondaryDominants.map((chord) => { if (!chord) return ""; const domRoot = chord.slice(0, -1); const subRoot = (0, import_note.transpose)(domRoot, "5d"); return subRoot + "7"; }); const substituteDominantSupertonics = supertonics( substituteDominants, triads ); return { tonic, grades, intervals, scale, triads: mapScaleToType(scale, triads), chords, chordsHarmonicFunction: harmonicFunctions.slice(), chordScales: mapScaleToType(scale, chordScales, " "), secondaryDominants, secondaryDominantSupertonics, substituteDominants, substituteDominantSupertonics, // @deprecated use secondaryDominantsSupertonic secondaryDominantsMinorRelative: secondaryDominantSupertonics, // @deprecated use secondaryDominantsSupertonic substituteDominantsMinorRelative: substituteDominantSupertonics }; }; } var supertonics = (dominants, targetTriads) => { return dominants.map((chord, index) => { if (!chord) return ""; const domRoot = chord.slice(0, -1); const minorRoot = (0, import_note.transpose)(domRoot, "5P"); const target = targetTriads[index]; const isMinor = target.endsWith("m"); return isMinor ? minorRoot + "m7" : minorRoot + "m7b5"; }); }; var distInFifths = (from, to) => { const f = (0, import_pitch_note.note)(from); const t = (0, import_pitch_note.note)(to); return f.empty || t.empty ? 0 : t.coord[0] - f.coord[0]; }; var MajorScale = keyScale( "I II III IV V VI VII".split(" "), " m m m dim".split(" "), "maj7 m7 m7 maj7 7 m7 m7b5".split(" "), "T SD T SD D T D".split(" "), "major,dorian,phrygian,lydian,mixolydian,minor,locrian".split(",") ); var NaturalScale = keyScale( "I II bIII IV V bVI bVII".split(" "), "m dim m m ".split(" "), "m7 m7b5 maj7 m7 m7 maj7 7".split(" "), "T SD T SD D SD SD".split(" "), "minor,locrian,major,dorian,phrygian,lydian,mixolydian".split(",") ); var HarmonicScale = keyScale( "I II bIII IV V bVI VII".split(" "), "m dim aug m dim".split(" "), "mMaj7 m7b5 +maj7 m7 7 maj7 o7".split(" "), "T SD T SD D SD D".split(" "), "harmonic minor,locrian 6,major augmented,lydian diminished,phrygian dominant,lydian #9,ultralocrian".split( "," ) ); var MelodicScale = keyScale( "I II bIII IV V VI VII".split(" "), "m m aug dim dim".split(" "), "m6 m7 +maj7 7 7 m7b5 m7b5".split(" "), "T SD T SD D ".split(" "), "melodic minor,dorian b2,lydian augmented,lydian dominant,mixolydian b6,locrian #2,altered".split( "," ) ); function majorKey(tonic) { const pc = (0, import_pitch_note.note)(tonic).pc; if (!pc) return NoMajorKey; const keyScale2 = MajorScale(pc); const alteration = distInFifths("C", pc); return { ...keyScale2, type: "major", minorRelative: (0, import_note.transpose)(pc, "-3m"), alteration, keySignature: (0, import_pitch_note.altToAcc)(alteration) }; } function majorKeyChords(tonic) { const key = majorKey(tonic); const chords = []; keyChordsOf(key, chords); return chords; } function minorKeyChords(tonic) { const key = minorKey(tonic); const chords = []; keyChordsOf(key.natural, chords); keyChordsOf(key.harmonic, chords); keyChordsOf(key.melodic, chords); return chords; } function keyChordsOf(key, chords) { const updateChord = (name, newRole) => { if (!name) return; let keyChord = chords.find((chord) => chord.name === name); if (!keyChord) { keyChord = { name, roles: [] }; chords.push(keyChord); } if (newRole && !keyChord.roles.includes(newRole)) { keyChord.roles.push(newRole); } }; key.chords.forEach( (chordName, index) => updateChord(chordName, key.chordsHarmonicFunction[index]) ); key.secondaryDominants.forEach( (chordName, index) => updateChord(chordName, `V/${key.grades[index]}`) ); key.secondaryDominantSupertonics.forEach( (chordName, index) => updateChord(chordName, `ii/${key.grades[index]}`) ); key.substituteDominants.forEach( (chordName, index) => updateChord(chordName, `subV/${key.grades[index]}`) ); key.substituteDominantSupertonics.forEach( (chordName, index) => updateChord(chordName, `subii/${key.grades[index]}`) ); } function minorKey(tnc) { const pc = (0, import_pitch_note.note)(tnc).pc; if (!pc) return NoMinorKey; const alteration = distInFifths("C", pc) - 3; return { type: "minor", tonic: pc, relativeMajor: (0, import_note.transpose)(pc, "3m"), alteration, keySignature: (0, import_pitch_note.altToAcc)(alteration), natural: NaturalScale(pc), harmonic: HarmonicScale(pc), melodic: MelodicScale(pc) }; } function majorTonicFromKeySignature(sig) { if (typeof sig === "number") { return (0, import_note.transposeFifths)("C", sig); } else if (typeof sig === "string" && /^b+|#+$/.test(sig)) { return (0, import_note.transposeFifths)("C", (0, import_pitch_note.accToAlt)(sig)); } return null; } var index_default = { majorKey, majorTonicFromKeySignature, minorKey }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { majorKey, majorKeyChords, majorTonicFromKeySignature, minorKey, minorKeyChords }); //# sourceMappingURL=index.js.map