tonal-distance
Advanced tools
Comparing version 0.69.7 to 1.0.0-0
@@ -5,44 +5,213 @@ 'use strict'; | ||
var tonalPitch = require('tonal-pitch'); | ||
var index = require('tonal-note/index'); | ||
var index$1 = require('tonal-interval/index'); | ||
/** | ||
* Functions to calculate distances between notes | ||
* [![npm version](https://img.shields.io/npm/v/tonal-distance.svg)](https://www.npmjs.com/package/tonal-distance) | ||
* [![tonal](https://img.shields.io/badge/tonal-distance-yellow.svg)](https://github.com/danigb/tonal/tree/master/packages/tonal/distance) | ||
* | ||
* Transpose notes by intervals and find distances between notes | ||
* | ||
* @example | ||
* // using node's require | ||
* var distance = require('tonal-distance') | ||
* distance.interval('C4', 'G4') // => '5P' | ||
* | ||
* @example | ||
* // using ES6 import | ||
* import { interval, semitones } from 'tonal-distance' | ||
* import { interval, semitones, transpose } from 'tonal-distance' | ||
* semitones('C' ,'D') // => 2 | ||
* interval('C4', 'G4') // => '5P' | ||
* transpose('C4', 'P5') // => 'G4' | ||
* | ||
* // included in tonal facade | ||
* const tonal = require('tonal'); | ||
* tonal.distance.transpose('C4', 'P5') | ||
* tonal.distance.transposeBy('P5', 'C4') | ||
* | ||
* @module distance | ||
*/ | ||
// substract two pitches | ||
function substr (a, b) { | ||
if (!a || !b || a[1].length !== b[1].length) return null | ||
var f = tonalPitch.fifths(b) - tonalPitch.fifths(a); | ||
if (tonalPitch.isPC(a)) return tonalPitch.pitch(f, -Math.floor(f * 7 / 12), 1) | ||
var o = tonalPitch.focts(b) - tonalPitch.focts(a); | ||
var d = tonalPitch.height(b) - tonalPitch.height(a) < 0 ? -1 : 1; | ||
return tonalPitch.pitch(d * f, d * o, d) | ||
// Map from letter step to number of fifths starting from 'C': | ||
// { C: 0, D: 2, E: 4, F: -1, G: 1, A: 3, B: 5 } | ||
const FIFTHS = [0, 2, 4, -1, 1, 3, 5]; | ||
// Given a number of fifths, return the octaves they span | ||
const fOcts = f => Math.floor(f * 7 / 12); | ||
// Get the number of octaves it span each step | ||
const FIFTH_OCTS = FIFTHS.map(fOcts); | ||
const encode = ({ step, alt, oct, dir = 1 }) => { | ||
const f = FIFTHS[step] + 7 * alt; | ||
if (oct === null) return [dir * f]; | ||
const o = oct - FIFTH_OCTS[step] - 4 * alt; | ||
return [dir * f, dir * o]; | ||
}; | ||
// We need to get the steps from fifths | ||
// Fifths for CDEFGAB are [ 0, 2, 4, -1, 1, 3, 5 ] | ||
// We add 1 to fifths to avoid negative numbers, so: | ||
// for ['F', 'C', 'G', 'D', 'A', 'E', 'B'] we have: | ||
const STEPS = [3, 0, 4, 1, 5, 2, 6]; | ||
// Return the number of fifths as if it were unaltered | ||
function unaltered(f) { | ||
const i = (f + 1) % 7; | ||
return i < 0 ? 7 + i : i; | ||
} | ||
const decode = (f, o, dir) => { | ||
const step = STEPS[unaltered(f)]; | ||
const alt = Math.floor((f + 1) / 7); | ||
if (o === undefined) return { step, alt, dir }; | ||
const oct = o + 4 * alt + FIFTH_OCTS[step]; | ||
return { step, alt, oct, dir }; | ||
}; | ||
const memo = (fn, cache = {}) => str => cache[str] || (cache[str] = fn(str)); | ||
const encoder = props$$1 => | ||
memo(str => { | ||
const p = props$$1(str); | ||
return p.name === null ? null : encode(p); | ||
}); | ||
const encodeNote = encoder(index.props); | ||
const encodeIvl = encoder(index$1.props); | ||
/** | ||
* Find the interval between two pitches. Both pitches MUST be of the same type: | ||
* Transpose a note by an interval. The note can be a pitch class. | ||
* | ||
* This function can be partially applied. | ||
* | ||
* @param {String} note | ||
* @param {String} interval | ||
* @return {String} the transposed note | ||
* @example | ||
* import { tranpose } from 'tonal-distance' | ||
* transpose('d3', '3M') // => 'F#3' | ||
* // it works with pitch classes | ||
* transpose('D', '3M') // => 'F#' | ||
* // can be partially applied | ||
* ['C', 'D', 'E', 'F', 'G'].map(transpose('M3)) // => ['E', 'F#', 'G#', 'A', 'B'] | ||
*/ | ||
function transpose(note, interval) { | ||
if (arguments.length === 1) return i => transpose(note, i); | ||
const n = encodeNote(note); | ||
const i = encodeIvl(interval); | ||
if (n === null || i === null) return null; | ||
const tr = n.length === 1 ? [n[0] + i[0]] : [n[0] + i[0], n[1] + i[1]]; | ||
return index.build(decode(tr[0], tr[1])); | ||
} | ||
/** | ||
* Transpose a pitch class by a number of perfect fifths. | ||
* | ||
* It can be partially applied. | ||
* | ||
* - notes: it returns the interval between the first and the second | ||
* - pitch classes: it returns the __ascending__ interval between both | ||
* - intervals: substract one from the other | ||
* @function | ||
* @param {String} pitchClass - the pitch class | ||
* @param {Integer} fifhts - the number of fifths | ||
* @return {String} the transposed pitch class | ||
* | ||
* @example | ||
* import { trFifths } from 'tonal-transpose' | ||
* [0, 1, 2, 3, 4].map(trFifths('C')) // => ['C', 'G', 'D', 'A', 'E'] | ||
* // or using tonal | ||
* tonal.trFifths('G4', 1) // => 'D' | ||
*/ | ||
function trFifths(note, fifths) { | ||
if (arguments.length === 1) return f => trFifths(note, f); | ||
const n = encodeNote(note); | ||
if (n === null) return null; | ||
return index.build(decode(n[0] + fifths)); | ||
} | ||
/** | ||
* Get the distance in fifths between pitch classes | ||
* | ||
* Can be partially applied. | ||
* | ||
* @param {String} to - note or pitch class | ||
* @param {String} from - note or pitch class | ||
*/ | ||
function fifths(from, to) { | ||
if (arguments.length === 1) return to => fifths(from, to); | ||
const f = encodeNote(from); | ||
const t = encodeNote(to); | ||
if (t === null || f === null) return null; | ||
return t[0] - f[0]; | ||
} | ||
/** | ||
* The same as transpose with the arguments inverted. | ||
* | ||
* Can be partially applied. | ||
* | ||
* @param {String} note | ||
* @param {String} interval | ||
* @return {String} the transposed note | ||
* @example | ||
* import { tranposeBy } from 'tonal-distance' | ||
* transposeBy('3m', '5P') // => '7m' | ||
*/ | ||
function transposeBy(interval, note) { | ||
if (arguments.length === 1) return n => transpose(n, interval); | ||
return transpose(note, interval); | ||
} | ||
const isDescending = e => e[0] * 7 + e[1] * 12 < 0; | ||
const decodeIvl = i => | ||
isDescending(i) ? decode(-i[0], -i[1], -1) : decode(i[0], i[1], 1); | ||
function addIntervals(ivl1, ivl2, dir) { | ||
const i1 = encodeIvl(ivl1); | ||
const i2 = encodeIvl(ivl2); | ||
if (i1 === null || i2 === null) return null; | ||
const i = [i1[0] + dir * i2[0], i1[1] + dir * i2[1]]; | ||
return index$1.build(decodeIvl(i)); | ||
} | ||
/** | ||
* Add two intervals | ||
* | ||
* Can be partially applied. | ||
* | ||
* @param {String} interval1 | ||
* @param {String} interval2 | ||
* @return {String} the resulting interval | ||
* @example | ||
* import { add } from 'tonal-distance' | ||
* add('3m', '5P') // => '7m' | ||
*/ | ||
function add(ivl1, ivl2) { | ||
if (arguments.length === 1) return i2 => add(ivl1, i2); | ||
return addIntervals(ivl1, ivl2, 1); | ||
} | ||
/** | ||
* Subtract two intervals | ||
* | ||
* Can be partially applied | ||
* | ||
* @param {String} minuend | ||
* @param {String} subtrahend | ||
* @return {String} interval diference | ||
*/ | ||
function subtract(ivl1, ivl2) { | ||
if (arguments.length === 1) return i2 => add(ivl1, i2); | ||
return addIntervals(ivl1, ivl2, -1); | ||
} | ||
/** | ||
* Find the interval between two pitches. It works with pitch classes | ||
* (both must be pitch classes and the interval is always ascending) | ||
* | ||
* Can be partially applied | ||
* | ||
* @param {Pitch|String} from - distance from | ||
* @param {Pitch|String} to - distance to | ||
* @return {Interval} the distance between pitches | ||
* @param {String} from - distance from | ||
* @param {String} to - distance to | ||
* @return {String} the interval distance | ||
* | ||
* @example | ||
* var distance = require('tonal-distance') | ||
* distance.interval('C2', 'C3') // => 'P8' | ||
* distance.interval('G', 'B') // => 'M3' | ||
* import { interval } from 'tonal-distance' | ||
* interval('C2', 'C3') // => 'P8' | ||
* interval('G', 'B') // => 'M3' | ||
* | ||
* // or use tonal | ||
@@ -52,9 +221,12 @@ * var tonal = require('tonal') | ||
*/ | ||
function interval (a, b) { | ||
if (arguments.length === 1) return function (b) { return interval(a, b) } | ||
var pa = tonalPitch.asPitch(a); | ||
var pb = tonalPitch.asPitch(b); | ||
var i = substr(pa, pb); | ||
// if a and b are in array notation, no conversion back | ||
return a === pa && b === pb ? i : tonalPitch.strIvl(i) | ||
function interval(from, to) { | ||
if (arguments.length === 1) return t => interval(from, t); | ||
const f = encodeNote(from); | ||
const t = encodeNote(to); | ||
if (f === null || t === null || f.length !== t.length) return null; | ||
const d = | ||
f.length === 1 | ||
? [t[0] - f[0], -Math.floor((t[0] - f[0]) * 7 / 12)] | ||
: [t[0] - f[0], t[1] - f[1]]; | ||
return index$1.build(decodeIvl(d)); | ||
} | ||
@@ -64,2 +236,3 @@ | ||
* Get the distance between two notes in semitones | ||
* | ||
* @param {String|Pitch} from - first note | ||
@@ -74,8 +247,21 @@ * @param {String|Pitch} to - last note | ||
*/ | ||
function semitones (a, b) { | ||
var i = substr(tonalPitch.asPitch(a), tonalPitch.asPitch(b)); | ||
return i ? tonalPitch.height(i) : null | ||
function semitones(from, to) { | ||
if (arguments.length === 1) return t => semitones(from, t); | ||
const f = index.props(from); | ||
const t = index.props(to); | ||
return f.midi !== null && t.midi !== null | ||
? t.midi - f.midi | ||
: f.chroma !== null && t.chroma !== null | ||
? (t.chroma - f.chroma + 12) % 12 | ||
: null; | ||
} | ||
exports.transpose = transpose; | ||
exports.trFifths = trFifths; | ||
exports.fifths = fifths; | ||
exports.transposeBy = transposeBy; | ||
exports.addIntervals = addIntervals; | ||
exports.add = add; | ||
exports.subtract = subtract; | ||
exports.interval = interval; | ||
exports.semitones = semitones; |
251
index.js
/** | ||
* Functions to calculate distances between notes | ||
* [![npm version](https://img.shields.io/npm/v/tonal-distance.svg)](https://www.npmjs.com/package/tonal-distance) | ||
* [![tonal](https://img.shields.io/badge/tonal-distance-yellow.svg)](https://github.com/danigb/tonal/tree/master/packages/tonal/distance) | ||
* | ||
* Transpose notes by intervals and find distances between notes | ||
* | ||
* @example | ||
* // using node's require | ||
* var distance = require('tonal-distance') | ||
* distance.interval('C4', 'G4') // => '5P' | ||
* | ||
* @example | ||
* // using ES6 import | ||
* import { interval, semitones } from 'tonal-distance' | ||
* import { interval, semitones, transpose } from 'tonal-distance' | ||
* semitones('C' ,'D') // => 2 | ||
* interval('C4', 'G4') // => '5P' | ||
* transpose('C4', 'P5') // => 'G4' | ||
* | ||
* // included in tonal facade | ||
* const tonal = require('tonal'); | ||
* tonal.distance.transpose('C4', 'P5') | ||
* tonal.distance.transposeBy('P5', 'C4') | ||
* | ||
* @module distance | ||
*/ | ||
import { isPC, fifths, focts, pitch, height, asPitch, strIvl } from 'tonal-pitch' | ||
import { props as nprops, build as nbuild } from "tonal-note/index"; | ||
import { props as iprops, build as ibuild } from "tonal-interval/index"; | ||
// substract two pitches | ||
function substr (a, b) { | ||
if (!a || !b || a[1].length !== b[1].length) return null | ||
var f = fifths(b) - fifths(a) | ||
if (isPC(a)) return pitch(f, -Math.floor(f * 7 / 12), 1) | ||
var o = focts(b) - focts(a) | ||
var d = height(b) - height(a) < 0 ? -1 : 1 | ||
return pitch(d * f, d * o, d) | ||
// Map from letter step to number of fifths starting from 'C': | ||
// { C: 0, D: 2, E: 4, F: -1, G: 1, A: 3, B: 5 } | ||
const FIFTHS = [0, 2, 4, -1, 1, 3, 5]; | ||
// Given a number of fifths, return the octaves they span | ||
const fOcts = f => Math.floor(f * 7 / 12); | ||
// Get the number of octaves it span each step | ||
const FIFTH_OCTS = FIFTHS.map(fOcts); | ||
const encode = ({ step, alt, oct, dir = 1 }) => { | ||
const f = FIFTHS[step] + 7 * alt; | ||
if (oct === null) return [dir * f]; | ||
const o = oct - FIFTH_OCTS[step] - 4 * alt; | ||
return [dir * f, dir * o]; | ||
}; | ||
// We need to get the steps from fifths | ||
// Fifths for CDEFGAB are [ 0, 2, 4, -1, 1, 3, 5 ] | ||
// We add 1 to fifths to avoid negative numbers, so: | ||
// for ['F', 'C', 'G', 'D', 'A', 'E', 'B'] we have: | ||
const STEPS = [3, 0, 4, 1, 5, 2, 6]; | ||
// Return the number of fifths as if it were unaltered | ||
function unaltered(f) { | ||
const i = (f + 1) % 7; | ||
return i < 0 ? 7 + i : i; | ||
} | ||
const decode = (f, o, dir) => { | ||
const step = STEPS[unaltered(f)]; | ||
const alt = Math.floor((f + 1) / 7); | ||
if (o === undefined) return { step, alt, dir }; | ||
const oct = o + 4 * alt + FIFTH_OCTS[step]; | ||
return { step, alt, oct, dir }; | ||
}; | ||
const memo = (fn, cache = {}) => str => cache[str] || (cache[str] = fn(str)); | ||
const encoder = props => | ||
memo(str => { | ||
const p = props(str); | ||
return p.name === null ? null : encode(p); | ||
}); | ||
const encodeNote = encoder(nprops); | ||
const encodeIvl = encoder(iprops); | ||
/** | ||
* Find the interval between two pitches. Both pitches MUST be of the same type: | ||
* Transpose a note by an interval. The note can be a pitch class. | ||
* | ||
* This function can be partially applied. | ||
* | ||
* @param {String} note | ||
* @param {String} interval | ||
* @return {String} the transposed note | ||
* @example | ||
* import { tranpose } from 'tonal-distance' | ||
* transpose('d3', '3M') // => 'F#3' | ||
* // it works with pitch classes | ||
* transpose('D', '3M') // => 'F#' | ||
* // can be partially applied | ||
* ['C', 'D', 'E', 'F', 'G'].map(transpose('M3)) // => ['E', 'F#', 'G#', 'A', 'B'] | ||
*/ | ||
export function transpose(note, interval) { | ||
if (arguments.length === 1) return i => transpose(note, i); | ||
const n = encodeNote(note); | ||
const i = encodeIvl(interval); | ||
if (n === null || i === null) return null; | ||
const tr = n.length === 1 ? [n[0] + i[0]] : [n[0] + i[0], n[1] + i[1]]; | ||
return nbuild(decode(tr[0], tr[1])); | ||
} | ||
/** | ||
* Transpose a pitch class by a number of perfect fifths. | ||
* | ||
* It can be partially applied. | ||
* | ||
* - notes: it returns the interval between the first and the second | ||
* - pitch classes: it returns the __ascending__ interval between both | ||
* - intervals: substract one from the other | ||
* @function | ||
* @param {String} pitchClass - the pitch class | ||
* @param {Integer} fifhts - the number of fifths | ||
* @return {String} the transposed pitch class | ||
* | ||
* @example | ||
* import { trFifths } from 'tonal-transpose' | ||
* [0, 1, 2, 3, 4].map(trFifths('C')) // => ['C', 'G', 'D', 'A', 'E'] | ||
* // or using tonal | ||
* tonal.trFifths('G4', 1) // => 'D' | ||
*/ | ||
export function trFifths(note, fifths) { | ||
if (arguments.length === 1) return f => trFifths(note, f); | ||
const n = encodeNote(note); | ||
if (n === null) return null; | ||
return nbuild(decode(n[0] + fifths)); | ||
} | ||
/** | ||
* Get the distance in fifths between pitch classes | ||
* | ||
* Can be partially applied. | ||
* | ||
* @param {String} to - note or pitch class | ||
* @param {String} from - note or pitch class | ||
*/ | ||
export function fifths(from, to) { | ||
if (arguments.length === 1) return to => fifths(from, to); | ||
const f = encodeNote(from); | ||
const t = encodeNote(to); | ||
if (t === null || f === null) return null; | ||
return t[0] - f[0]; | ||
} | ||
/** | ||
* The same as transpose with the arguments inverted. | ||
* | ||
* Can be partially applied. | ||
* | ||
* @param {String} note | ||
* @param {String} interval | ||
* @return {String} the transposed note | ||
* @example | ||
* import { tranposeBy } from 'tonal-distance' | ||
* transposeBy('3m', '5P') // => '7m' | ||
*/ | ||
export function transposeBy(interval, note) { | ||
if (arguments.length === 1) return n => transpose(n, interval); | ||
return transpose(note, interval); | ||
} | ||
const isDescending = e => e[0] * 7 + e[1] * 12 < 0; | ||
const decodeIvl = i => | ||
isDescending(i) ? decode(-i[0], -i[1], -1) : decode(i[0], i[1], 1); | ||
export function addIntervals(ivl1, ivl2, dir) { | ||
const i1 = encodeIvl(ivl1); | ||
const i2 = encodeIvl(ivl2); | ||
if (i1 === null || i2 === null) return null; | ||
const i = [i1[0] + dir * i2[0], i1[1] + dir * i2[1]]; | ||
return ibuild(decodeIvl(i)); | ||
} | ||
/** | ||
* Add two intervals | ||
* | ||
* Can be partially applied. | ||
* | ||
* @param {String} interval1 | ||
* @param {String} interval2 | ||
* @return {String} the resulting interval | ||
* @example | ||
* import { add } from 'tonal-distance' | ||
* add('3m', '5P') // => '7m' | ||
*/ | ||
export function add(ivl1, ivl2) { | ||
if (arguments.length === 1) return i2 => add(ivl1, i2); | ||
return addIntervals(ivl1, ivl2, 1); | ||
} | ||
/** | ||
* Subtract two intervals | ||
* | ||
* Can be partially applied | ||
* | ||
* @param {String} minuend | ||
* @param {String} subtrahend | ||
* @return {String} interval diference | ||
*/ | ||
export function subtract(ivl1, ivl2) { | ||
if (arguments.length === 1) return i2 => add(ivl1, i2); | ||
return addIntervals(ivl1, ivl2, -1); | ||
} | ||
/** | ||
* Find the interval between two pitches. It works with pitch classes | ||
* (both must be pitch classes and the interval is always ascending) | ||
* | ||
* Can be partially applied | ||
* | ||
* @param {Pitch|String} from - distance from | ||
* @param {Pitch|String} to - distance to | ||
* @return {Interval} the distance between pitches | ||
* @param {String} from - distance from | ||
* @param {String} to - distance to | ||
* @return {String} the interval distance | ||
* | ||
* @example | ||
* var distance = require('tonal-distance') | ||
* distance.interval('C2', 'C3') // => 'P8' | ||
* distance.interval('G', 'B') // => 'M3' | ||
* import { interval } from 'tonal-distance' | ||
* interval('C2', 'C3') // => 'P8' | ||
* interval('G', 'B') // => 'M3' | ||
* | ||
* // or use tonal | ||
@@ -47,9 +216,12 @@ * var tonal = require('tonal') | ||
*/ | ||
export function interval (a, b) { | ||
if (arguments.length === 1) return function (b) { return interval(a, b) } | ||
var pa = asPitch(a) | ||
var pb = asPitch(b) | ||
var i = substr(pa, pb) | ||
// if a and b are in array notation, no conversion back | ||
return a === pa && b === pb ? i : strIvl(i) | ||
export function interval(from, to) { | ||
if (arguments.length === 1) return t => interval(from, t); | ||
const f = encodeNote(from); | ||
const t = encodeNote(to); | ||
if (f === null || t === null || f.length !== t.length) return null; | ||
const d = | ||
f.length === 1 | ||
? [t[0] - f[0], -Math.floor((t[0] - f[0]) * 7 / 12)] | ||
: [t[0] - f[0], t[1] - f[1]]; | ||
return ibuild(decodeIvl(d)); | ||
} | ||
@@ -59,2 +231,3 @@ | ||
* Get the distance between two notes in semitones | ||
* | ||
* @param {String|Pitch} from - first note | ||
@@ -69,5 +242,11 @@ * @param {String|Pitch} to - last note | ||
*/ | ||
export function semitones (a, b) { | ||
var i = substr(asPitch(a), asPitch(b)) | ||
return i ? height(i) : null | ||
export function semitones(from, to) { | ||
if (arguments.length === 1) return t => semitones(from, t); | ||
const f = nprops(from); | ||
const t = nprops(to); | ||
return f.midi !== null && t.midi !== null | ||
? t.midi - f.midi | ||
: f.chroma !== null && t.chroma !== null | ||
? (t.chroma - f.chroma + 12) % 12 | ||
: null; | ||
} |
{ | ||
"name": "tonal-distance", | ||
"version": "0.69.7", | ||
"description": "Find distances between musical notes", | ||
"version": "1.0.0-0", | ||
"description": "Transpose notes and find intervals between them", | ||
"keywords": [ | ||
"transpose", | ||
"interval", | ||
"distance", | ||
"semitones", | ||
"music", | ||
"theory", | ||
"interval", | ||
"distance", | ||
"tonal" | ||
], | ||
"scripts": { | ||
"test": "jest --coverage" | ||
"test": "jest --coverage", | ||
"docs": "jsdoc2md -d 1 --name-format --member-index-format grouped index.js > README.md" | ||
}, | ||
@@ -20,4 +23,15 @@ "main": "build/index.js", | ||
"dependencies": { | ||
"tonal-pitch": "^0.69.7" | ||
"tonal-interval": "^1.0.0-0", | ||
"tonal-note": "^1.0.0-0" | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"es2015" | ||
] | ||
}, | ||
"jest": { | ||
"transformIgnorePatterns": [ | ||
"<rootDir>/node_modules/(?!tonal)" | ||
] | ||
} | ||
} |
209
README.md
@@ -1,57 +0,180 @@ | ||
# tonal-distance [![npm version](https://img.shields.io/npm/v/tonal-distance.svg)](https://www.npmjs.com/package/tonal-distance) | ||
<a name="module_distance"></a> | ||
[![tonal](https://img.shields.io/badge/tonal-distance-yellow.svg)](https://www.npmjs.com/browse/keyword/tonal) | ||
# distance | ||
[![npm version](https://img.shields.io/npm/v/tonal-distance.svg)](https://www.npmjs.com/package/tonal-distance) | ||
[![tonal](https://img.shields.io/badge/tonal-distance-yellow.svg)](https://github.com/danigb/tonal/tree/master/packages/tonal/distance) | ||
`tonal-distance` is a collection of functions to find distances between music notes. | ||
Transpose notes by intervals and find distances between notes | ||
This is part of [tonal](https://www.npmjs.com/package/tonal) music theory library. | ||
**Example** | ||
```js | ||
// using ES6 import | ||
import { interval, semitones, transpose } from 'tonal-distance' | ||
semitones('C' ,'D') // => 2 | ||
interval('C4', 'G4') // => '5P' | ||
transpose('C4', 'P5') // => 'G4' | ||
You can install via npm: `npm i --save tonal-distance` | ||
// included in tonal facade | ||
const tonal = require('tonal'); | ||
tonal.distance.transpose('C4', 'P5') | ||
tonal.distance.transposeBy('P5', 'C4') | ||
``` | ||
## API Reference | ||
* [distance](#module_distance) | ||
* [`.transpose(note, interval)`](#module_distance.transpose) ⇒ <code>String</code> | ||
* [`.trFifths(pitchClass, fifhts)`](#module_distance.trFifths) ⇒ <code>String</code> | ||
* [`.fifths(to, from)`](#module_distance.fifths) | ||
* [`.transposeBy(note, interval)`](#module_distance.transposeBy) ⇒ <code>String</code> | ||
* [`.add(interval1, interval2)`](#module_distance.add) ⇒ <code>String</code> | ||
* [`.subtract(minuend, subtrahend)`](#module_distance.subtract) ⇒ <code>String</code> | ||
* [`.interval(from, to)`](#module_distance.interval) ⇒ <code>String</code> | ||
* [`.semitones(from, to)`](#module_distance.semitones) ⇒ <code>Integer</code> | ||
<dl> | ||
<dt><a href="#distance">distance(from, to)</a> ⇒ <code>Interval</code></dt> | ||
<dd><p>Find distance between two pitches. Both pitches MUST be of the same type. | ||
Distances between pitch classes always returns ascending intervals. | ||
Distances between intervals substract one from the other.</p> | ||
</dd> | ||
<dt><a href="#distInSemitones">distInSemitones(from, to)</a> ⇒ <code>Integer</code></dt> | ||
<dd><p>Get the distance between two notes in semitones</p> | ||
</dd> | ||
<dt><a href="#interval">interval()</a></dt> | ||
<dd><p>An alias for <code>distance</code></p> | ||
</dd> | ||
</dl> | ||
<a name="module_distance.transpose"></a> | ||
<a name="distance"></a> | ||
## `distance.transpose(note, interval)` ⇒ <code>String</code> | ||
Transpose a note by an interval. The note can be a pitch class. | ||
## distance(from, to) ⇒ <code>Interval</code> | ||
Find distance between two pitches. Both pitches MUST be of the same type. | ||
Distances between pitch classes always returns ascending intervals. | ||
Distances between intervals substract one from the other. | ||
This function can be partially applied. | ||
**Kind**: global function | ||
**Returns**: <code>Interval</code> - the distance between pitches | ||
**Kind**: static method of [<code>distance</code>](#module_distance) | ||
**Returns**: <code>String</code> - the transposed note | ||
| Param | Type | | ||
| --- | --- | | ||
| note | <code>String</code> | | ||
| interval | <code>String</code> | | ||
**Example** | ||
```js | ||
import { tranpose } from 'tonal-distance' | ||
transpose('d3', '3M') // => 'F#3' | ||
// it works with pitch classes | ||
transpose('D', '3M') // => 'F#' | ||
// can be partially applied | ||
['C', 'D', 'E', 'F', 'G'].map(transpose('M3)) // => ['E', 'F#', 'G#', 'A', 'B'] | ||
``` | ||
<a name="module_distance.trFifths"></a> | ||
## `distance.trFifths(pitchClass, fifhts)` ⇒ <code>String</code> | ||
Transpose a pitch class by a number of perfect fifths. | ||
It can be partially applied. | ||
**Kind**: static method of [<code>distance</code>](#module_distance) | ||
**Returns**: <code>String</code> - the transposed pitch class | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| from | <code>Pitch</code> | <code>String</code> | distance from | | ||
| to | <code>Pitch</code> | <code>String</code> | distance to | | ||
| pitchClass | <code>String</code> | the pitch class | | ||
| fifhts | <code>Integer</code> | the number of fifths | | ||
**Example** | ||
```js | ||
import { distance } from 'tonal-distance' | ||
distance('C2', 'C3') // => 'P8' | ||
distance('G', 'B') // => 'M3' | ||
import { trFifths } from 'tonal-transpose' | ||
[0, 1, 2, 3, 4].map(trFifths('C')) // => ['C', 'G', 'D', 'A', 'E'] | ||
// or using tonal | ||
tonal.trFifths('G4', 1) // => 'D' | ||
``` | ||
<a name="module_distance.fifths"></a> | ||
## `distance.fifths(to, from)` | ||
Get the distance in fifths between pitch classes | ||
Can be partially applied. | ||
**Kind**: static method of [<code>distance</code>](#module_distance) | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| to | <code>String</code> | note or pitch class | | ||
| from | <code>String</code> | note or pitch class | | ||
<a name="module_distance.transposeBy"></a> | ||
## `distance.transposeBy(note, interval)` ⇒ <code>String</code> | ||
The same as transpose with the arguments inverted. | ||
Can be partially applied. | ||
**Kind**: static method of [<code>distance</code>](#module_distance) | ||
**Returns**: <code>String</code> - the transposed note | ||
| Param | Type | | ||
| --- | --- | | ||
| note | <code>String</code> | | ||
| interval | <code>String</code> | | ||
**Example** | ||
```js | ||
import { tranposeBy } from 'tonal-distance' | ||
transposeBy('3m', '5P') // => '7m' | ||
``` | ||
<a name="module_distance.add"></a> | ||
## `distance.add(interval1, interval2)` ⇒ <code>String</code> | ||
Add two intervals | ||
Can be partially applied. | ||
**Kind**: static method of [<code>distance</code>](#module_distance) | ||
**Returns**: <code>String</code> - the resulting interval | ||
| Param | Type | | ||
| --- | --- | | ||
| interval1 | <code>String</code> | | ||
| interval2 | <code>String</code> | | ||
**Example** | ||
```js | ||
import { add } from 'tonal-distance' | ||
add('3m', '5P') // => '7m' | ||
``` | ||
<a name="module_distance.subtract"></a> | ||
## `distance.subtract(minuend, subtrahend)` ⇒ <code>String</code> | ||
Subtract two intervals | ||
Can be partially applied | ||
**Kind**: static method of [<code>distance</code>](#module_distance) | ||
**Returns**: <code>String</code> - interval diference | ||
| Param | Type | | ||
| --- | --- | | ||
| minuend | <code>String</code> | | ||
| subtrahend | <code>String</code> | | ||
<a name="module_distance.interval"></a> | ||
## `distance.interval(from, to)` ⇒ <code>String</code> | ||
Find the interval between two pitches. It works with pitch classes | ||
(both must be pitch classes and the interval is always ascending) | ||
Can be partially applied | ||
**Kind**: static method of [<code>distance</code>](#module_distance) | ||
**Returns**: <code>String</code> - the interval distance | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| from | <code>String</code> | distance from | | ||
| to | <code>String</code> | distance to | | ||
**Example** | ||
```js | ||
import { interval } from 'tonal-distance' | ||
interval('C2', 'C3') // => 'P8' | ||
interval('G', 'B') // => 'M3' | ||
// or use tonal | ||
var tonal = require('tonal') | ||
tonal.distance('M2', 'P5') // => 'P4' | ||
tonal.distance.interval('M2', 'P5') // => 'P4' | ||
``` | ||
<a name="distInSemitones"></a> | ||
<a name="module_distance.semitones"></a> | ||
## distInSemitones(from, to) ⇒ <code>Integer</code> | ||
## `distance.semitones(from, to)` ⇒ <code>Integer</code> | ||
Get the distance between two notes in semitones | ||
**Kind**: global function | ||
**Kind**: static method of [<code>distance</code>](#module_distance) | ||
**Returns**: <code>Integer</code> - the distance in semitones or null if not valid notes | ||
@@ -61,17 +184,11 @@ | ||
| --- | --- | --- | | ||
| from | <code>String</code> | <code>Pitch</code> | first note | | ||
| to | <code>String</code> | <code>Pitch</code> | last note | | ||
| from | <code>String</code> \| <code>Pitch</code> | first note | | ||
| to | <code>String</code> \| <code>Pitch</code> | last note | | ||
**Example** | ||
```js | ||
import { distInSemitones } from 'tonal-distance' | ||
distInSemitones('C3', 'A2') // => -3 | ||
import { semitones } from 'tonal-distance' | ||
semitones('C3', 'A2') // => -3 | ||
// or use tonal | ||
tonal.distInSemitones('C3', 'G3') // => 7 | ||
tonal.distance.semitones('C3', 'G3') // => 7 | ||
``` | ||
<a name="interval"></a> | ||
## interval() | ||
An alias for `distance` | ||
**Kind**: global function |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
26519
6
569
194
2
1
+ Addedtonal-interval@^1.0.0-0
+ Addedtonal-note@^1.0.0-0
+ Addedtonal-interval@1.1.2(transitive)
+ Addedtonal-note@1.1.2(transitive)
- Removedtonal-pitch@^0.69.7
- Removedinterval-notation@1.0.1(transitive)
- Removednote-parser@2.0.1(transitive)
- Removedtonal-encoding@0.69.7(transitive)
- Removedtonal-pitch@0.69.7(transitive)