@tonaljs/scale
Version:
Musical scales and its relations
202 lines (201 loc) • 6.77 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all2) => {
for (var name in all2)
__defProp(target, name, { get: all2[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,
degrees: () => degrees,
detect: () => detect,
extended: () => extended,
get: () => get,
modeNames: () => modeNames,
names: () => names,
rangeOf: () => rangeOf,
reduced: () => reduced,
scale: () => scale,
scaleChords: () => scaleChords,
scaleNotes: () => scaleNotes,
steps: () => steps,
tokenize: () => tokenize
});
module.exports = __toCommonJS(index_exports);
var import_chord_type = require("@tonaljs/chord-type");
var import_collection = require("@tonaljs/collection");
var import_note = require("@tonaljs/note");
var import_pcset = require("@tonaljs/pcset");
var import_pitch_distance = require("@tonaljs/pitch-distance");
var import_pitch_note = require("@tonaljs/pitch-note");
var import_scale_type = require("@tonaljs/scale-type");
var NoScale = {
empty: true,
name: "",
type: "",
tonic: null,
setNum: NaN,
chroma: "",
normalized: "",
aliases: [],
notes: [],
intervals: []
};
function tokenize(name) {
if (typeof name !== "string") {
return ["", ""];
}
const i = name.indexOf(" ");
const tonic = (0, import_pitch_note.note)(name.substring(0, i));
if (tonic.empty) {
const n = (0, import_pitch_note.note)(name);
return n.empty ? ["", name.toLowerCase()] : [n.name, ""];
}
const type = name.substring(tonic.name.length + 1).toLowerCase();
return [tonic.name, type.length ? type : ""];
}
var names = import_scale_type.names;
function get(src) {
const tokens = Array.isArray(src) ? src : tokenize(src);
const tonic = (0, import_pitch_note.note)(tokens[0]).name;
const st = (0, import_scale_type.get)(tokens[1]);
if (st.empty) {
return NoScale;
}
const type = st.name;
const notes = tonic ? st.intervals.map((i) => (0, import_pitch_distance.transpose)(tonic, i)) : [];
const name = tonic ? tonic + " " + type : type;
return { ...st, name, type, tonic, notes };
}
var scale = get;
function detect(notes, options = {}) {
const notesChroma = (0, import_pcset.chroma)(notes);
const tonic = (0, import_pitch_note.note)(options.tonic ?? notes[0] ?? "");
const tonicChroma = tonic.chroma;
if (tonicChroma === void 0) {
return [];
}
const pitchClasses = notesChroma.split("");
pitchClasses[tonicChroma] = "1";
const scaleChroma = (0, import_collection.rotate)(tonicChroma, pitchClasses).join("");
const match = (0, import_scale_type.all)().find((scaleType) => scaleType.chroma === scaleChroma);
const results = [];
if (match) {
results.push(tonic.name + " " + match.name);
}
if (options.match === "exact") {
return results;
}
extended(scaleChroma).forEach((scaleName) => {
results.push(tonic.name + " " + scaleName);
});
return results;
}
function scaleChords(name) {
const s = get(name);
const inScale = (0, import_pcset.isSubsetOf)(s.chroma);
return (0, import_chord_type.all)().filter((chord) => inScale(chord.chroma)).map((chord) => chord.aliases[0]);
}
function extended(name) {
const chroma2 = (0, import_pcset.isChroma)(name) ? name : get(name).chroma;
const isSuperset = (0, import_pcset.isSupersetOf)(chroma2);
return (0, import_scale_type.all)().filter((scale2) => isSuperset(scale2.chroma)).map((scale2) => scale2.name);
}
function reduced(name) {
const isSubset = (0, import_pcset.isSubsetOf)(get(name).chroma);
return (0, import_scale_type.all)().filter((scale2) => isSubset(scale2.chroma)).map((scale2) => scale2.name);
}
function scaleNotes(notes) {
const pcset = notes.map((n) => (0, import_pitch_note.note)(n).pc).filter((x) => x);
const tonic = pcset[0];
const scale2 = (0, import_note.sortedUniqNames)(pcset);
return (0, import_collection.rotate)(scale2.indexOf(tonic), scale2);
}
function modeNames(name) {
const s = get(name);
if (s.empty) {
return [];
}
const tonics = s.tonic ? s.notes : s.intervals;
return (0, import_pcset.modes)(s.chroma).map((chroma2, i) => {
const modeName = get(chroma2).name;
return modeName ? [tonics[i], modeName] : ["", ""];
}).filter((x) => x[0]);
}
function getNoteNameOf(scale2) {
const names2 = Array.isArray(scale2) ? scaleNotes(scale2) : get(scale2).notes;
const chromas = names2.map((name) => (0, import_pitch_note.note)(name).chroma);
return (noteOrMidi) => {
const currNote = typeof noteOrMidi === "number" ? (0, import_pitch_note.note)((0, import_note.fromMidi)(noteOrMidi)) : (0, import_pitch_note.note)(noteOrMidi);
const height = currNote.height;
if (height === void 0) return void 0;
const chroma2 = height % 12;
const position = chromas.indexOf(chroma2);
if (position === -1) return void 0;
return (0, import_note.enharmonic)(currNote.name, names2[position]);
};
}
function rangeOf(scale2) {
const getName = getNoteNameOf(scale2);
return (fromNote, toNote) => {
const from = (0, import_pitch_note.note)(fromNote).height;
const to = (0, import_pitch_note.note)(toNote).height;
if (from === void 0 || to === void 0) return [];
return (0, import_collection.range)(from, to).map(getName).filter((x) => x);
};
}
function degrees(scaleName) {
const { intervals, tonic } = get(scaleName);
const transpose2 = (0, import_pitch_distance.tonicIntervalsTransposer)(intervals, tonic);
return (degree) => degree ? transpose2(degree > 0 ? degree - 1 : degree) : "";
}
function steps(scaleName) {
const { intervals, tonic } = get(scaleName);
return (0, import_pitch_distance.tonicIntervalsTransposer)(intervals, tonic);
}
var index_default = {
degrees,
detect,
extended,
get,
modeNames,
names,
rangeOf,
reduced,
scaleChords,
scaleNotes,
steps,
tokenize,
// deprecated
scale
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
degrees,
detect,
extended,
get,
modeNames,
names,
rangeOf,
reduced,
scale,
scaleChords,
scaleNotes,
steps,
tokenize
});
//# sourceMappingURL=index.js.map