UNPKG

@tonaljs/pitch-interval

Version:

Parse intervals in shorthand notation

138 lines (137 loc) 4.29 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 pitch_interval_exports = {}; __export(pitch_interval_exports, { coordToInterval: () => coordToInterval, interval: () => interval, tokenizeInterval: () => tokenizeInterval }); module.exports = __toCommonJS(pitch_interval_exports); var import_pitch = require("@tonaljs/pitch"); var fillStr = (s, n) => Array(Math.abs(n) + 1).join(s); var NoInterval = Object.freeze({ empty: true, name: "", num: NaN, q: "", type: "", step: NaN, alt: NaN, dir: NaN, simple: NaN, semitones: NaN, chroma: NaN, coord: [], oct: NaN }); var INTERVAL_TONAL_REGEX = "([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})"; var INTERVAL_SHORTHAND_REGEX = "(AA|A|P|M|m|d|dd)([-+]?\\d+)"; var REGEX = new RegExp( "^" + INTERVAL_TONAL_REGEX + "|" + INTERVAL_SHORTHAND_REGEX + "$" ); function tokenizeInterval(str) { const m = REGEX.exec(`${str}`); if (m === null) { return ["", ""]; } return m[1] ? [m[1], m[2]] : [m[4], m[3]]; } var cache = {}; function interval(src) { return typeof src === "string" ? cache[src] || (cache[src] = parse(src)) : (0, import_pitch.isPitch)(src) ? interval(pitchName(src)) : (0, import_pitch.isNamedPitch)(src) ? interval(src.name) : NoInterval; } var SIZES = [0, 2, 4, 5, 7, 9, 11]; var TYPES = "PMMPPMM"; function parse(str) { const tokens = tokenizeInterval(str); if (tokens[0] === "") { return NoInterval; } const num = +tokens[0]; const q = tokens[1]; const step = (Math.abs(num) - 1) % 7; const t = TYPES[step]; if (t === "M" && q === "P") { return NoInterval; } const type = t === "M" ? "majorable" : "perfectable"; const name = "" + num + q; const dir = num < 0 ? -1 : 1; const simple = num === 8 || num === -8 ? num : dir * (step + 1); const alt = qToAlt(type, q); const oct = Math.floor((Math.abs(num) - 1) / 7); const semitones = dir * (SIZES[step] + alt + 12 * oct); const chroma = (dir * (SIZES[step] + alt) % 12 + 12) % 12; const coord = (0, import_pitch.coordinates)({ step, alt, oct, dir }); return { empty: false, name, num, q, step, alt, dir, type, simple, semitones, chroma, coord, oct }; } function coordToInterval(coord, forceDescending) { const [f, o = 0] = coord; const isDescending = f * 7 + o * 12 < 0; const ivl = forceDescending || isDescending ? [-f, -o, -1] : [f, o, 1]; return interval((0, import_pitch.pitch)(ivl)); } function qToAlt(type, q) { return q === "M" && type === "majorable" || q === "P" && type === "perfectable" ? 0 : q === "m" && type === "majorable" ? -1 : /^A+$/.test(q) ? q.length : /^d+$/.test(q) ? -1 * (type === "perfectable" ? q.length : q.length + 1) : 0; } function pitchName(props) { const { step, alt, oct = 0, dir } = props; if (!dir) { return ""; } const calcNum = step + 1 + 7 * oct; const num = calcNum === 0 ? step + 1 : calcNum; const d = dir < 0 ? "-" : ""; const type = TYPES[step] === "M" ? "majorable" : "perfectable"; const name = d + num + altToQ(type, alt); return name; } function altToQ(type, alt) { if (alt === 0) { return type === "majorable" ? "M" : "P"; } else if (alt === -1 && type === "majorable") { return "m"; } else if (alt > 0) { return fillStr("A", alt); } else { return fillStr("d", type === "perfectable" ? alt : alt + 1); } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { coordToInterval, interval, tokenizeInterval }); //# sourceMappingURL=index.js.map