danigb/interval-notation

View on GitHub
dist/interval-notation.js.map

Summary

Maintainability
Test Coverage
{"version":3,"file":"interval-notation.js","sources":["../index.js"],"sourcesContent":["// shorthand tonal notation (with quality after number)\nvar IVL_TNL = '([-+]?)(\\\\d+)(d{1,4}|m|M|P|A{1,4})'\n// standard shorthand notation (with quality before number)\nvar IVL_STR = '(AA|A|P|M|m|d|dd)([-+]?)(\\\\d+)'\nvar COMPOSE = '(?:(' + IVL_TNL + ')|(' + IVL_STR + '))'\nvar IVL_REGEX = new RegExp('^' + COMPOSE + '$')\n\n/**\n * Parse a string with an interval in shorthand notation (https://en.wikipedia.org/wiki/Interval_(music)#Shorthand_notation)\n * and returns an object with interval properties.\n *\n * @param {String} str - the string with the interval\n * @param {Boolean} strict - (Optional) if its false, it doesn't check if the\n * interval is valid or not. For example, parse('P2') returns null\n * (because a perfect second is not a valid interval), but\n * parse('P2', false) it returns { num: 2, dir: 1, q: 'P'... }\n * @return {Object} an object properties or null if not valid interval string\n * The returned object contains:\n * - `num`: the interval number\n * - `q`: the interval quality string (M is major, m is minor, P is perfect...)\n * - `simple`: the simplified number (from 1 to 7)\n * - `dir`: the interval direction (1 ascending, -1 descending)\n * - `type`: the interval type (P is perfectable, M is majorable)\n * - `alt`: the alteration, a numeric representation of the quality\n * - `oct`: the number of octaves the interval spans. 0 for simple intervals.\n * - `size`: the size of the interval in semitones\n * @example\n * var parse = require('interval-notation').parse\n * parse('M3')\n * // => { num: 3, q: 'M', dir: 1, simple: 3,\n * //      type: 'M', alt: 0, oct: 0, size: 4 }\n */\nexport function parse (str, strict) {\n  if (typeof str !== 'string') return null\n  var m = IVL_REGEX.exec(str)\n  if (!m) return null\n  var i = { num: +(m[3] || m[8]), q: m[4] || m[6] }\n  i.dir = (m[2] || m[7]) === '-' ? -1 : 1\n  var step = (i.num - 1) % 7\n  i.simple = step + 1\n  i.type = TYPES[step]\n  i.alt = qToAlt(i.type, i.q)\n  i.oct = Math.floor((i.num - 1) / 7)\n  i.size = i.dir * (SIZES[step] + i.alt + 12 * i.oct)\n  if (strict !== false) {\n    if (i.type === 'M' && i.q === 'P') return null\n  }\n  return i\n}\nvar SIZES = [0, 2, 4, 5, 7, 9, 11]\n\nvar TYPES = 'PMMPPMM'\n/**\n * Get the type of interval. Can be perfectavle ('P') or majorable ('M')\n * @param {Integer} num - the interval number\n * @return {String} `P` if it's perfectable, `M` if it's majorable.\n */\nexport function type (num) {\n  return TYPES[(num - 1) % 7]\n}\n\nfunction dirStr (dir) { return dir === -1 ? '-' : '' }\nfunction num (simple, oct) { return simple + 7 * oct }\n\n/**\n * Build a shorthand interval notation string from properties.\n *\n * @param {Integer} simple - the interval simple number (from 1 to 7)\n * @param {Integer} alt - the quality expressed in numbers. 0 means perfect\n * or major, depending of the interval number.\n * @param {Integer} oct - the number of octaves the interval spans.\n * 0 por simple intervals. Positive number.\n * @param {Integer} dir - the interval direction: 1 ascending, -1 descending.\n * @example\n * var interval = require('interval-notation')\n * interval.shorthand(3, 0, 0, 1) // => 'M3'\n * interval.shorthand(3, -1, 0, -1) // => 'm-3'\n * interval.shorthand(3, 1, 1, 1) // => 'A10'\n */\nexport function shorthand (simple, alt, oct, dir) {\n  return altToQ(simple, alt) + dirStr(dir) + num(simple, oct)\n}\n/**\n * Build a special shorthand interval notation string from properties.\n * The special shorthand interval notation changes the order or the standard\n * shorthand notation so instead of 'M-3' it returns '-3M'.\n *\n * The standard shorthand notation has a string 'A4' (augmented four) that can't\n * be differenciate from 'A4' (the A note in 4th octave), so the purpose of this\n * notation is avoid collisions\n *\n * @param {Integer} simple - the interval simple number (from 1 to 7)\n * @param {Integer} alt - the quality expressed in numbers. 0 means perfect\n * or major, depending of the interval number.\n * @param {Integer} oct - the number of octaves the interval spans.\n * 0 por simple intervals. Positive number.\n * @param {Integer} dir - the interval direction: 1 ascending, -1 descending.\n * @example\n * var interval = require('interval-notation')\n * interval.build(3, 0, 0, 1) // => '3M'\n * interval.build(3, -1, 0, -1) // => '-3m'\n * interval.build(3, 1, 1, 1) // => '10A'\n */\nexport function build (simple, alt, oct, dir) {\n  return dirStr(dir) + num(simple, oct) + altToQ(simple, alt)\n}\n\n/**\n * Get an alteration number from an interval quality string.\n * It accepts the standard `dmMPA` but also sharps and flats.\n *\n * @param {Integer|String} num - the interval number or a string representing\n * the interval type ('P' or 'M')\n * @param {String} quality - the quality string\n * @return {Integer} the interval alteration\n * @example\n * qToAlt('M', 'm') // => -1 (for majorables, 'm' is -1)\n * qToAlt('P', 'A') // => 1 (for perfectables, 'A' means 1)\n * qToAlt('M', 'P') // => null (majorables can't be perfect)\n */\nexport function qToAlt (num, q) {\n  var t = typeof num === 'number' ? type(num) : num\n  if (q === 'M' && t === 'M') return 0\n  if (q === 'P' && t === 'P') return 0\n  if (q === 'm' && t === 'M') return -1\n  if (/^A+$/.test(q)) return q.length\n  if (/^d+$/.test(q)) return t === 'P' ? -q.length : -q.length - 1\n  return null\n}\n\nfunction fillStr (s, n) { return Array(Math.abs(n) + 1).join(s) }\n/**\n * Get interval quality from interval type and alteration\n *\n * @function\n * @param {Integer|String} num - the interval number of the the interval\n * type ('M' for majorables, 'P' for perfectables)\n * @param {Integer} alt - the interval alteration\n * @return {String} the quality string\n * @example\n * altToQ('M', 0) // => 'M'\n */\nexport function altToQ (num, alt) {\n  var t = typeof num === 'number' ? type(Math.abs(num)) : num\n  if (alt === 0) return t === 'M' ? 'M' : 'P'\n  else if (alt === -1 && t === 'M') return 'm'\n  else if (alt > 0) return fillStr('A', alt)\n  else if (alt < 0) return fillStr('d', t === 'P' ? alt : alt + 1)\n  else return null\n}\n\n"],"names":["parse","str","strict","m","IVL_REGEX","exec","i","num","q","dir","step","simple","type","TYPES","alt","qToAlt","oct","Math","floor","size","SIZES","dirStr","shorthand","altToQ","build","t","test","length","fillStr","s","n","Array","abs","join","RegExp"],"mappings":"sNAgCA,SAAgBA,GAAOC,EAAKC,GAC1B,GAAmB,gBAARD,GAAkB,MAAO,KACpC,IAAIE,GAAIC,EAAUC,KAAKJ,EACvB,KAAKE,EAAG,MAAO,KACf,IAAIG,IAAMC,MAAOJ,EAAE,IAAMA,EAAE,IAAKK,EAAGL,EAAE,IAAMA,EAAE,GAC7CG,GAAEG,IAAyB,OAAlBN,EAAE,IAAMA,EAAE,KAAe,EAAI,CACtC,IAAIO,IAAQJ,EAAEC,IAAM,GAAK,CAMzB,OALAD,GAAEK,OAASD,EAAO,EAClBJ,EAAEM,KAAOC,EAAMH,GACfJ,EAAEQ,IAAMC,EAAOT,EAAEM,KAAMN,EAAEE,GACzBF,EAAEU,IAAMC,KAAKC,OAAOZ,EAAEC,IAAM,GAAK,GACjCD,EAAEa,KAAOb,EAAEG,KAAOW,EAAMV,GAAQJ,EAAEQ,IAAM,GAAKR,EAAEU,MAChC,IAAXd,GACa,MAAXI,EAAEM,MAAwB,MAARN,EAAEE,EAAkB,KAErCF,EAUT,QAAgBM,GAAML,GACpB,MAAOM,IAAON,EAAM,GAAK,GAG3B,QAASc,GAAQZ,GAAO,OAAgB,IAATA,EAAa,IAAM,GAClD,QAASF,GAAKI,EAAQK,GAAO,MAAOL,GAAS,EAAIK,EAiBjD,QAAgBM,GAAWX,EAAQG,EAAKE,EAAKP,GAC3C,MAAOc,GAAOZ,EAAQG,GAAOO,EAAOZ,GAAOF,EAAII,EAAQK,GAuBzD,QAAgBQ,GAAOb,EAAQG,EAAKE,EAAKP,GACvC,MAAOY,GAAOZ,GAAOF,EAAII,EAAQK,GAAOO,EAAOZ,EAAQG,GAgBzD,QAAgBC,GAAQR,EAAKC,GAC3B,GAAIiB,GAAmB,gBAARlB,GAAmBK,EAAKL,GAAOA,CAC9C,OAAU,MAANC,GAAmB,MAANiB,EAAkB,EACzB,MAANjB,GAAmB,MAANiB,EAAkB,EACzB,MAANjB,GAAmB,MAANiB,GAAmB,EAChC,OAAOC,KAAKlB,GAAWA,EAAEmB,OACzB,OAAOD,KAAKlB,GAAiB,MAANiB,GAAajB,EAAEmB,QAAUnB,EAAEmB,OAAS,EACxD,KAGT,QAASC,GAASC,EAAGC,GAAK,MAAOC,OAAMd,KAAKe,IAAIF,GAAK,GAAGG,KAAKJ,GAY7D,QAAgBN,GAAQhB,EAAKO,GAC3B,GAAIW,GAAmB,gBAARlB,GAAmBK,EAAKK,KAAKe,IAAIzB,IAAQA,CACxD,OAAY,KAARO,EAAwB,MAANW,EAAY,IAAM,KACtB,IAATX,GAAoB,MAANW,EAAkB,IAChCX,EAAM,EAAUc,EAAQ,IAAKd,GAC7BA,EAAM,EAAUc,EAAQ,IAAW,MAANH,EAAYX,EAAMA,EAAM,GAClD,KAnJd,GAIIV,GAAY,GAAI8B,QAAO,+EA4CvBd,GAAS,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,IAE3BP,EAAQ"}