New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

tonal-interval

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tonal-interval - npm Package Compare versions

Comparing version 0.69.9 to 1.0.0-0

test/interval.spec.js

347

build/index.js

@@ -5,5 +5,2 @@ 'use strict';

var intervalNotation = require('interval-notation');
var tonalPitch = require('tonal-pitch');
/**

@@ -31,3 +28,3 @@ * [![npm version](https://img.shields.io/npm/v/tonal-interval.svg)](https://www.npmjs.com/package/tonal-interval)

* import * as interval from 'tonal-interval'
* // or var interval = require('tonal-interval')
* // or const interval = require('tonal-interval')
* interval.semitones('4P') // => 5

@@ -46,92 +43,138 @@ * interval.invert('3m') // => '6M'

*/
// shorthand tonal notation (with quality after number)
const IVL_TNL = "([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})";
// standard shorthand notation (with quality before number)
const IVL_STR = "(AA|A|P|M|m|d|dd)([-+]?\\d+)";
const REGEX = new RegExp("^" + IVL_TNL + "|" + IVL_STR + "$");
const SIZES = [0, 2, 4, 5, 7, 9, 11];
const TYPES = "PMMPPMM";
const CLASSES = [0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1];
const tokenize = str => {
const m = REGEX.exec(str);
return m === null ? null : m[1] ? [m[1], m[2]] : [m[4], m[3]];
};
const NO_IVL = Object.freeze({
name: null,
num: null,
q: null,
step: null,
alt: null,
dir: null,
type: null,
simple: null,
semitones: null,
chroma: null,
ic: null
});
const fillStr = (s, n) => Array(Math.abs(n) + 1).join(s);
const qToAlt = (type, q) => {
if (q === "M" && type === "M") return 0;
if (q === "P" && type === "P") return 0;
if (q === "m" && type === "M") return -1;
if (/^A+$/.test(q)) return q.length;
if (/^d+$/.test(q)) return type === "P" ? -q.length : -q.length - 1;
return null;
};
const altToQ = (type, alt) => {
if (alt === 0) return type === "M" ? "M" : "P";
else if (alt === -1 && type === "M") return "m";
else if (alt > 0) return fillStr("A", alt);
else if (alt < 0) return fillStr("d", type === "P" ? alt : alt + 1);
else return null;
};
const properties = str => {
const t = tokenize(str);
if (t === null) return NO_IVL;
const p = { num: +t[0], q: t[1] };
p.step = (Math.abs(p.num) - 1) % 7;
p.type = TYPES[p.step];
if (p.type === "M" && p.q === "P") return NO_IVL;
p.name = "" + p.num + p.q;
p.dir = p.num < 0 ? -1 : 1;
p.simple = p.num === 8 || p.num === -8 ? p.num : p.dir * (p.step + 1);
p.alt = qToAlt(p.type, p.q);
p.oct = Math.floor((Math.abs(p.num) - 1) / 7);
p.semitones = p.dir * (SIZES[p.step] + p.alt + 12 * p.oct);
p.chroma = ((p.dir * (SIZES[p.step] + p.alt)) % 12 + 12) % 12;
p.ic = CLASSES[p.chroma];
return Object.freeze(p);
};
const cache = {};
/**
* Get interval name. Can be used to test if it's an interval. It accepts intervals
* as pitch or string in shorthand notation or tonal notation. It returns always
* intervals in tonal notation.
* Get interval properties. It returns an object with:
*
* @param {String|Pitch} interval - the interval string or array
* @return {String} the interval name or null if not valid interval
* @example
* interval.toInterval('m-3') // => '-3m'
* interval.toInterval('3') // => null
* - name: name
* - num: number
* - q: quality
* - step: step
* - alt: alteration
* - dir: direction (1 ascending, -1 descending)
* - type: "P" or "M" for perfectable or majorable
* - simple: the simplified number
* - semitones: the size in semitones
* - chroma: the interval chroma
* - ic: the interval class
*
* @function
* @param {String} interval - the interval
* @return {Object} the interval in the form [number, alt]
*/
function toInterval (ivl) {
var i = tonalPitch.asIvlPitch(ivl);
return i ? tonalPitch.strIvl(i) : null
function props(str) {
if (typeof str !== "string") return NO_IVL;
return cache[str] || (cache[str] = properties(str));
}
/**
* Get the number of the interval (same as value, but always positive)
* Get the number of the interval
*
* @param {String|Pitch} interval - the interval
* @return {Integer} the positive interval number (P1 is 1, m2 is 2, ...)
* @function
* @param {String} interval - the interval
* @return {Integer}
* @example
* interval.num('m2') // => 2
* interval.num('P9') // => 9
* interval.num('P-4') // => 4
* interval.num('P-4') // => -4
*/
function num (ivl) {
var p = props(ivl);
return p ? p.num : null
}
const num = str => props(str).num;
/**
* Get the interval value (the interval number, but positive or negative
* depending the interval direction)
* Get interval name. Can be used to test if it's an interval. It accepts intervals
* as pitch or string in shorthand notation or tonal notation. It returns always
* intervals in tonal notation.
*
* @param {String|Pitch} interval - the interval
* @return {Integer} the positive interval number (P1 is 1, m-2 is -2, ...)
* @function
* @param {String} interval - the interval string or array
* @return {String} the interval name or null if not valid interval
* @example
* interval.num('m2') // => 2
* interval.num('m9') // => 9
* interval.num('P-4') // => -4
* interval.num('m-9') // => -9
* interval.name('m-3') // => '-3m'
* interval.name('3') // => null
*/
function value (ivl) {
var p = props(ivl);
return p ? p.num * p.dir : null
}
const name = str => props(str).name;
/**
* Get interval properties. It returns an object with:
* Get interval type. Can be perfectable (1, 4, 5) or majorable (2, 3, 6, 7)
* It does NOT return the actual quality.
*
* - num: the interval number (always positive)
* - alt: the interval alteration (0 for perfect in perfectables, or 0 for major in _majorables_)
* - dir: the interval direction (1 ascending, -1 descending)
*
* @param {String|Pitch} interval - the interval
* @return {Array} the interval in the form [number, alt]
* @function
* @param {String} interval
* @return {String} 'P' for perfectables, 'M' for majorables or null if not
* valid interval
* @example
* interval.parse('m2') // => { num: 2, alt: -1, dir: 1 }
* interval.parse('m9') // => { num: 9, alt: -1, dir: 1 }
* interval.parse('P-4') // => { num: 4, alt: 0, dir: -1}
* interval.parse('m-9') // => { num: 9, alt: -1, dir: -1 }
* interval.type('5A') // => 'P'
*/
function props (ivl) {
var i = tonalPitch.asIvlPitch(ivl);
if (!i) return null
var d = tonalPitch.decode(i);
return { num: d[0] + 1 + d[2] * 7, alt: d[1], dir: i[2] }
}
const type = str => props(str).type;
/**
* Given a interval property object, get the interval name
*
* @param {Object} props - the interval property object
*
* - num: the interval number
* - alt: the interval alteration
* - dir: the direction
* @return {String} the interval name
*/
function fromProps (props) {
if (!props || props.num < 1) return null
var octs = Math.floor((props.num) / 8);
var simple = props.num - 7 * octs;
return intervalNotation.build(simple, props.alt || 0, octs, props.dir)
}
/**
* Get size in semitones of an interval
* @param {String|Pitch} ivl
*
* @function
* @param {String} ivl
* @return {Integer} the number of semitones or null if not an interval

@@ -142,34 +185,16 @@ * @example

* // or using tonal
* tonal.semitones('P5') // => 7
* tonal.interval.semitones('P5') // => 7
*/
function semitones (ivl) {
var i = tonalPitch.asIvlPitch(ivl);
return i ? tonalPitch.height(i) : null
}
const semitones = str => props(str).semitones;
// interval numbers
var IN = [1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7];
// interval qualities
var IQ = 'P m M m M P d P m M m M'.split(' ');
/**
* Get interval name from semitones number. Since there are several interval
* names for the same number, the name it's arbitraty, but deterministic.
* @param {Integer} num - the number of semitones (can be negative)
* @return {String} the interval name
* @example
* import { fromSemitones } from 'tonal-interval'
* fromSemitones(7) // => '5P'
* // or using tonal
* tonal.fromSemitones(-7) // => '-5P'
* Get the chroma of the interval. The chroma is a number between 0 and 7
* that represents the position within an octave (pitch set)
*
* @function
* @param {String} str
* @return {Number}
*/
function fromSemitones (num) {
var d = num < 0 ? -1 : 1;
var n = Math.abs(num);
var c = n % 12;
var o = Math.floor(n / 12);
return d * (IN[c] + 7 * o) + IQ[c]
}
const chroma = str => props(str).chroma;
var CLASSES = [0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1];
/**

@@ -185,2 +210,3 @@ * Get the [interval class](https://en.wikipedia.org/wiki/Interval_class)

*
* @function
* @param {String|Integer} interval - the interval or the number of semitones

@@ -194,25 +220,48 @@ * @return {Integer} A value between 0 and 6

*/
function ic (ivl) {
var i = tonalPitch.asIvlPitch(ivl);
var s = i ? tonalPitch.chr(i) : Math.round(ivl);
return isNaN(s) ? null : CLASSES[Math.abs(s) % 12]
}
const ic = str => props(str).ic;
var TYPES = 'PMMPPMM';
/**
* Get interval type. Can be perfectable (1, 4, 5) or majorable (2, 3, 6, 7)
* It does NOT return the actual quality.
* Given a interval property object, get the interval name
*
* @param {String|Pitch} interval
* @return {String} 'P' for perfectables, 'M' for majorables or null if not
* valid interval
* @function
* @param {Object} props - the interval property object
*
* - num: the interval number
* - alt: the interval alteration
* - oct: the number of octaves
* - dir: the direction
*
* @return {String} the interval name
* @example
* interval.type('5A') // => 'P'
* interval.build({ step: 1, alt: -1, oct: 0, dir: 1 }) // => "1d"
*/
function type (ivl) {
var i = tonalPitch.asIvlPitch(ivl);
return i ? TYPES[tonalPitch.decode(i)[0]] : null
}
const build = ({ step, alt, oct, dir } = {}) => {
if (step === undefined) return null;
const d = dir < 0 ? "-" : "";
const num = step + 1 + 7 * oct;
const type = TYPES[step];
return d + num + altToQ(type, alt);
};
/**
* Get the simplified version of an interval.
*
* @function
* @param {String} interval - the interval to simplify
* @return {String} the simplified interval
*
* @example
* interval.simplify('9M') // => '2M'
* ['8P', '9M', '10M', '11P', '12P', '13M', '14M', '15P'].map(interval.simplify)
* // => [ '8P', '2M', '3M', '4P', '5P', '6M', '7M', '8P' ]
* interval.simplify('2M') // => '2M'
* interval.simplify('-2M') // => '7m'
*/
const simplify = str => {
const p = props(str);
if (p === NO_IVL) return null;
return p.simple + p.q;
};
/**
* Get the inversion (https://en.wikipedia.org/wiki/Inversion_(music)#Intervals)

@@ -222,5 +271,5 @@ * of an interval.

* @function
* @param {String|Pitch} interval - the interval to invert in interval shorthand
* @param {String} interval - the interval to invert in interval shorthand
* notation or interval array notation
* @return {String|Pitch} the inverted interval
* @return {String} the inverted interval
*

@@ -231,43 +280,47 @@ * @example

*/
var invert = tonalPitch.ivlFn(function (i) {
var d = tonalPitch.decode(i);
// d = [step, alt, oct]
var step = (7 - d[0]) % 7;
var alt = TYPES[d[0]] === 'P' ? -d[1] : -(d[1] + 1);
return tonalPitch.encode(step, alt, d[2], tonalPitch.dir(i))
});
const invert = str => {
const p = props(str);
if (p === NO_IVL) return null;
const step = (7 - p.step) % 7;
const alt = p.type === "P" ? -p.alt : -(p.alt + 1);
return build({ step, alt, oct: p.oct, dir: p.dir });
};
// interval numbers
var IN = [1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7];
// interval qualities
var IQ = "P m M m M P d P m M m M".split(" ");
/**
* Get the simplified version of an interval.
*
* Get interval name from semitones number. Since there are several interval
* names for the same number, the name it's arbitraty, but deterministic.
*
* @function
* @param {String|Array} interval - the interval to simplify
* @return {String|Array} the simplified interval
*
* @param {Integer} num - the number of semitones (can be negative)
* @return {String} the interval name
* @example
* interval.simplify('9M') // => '2M'
* ['8P', '9M', '10M', '11P', '12P', '13M', '14M', '15P'].map(interval.simplify)
* // => [ '8P', '2M', '3M', '4P', '5P', '6M', '7M', '8P' ]
* interval.simplify('2M') // => '2M'
* interval.simplify('-2M') // => '7m'
* import { fromSemitones } from 'tonal-interval'
* fromSemitones(7) // => '5P'
* // or using tonal
* tonal.fromSemitones(-7) // => '-5P'
*/
var simplify = tonalPitch.ivlFn(function (i) {
// decode to [step, alt, octave]
var dec = tonalPitch.decode(i);
// if it's not 8 reduce the octaves to 0
if (dec[0] !== 0 || dec[2] !== 1) dec[2] = 0;
// encode back
return tonalPitch.encode(dec[0], dec[1], dec[2], tonalPitch.dir(i))
});
const fromSemitones = num => {
var d = num < 0 ? -1 : 1;
var n = Math.abs(num);
var c = n % 12;
var o = Math.floor(n / 12);
return d * (IN[c] + 7 * o) + IQ[c];
};
exports.toInterval = toInterval;
exports.tokenize = tokenize;
exports.props = props;
exports.num = num;
exports.value = value;
exports.props = props;
exports.fromProps = fromProps;
exports.name = name;
exports.type = type;
exports.semitones = semitones;
exports.fromSemitones = fromSemitones;
exports.chroma = chroma;
exports.ic = ic;
exports.type = type;
exports.build = build;
exports.simplify = simplify;
exports.invert = invert;
exports.simplify = simplify;
exports.fromSemitones = fromSemitones;

@@ -23,3 +23,3 @@ /**

* import * as interval from 'tonal-interval'
* // or var interval = require('tonal-interval')
* // or const interval = require('tonal-interval')
* interval.semitones('4P') // => 5

@@ -38,96 +38,138 @@ * interval.invert('3m') // => '6M'

*/
import { build } from 'interval-notation'
import { asIvlPitch, ivlFn, chr, dir,
strIvl, encode, decode, height } from 'tonal-pitch'
// shorthand tonal notation (with quality after number)
const IVL_TNL = "([-+]?\\d+)(d{1,4}|m|M|P|A{1,4})";
// standard shorthand notation (with quality before number)
const IVL_STR = "(AA|A|P|M|m|d|dd)([-+]?\\d+)";
const REGEX = new RegExp("^" + IVL_TNL + "|" + IVL_STR + "$");
const SIZES = [0, 2, 4, 5, 7, 9, 11];
const TYPES = "PMMPPMM";
const CLASSES = [0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1];
export const tokenize = str => {
const m = REGEX.exec(str);
return m === null ? null : m[1] ? [m[1], m[2]] : [m[4], m[3]];
};
const NO_IVL = Object.freeze({
name: null,
num: null,
q: null,
step: null,
alt: null,
dir: null,
type: null,
simple: null,
semitones: null,
chroma: null,
ic: null
});
const fillStr = (s, n) => Array(Math.abs(n) + 1).join(s);
const qToAlt = (type, q) => {
if (q === "M" && type === "M") return 0;
if (q === "P" && type === "P") return 0;
if (q === "m" && type === "M") return -1;
if (/^A+$/.test(q)) return q.length;
if (/^d+$/.test(q)) return type === "P" ? -q.length : -q.length - 1;
return null;
};
const altToQ = (type, alt) => {
if (alt === 0) return type === "M" ? "M" : "P";
else if (alt === -1 && type === "M") return "m";
else if (alt > 0) return fillStr("A", alt);
else if (alt < 0) return fillStr("d", type === "P" ? alt : alt + 1);
else return null;
};
const properties = str => {
const t = tokenize(str);
if (t === null) return NO_IVL;
const p = { num: +t[0], q: t[1] };
p.step = (Math.abs(p.num) - 1) % 7;
p.type = TYPES[p.step];
if (p.type === "M" && p.q === "P") return NO_IVL;
p.name = "" + p.num + p.q;
p.dir = p.num < 0 ? -1 : 1;
p.simple = p.num === 8 || p.num === -8 ? p.num : p.dir * (p.step + 1);
p.alt = qToAlt(p.type, p.q);
p.oct = Math.floor((Math.abs(p.num) - 1) / 7);
p.semitones = p.dir * (SIZES[p.step] + p.alt + 12 * p.oct);
p.chroma = ((p.dir * (SIZES[p.step] + p.alt)) % 12 + 12) % 12;
p.ic = CLASSES[p.chroma];
return Object.freeze(p);
};
const cache = {};
/**
* Get interval name. Can be used to test if it's an interval. It accepts intervals
* as pitch or string in shorthand notation or tonal notation. It returns always
* intervals in tonal notation.
* Get interval properties. It returns an object with:
*
* @param {String|Pitch} interval - the interval string or array
* @return {String} the interval name or null if not valid interval
* @example
* interval.toInterval('m-3') // => '-3m'
* interval.toInterval('3') // => null
* - name: name
* - num: number
* - q: quality
* - step: step
* - alt: alteration
* - dir: direction (1 ascending, -1 descending)
* - type: "P" or "M" for perfectable or majorable
* - simple: the simplified number
* - semitones: the size in semitones
* - chroma: the interval chroma
* - ic: the interval class
*
* @function
* @param {String} interval - the interval
* @return {Object} the interval in the form [number, alt]
*/
export function toInterval (ivl) {
var i = asIvlPitch(ivl)
return i ? strIvl(i) : null
export function props(str) {
if (typeof str !== "string") return NO_IVL;
return cache[str] || (cache[str] = properties(str));
}
/**
* Get the number of the interval (same as value, but always positive)
* Get the number of the interval
*
* @param {String|Pitch} interval - the interval
* @return {Integer} the positive interval number (P1 is 1, m2 is 2, ...)
* @function
* @param {String} interval - the interval
* @return {Integer}
* @example
* interval.num('m2') // => 2
* interval.num('P9') // => 9
* interval.num('P-4') // => 4
* interval.num('P-4') // => -4
*/
export function num (ivl) {
var p = props(ivl)
return p ? p.num : null
}
export const num = str => props(str).num;
/**
* Get the interval value (the interval number, but positive or negative
* depending the interval direction)
* Get interval name. Can be used to test if it's an interval. It accepts intervals
* as pitch or string in shorthand notation or tonal notation. It returns always
* intervals in tonal notation.
*
* @param {String|Pitch} interval - the interval
* @return {Integer} the positive interval number (P1 is 1, m-2 is -2, ...)
* @function
* @param {String} interval - the interval string or array
* @return {String} the interval name or null if not valid interval
* @example
* interval.num('m2') // => 2
* interval.num('m9') // => 9
* interval.num('P-4') // => -4
* interval.num('m-9') // => -9
* interval.name('m-3') // => '-3m'
* interval.name('3') // => null
*/
export function value (ivl) {
var p = props(ivl)
return p ? p.num * p.dir : null
}
export const name = str => props(str).name;
/**
* Get interval properties. It returns an object with:
* Get interval type. Can be perfectable (1, 4, 5) or majorable (2, 3, 6, 7)
* It does NOT return the actual quality.
*
* - num: the interval number (always positive)
* - alt: the interval alteration (0 for perfect in perfectables, or 0 for major in _majorables_)
* - dir: the interval direction (1 ascending, -1 descending)
*
* @param {String|Pitch} interval - the interval
* @return {Array} the interval in the form [number, alt]
* @function
* @param {String} interval
* @return {String} 'P' for perfectables, 'M' for majorables or null if not
* valid interval
* @example
* interval.parse('m2') // => { num: 2, alt: -1, dir: 1 }
* interval.parse('m9') // => { num: 9, alt: -1, dir: 1 }
* interval.parse('P-4') // => { num: 4, alt: 0, dir: -1}
* interval.parse('m-9') // => { num: 9, alt: -1, dir: -1 }
* interval.type('5A') // => 'P'
*/
export function props (ivl) {
var i = asIvlPitch(ivl)
if (!i) return null
var d = decode(i)
return { num: d[0] + 1 + d[2] * 7, alt: d[1], dir: i[2] }
}
export const type = str => props(str).type;
/**
* Given a interval property object, get the interval name
*
* @param {Object} props - the interval property object
*
* - num: the interval number
* - alt: the interval alteration
* - dir: the direction
* @return {String} the interval name
*/
export function fromProps (props) {
if (!props || props.num < 1) return null
var octs = Math.floor((props.num) / 8)
var simple = props.num - 7 * octs
return build(simple, props.alt || 0, octs, props.dir)
}
/**
* Get size in semitones of an interval
* @param {String|Pitch} ivl
*
* @function
* @param {String} ivl
* @return {Integer} the number of semitones or null if not an interval

@@ -138,34 +180,16 @@ * @example

* // or using tonal
* tonal.semitones('P5') // => 7
* tonal.interval.semitones('P5') // => 7
*/
export function semitones (ivl) {
var i = asIvlPitch(ivl)
return i ? height(i) : null
}
export const semitones = str => props(str).semitones;
// interval numbers
var IN = [1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7]
// interval qualities
var IQ = 'P m M m M P d P m M m M'.split(' ')
/**
* Get interval name from semitones number. Since there are several interval
* names for the same number, the name it's arbitraty, but deterministic.
* @param {Integer} num - the number of semitones (can be negative)
* @return {String} the interval name
* @example
* import { fromSemitones } from 'tonal-interval'
* fromSemitones(7) // => '5P'
* // or using tonal
* tonal.fromSemitones(-7) // => '-5P'
* Get the chroma of the interval. The chroma is a number between 0 and 7
* that represents the position within an octave (pitch set)
*
* @function
* @param {String} str
* @return {Number}
*/
export function fromSemitones (num) {
var d = num < 0 ? -1 : 1
var n = Math.abs(num)
var c = n % 12
var o = Math.floor(n / 12)
return d * (IN[c] + 7 * o) + IQ[c]
}
export const chroma = str => props(str).chroma;
var CLASSES = [0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]
/**

@@ -181,2 +205,3 @@ * Get the [interval class](https://en.wikipedia.org/wiki/Interval_class)

*
* @function
* @param {String|Integer} interval - the interval or the number of semitones

@@ -190,25 +215,48 @@ * @return {Integer} A value between 0 and 6

*/
export function ic (ivl) {
var i = asIvlPitch(ivl)
var s = i ? chr(i) : Math.round(ivl)
return isNaN(s) ? null : CLASSES[Math.abs(s) % 12]
}
export const ic = str => props(str).ic;
var TYPES = 'PMMPPMM'
/**
* Get interval type. Can be perfectable (1, 4, 5) or majorable (2, 3, 6, 7)
* It does NOT return the actual quality.
* Given a interval property object, get the interval name
*
* @param {String|Pitch} interval
* @return {String} 'P' for perfectables, 'M' for majorables or null if not
* valid interval
* @function
* @param {Object} props - the interval property object
*
* - num: the interval number
* - alt: the interval alteration
* - oct: the number of octaves
* - dir: the direction
*
* @return {String} the interval name
* @example
* interval.type('5A') // => 'P'
* interval.build({ step: 1, alt: -1, oct: 0, dir: 1 }) // => "1d"
*/
export function type (ivl) {
var i = asIvlPitch(ivl)
return i ? TYPES[decode(i)[0]] : null
}
export const build = ({ step, alt, oct, dir } = {}) => {
if (step === undefined) return null;
const d = dir < 0 ? "-" : "";
const num = step + 1 + 7 * oct;
const type = TYPES[step];
return d + num + altToQ(type, alt);
};
/**
* Get the simplified version of an interval.
*
* @function
* @param {String} interval - the interval to simplify
* @return {String} the simplified interval
*
* @example
* interval.simplify('9M') // => '2M'
* ['8P', '9M', '10M', '11P', '12P', '13M', '14M', '15P'].map(interval.simplify)
* // => [ '8P', '2M', '3M', '4P', '5P', '6M', '7M', '8P' ]
* interval.simplify('2M') // => '2M'
* interval.simplify('-2M') // => '7m'
*/
export const simplify = str => {
const p = props(str);
if (p === NO_IVL) return null;
return p.simple + p.q;
};
/**
* Get the inversion (https://en.wikipedia.org/wiki/Inversion_(music)#Intervals)

@@ -218,5 +266,5 @@ * of an interval.

* @function
* @param {String|Pitch} interval - the interval to invert in interval shorthand
* @param {String} interval - the interval to invert in interval shorthand
* notation or interval array notation
* @return {String|Pitch} the inverted interval
* @return {String} the inverted interval
*

@@ -227,31 +275,34 @@ * @example

*/
export var invert = ivlFn(function (i) {
var d = decode(i)
// d = [step, alt, oct]
var step = (7 - d[0]) % 7
var alt = TYPES[d[0]] === 'P' ? -d[1] : -(d[1] + 1)
return encode(step, alt, d[2], dir(i))
})
export const invert = str => {
const p = props(str);
if (p === NO_IVL) return null;
const step = (7 - p.step) % 7;
const alt = p.type === "P" ? -p.alt : -(p.alt + 1);
return build({ step, alt, oct: p.oct, dir: p.dir });
};
// interval numbers
var IN = [1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7];
// interval qualities
var IQ = "P m M m M P d P m M m M".split(" ");
/**
* Get the simplified version of an interval.
*
* Get interval name from semitones number. Since there are several interval
* names for the same number, the name it's arbitraty, but deterministic.
*
* @function
* @param {String|Array} interval - the interval to simplify
* @return {String|Array} the simplified interval
*
* @param {Integer} num - the number of semitones (can be negative)
* @return {String} the interval name
* @example
* interval.simplify('9M') // => '2M'
* ['8P', '9M', '10M', '11P', '12P', '13M', '14M', '15P'].map(interval.simplify)
* // => [ '8P', '2M', '3M', '4P', '5P', '6M', '7M', '8P' ]
* interval.simplify('2M') // => '2M'
* interval.simplify('-2M') // => '7m'
* import { fromSemitones } from 'tonal-interval'
* fromSemitones(7) // => '5P'
* // or using tonal
* tonal.fromSemitones(-7) // => '-5P'
*/
export var simplify = ivlFn(function (i) {
// decode to [step, alt, octave]
var dec = decode(i)
// if it's not 8 reduce the octaves to 0
if (dec[0] !== 0 || dec[2] !== 1) dec[2] = 0
// encode back
return encode(dec[0], dec[1], dec[2], dir(i))
})
export const fromSemitones = num => {
var d = num < 0 ? -1 : 1;
var n = Math.abs(num);
var c = n % 12;
var o = Math.floor(n / 12);
return d * (IN[c] + 7 * o) + IQ[c];
};
{
"name": "tonal-interval",
"version": "0.69.9",
"version": "1.0.0-0",
"description": "Music interval creation and manipulation",

@@ -20,6 +20,7 @@ "repository": "https://github.com/danigb/tonal/packages/interval",

"license": "MIT",
"dependencies": {
"interval-notation": "^1.0.0",
"tonal-pitch": "^0.69.7"
"babel": {
"presets": [
"es2015"
]
}
}

@@ -25,3 +25,3 @@ <a name="module_interval"></a>

import * as interval from 'tonal-interval'
// or var interval = require('tonal-interval')
// or const interval = require('tonal-interval')
interval.semitones('4P') // => 5

@@ -40,44 +40,48 @@ interval.invert('3m') // => '6M'

* [interval](#module_interval)
* [`.toInterval(interval)`](#module_interval.toInterval) ⇒ <code>String</code>
* [`.props(interval)`](#module_interval.props) ⇒ <code>Object</code>
* [`.num(interval)`](#module_interval.num) ⇒ <code>Integer</code>
* [`.value(interval)`](#module_interval.value) ⇒ <code>Integer</code>
* [`.props(interval)`](#module_interval.props) ⇒ <code>Array</code>
* [`.fromProps(props)`](#module_interval.fromProps) ⇒ <code>String</code>
* [`.name(interval)`](#module_interval.name) ⇒ <code>String</code>
* [`.type(interval)`](#module_interval.type) ⇒ <code>String</code>
* [`.semitones(ivl)`](#module_interval.semitones) ⇒ <code>Integer</code>
* [`.chroma(str)`](#module_interval.chroma) ⇒ <code>Number</code>
* [`.ic(interval)`](#module_interval.ic) ⇒ <code>Integer</code>
* [`.build(props)`](#module_interval.build) ⇒ <code>String</code>
* [`.simplify(interval)`](#module_interval.simplify) ⇒ <code>String</code>
* [`.invert(interval)`](#module_interval.invert) ⇒ <code>String</code>
* [`.fromSemitones(num)`](#module_interval.fromSemitones) ⇒ <code>String</code>
* [`.ic(interval)`](#module_interval.ic) ⇒ <code>Integer</code>
* [`.type(interval)`](#module_interval.type) ⇒ <code>String</code>
* [`.invert(interval)`](#module_interval.invert) ⇒ <code>String</code> \| <code>Pitch</code>
* [`.simplify(interval)`](#module_interval.simplify) ⇒ <code>String</code> \| <code>Array</code>
<a name="module_interval.toInterval"></a>
<a name="module_interval.props"></a>
## `interval.toInterval(interval)` ⇒ <code>String</code>
Get interval name. Can be used to test if it's an interval. It accepts intervals
as pitch or string in shorthand notation or tonal notation. It returns always
intervals in tonal notation.
## `interval.props(interval)` ⇒ <code>Object</code>
Get interval properties. It returns an object with:
- name: name
- num: number
- q: quality
- step: step
- alt: alteration
- dir: direction (1 ascending, -1 descending)
- type: "P" or "M" for perfectable or majorable
- simple: the simplified number
- semitones: the size in semitones
- chroma: the interval chroma
- ic: the interval class
**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>String</code> - the interval name or null if not valid interval
**Returns**: <code>Object</code> - the interval in the form [number, alt]
| Param | Type | Description |
| --- | --- | --- |
| interval | <code>String</code> \| <code>Pitch</code> | the interval string or array |
| interval | <code>String</code> | the interval |
**Example**
```js
interval.toInterval('m-3') // => '-3m'
interval.toInterval('3') // => null
```
<a name="module_interval.num"></a>
## `interval.num(interval)` ⇒ <code>Integer</code>
Get the number of the interval (same as value, but always positive)
Get the number of the interval
**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>Integer</code> - the positive interval number (P1 is 1, m2 is 2, ...)
| Param | Type | Description |
| --- | --- | --- |
| interval | <code>String</code> \| <code>Pitch</code> | the interval |
| interval | <code>String</code> | the interval |

@@ -88,59 +92,41 @@ **Example**

interval.num('P9') // => 9
interval.num('P-4') // => 4
interval.num('P-4') // => -4
```
<a name="module_interval.value"></a>
<a name="module_interval.name"></a>
## `interval.value(interval)` ⇒ <code>Integer</code>
Get the interval value (the interval number, but positive or negative
depending the interval direction)
## `interval.name(interval)` ⇒ <code>String</code>
Get interval name. Can be used to test if it's an interval. It accepts intervals
as pitch or string in shorthand notation or tonal notation. It returns always
intervals in tonal notation.
**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>Integer</code> - the positive interval number (P1 is 1, m-2 is -2, ...)
**Returns**: <code>String</code> - the interval name or null if not valid interval
| Param | Type | Description |
| --- | --- | --- |
| interval | <code>String</code> \| <code>Pitch</code> | the interval |
| interval | <code>String</code> | the interval string or array |
**Example**
```js
interval.num('m2') // => 2
interval.num('m9') // => 9
interval.num('P-4') // => -4
interval.num('m-9') // => -9
interval.name('m-3') // => '-3m'
interval.name('3') // => null
```
<a name="module_interval.props"></a>
<a name="module_interval.type"></a>
## `interval.props(interval)` ⇒ <code>Array</code>
Get interval properties. It returns an object with:
## `interval.type(interval)` ⇒ <code>String</code>
Get interval type. Can be perfectable (1, 4, 5) or majorable (2, 3, 6, 7)
It does NOT return the actual quality.
- num: the interval number (always positive)
- alt: the interval alteration (0 for perfect in perfectables, or 0 for major in _majorables_)
- dir: the interval direction (1 ascending, -1 descending)
**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>Array</code> - the interval in the form [number, alt]
**Returns**: <code>String</code> - 'P' for perfectables, 'M' for majorables or null if not
valid interval
| Param | Type | Description |
| --- | --- | --- |
| interval | <code>String</code> \| <code>Pitch</code> | the interval |
| Param | Type |
| --- | --- |
| interval | <code>String</code> |
**Example**
```js
interval.parse('m2') // => { num: 2, alt: -1, dir: 1 }
interval.parse('m9') // => { num: 9, alt: -1, dir: 1 }
interval.parse('P-4') // => { num: 4, alt: 0, dir: -1}
interval.parse('m-9') // => { num: 9, alt: -1, dir: -1 }
interval.type('5A') // => 'P'
```
<a name="module_interval.fromProps"></a>
## `interval.fromProps(props)` ⇒ <code>String</code>
Given a interval property object, get the interval name
**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>String</code> - the interval name
| Param | Type | Description |
| --- | --- | --- |
| props | <code>Object</code> | the interval property object - num: the interval number - alt: the interval alteration - dir: the direction |
<a name="module_interval.semitones"></a>

@@ -156,3 +142,3 @@

| --- | --- |
| ivl | <code>String</code> \| <code>Pitch</code> |
| ivl | <code>String</code> |

@@ -164,24 +150,16 @@ **Example**

// or using tonal
tonal.semitones('P5') // => 7
tonal.interval.semitones('P5') // => 7
```
<a name="module_interval.fromSemitones"></a>
<a name="module_interval.chroma"></a>
## `interval.fromSemitones(num)` ⇒ <code>String</code>
Get interval name from semitones number. Since there are several interval
names for the same number, the name it's arbitraty, but deterministic.
## `interval.chroma(str)` ⇒ <code>Number</code>
Get the chroma of the interval. The chroma is a number between 0 and 7
that represents the position within an octave (pitch set)
**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>String</code> - the interval name
| Param | Type | Description |
| --- | --- | --- |
| num | <code>Integer</code> | the number of semitones (can be negative) |
| Param | Type |
| --- | --- |
| str | <code>String</code> |
**Example**
```js
import { fromSemitones } from 'tonal-interval'
fromSemitones(7) // => '5P'
// or using tonal
tonal.fromSemitones(-7) // => '-5P'
```
<a name="module_interval.ic"></a>

@@ -212,23 +190,41 @@

```
<a name="module_interval.type"></a>
<a name="module_interval.build"></a>
## `interval.type(interval)` ⇒ <code>String</code>
Get interval type. Can be perfectable (1, 4, 5) or majorable (2, 3, 6, 7)
It does NOT return the actual quality.
## `interval.build(props)` ⇒ <code>String</code>
Given a interval property object, get the interval name
**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>String</code> - 'P' for perfectables, 'M' for majorables or null if not
valid interval
**Returns**: <code>String</code> - the interval name
| Param | Type |
| --- | --- |
| interval | <code>String</code> \| <code>Pitch</code> |
| Param | Type | Description |
| --- | --- | --- |
| props | <code>Object</code> | the interval property object - num: the interval number - alt: the interval alteration - oct: the number of octaves - dir: the direction |
**Example**
```js
interval.type('5A') // => 'P'
interval.build({ step: 1, alt: -1, oct: 0, dir: 1 }) // => "1d"
```
<a name="module_interval.simplify"></a>
## `interval.simplify(interval)` ⇒ <code>String</code>
Get the simplified version of an interval.
**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>String</code> - the simplified interval
| Param | Type | Description |
| --- | --- | --- |
| interval | <code>String</code> | the interval to simplify |
**Example**
```js
interval.simplify('9M') // => '2M'
['8P', '9M', '10M', '11P', '12P', '13M', '14M', '15P'].map(interval.simplify)
// => [ '8P', '2M', '3M', '4P', '5P', '6M', '7M', '8P' ]
interval.simplify('2M') // => '2M'
interval.simplify('-2M') // => '7m'
```
<a name="module_interval.invert"></a>
## `interval.invert(interval)` ⇒ <code>String</code> \| <code>Pitch</code>
## `interval.invert(interval)` ⇒ <code>String</code>
Get the inversion (https://en.wikipedia.org/wiki/Inversion_(music)#Intervals)

@@ -238,7 +234,7 @@ of an interval.

**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>String</code> \| <code>Pitch</code> - the inverted interval
**Returns**: <code>String</code> - the inverted interval
| Param | Type | Description |
| --- | --- | --- |
| interval | <code>String</code> \| <code>Pitch</code> | the interval to invert in interval shorthand notation or interval array notation |
| interval | <code>String</code> | the interval to invert in interval shorthand notation or interval array notation |

@@ -250,21 +246,21 @@ **Example**

```
<a name="module_interval.simplify"></a>
<a name="module_interval.fromSemitones"></a>
## `interval.simplify(interval)` ⇒ <code>String</code> \| <code>Array</code>
Get the simplified version of an interval.
## `interval.fromSemitones(num)` ⇒ <code>String</code>
Get interval name from semitones number. Since there are several interval
names for the same number, the name it's arbitraty, but deterministic.
**Kind**: static method of [<code>interval</code>](#module_interval)
**Returns**: <code>String</code> \| <code>Array</code> - the simplified interval
**Returns**: <code>String</code> - the interval name
| Param | Type | Description |
| --- | --- | --- |
| interval | <code>String</code> \| <code>Array</code> | the interval to simplify |
| num | <code>Integer</code> | the number of semitones (can be negative) |
**Example**
```js
interval.simplify('9M') // => '2M'
['8P', '9M', '10M', '11P', '12P', '13M', '14M', '15P'].map(interval.simplify)
// => [ '8P', '2M', '3M', '4P', '5P', '6M', '7M', '8P' ]
interval.simplify('2M') // => '2M'
interval.simplify('-2M') // => '7m'
import { fromSemitones } from 'tonal-interval'
fromSemitones(7) // => '5P'
// or using tonal
tonal.fromSemitones(-7) // => '-5P'
```
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc