Comparing version 0.68.0 to 0.68.1
@@ -12,31 +12,108 @@ 'use strict'; | ||
var isArr = Array.isArray | ||
/** | ||
* _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. | ||
* | ||
* This is a collection of functions related to keys. | ||
* | ||
* @example | ||
* var key = require('tonal-key') | ||
* key.scale('E mixolydian') // => [ 'E', 'F#', 'G#', 'A', 'B', 'C#', 'D' ] | ||
* key.relative('minor', 'C major') // => 'A minor' | ||
* | ||
* @module key | ||
*/ | ||
// Order matters: use an array | ||
var MODES = ['ionian', 'dorian', 'phrygian', 'lydian', 'mixolydian', | ||
'aeolian', 'locrian', 'major', 'minor'] | ||
'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 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'])) | ||
}) | ||
}); | ||
// 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 | ||
} | ||
/** | ||
* Get scale of a key (with optionally a mode) | ||
* Return the key properties, an object with { tonic, mode } | ||
* | ||
* @param {String|Object} key | ||
* @return {Array} the key scale | ||
* @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.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.props('C3 dorian') // => { tonic: 'C', mode: 'dorian' } | ||
* key.props('dorian') // => { tonic: false, mode: 'dorian' } | ||
* key.props('Ab bebop') // => null | ||
* key.props('blah') // => null | ||
*/ | ||
function scale (key) { | ||
var k = asKey(key) | ||
if (!k || !hasTonic(k)) return null | ||
return tonalHarmonizer.harmonize(SCALES[MODES.indexOf(k[0])], k[1]) | ||
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 | ||
@@ -50,15 +127,16 @@ * key signature (for example C major and A minor) | ||
* @example | ||
* key.relative('dorian', 'C major') // => ['dorian', 'D'] | ||
* // partially application | ||
* key.relative('dorian', 'B major') // => 'C# dorian' | ||
* // partial application | ||
* var minor = key.relative('minor') | ||
* minor('C major') // => ['minor', 'A'] | ||
* 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) } | ||
var r = asKey(rel) | ||
if (!r || hasTonic(r)) return null | ||
var k = asKey(key) | ||
if (!k || !hasTonic(k)) return null | ||
var tonic = tonalTranspose.trFifths(k[1], modeNum(r) - modeNum(k)) | ||
return build(tonic, rel) | ||
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) | ||
} | ||
@@ -76,3 +154,3 @@ | ||
function alteredNotes (key) { | ||
var alt = alteration(key) | ||
var alt = alteration(key); | ||
return alt === null ? null | ||
@@ -89,4 +167,9 @@ : alt < 0 ? tonalRange.numeric([-1, alt]).map(tonalTranspose.trFifths('F')) | ||
* @return {Array} an array of strings | ||
* @example | ||
* key.modes() // => [ 'ionian', 'dorian', 'phrygian', 'lydian', | ||
* // 'mixolydian', 'aeolian', 'locrian' ] | ||
* key.modes(true) // => [ 'ionian', 'dorian', 'phrygian', 'lydian', | ||
* // 'mixolydian', 'aeolian', 'locrian', 'major', 'minor' ] | ||
*/ | ||
function names (alias) { | ||
function modes (alias) { | ||
return alias ? MODES.slice() : MODES.slice(0, -2) | ||
@@ -96,37 +179,2 @@ } | ||
/** | ||
* Check if the given string is a valid mode name | ||
* @param {String} | ||
* @return {Boolean} | ||
*/ | ||
function isKeyMode (m) { return MODES.indexOf(m) !== -1 } | ||
/** | ||
* Build a key object from tonic a mode. | ||
* | ||
* A key object is an array with the mode name and the tonic (or false if | ||
* no tonic specified) | ||
* | ||
* @param {String} tonic - the key tonic (or null or false to no tonic) | ||
* @param {String} mode - the keymode | ||
* @return {Key} a key data object | ||
* @example | ||
* var key = require('tonal-key') | ||
* key.build('g3', 'minor') // => ['minor', 'G'] | ||
* key.build(false, 'locrian') // => ['locrian', false] | ||
*/ | ||
function build (tonic, mode) { | ||
if (typeof mode !== 'string') return null | ||
var m = mode.trim().toLowerCase() | ||
if (!isKeyMode(m)) return null | ||
if (tonic === false || tonic === null) return [m, false] | ||
var t = tonalNote.pc(tonic) | ||
return t ? [m, t] : null | ||
} | ||
function isKey (o) { return isArr(o) && isKeyMode(o[0]) } | ||
function hasTonic (o) { return isKey(o) && o[1] } | ||
function majorKey (n) { return build(tonalTranspose.trFifths('C', n), 'major') } | ||
/** | ||
* Create a major key from alterations | ||
@@ -138,3 +186,3 @@ * @function | ||
* var key = require('tonal-key') | ||
* key.fromAlter(2) // => ['major', 'D'] | ||
* key.fromAlter(2) // => 'D major' | ||
*/ | ||
@@ -146,3 +194,4 @@ function fromAlter (n) { | ||
/** | ||
* Create a major key from accidentals | ||
* Get key name from accidentals | ||
* | ||
* @param {String} acc - the accidentals string | ||
@@ -152,3 +201,4 @@ * @return {Key} the key object | ||
* var key = require('tonal-key') | ||
* key.fromAlter('bb') // => ['major', 'Bb'] | ||
* key.fromAcc('b') // => 'F major' | ||
* key.fromAcc('##') // => 'D major' | ||
*/ | ||
@@ -162,34 +212,19 @@ function fromAcc (s) { | ||
/** | ||
* Create a key from key name | ||
* @param {String} name - the key name | ||
* @return {Key} the key object or null if not valid key | ||
* Get scale of a key | ||
* | ||
* @param {String|Object} key | ||
* @return {Array} the key scale | ||
* @example | ||
* var key = require('tonal-key') | ||
* key.fromName('C3 dorian') // => ['dorian', 'C'] | ||
* key.fromName('blah') // => null | ||
* 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' ] | ||
*/ | ||
function fromName (str) { | ||
if (typeof str !== 'string') return null | ||
var p = str.split(/\s+/) | ||
switch (p.length) { | ||
case 1: return tonalNote.pc(p[0]) ? build(p[0], 'major') : build(false, p[0]) | ||
case 2: return build(p[0], p[1]) | ||
default: return null | ||
} | ||
function scale (key) { | ||
var p = props(key); | ||
if (!p || !p.tonic) return null | ||
return tonalHarmonizer.harmonize(SCALES[MODES.indexOf(p.mode)], p.tonic) | ||
} | ||
/** | ||
* 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. | ||
* @function | ||
* @param {Object} obj | ||
* @return {Key} the key object or null | ||
*/ | ||
function asKey (obj) { | ||
return isKey(obj) ? obj : fromName(obj) || fromAcc(obj) || fromAlter(obj) | ||
} | ||
function modeNum (k) { return FIFTHS[MODES.indexOf(k[0])] } | ||
/** | ||
* Get key alteration. The alteration is a number indicating the number of | ||
@@ -204,6 +239,6 @@ * sharpen notes (positive) or flaten notes (negative) | ||
function alteration (key) { | ||
var k = asKey(key) | ||
if (!k || !hasTonic(k)) return null | ||
var toMajor = modeNum(k) | ||
var toC = tonalNote.pcFifths(k[1]) | ||
var k = props(key); | ||
if (!k || !k.tonic) return null | ||
var toMajor = modeNum(k.mode); | ||
var toC = tonalNote.pcFifths(k.tonic); | ||
return toC - toMajor | ||
@@ -226,16 +261,16 @@ } | ||
*/ | ||
var accidentals = signature | ||
var accidentals = signature; | ||
exports.scale = scale; | ||
exports.props = props; | ||
exports.isKeyName = isKeyName; | ||
exports.tonic = tonic; | ||
exports.mode = mode; | ||
exports.relative = relative; | ||
exports.alteredNotes = alteredNotes; | ||
exports.names = names; | ||
exports.isKeyMode = isKeyMode; | ||
exports.build = build; | ||
exports.modes = modes; | ||
exports.fromAlter = fromAlter; | ||
exports.fromAcc = fromAcc; | ||
exports.fromName = fromName; | ||
exports.asKey = asKey; | ||
exports.scale = scale; | ||
exports.alteration = alteration; | ||
exports.signature = signature; | ||
exports.accidentals = accidentals; | ||
exports.accidentals = accidentals; |
204
index.js
@@ -11,3 +11,3 @@ /** | ||
* key.scale('E mixolydian') // => [ 'E', 'F#', 'G#', 'A', 'B', 'C#', 'D' ] | ||
* key.relative('minor', 'C major') // => ['minor', 'A'] | ||
* key.relative('minor', 'C major') // => 'A minor' | ||
* | ||
@@ -24,3 +24,2 @@ * @module key | ||
var isArr = Array.isArray | ||
// Order matters: use an array | ||
@@ -35,21 +34,84 @@ var MODES = ['ionian', 'dorian', 'phrygian', 'lydian', 'mixolydian', | ||
// 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 | ||
} | ||
/** | ||
* Get scale of a key (with optionally a mode) | ||
* Return the key properties, an object with { tonic, mode } | ||
* | ||
* @param {String|Object} key | ||
* @return {Array} the key scale | ||
* @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.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.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 scale (key) { | ||
var k = asKey(key) | ||
if (!k || !hasTonic(k)) return null | ||
return harmonize(SCALES[MODES.indexOf(k[0])], k[1]) | ||
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 | ||
@@ -63,15 +125,16 @@ * key signature (for example C major and A minor) | ||
* @example | ||
* key.relative('dorian', 'C major') // => ['dorian', 'D'] | ||
* // partially application | ||
* key.relative('dorian', 'B major') // => 'C# dorian' | ||
* // partial application | ||
* var minor = key.relative('minor') | ||
* minor('C major') // => ['minor', 'A'] | ||
* 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) } | ||
var r = asKey(rel) | ||
if (!r || hasTonic(r)) return null | ||
var k = asKey(key) | ||
if (!k || !hasTonic(k)) return null | ||
var tonic = trFifths(k[1], modeNum(r) - modeNum(k)) | ||
return build(tonic, rel) | ||
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) | ||
} | ||
@@ -101,4 +164,9 @@ | ||
* @return {Array} an array of strings | ||
* @example | ||
* key.modes() // => [ 'ionian', 'dorian', 'phrygian', 'lydian', | ||
* // 'mixolydian', 'aeolian', 'locrian' ] | ||
* key.modes(true) // => [ 'ionian', 'dorian', 'phrygian', 'lydian', | ||
* // 'mixolydian', 'aeolian', 'locrian', 'major', 'minor' ] | ||
*/ | ||
export function names (alias) { | ||
export function modes (alias) { | ||
return alias ? MODES.slice() : MODES.slice(0, -2) | ||
@@ -108,37 +176,2 @@ } | ||
/** | ||
* Check if the given string is a valid mode name | ||
* @param {String} | ||
* @return {Boolean} | ||
*/ | ||
export function isKeyMode (m) { return MODES.indexOf(m) !== -1 } | ||
/** | ||
* Build a key object from tonic a mode. | ||
* | ||
* A key object is an array with the mode name and the tonic (or false if | ||
* no tonic specified) | ||
* | ||
* @param {String} tonic - the key tonic (or null or false to no tonic) | ||
* @param {String} mode - the keymode | ||
* @return {Key} a key data object | ||
* @example | ||
* var key = require('tonal-key') | ||
* key.build('g3', 'minor') // => ['minor', 'G'] | ||
* key.build(false, 'locrian') // => ['locrian', false] | ||
*/ | ||
export function build (tonic, mode) { | ||
if (typeof mode !== 'string') return null | ||
var m = mode.trim().toLowerCase() | ||
if (!isKeyMode(m)) return null | ||
if (tonic === false || tonic === null) return [m, false] | ||
var t = pc(tonic) | ||
return t ? [m, t] : null | ||
} | ||
function isKey (o) { return isArr(o) && isKeyMode(o[0]) } | ||
function hasTonic (o) { return isKey(o) && o[1] } | ||
function majorKey (n) { return build(trFifths('C', n), 'major') } | ||
/** | ||
* Create a major key from alterations | ||
@@ -150,3 +183,3 @@ * @function | ||
* var key = require('tonal-key') | ||
* key.fromAlter(2) // => ['major', 'D'] | ||
* key.fromAlter(2) // => 'D major' | ||
*/ | ||
@@ -158,3 +191,4 @@ export function fromAlter (n) { | ||
/** | ||
* Create a major key from accidentals | ||
* Get key name from accidentals | ||
* | ||
* @param {String} acc - the accidentals string | ||
@@ -164,3 +198,4 @@ * @return {Key} the key object | ||
* var key = require('tonal-key') | ||
* key.fromAlter('bb') // => ['major', 'Bb'] | ||
* key.fromAcc('b') // => 'F major' | ||
* key.fromAcc('##') // => 'D major' | ||
*/ | ||
@@ -174,34 +209,19 @@ export function fromAcc (s) { | ||
/** | ||
* Create a key from key name | ||
* @param {String} name - the key name | ||
* @return {Key} the key object or null if not valid key | ||
* Get scale of a key | ||
* | ||
* @param {String|Object} key | ||
* @return {Array} the key scale | ||
* @example | ||
* var key = require('tonal-key') | ||
* key.fromName('C3 dorian') // => ['dorian', 'C'] | ||
* key.fromName('blah') // => null | ||
* 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' ] | ||
*/ | ||
export function fromName (str) { | ||
if (typeof str !== 'string') return null | ||
var p = str.split(/\s+/) | ||
switch (p.length) { | ||
case 1: return pc(p[0]) ? build(p[0], 'major') : build(false, p[0]) | ||
case 2: return build(p[0], p[1]) | ||
default: return null | ||
} | ||
export function scale (key) { | ||
var p = props(key) | ||
if (!p || !p.tonic) return null | ||
return harmonize(SCALES[MODES.indexOf(p.mode)], p.tonic) | ||
} | ||
/** | ||
* 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. | ||
* @function | ||
* @param {Object} obj | ||
* @return {Key} the key object or null | ||
*/ | ||
export function asKey (obj) { | ||
return isKey(obj) ? obj : fromName(obj) || fromAcc(obj) || fromAlter(obj) | ||
} | ||
function modeNum (k) { return FIFTHS[MODES.indexOf(k[0])] } | ||
/** | ||
* Get key alteration. The alteration is a number indicating the number of | ||
@@ -216,6 +236,6 @@ * sharpen notes (positive) or flaten notes (negative) | ||
export function alteration (key) { | ||
var k = asKey(key) | ||
if (!k || !hasTonic(k)) return null | ||
var toMajor = modeNum(k) | ||
var toC = pcFifths(k[1]) | ||
var k = props(key) | ||
if (!k || !k.tonic) return null | ||
var toMajor = modeNum(k.mode) | ||
var toC = pcFifths(k.tonic) | ||
return toC - toMajor | ||
@@ -222,0 +242,0 @@ } |
{ | ||
"name": "tonal-key", | ||
"version": "0.68.0", | ||
"version": "0.68.1", | ||
"description": "Conversion between key numbers and note names", | ||
@@ -23,7 +23,7 @@ "repository": "https://github.com/danigb/tonal/packages/key", | ||
"tonal-transpose": "^0.66.0", | ||
"tonal-note": "^0.68.0", | ||
"tonal-note": "^0.68.1", | ||
"tonal-array": "^0.68.0", | ||
"tonal-harmonizer": "^0.68.0", | ||
"tonal-range": "^0.68.0" | ||
"tonal-harmonizer": "^0.68.1", | ||
"tonal-range": "^0.68.1" | ||
} | ||
} |
@@ -5,83 +5,73 @@ | ||
test('scale', function (t) { | ||
t.deepEqual(key.scale('C major'), [ 'C', 'D', 'E', 'F', 'G', 'A', 'B' ]) | ||
t.deepEqual(key.scale('C dorian'), [ 'C', 'D', 'Eb', 'F', 'G', 'A', 'Bb' ]) | ||
t.deepEqual(key.scale('E mixolydian'), [ 'E', 'F#', 'G#', 'A', 'B', 'C#', 'D' ]) | ||
t.end() | ||
}) | ||
test('isKeyMode', function (t) { | ||
key.names(true).forEach(function (m) { | ||
t.ok(key.isKeyMode(m), m) | ||
test('key: mode', function (t) { | ||
t.equal(key.mode('mixophrygian'), null) | ||
t.equal(key.mode('blah'), null) | ||
t.equal(key.mode(null), null) | ||
key.modes(true).forEach(function (m) { | ||
t.equal(key.mode(m), m) | ||
}) | ||
t.equal(key.isKeyMode('blah'), false) | ||
t.equal(key.isKeyMode(null), false) | ||
t.end() | ||
}) | ||
test('names', function (t) { | ||
t.deepEqual(key.names(false), | ||
[ 'ionian', 'dorian', 'phrygian', 'lydian', 'mixolydian', 'aeolian', 'locrian' ]) | ||
t.deepEqual(key.names(true), | ||
[ 'ionian', 'dorian', 'phrygian', 'lydian', 'mixolydian', 'aeolian', 'locrian', | ||
'major', 'minor' ]) | ||
test('key: tonic', function (t) { | ||
t.equal(key.tonic('c4 mixolydian'), 'C') | ||
t.equal(key.tonic('mixolydian'), null) | ||
t.end() | ||
}) | ||
test('build', function (t) { | ||
t.deepEqual(key.build('C3', 'mixolydian'), | ||
['mixolydian', 'C']) | ||
t.deepEqual(key.build(null, 'phrygian'), | ||
['phrygian', false]) | ||
t.deepEqual(key.build('blah', 'major'), null) | ||
t.deepEqual(key.build('C', 'blah'), null) | ||
test('key: props', function (t) { | ||
t.deepEqual(key.props('Eb mixolydian'), { mode: 'mixolydian', tonic: 'Eb' }) | ||
t.deepEqual(key.props('lydian'), { mode: 'lydian', tonic: false }) | ||
t.deepEqual(key.props('F#'), { mode: 'major', tonic: 'F#' }) | ||
t.deepEqual(key.props('blah'), null) | ||
t.deepEqual(key.props('Eb blah'), null) | ||
t.end() | ||
}) | ||
test('from alter', function (t) { | ||
t.deepEqual([0, 1, 2, 3, 4, 5, 6, 7].map(key.fromAlter), | ||
[ [ 'major', 'C' ], [ 'major', 'G' ], [ 'major', 'D' ], [ 'major', 'A' ], | ||
[ 'major', 'E' ], [ 'major', 'B' ], [ 'major', 'F#' ], [ 'major', 'C#' ] ]) | ||
t.deepEqual([-0, -1, -2, -3, -4, -5, -6, -7, -8].map(key.fromAlter), | ||
[ [ 'major', 'C' ], [ 'major', 'F' ], [ 'major', 'Bb' ], [ 'major', 'Eb' ], | ||
[ 'major', 'Ab' ], [ 'major', 'Db' ], [ 'major', 'Gb' ], [ 'major', 'Cb' ], | ||
[ 'major', 'Fb' ] ]) | ||
test('key: scale', function (t) { | ||
t.deepEqual(key.scale('C major'), [ 'C', 'D', 'E', 'F', 'G', 'A', 'B' ]) | ||
t.deepEqual(key.scale('C dorian'), [ 'C', 'D', 'Eb', 'F', 'G', 'A', 'Bb' ]) | ||
t.deepEqual(key.scale('E mixolydian'), [ 'E', 'F#', 'G#', 'A', 'B', 'C#', 'D' ]) | ||
t.end() | ||
}) | ||
test('from accidentals', function (t) { | ||
t.deepEqual(key.fromAcc('###'), [ 'major', 'A' ]) | ||
t.deepEqual(key.fromAcc('bbb'), [ 'major', 'Eb' ]) | ||
test('key: modes', function (t) { | ||
t.deepEqual(key.modes(false), | ||
[ 'ionian', 'dorian', 'phrygian', 'lydian', 'mixolydian', 'aeolian', 'locrian' ]) | ||
t.deepEqual(key.modes(true), | ||
[ 'ionian', 'dorian', 'phrygian', 'lydian', 'mixolydian', 'aeolian', 'locrian', | ||
'major', 'minor' ]) | ||
t.end() | ||
}) | ||
test('from name', function (t) { | ||
t.deepEqual(key.fromName('Eb mixolydian'), [ 'mixolydian', 'Eb' ]) | ||
t.deepEqual(key.fromName('lydian'), [ 'lydian', false ]) | ||
t.deepEqual(key.fromName('F#'), [ 'major', 'F#' ]) | ||
t.equal(key.fromName('blah'), null) | ||
t.equal(key.fromName('Eb blah'), null) | ||
test('from alter', function (t) { | ||
t.deepEqual([0, 1, 2, 3, 4, 5, 6, 7].map(key.fromAlter), | ||
[ 'C major', 'G major', 'D major', 'A major', 'E major', | ||
'B major', 'F# major', 'C# major' ]) | ||
t.deepEqual([-0, -1, -2, -3, -4, -5, -6, -7, -8].map(key.fromAlter), | ||
[ 'C major', 'F major', 'Bb major', 'Eb major', 'Ab major', | ||
'Db major', 'Gb major', 'Cb major', 'Fb major' ]) | ||
t.end() | ||
}) | ||
test('asKey', function (t) { | ||
t.deepEqual(key.asKey('C minor'), ['minor', 'C']) | ||
t.equal(key.asKey('blah'), null) | ||
test('key: from accidentals', function (t) { | ||
t.equal(key.fromAcc('###'), 'A major') | ||
t.equal(key.fromAcc('bbb'), 'Eb major') | ||
t.end() | ||
}) | ||
test('relative', function (t) { | ||
t.deepEqual(key.relative('minor', 'Eb major'), ['minor', 'C']) | ||
t.deepEqual(key.relative('dorian', 'Bb mixolydian'), ['dorian', 'F']) | ||
test('key: relative', function (t) { | ||
t.equal(key.relative('minor', 'Eb major'), 'C minor') | ||
t.equal(key.relative('dorian', 'Bb mixolydian'), 'F dorian') | ||
t.equal(key.relative('blah', 'C major'), null) | ||
var minor = key.relative('minor') | ||
t.deepEqual(minor('C'), [ 'minor', 'A' ]) | ||
t.equal(minor('C'), 'A minor') | ||
t.end() | ||
}) | ||
test('alteration', function (t) { | ||
test('key: alteration', function (t) { | ||
t.equal(key.alteration('A major'), 3) | ||
var Amaj = 'A B C# D E F# G#'.split(' ') | ||
var modes = key.names(false) | ||
var modes = key.modes(false) | ||
Amaj.forEach(function (tonic, i) { | ||
@@ -88,0 +78,0 @@ t.equal(key.alteration(tonic + ' ' + modes[i]), 3) |
25938
557
Updatedtonal-harmonizer@^0.68.1
Updatedtonal-note@^0.68.1
Updatedtonal-range@^0.68.1