Comparing version 0.69.9 to 1.0.0-0
@@ -5,18 +5,16 @@ 'use strict'; | ||
var tonalNotation = require('tonal-notation'); | ||
var tonalTranspose = require('tonal-transpose'); | ||
var tonalNote = require('tonal-note'); | ||
var tonalRange = require('tonal-range'); | ||
var tonalArray = require('tonal-array'); | ||
var tonalHarmonizer = require('tonal-harmonizer'); | ||
var index = require('tonal-array/index'); | ||
var index$1 = require('tonal-note/index'); | ||
var index$2 = require('tonal-distance/index'); | ||
/** | ||
* _Key_ refers to the tonal system based on the major and minor scales. This is | ||
* is the most common tonal system, but tonality can be present in music | ||
* based in other scales or concepts. | ||
* [![npm version](https://img.shields.io/npm/v/tonal-key.svg?style=flat-square)](https://www.npmjs.com/package/tonal-key) | ||
* [![tonal](https://img.shields.io/badge/tonal-key-yellow.svg?style=flat-square)](https://www.npmjs.com/browse/keyword/tonal) | ||
* | ||
* This is a collection of functions related to keys. | ||
* `tonal-key` is a collection of functions to query about tonal keys. | ||
* | ||
* This is part of [tonal](https://www.npmjs.com/package/tonal) music theory library. | ||
* | ||
* @example | ||
* var key = require('tonal-key') | ||
* const key = require('tonal-key') | ||
* key.scale('E mixolydian') // => [ 'E', 'F#', 'G#', 'A', 'B', 'C#', 'D' ] | ||
@@ -27,138 +25,17 @@ * key.relative('minor', 'C major') // => 'A minor' | ||
*/ | ||
const MODES = "major dorian phrygian lydian mixolydian minor locrian ionian aeolian".split( | ||
" " | ||
); | ||
const NUMS = [0, 1, 2, 3, 4, 5, 6, 0, 5]; | ||
const NOTES = "C D E F G A B".split(" "); | ||
const CHORDS = "Maj7 m7 m7 Maj7 7 m7 m7b5".split(" "); | ||
const FIFTHS = [0, 2, 4, -1, 1, 3, 5, 0, 3]; | ||
// Order matters: use an array | ||
var MODES = ['ionian', 'dorian', 'phrygian', 'lydian', 'mixolydian', | ||
'aeolian', 'locrian', 'major', 'minor']; | ||
// { C: 0, D: 2, E: 4, F: -1, G: 1, A: 3, B: 5 } | ||
var FIFTHS = [0, 2, 4, -1, 1, 3, 5, 0, 3]; | ||
var SCALES = [0, 1, 2, 3, 4, 5, 6, 0, 5].map(function (n) { | ||
return tonalHarmonizer.harmonics(tonalArray.rotate(n, ['C', 'D', 'E', 'F', 'G', 'A', 'B'])) | ||
}); | ||
const modenum = mode => NUMS[MODES.indexOf(mode)]; | ||
// PRIVATE | ||
// Given a tonic, mode pair, return the key string | ||
function toKey (t, m) { return !t ? m : t + ' ' + m } | ||
// Given the alterations, return the major key | ||
function majorKey (n) { return toKey(tonalTranspose.trFifths('C', n), 'major') } | ||
// given the mode name, return the alterations | ||
function modeNum (mode) { return FIFTHS[MODES.indexOf(mode)] } | ||
// given a string, return the valid mode it represents or null | ||
function validMode (m) { | ||
m = m.trim().toLowerCase(); | ||
return MODES.indexOf(m) === -1 ? null : m | ||
} | ||
/** | ||
* Return the key properties, an object with { tonic, mode } | ||
* | ||
* @param {String} name - the key name | ||
* @return {Key} the key properties object or null if not a valid key | ||
* @example | ||
* var key = require('tonal-key') | ||
* key.props('C3 dorian') // => { tonic: 'C', mode: 'dorian' } | ||
* key.props('dorian') // => { tonic: false, mode: 'dorian' } | ||
* key.props('Ab bebop') // => null | ||
* key.props('blah') // => null | ||
*/ | ||
function props (str) { | ||
if (typeof str !== 'string') return null | ||
var ndx = str.indexOf(' '); | ||
var key; | ||
if (ndx === -1) { | ||
var p = tonalNote.pc(str); | ||
key = p ? { tonic: p, mode: 'major' } | ||
: { tonic: false, mode: validMode(str) }; | ||
} else { | ||
key = { tonic: tonalNote.pc(str.slice(0, ndx)), mode: validMode(str.slice(ndx + 1)) }; | ||
} | ||
return key.mode ? key : null | ||
} | ||
/** | ||
* Test if a given name is a valid key name | ||
* | ||
* @param {String} name | ||
* @param {Boolean} | ||
* @example | ||
* key.isKeyName('C major') // => true | ||
* key.isKeyName('major') // => true | ||
* key.isKeyName('Bb bebop') // => false | ||
*/ | ||
function isKeyName (name) { | ||
return props(name) !== null | ||
} | ||
/** | ||
* Get the tonic of a key | ||
* | ||
* @param {String} key - the key | ||
* @return {String} the tonic or false is no tonic, or null if its not a valid key | ||
* @example | ||
* key.tonic('c3 major') // => 'C' | ||
* key.tonic('minor') // => false | ||
* key.tonic('bebop') // null | ||
*/ | ||
function tonic (key) { | ||
return (props(key) || key || {}).tonic || null | ||
} | ||
/** | ||
* Get the mode of a key. It can be used to test if its a valid key mode. | ||
* | ||
* @param {String} | ||
* @return {Boolean} | ||
* @example | ||
* key.mode('A dorian') // => 'dorian' | ||
* key.mode('DORIAN') // => 'dorian' | ||
* key.mode('mixophrygian') // => null | ||
*/ | ||
function mode (key) { | ||
return (props(key) || key || {}).mode || null | ||
} | ||
/** | ||
* Get relative of a key. Two keys are relative when the have the same | ||
* key signature (for example C major and A minor) | ||
* | ||
* It can be partially applied. | ||
* | ||
* @param {String} mode - the relative destination | ||
* @param {String} key - the key source | ||
* @example | ||
* key.relative('dorian', 'B major') // => 'C# dorian' | ||
* // partial application | ||
* var minor = key.relative('minor') | ||
* minor('C major') // => 'A minor' | ||
* minor('E major') // => 'C# minor' | ||
*/ | ||
function relative (rel, key) { | ||
if (arguments.length === 1) return function (k) { return relative(rel, k) } | ||
rel = props(rel); | ||
if (!rel || rel.tonic) return null | ||
key = props(key); | ||
if (!key || !key.tonic) return null | ||
var tonic = tonalTranspose.trFifths(key.tonic, modeNum(rel.mode) - modeNum(key.mode)); | ||
return toKey(tonic, rel.mode) | ||
} | ||
/** | ||
* Get a list of the altered notes of a given key. The notes will be in | ||
* the same order than in the key signature. | ||
* @param {String|Nunber} key | ||
* @return {Array} | ||
* @example | ||
* var key = require('tonal-keys') | ||
* key.alteredNotes('Eb major') // => [ 'Bb', 'Eb', 'Ab' ] | ||
*/ | ||
function alteredNotes (key) { | ||
var alt = alteration(key); | ||
return alt === null ? null | ||
: alt < 0 ? tonalRange.numeric([-1, alt]).map(tonalTranspose.trFifths('F')) | ||
: tonalRange.numeric([1, alt]).map(tonalTranspose.trFifths('B')) | ||
} | ||
/** | ||
* Get a list of valid mode names. The list of modes will be always in | ||
* increasing order (ionian to locrian) | ||
* | ||
* @function | ||
* @param {Boolean} alias - true to get aliases names | ||
@@ -172,8 +49,8 @@ * @return {Array} an array of strings | ||
*/ | ||
function modes (alias) { | ||
return alias ? MODES.slice() : MODES.slice(0, -2) | ||
} | ||
const modeNames = aliases => | ||
aliases === true ? MODES.slice() : MODES.slice(0, 7); | ||
/** | ||
* Create a major key from alterations | ||
* | ||
* @function | ||
@@ -186,21 +63,58 @@ * @param {Integer} alt - the alteration number (positive sharps, negative flats) | ||
*/ | ||
function fromAlter (n) { | ||
return typeof n === 'number' ? majorKey(n) : null | ||
} | ||
const fromAlter = i => index$2.trFifths("C", i) + " major"; | ||
const names = (alt = 4) => { | ||
alt = Math.abs(alt); | ||
const result = []; | ||
for (let i = -alt; i <= alt; i++) result.push(fromAlter(i)); | ||
return result; | ||
}; | ||
const NO_KEY = Object.freeze({ | ||
name: null, | ||
tonic: null, | ||
mode: null, | ||
modenum: null, | ||
intervals: [], | ||
scale: [], | ||
alteration: null, | ||
accidentals: null | ||
}); | ||
const properties = name => { | ||
const p = tokenize$1(name); | ||
if (p[0] === null) return NO_KEY; | ||
const k = { tonic: p[0], mode: p[1] }; | ||
k.name = k.tonic + " " + k.mode; | ||
k.modenum = modenum(k.mode); | ||
const cs = index.rotate(k.modenum, NOTES); | ||
k.intervals = cs.map(index$2.interval(cs[0])); | ||
k.scale = k.intervals.map(index$2.transpose(k.tonic)); | ||
k.alteration = index$2.fifths("C", k.tonic) - FIFTHS[MODES.indexOf(k.mode)]; | ||
k.accidentals = index$1.altToAcc(k.alteration); | ||
return Object.freeze(k); | ||
}; | ||
const memo = (fn, cache = {}) => str => cache[str] || (cache[str] = fn(str)); | ||
/** | ||
* Get key name from accidentals | ||
* Return the a key properties object with the following information: | ||
* | ||
* @param {String} acc - the accidentals string | ||
* @return {Key} the key object | ||
* - name: name | ||
* - tonic: key tonic | ||
* - mode: key mode | ||
* - modenum: mode number (0 major, 1 dorian, ...) | ||
* - intervals: the scale intervals | ||
* - scale: the scale notes | ||
* - alteration: alteration number | ||
* - accidentals: accidentals | ||
* | ||
* @function | ||
* @param {String} name - the key name | ||
* @return {Object} the key properties object or null if not a valid key | ||
* @example | ||
* var key = require('tonal-key') | ||
* key.fromAcc('b') // => 'F major' | ||
* key.fromAcc('##') // => 'D major' | ||
* key.props('C3 dorian') // => { tonic: 'C', mode: 'dorian', ... } | ||
*/ | ||
function fromAcc (s) { | ||
return tonalNotation.areSharps(s) ? majorKey(s.length) | ||
: tonalNotation.areFlats(s) ? majorKey(-s.length) | ||
: null | ||
} | ||
const props = memo(properties); | ||
@@ -210,2 +124,3 @@ /** | ||
* | ||
* @function | ||
* @param {String|Object} key | ||
@@ -219,7 +134,3 @@ * @return {Array} the key scale | ||
*/ | ||
function scale (key) { | ||
var p = props(key); | ||
if (!p || !p.tonic) return null | ||
return tonalHarmonizer.harmonize(SCALES[MODES.indexOf(p.mode)], p.tonic) | ||
} | ||
const scale = str => props(str).scale; | ||
@@ -229,2 +140,4 @@ /** | ||
* sharpen notes (positive) or flaten notes (negative) | ||
* | ||
* @function | ||
* @param {String|Integer} key | ||
@@ -236,38 +149,108 @@ * @return {Integer} | ||
*/ | ||
function alteration (key) { | ||
var k = props(key); | ||
if (!k || !k.tonic) return null | ||
var toMajor = modeNum(k.mode); | ||
var toC = tonalNote.pcFifths(k.tonic); | ||
return toC - toMajor | ||
} | ||
const alteration = str => props(str).alteration; | ||
/** | ||
* Get the signature of a key. The signature is a string with sharps or flats. | ||
* Get a list of the altered notes of a given key. The notes will be in | ||
* the same order than in the key signature. | ||
* | ||
* @function | ||
* @param {String} key - the key name | ||
* @return {Array} | ||
* @example | ||
* var key = require('tonal-keys') | ||
* key.signature('A major') // => '###' | ||
* key.alteredNotes('Eb major') // => [ 'Bb', 'Eb', 'Ab' ] | ||
*/ | ||
function signature (key) { | ||
return tonalNotation.toAcc(alteration(key)) | ||
} | ||
const alteredNotes = name => { | ||
const alt = props(name).alteration; | ||
if (alt === null) return null; | ||
return alt === 0 | ||
? [] | ||
: alt > 0 | ||
? index.range(1, alt).map(index$2.trFifths("B")) | ||
: index.range(-1, alt).map(index$2.trFifths("F")); | ||
}; | ||
/** | ||
* An alias for `signature()` | ||
* Get key chords | ||
* | ||
* @function | ||
* @param {String} name - the key name | ||
* @return {Array} | ||
* @example | ||
* key.chords("A major") // => ["AMaj7", "Bm7", "C#m7", "DMaj7", ..,] | ||
*/ | ||
var accidentals = signature; | ||
const chords = str => { | ||
const p = props(str); | ||
if (!p.name) return []; | ||
const chords = index.rotate(p.modenum, CHORDS); | ||
return p.scale.map((tonic, i) => tonic + chords[i]); | ||
}; | ||
/** | ||
* Get secondary dominant key chords | ||
* | ||
* @function | ||
* @param {String} name - the key name | ||
* @return {Array} | ||
* @example | ||
* key.secDomChords("A major") // => ["E7", "F#7", ...] | ||
*/ | ||
const secDomChords = name => { | ||
const p = props(name); | ||
if (!p.name) return []; | ||
return p.scale.map(t => index$2.transpose(t, "P5") + "7"); | ||
}; | ||
/** | ||
* Get relative of a key. Two keys are relative when the have the same | ||
* key signature (for example C major and A minor) | ||
* | ||
* It can be partially applied. | ||
* | ||
* @function | ||
* @param {String} mode - the relative destination | ||
* @param {String} key - the key source | ||
* @example | ||
* key.relative('dorian', 'B major') // => 'C# dorian' | ||
* // partial application | ||
* var minor = key.relative('minor') | ||
* minor('C major') // => 'A minor' | ||
* minor('E major') // => 'C# minor' | ||
*/ | ||
const relative = (mode, key) => { | ||
if (arguments.length === 1) return key => relative(mode, key); | ||
const num = modenum(mode.toLowerCase()); | ||
if (num === undefined) return null; | ||
const k = props(key); | ||
if (k.name === null) return null; | ||
return index$2.trFifths(k.tonic, FIFTHS[num] - FIFTHS[k.modenum]) + " " + mode; | ||
}; | ||
/** | ||
* Split the key name into its components (pitch class tonic and mode name) | ||
* | ||
* @function | ||
* @param {String} name | ||
* @return {Array} an array in the form [tonic, key] | ||
* @example | ||
* key.tokenize('C major') // => ['C', 'major'] | ||
*/ | ||
const tokenize$1 = name => { | ||
const p = index$1.tokenize(name); | ||
p[3] = p[3].toLowerCase(); | ||
if (p[0] === "" || MODES.indexOf(p[3]) === -1) return [null, null]; | ||
return [p[0] + p[1], p[3]]; | ||
}; | ||
exports.modeNames = modeNames; | ||
exports.fromAlter = fromAlter; | ||
exports.names = names; | ||
exports.props = props; | ||
exports.isKeyName = isKeyName; | ||
exports.tonic = tonic; | ||
exports.mode = mode; | ||
exports.relative = relative; | ||
exports.alteredNotes = alteredNotes; | ||
exports.modes = modes; | ||
exports.fromAlter = fromAlter; | ||
exports.fromAcc = fromAcc; | ||
exports.scale = scale; | ||
exports.alteration = alteration; | ||
exports.signature = signature; | ||
exports.accidentals = accidentals; | ||
exports.alteredNotes = alteredNotes; | ||
exports.chords = chords; | ||
exports.secDomChords = secDomChords; | ||
exports.relative = relative; | ||
exports.tokenize = tokenize$1; |
337
index.js
/** | ||
* _Key_ refers to the tonal system based on the major and minor scales. This is | ||
* is the most common tonal system, but tonality can be present in music | ||
* based in other scales or concepts. | ||
* [![npm version](https://img.shields.io/npm/v/tonal-key.svg?style=flat-square)](https://www.npmjs.com/package/tonal-key) | ||
* [![tonal](https://img.shields.io/badge/tonal-key-yellow.svg?style=flat-square)](https://www.npmjs.com/browse/keyword/tonal) | ||
* | ||
* This is a collection of functions related to keys. | ||
* `tonal-key` is a collection of functions to query about tonal keys. | ||
* | ||
* This is part of [tonal](https://www.npmjs.com/package/tonal) music theory library. | ||
* | ||
* @example | ||
* var key = require('tonal-key') | ||
* const key = require('tonal-key') | ||
* key.scale('E mixolydian') // => [ 'E', 'F#', 'G#', 'A', 'B', 'C#', 'D' ] | ||
@@ -15,145 +16,21 @@ * key.relative('minor', 'C major') // => 'A minor' | ||
*/ | ||
import { rotate, range } from "tonal-array/index"; | ||
import { tokenize as split, altToAcc } from "tonal-note/index"; | ||
import { trFifths, fifths, interval, transpose } from "tonal-distance/index"; | ||
import { areFlats, areSharps, toAcc } from 'tonal-notation' | ||
import { trFifths } from 'tonal-transpose' | ||
import { pc, pcFifths } from 'tonal-note' | ||
import { numeric } from 'tonal-range' | ||
import { rotate } from 'tonal-array' | ||
import { harmonics, harmonize } from 'tonal-harmonizer' | ||
const MODES = "major dorian phrygian lydian mixolydian minor locrian ionian aeolian".split( | ||
" " | ||
); | ||
const NUMS = [0, 1, 2, 3, 4, 5, 6, 0, 5]; | ||
const NOTES = "C D E F G A B".split(" "); | ||
const CHORDS = "Maj7 m7 m7 Maj7 7 m7 m7b5".split(" "); | ||
const FIFTHS = [0, 2, 4, -1, 1, 3, 5, 0, 3]; | ||
// Order matters: use an array | ||
var MODES = ['ionian', 'dorian', 'phrygian', 'lydian', 'mixolydian', | ||
'aeolian', 'locrian', 'major', 'minor'] | ||
// { C: 0, D: 2, E: 4, F: -1, G: 1, A: 3, B: 5 } | ||
var FIFTHS = [0, 2, 4, -1, 1, 3, 5, 0, 3] | ||
var SCALES = [0, 1, 2, 3, 4, 5, 6, 0, 5].map(function (n) { | ||
return harmonics(rotate(n, ['C', 'D', 'E', 'F', 'G', 'A', 'B'])) | ||
}) | ||
const modenum = mode => NUMS[MODES.indexOf(mode)]; | ||
// PRIVATE | ||
// Given a tonic, mode pair, return the key string | ||
function toKey (t, m) { return !t ? m : t + ' ' + m } | ||
// Given the alterations, return the major key | ||
function majorKey (n) { return toKey(trFifths('C', n), 'major') } | ||
// given the mode name, return the alterations | ||
function modeNum (mode) { return FIFTHS[MODES.indexOf(mode)] } | ||
// given a string, return the valid mode it represents or null | ||
function validMode (m) { | ||
m = m.trim().toLowerCase() | ||
return MODES.indexOf(m) === -1 ? null : m | ||
} | ||
/** | ||
* Return the key properties, an object with { tonic, mode } | ||
* | ||
* @param {String} name - the key name | ||
* @return {Key} the key properties object or null if not a valid key | ||
* @example | ||
* var key = require('tonal-key') | ||
* key.props('C3 dorian') // => { tonic: 'C', mode: 'dorian' } | ||
* key.props('dorian') // => { tonic: false, mode: 'dorian' } | ||
* key.props('Ab bebop') // => null | ||
* key.props('blah') // => null | ||
*/ | ||
export function props (str) { | ||
if (typeof str !== 'string') return null | ||
var ndx = str.indexOf(' ') | ||
var key | ||
if (ndx === -1) { | ||
var p = pc(str) | ||
key = p ? { tonic: p, mode: 'major' } | ||
: { tonic: false, mode: validMode(str) } | ||
} else { | ||
key = { tonic: pc(str.slice(0, ndx)), mode: validMode(str.slice(ndx + 1)) } | ||
} | ||
return key.mode ? key : null | ||
} | ||
/** | ||
* Test if a given name is a valid key name | ||
* | ||
* @param {String} name | ||
* @param {Boolean} | ||
* @example | ||
* key.isKeyName('C major') // => true | ||
* key.isKeyName('major') // => true | ||
* key.isKeyName('Bb bebop') // => false | ||
*/ | ||
export function isKeyName (name) { | ||
return props(name) !== null | ||
} | ||
/** | ||
* Get the tonic of a key | ||
* | ||
* @param {String} key - the key | ||
* @return {String} the tonic or false is no tonic, or null if its not a valid key | ||
* @example | ||
* key.tonic('c3 major') // => 'C' | ||
* key.tonic('minor') // => false | ||
* key.tonic('bebop') // null | ||
*/ | ||
export function tonic (key) { | ||
return (props(key) || key || {}).tonic || null | ||
} | ||
/** | ||
* Get the mode of a key. It can be used to test if its a valid key mode. | ||
* | ||
* @param {String} | ||
* @return {Boolean} | ||
* @example | ||
* key.mode('A dorian') // => 'dorian' | ||
* key.mode('DORIAN') // => 'dorian' | ||
* key.mode('mixophrygian') // => null | ||
*/ | ||
export function mode (key) { | ||
return (props(key) || key || {}).mode || null | ||
} | ||
/** | ||
* Get relative of a key. Two keys are relative when the have the same | ||
* key signature (for example C major and A minor) | ||
* | ||
* It can be partially applied. | ||
* | ||
* @param {String} mode - the relative destination | ||
* @param {String} key - the key source | ||
* @example | ||
* key.relative('dorian', 'B major') // => 'C# dorian' | ||
* // partial application | ||
* var minor = key.relative('minor') | ||
* minor('C major') // => 'A minor' | ||
* minor('E major') // => 'C# minor' | ||
*/ | ||
export function relative (rel, key) { | ||
if (arguments.length === 1) return function (k) { return relative(rel, k) } | ||
rel = props(rel) | ||
if (!rel || rel.tonic) return null | ||
key = props(key) | ||
if (!key || !key.tonic) return null | ||
var tonic = trFifths(key.tonic, modeNum(rel.mode) - modeNum(key.mode)) | ||
return toKey(tonic, rel.mode) | ||
} | ||
/** | ||
* Get a list of the altered notes of a given key. The notes will be in | ||
* the same order than in the key signature. | ||
* @param {String|Nunber} key | ||
* @return {Array} | ||
* @example | ||
* var key = require('tonal-keys') | ||
* key.alteredNotes('Eb major') // => [ 'Bb', 'Eb', 'Ab' ] | ||
*/ | ||
export function alteredNotes (key) { | ||
var alt = alteration(key) | ||
return alt === null ? null | ||
: alt < 0 ? numeric([-1, alt]).map(trFifths('F')) | ||
: numeric([1, alt]).map(trFifths('B')) | ||
} | ||
/** | ||
* Get a list of valid mode names. The list of modes will be always in | ||
* increasing order (ionian to locrian) | ||
* | ||
* @function | ||
* @param {Boolean} alias - true to get aliases names | ||
@@ -167,8 +44,8 @@ * @return {Array} an array of strings | ||
*/ | ||
export function modes (alias) { | ||
return alias ? MODES.slice() : MODES.slice(0, -2) | ||
} | ||
export const modeNames = aliases => | ||
aliases === true ? MODES.slice() : MODES.slice(0, 7); | ||
/** | ||
* Create a major key from alterations | ||
* | ||
* @function | ||
@@ -181,21 +58,58 @@ * @param {Integer} alt - the alteration number (positive sharps, negative flats) | ||
*/ | ||
export function fromAlter (n) { | ||
return typeof n === 'number' ? majorKey(n) : null | ||
} | ||
export const fromAlter = i => trFifths("C", i) + " major"; | ||
export const names = (alt = 4) => { | ||
alt = Math.abs(alt); | ||
const result = []; | ||
for (let i = -alt; i <= alt; i++) result.push(fromAlter(i)); | ||
return result; | ||
}; | ||
const NO_KEY = Object.freeze({ | ||
name: null, | ||
tonic: null, | ||
mode: null, | ||
modenum: null, | ||
intervals: [], | ||
scale: [], | ||
alteration: null, | ||
accidentals: null | ||
}); | ||
const properties = name => { | ||
const p = tokenize(name); | ||
if (p[0] === null) return NO_KEY; | ||
const k = { tonic: p[0], mode: p[1] }; | ||
k.name = k.tonic + " " + k.mode; | ||
k.modenum = modenum(k.mode); | ||
const cs = rotate(k.modenum, NOTES); | ||
k.intervals = cs.map(interval(cs[0])); | ||
k.scale = k.intervals.map(transpose(k.tonic)); | ||
k.alteration = fifths("C", k.tonic) - FIFTHS[MODES.indexOf(k.mode)]; | ||
k.accidentals = altToAcc(k.alteration); | ||
return Object.freeze(k); | ||
}; | ||
const memo = (fn, cache = {}) => str => cache[str] || (cache[str] = fn(str)); | ||
/** | ||
* Get key name from accidentals | ||
* Return the a key properties object with the following information: | ||
* | ||
* @param {String} acc - the accidentals string | ||
* @return {Key} the key object | ||
* - name: name | ||
* - tonic: key tonic | ||
* - mode: key mode | ||
* - modenum: mode number (0 major, 1 dorian, ...) | ||
* - intervals: the scale intervals | ||
* - scale: the scale notes | ||
* - alteration: alteration number | ||
* - accidentals: accidentals | ||
* | ||
* @function | ||
* @param {String} name - the key name | ||
* @return {Object} the key properties object or null if not a valid key | ||
* @example | ||
* var key = require('tonal-key') | ||
* key.fromAcc('b') // => 'F major' | ||
* key.fromAcc('##') // => 'D major' | ||
* key.props('C3 dorian') // => { tonic: 'C', mode: 'dorian', ... } | ||
*/ | ||
export function fromAcc (s) { | ||
return areSharps(s) ? majorKey(s.length) | ||
: areFlats(s) ? majorKey(-s.length) | ||
: null | ||
} | ||
export const props = memo(properties); | ||
@@ -205,2 +119,3 @@ /** | ||
* | ||
* @function | ||
* @param {String|Object} key | ||
@@ -214,7 +129,3 @@ * @return {Array} the key scale | ||
*/ | ||
export function scale (key) { | ||
var p = props(key) | ||
if (!p || !p.tonic) return null | ||
return harmonize(SCALES[MODES.indexOf(p.mode)], p.tonic) | ||
} | ||
export const scale = str => props(str).scale; | ||
@@ -224,2 +135,4 @@ /** | ||
* sharpen notes (positive) or flaten notes (negative) | ||
* | ||
* @function | ||
* @param {String|Integer} key | ||
@@ -231,24 +144,96 @@ * @return {Integer} | ||
*/ | ||
export function alteration (key) { | ||
var k = props(key) | ||
if (!k || !k.tonic) return null | ||
var toMajor = modeNum(k.mode) | ||
var toC = pcFifths(k.tonic) | ||
return toC - toMajor | ||
} | ||
export const alteration = str => props(str).alteration; | ||
/** | ||
* Get the signature of a key. The signature is a string with sharps or flats. | ||
* Get a list of the altered notes of a given key. The notes will be in | ||
* the same order than in the key signature. | ||
* | ||
* @function | ||
* @param {String} key - the key name | ||
* @return {Array} | ||
* @example | ||
* var key = require('tonal-keys') | ||
* key.signature('A major') // => '###' | ||
* key.alteredNotes('Eb major') // => [ 'Bb', 'Eb', 'Ab' ] | ||
*/ | ||
export function signature (key) { | ||
return toAcc(alteration(key)) | ||
} | ||
export const alteredNotes = name => { | ||
const alt = props(name).alteration; | ||
if (alt === null) return null; | ||
return alt === 0 | ||
? [] | ||
: alt > 0 | ||
? range(1, alt).map(trFifths("B")) | ||
: range(-1, alt).map(trFifths("F")); | ||
}; | ||
/** | ||
* An alias for `signature()` | ||
* Get key chords | ||
* | ||
* @function | ||
* @param {String} name - the key name | ||
* @return {Array} | ||
* @example | ||
* key.chords("A major") // => ["AMaj7", "Bm7", "C#m7", "DMaj7", ..,] | ||
*/ | ||
export var accidentals = signature | ||
export const chords = str => { | ||
const p = props(str); | ||
if (!p.name) return []; | ||
const chords = rotate(p.modenum, CHORDS); | ||
return p.scale.map((tonic, i) => tonic + chords[i]); | ||
}; | ||
/** | ||
* Get secondary dominant key chords | ||
* | ||
* @function | ||
* @param {String} name - the key name | ||
* @return {Array} | ||
* @example | ||
* key.secDomChords("A major") // => ["E7", "F#7", ...] | ||
*/ | ||
export const secDomChords = name => { | ||
const p = props(name); | ||
if (!p.name) return []; | ||
return p.scale.map(t => transpose(t, "P5") + "7"); | ||
}; | ||
/** | ||
* Get relative of a key. Two keys are relative when the have the same | ||
* key signature (for example C major and A minor) | ||
* | ||
* It can be partially applied. | ||
* | ||
* @function | ||
* @param {String} mode - the relative destination | ||
* @param {String} key - the key source | ||
* @example | ||
* key.relative('dorian', 'B major') // => 'C# dorian' | ||
* // partial application | ||
* var minor = key.relative('minor') | ||
* minor('C major') // => 'A minor' | ||
* minor('E major') // => 'C# minor' | ||
*/ | ||
export const relative = (mode, key) => { | ||
if (arguments.length === 1) return key => relative(mode, key); | ||
const num = modenum(mode.toLowerCase()); | ||
if (num === undefined) return null; | ||
const k = props(key); | ||
if (k.name === null) return null; | ||
return trFifths(k.tonic, FIFTHS[num] - FIFTHS[k.modenum]) + " " + mode; | ||
}; | ||
/** | ||
* Split the key name into its components (pitch class tonic and mode name) | ||
* | ||
* @function | ||
* @param {String} name | ||
* @return {Array} an array in the form [tonic, key] | ||
* @example | ||
* key.tokenize('C major') // => ['C', 'major'] | ||
*/ | ||
export const tokenize = name => { | ||
const p = split(name); | ||
p[3] = p[3].toLowerCase(); | ||
if (p[0] === "" || MODES.indexOf(p[3]) === -1) return [null, null]; | ||
return [p[0] + p[1], p[3]]; | ||
}; |
{ | ||
"name": "tonal-key", | ||
"version": "0.69.9", | ||
"version": "1.0.0-0", | ||
"description": "Conversion between key numbers and note names", | ||
@@ -12,2 +12,3 @@ "repository": "https://github.com/danigb/tonal/packages/key", | ||
"scripts": { | ||
"docs": "jsdoc2md -d 1 --name-format --member-index-format list index.js > README.md", | ||
"test": "jest --coverage" | ||
@@ -20,9 +21,16 @@ }, | ||
"dependencies": { | ||
"tonal-array": "^0.69.7", | ||
"tonal-harmonizer": "^0.69.7", | ||
"tonal-notation": "^0.69.7", | ||
"tonal-note": "^0.69.9", | ||
"tonal-range": "^0.69.9", | ||
"tonal-transpose": "^0.69.7" | ||
"tonal-array": "^1.0.0-0", | ||
"tonal-distance": "^1.0.0-0", | ||
"tonal-note": "^1.0.0-0" | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"es2015" | ||
] | ||
}, | ||
"jest": { | ||
"transformIgnorePatterns": [ | ||
"<rootDir>/node_modules/(?!tonal)" | ||
] | ||
} | ||
} |
306
README.md
@@ -1,262 +0,214 @@ | ||
# tonal-key [![npm version](https://img.shields.io/npm/v/tonal-key.svg)](https://www.npmjs.com/package/tonal-key) | ||
<a name="module_key"></a> | ||
[![tonal](https://img.shields.io/badge/tonal-key-yellow.svg)](https://www.npmjs.com/browse/keyword/tonal) | ||
# key | ||
[![npm version](https://img.shields.io/npm/v/tonal-key.svg?style=flat-square)](https://www.npmjs.com/package/tonal-key) | ||
[![tonal](https://img.shields.io/badge/tonal-key-yellow.svg?style=flat-square)](https://www.npmjs.com/browse/keyword/tonal) | ||
`tonal-key` is a collection of functions to create and manipulate music keys. | ||
`tonal-key` is a collection of functions to query about tonal keys. | ||
This is part of [tonal](https://www.npmjs.com/package/tonal) music theory library. | ||
You can install via npm: `npm i --save tonal-key` | ||
**Example** | ||
```js | ||
const key = require('tonal-key') | ||
key.scale('E mixolydian') // => [ 'E', 'F#', 'G#', 'A', 'B', 'C#', 'D' ] | ||
key.relative('minor', 'C major') // => 'A minor' | ||
``` | ||
## API Reference | ||
* [key](#module_key) | ||
* [`.modeNames(alias)`](#module_key.modeNames) ⇒ <code>Array</code> | ||
* [`.fromAlter(alt)`](#module_key.fromAlter) ⇒ <code>Key</code> | ||
* [`.props(name)`](#module_key.props) ⇒ <code>Object</code> | ||
* [`.scale(key)`](#module_key.scale) ⇒ <code>Array</code> | ||
* [`.alteration(key)`](#module_key.alteration) ⇒ <code>Integer</code> | ||
* [`.alteredNotes(key)`](#module_key.alteredNotes) ⇒ <code>Array</code> | ||
* [`.chords(name)`](#module_key.chords) ⇒ <code>Array</code> | ||
* [`.secDomChords(name)`](#module_key.secDomChords) ⇒ <code>Array</code> | ||
* [`.relative(mode, key)`](#module_key.relative) | ||
* [`.tokenize(name)`](#module_key.tokenize) ⇒ <code>Array</code> | ||
<dl> | ||
<dt><a href="#scale">scale(key)</a> ⇒ <code>Array</code></dt> | ||
<dd><p>Get scale of a key</p> | ||
</dd> | ||
<dt><a href="#relative">relative(mode, key)</a></dt> | ||
<dd><p>Get relative of a key. It can be partially applied.</p> | ||
</dd> | ||
<dt><a href="#alteredNotes">alteredNotes(key)</a> ⇒ <code>Array</code></dt> | ||
<dd><p>Get a list of the altered notes of a given key. The notes will be in | ||
the same order than in the key signature.</p> | ||
</dd> | ||
<dt><a href="#names">names(alias)</a> ⇒ <code>Array</code></dt> | ||
<dd><p>Get a list of valid mode names. The list of modes will be always in | ||
increasing order (ionian to locrian)</p> | ||
</dd> | ||
<dt><a href="#isKeyMode">isKeyMode(m)</a> ⇒ <code>Boolean</code></dt> | ||
<dd><p>Check if the given string is a valid mode name</p> | ||
</dd> | ||
<dt><a href="#build">build(tonic, mode)</a> ⇒ <code>Key</code></dt> | ||
<dd><p>Build a key object from tonic a mode.</p> | ||
<p>A key object is an array with the mode name and the tonic (or false if | ||
no tonic specified)</p> | ||
</dd> | ||
<dt><a href="#fromAlter">fromAlter(alt)</a> ⇒ <code>Key</code></dt> | ||
<dd><p>Create a major key from alterations</p> | ||
</dd> | ||
<dt><a href="#fromAcc">fromAcc(acc)</a> ⇒ <code>Key</code></dt> | ||
<dd><p>Create a major key from accidentals</p> | ||
</dd> | ||
<dt><a href="#fromName">fromName(name)</a> ⇒ <code>Key</code></dt> | ||
<dd><p>Create a key from key name</p> | ||
</dd> | ||
<dt><a href="#asKey">asKey(obj)</a> ⇒ <code>Key</code></dt> | ||
<dd><p>Try to interpret the given object as a key. Given an object it will try to | ||
parse as if it were a name, accidentals or alterations.</p> | ||
</dd> | ||
<dt><a href="#alteration">alteration(key)</a> ⇒ <code>Integer</code></dt> | ||
<dd><p>Get key alteration. The alteration is a number indicating the number of | ||
sharpen notes (positive) or flaten notes (negative)</p> | ||
</dd> | ||
<dt><a href="#signature">signature()</a></dt> | ||
<dd><p>Get the signature of a key. The signature is a string with sharps or flats.</p> | ||
</dd> | ||
<dt><a href="#accidentals">accidentals()</a></dt> | ||
<dd><p>An alias for <code>signature()</code></p> | ||
</dd> | ||
</dl> | ||
<a name="module_key.modeNames"></a> | ||
<a name="scale"></a> | ||
## `key.modeNames(alias)` ⇒ <code>Array</code> | ||
Get a list of valid mode names. The list of modes will be always in | ||
increasing order (ionian to locrian) | ||
## scale(key) ⇒ <code>Array</code> | ||
Get scale of a key | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
**Returns**: <code>Array</code> - an array of strings | ||
**Kind**: global function | ||
**Returns**: <code>Array</code> - the key scale | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| alias | <code>Boolean</code> | true to get aliases names | | ||
| Param | Type | | ||
| --- | --- | | ||
| key | <code>String</code> | <code>Object</code> | | ||
**Example** | ||
```js | ||
key.modes() // => [ 'ionian', 'dorian', 'phrygian', 'lydian', | ||
// 'mixolydian', 'aeolian', 'locrian' ] | ||
key.modes(true) // => [ 'ionian', 'dorian', 'phrygian', 'lydian', | ||
// 'mixolydian', 'aeolian', 'locrian', 'major', 'minor' ] | ||
``` | ||
<a name="module_key.fromAlter"></a> | ||
## `key.fromAlter(alt)` ⇒ <code>Key</code> | ||
Create a major key from alterations | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
**Returns**: <code>Key</code> - the key object | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| alt | <code>Integer</code> | the alteration number (positive sharps, negative flats) | | ||
**Example** | ||
```js | ||
var key = require('tonal-key') | ||
key.scale('A major') // => [ 'A', 'B', 'C#', 'D', 'E', 'F#', 'G#' ] | ||
key.scale('Bb minor') // => [ 'Bb', 'C', 'Db', 'Eb', 'F', 'Gb', 'Ab' ] | ||
key.scale('C dorian') // => [ 'C', 'D', 'Eb', 'F', 'G', 'A', 'Bb' ] | ||
key.scale('E mixolydian') // => [ 'E', 'F#', 'G#', 'A', 'B', 'C#', 'D' ] | ||
key.fromAlter(2) // => 'D major' | ||
``` | ||
<a name="relative"></a> | ||
<a name="module_key.props"></a> | ||
## relative(mode, key) | ||
Get relative of a key. It can be partially applied. | ||
## `key.props(name)` ⇒ <code>Object</code> | ||
Return the a key properties object with the following information: | ||
**Kind**: global function | ||
- name: name | ||
- tonic: key tonic | ||
- mode: key mode | ||
- modenum: mode number (0 major, 1 dorian, ...) | ||
- intervals: the scale intervals | ||
- scale: the scale notes | ||
- alteration: alteration number | ||
- accidentals: accidentals | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
**Returns**: <code>Object</code> - the key properties object or null if not a valid key | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| mode | <code>String</code> | the relative destination | | ||
| key | <code>String</code> | the key source | | ||
| name | <code>String</code> | the key name | | ||
**Example** | ||
```js | ||
var key = require('tonal-keys') | ||
key.relative('dorian', 'C major') // => ['dorian', 'D'] | ||
// partially application | ||
var minor = key.relative('minor') | ||
minor('C major') // => ['minor', 'A'] | ||
var key = require('tonal-key') | ||
key.props('C3 dorian') // => { tonic: 'C', mode: 'dorian', ... } | ||
``` | ||
<a name="alteredNotes"></a> | ||
<a name="module_key.scale"></a> | ||
## alteredNotes(key) ⇒ <code>Array</code> | ||
Get a list of the altered notes of a given key. The notes will be in | ||
the same order than in the key signature. | ||
## `key.scale(key)` ⇒ <code>Array</code> | ||
Get scale of a key | ||
**Kind**: global function | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
**Returns**: <code>Array</code> - the key scale | ||
| Param | Type | | ||
| --- | --- | | ||
| key | <code>String</code> | <code>Nunber</code> | | ||
| key | <code>String</code> \| <code>Object</code> | | ||
**Example** | ||
```js | ||
var key = require('tonal-keys') | ||
key.alteredNotes('Eb major') // => [ 'Bb', 'Eb', 'Ab' ] | ||
key.scale('A major') // => [ 'A', 'B', 'C#', 'D', 'E', 'F#', 'G#' ] | ||
key.scale('Bb minor') // => [ 'Bb', 'C', 'Db', 'Eb', 'F', 'Gb', 'Ab' ] | ||
key.scale('C dorian') // => [ 'C', 'D', 'Eb', 'F', 'G', 'A', 'Bb' ] | ||
key.scale('E mixolydian') // => [ 'E', 'F#', 'G#', 'A', 'B', 'C#', 'D' ] | ||
``` | ||
<a name="names"></a> | ||
<a name="module_key.alteration"></a> | ||
## names(alias) ⇒ <code>Array</code> | ||
Get a list of valid mode names. The list of modes will be always in | ||
increasing order (ionian to locrian) | ||
## `key.alteration(key)` ⇒ <code>Integer</code> | ||
Get key alteration. The alteration is a number indicating the number of | ||
sharpen notes (positive) or flaten notes (negative) | ||
**Kind**: global function | ||
**Returns**: <code>Array</code> - an array of strings | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| alias | <code>Boolean</code> | true to get aliases names | | ||
<a name="isKeyMode"></a> | ||
## isKeyMode(m) ⇒ <code>Boolean</code> | ||
Check if the given string is a valid mode name | ||
**Kind**: global function | ||
| Param | Type | | ||
| --- | --- | | ||
| m | <code>String</code> | | ||
| key | <code>String</code> \| <code>Integer</code> | | ||
<a name="build"></a> | ||
**Example** | ||
```js | ||
var key = require('tonal-keys') | ||
key.alteration('A major') // => 3 | ||
``` | ||
<a name="module_key.alteredNotes"></a> | ||
## build(tonic, mode) ⇒ <code>Key</code> | ||
Build a key object from tonic a mode. | ||
## `key.alteredNotes(key)` ⇒ <code>Array</code> | ||
Get a list of the altered notes of a given key. The notes will be in | ||
the same order than in the key signature. | ||
A key object is an array with the mode name and the tonic (or false if | ||
no tonic specified) | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
**Kind**: global function | ||
**Returns**: <code>Key</code> - a key data object | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| tonic | <code>String</code> | the key tonic (or null or false to no tonic) | | ||
| mode | <code>String</code> | the keymode | | ||
| key | <code>String</code> | the key name | | ||
**Example** | ||
```js | ||
var key = require('tonal-key') | ||
key.build('g3', 'minor') // => ['minor', 'G'] | ||
key.build(false, 'locrian') // => ['locrian', false] | ||
var key = require('tonal-keys') | ||
key.alteredNotes('Eb major') // => [ 'Bb', 'Eb', 'Ab' ] | ||
``` | ||
<a name="fromAlter"></a> | ||
<a name="module_key.chords"></a> | ||
## fromAlter(alt) ⇒ <code>Key</code> | ||
Create a major key from alterations | ||
## `key.chords(name)` ⇒ <code>Array</code> | ||
Get key chords | ||
**Kind**: global function | ||
**Returns**: <code>Key</code> - the key object | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| alt | <code>Integer</code> | the alteration number (positive sharps, negative flats) | | ||
| name | <code>String</code> | the key name | | ||
**Example** | ||
```js | ||
var key = require('tonal-key') | ||
key.fromAlter(2) // => ['major', 'D'] | ||
key.chords("A major") // => ["AMaj7", "Bm7", "C#m7", "DMaj7", ..,] | ||
``` | ||
<a name="fromAcc"></a> | ||
<a name="module_key.secDomChords"></a> | ||
## fromAcc(acc) ⇒ <code>Key</code> | ||
Create a major key from accidentals | ||
## `key.secDomChords(name)` ⇒ <code>Array</code> | ||
Get secondary dominant key chords | ||
**Kind**: global function | ||
**Returns**: <code>Key</code> - the key object | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| acc | <code>String</code> | the accidentals string | | ||
| name | <code>String</code> | the key name | | ||
**Example** | ||
```js | ||
var key = require('tonal-key') | ||
key.fromAlter('bb') // => ['major', 'Bb'] | ||
key.secDomChords("A major") // => ["E7", "F#7", ...] | ||
``` | ||
<a name="fromName"></a> | ||
<a name="module_key.relative"></a> | ||
## fromName(name) ⇒ <code>Key</code> | ||
Create a key from key name | ||
## `key.relative(mode, key)` | ||
Get relative of a key. Two keys are relative when the have the same | ||
key signature (for example C major and A minor) | ||
**Kind**: global function | ||
**Returns**: <code>Key</code> - the key object or null if not valid key | ||
It can be partially applied. | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
| Param | Type | Description | | ||
| --- | --- | --- | | ||
| name | <code>String</code> | the key name | | ||
| mode | <code>String</code> | the relative destination | | ||
| key | <code>String</code> | the key source | | ||
**Example** | ||
```js | ||
var key = require('tonal-key') | ||
key.fromName('C3 dorian') // => ['dorian', 'C'] | ||
key.fromName('blah') // => null | ||
key.relative('dorian', 'B major') // => 'C# dorian' | ||
// partial application | ||
var minor = key.relative('minor') | ||
minor('C major') // => 'A minor' | ||
minor('E major') // => 'C# minor' | ||
``` | ||
<a name="asKey"></a> | ||
<a name="module_key.tokenize"></a> | ||
## asKey(obj) ⇒ <code>Key</code> | ||
Try to interpret the given object as a key. Given an object it will try to | ||
parse as if it were a name, accidentals or alterations. | ||
## `key.tokenize(name)` ⇒ <code>Array</code> | ||
Split the key name into its components (pitch class tonic and mode name) | ||
**Kind**: global function | ||
**Returns**: <code>Key</code> - the key object or null | ||
**Kind**: static method of [<code>key</code>](#module_key) | ||
**Returns**: <code>Array</code> - an array in the form [tonic, key] | ||
| Param | Type | | ||
| --- | --- | | ||
| obj | <code>Object</code> | | ||
| name | <code>String</code> | | ||
<a name="alteration"></a> | ||
## alteration(key) ⇒ <code>Integer</code> | ||
Get key alteration. The alteration is a number indicating the number of | ||
sharpen notes (positive) or flaten notes (negative) | ||
**Kind**: global function | ||
| Param | Type | | ||
| --- | --- | | ||
| key | <code>String</code> | <code>Integer</code> | | ||
**Example** | ||
```js | ||
var key = require('tonal-keys') | ||
key.alteration('A major') // => 3 | ||
key.tokenize('C major') // => ['C', 'major'] | ||
``` | ||
<a name="signature"></a> | ||
## signature() | ||
Get the signature of a key. The signature is a string with sharps or flats. | ||
**Kind**: global function | ||
**Example** | ||
```js | ||
var key = require('tonal-keys') | ||
key.signature('A major') // => '###' | ||
``` | ||
<a name="accidentals"></a> | ||
## accidentals() | ||
An alias for `signature()` | ||
**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
127680
3
16
2991
215
1
+ Addedtonal-distance@^1.0.0-0
+ Addedtonal-array@1.1.2(transitive)
+ Addedtonal-distance@1.1.2(transitive)
+ Addedtonal-interval@1.1.2(transitive)
+ Addedtonal-note@1.1.2(transitive)
- Removedtonal-harmonizer@^0.69.7
- Removedtonal-notation@^0.69.7
- Removedtonal-range@^0.69.9
- Removedtonal-transpose@^0.69.7
- Removedinterval-notation@1.0.1(transitive)
- Removednote-parser@2.0.1(transitive)
- Removedtonal-array@0.69.7(transitive)
- Removedtonal-distance@0.69.7(transitive)
- Removedtonal-encoding@0.69.7(transitive)
- Removedtonal-freq@0.69.9(transitive)
- Removedtonal-harmonizer@0.69.7(transitive)
- Removedtonal-midi@0.69.7(transitive)
- Removedtonal-notation@0.69.7(transitive)
- Removedtonal-note@0.69.9(transitive)
- Removedtonal-pcset@0.69.9(transitive)
- Removedtonal-pitch@0.69.7(transitive)
- Removedtonal-range@0.69.9(transitive)
- Removedtonal-transpose@0.69.7(transitive)
Updatedtonal-array@^1.0.0-0
Updatedtonal-note@^1.0.0-0