UNPKG

@tonaljs/pcset

Version:

Functions to work with midi numbers

165 lines 3.93 kB
// index.ts import { compact, range, rotate } from "@tonaljs/collection"; import { transpose } from "@tonaljs/pitch-distance"; import { interval } from "@tonaljs/pitch-interval"; import { note } from "@tonaljs/pitch-note"; var EmptyPcset = { empty: true, name: "", setNum: 0, chroma: "000000000000", normalized: "000000000000", intervals: [] }; var setNumToChroma = (num2) => Number(num2).toString(2).padStart(12, "0"); var chromaToNumber = (chroma2) => parseInt(chroma2, 2); var REGEX = /^[01]{12}$/; function isChroma(set) { return REGEX.test(set); } var isPcsetNum = (set) => typeof set === "number" && set >= 0 && set <= 4095; var isPcset = (set) => set && isChroma(set.chroma); var cache = { [EmptyPcset.chroma]: EmptyPcset }; function get(src) { const chroma2 = isChroma(src) ? src : isPcsetNum(src) ? setNumToChroma(src) : Array.isArray(src) ? listToChroma(src) : isPcset(src) ? src.chroma : EmptyPcset.chroma; return cache[chroma2] = cache[chroma2] || chromaToPcset(chroma2); } var pcset = get; var chroma = (set) => get(set).chroma; var intervals = (set) => get(set).intervals; var num = (set) => get(set).setNum; var IVLS = [ "1P", "2m", "2M", "3m", "3M", "4P", "5d", "5P", "6m", "6M", "7m", "7M" ]; function chromaToIntervals(chroma2) { const intervals2 = []; for (let i = 0; i < 12; i++) { if (chroma2.charAt(i) === "1") intervals2.push(IVLS[i]); } return intervals2; } function notes(set) { return get(set).intervals.map((ivl) => transpose("C", ivl)); } function chromas() { return range(2048, 4095).map(setNumToChroma); } function modes(set, normalize = true) { const pcs = get(set); const binary = pcs.chroma.split(""); return compact( binary.map((_, i) => { const r = rotate(i, binary); return normalize && r[0] === "0" ? null : r.join(""); }) ); } function isEqual(s1, s2) { return get(s1).setNum === get(s2).setNum; } function isSubsetOf(set) { const s = get(set).setNum; return (notes2) => { const o = get(notes2).setNum; return s && s !== o && (o & s) === o; }; } function isSupersetOf(set) { const s = get(set).setNum; return (notes2) => { const o = get(notes2).setNum; return s && s !== o && (o | s) === o; }; } function isNoteIncludedIn(set) { const s = get(set); return (noteName) => { const n = note(noteName); return s && !n.empty && s.chroma.charAt(n.chroma) === "1"; }; } var includes = isNoteIncludedIn; function filter(set) { const isIncluded = isNoteIncludedIn(set); return (notes2) => { return notes2.filter(isIncluded); }; } var pcset_default = { get, chroma, num, intervals, chromas, isSupersetOf, isSubsetOf, isNoteIncludedIn, isEqual, filter, modes, notes, // deprecated pcset }; function chromaRotations(chroma2) { const binary = chroma2.split(""); return binary.map((_, i) => rotate(i, binary).join("")); } function chromaToPcset(chroma2) { const setNum = chromaToNumber(chroma2); const normalizedNum = chromaRotations(chroma2).map(chromaToNumber).filter((n) => n >= 2048).sort()[0]; const normalized = setNumToChroma(normalizedNum); const intervals2 = chromaToIntervals(chroma2); return { empty: false, name: "", setNum, chroma: chroma2, normalized, intervals: intervals2 }; } function listToChroma(set) { if (set.length === 0) { return EmptyPcset.chroma; } let pitch; const binary = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; for (let i = 0; i < set.length; i++) { pitch = note(set[i]); if (pitch.empty) pitch = interval(set[i]); if (!pitch.empty) binary[pitch.chroma] = 1; } return binary.join(""); } export { EmptyPcset, chroma, chromas, pcset_default as default, filter, get, includes, intervals, isChroma, isEqual, isNoteIncludedIn, isSubsetOf, isSupersetOf, modes, notes, num, pcset }; //# sourceMappingURL=index.mjs.map