|
|
|
|
|
var keys = { |
|
|
'C': { modes: ['CMaj', 'Amin', 'Am', 'GMix', 'DDor', 'EPhr', 'FLyd', 'BLoc'], stepsFromC: 0 }, |
|
|
'Db': { modes: ['DbMaj', 'Bbmin', 'Bbm', 'AbMix', 'EbDor', 'FPhr', 'GbLyd', 'CLoc'], stepsFromC: 1 }, |
|
|
'D': { modes: ['DMaj', 'Bmin', 'Bm', 'AMix', 'EDor', 'F#Phr', 'GLyd', 'C#Loc'], stepsFromC: 2 }, |
|
|
'Eb': { modes: ['EbMaj', 'Cmin', 'Cm', 'BbMix', 'FDor', 'GPhr', 'AbLyd', 'DLoc'], stepsFromC: 3 }, |
|
|
'E': { modes: ['EMaj', 'C#min', 'C#m', 'BMix', 'F#Dor', 'G#Phr', 'ALyd', 'D#Loc'], stepsFromC: 4 }, |
|
|
'F': { modes: ['FMaj', 'Dmin', 'Dm', 'CMix', 'GDor', 'APhr', 'BbLyd', 'ELoc'], stepsFromC: 5 }, |
|
|
'Gb': { modes: ['GbMaj', 'Ebmin', 'Ebm', 'DbMix', 'AbDor', 'BbPhr', 'CbLyd', 'FLoc'], stepsFromC: 6 }, |
|
|
'G': { modes: ['GMaj', 'Emin', 'Em', 'DMix', 'ADor', 'BPhr', 'CLyd', 'F#Loc'], stepsFromC: 7 }, |
|
|
'Ab': { modes: ['AbMaj', 'Fmin', 'Fm', 'EbMix', 'BbDor', 'CPhr', 'DbLyd', 'GLoc'], stepsFromC: 8 }, |
|
|
'A': { modes: ['AMaj', 'F#min', 'F#m', 'EMix', 'BDor', 'C#Phr', 'DLyd', 'G#Loc'], stepsFromC: 9 }, |
|
|
'Bb': { modes: ['BbMaj', 'Gmin', 'Gm', 'FMix', 'CDor', 'DPhr', 'EbLyd', 'ALoc'], stepsFromC: 10 }, |
|
|
'B': { modes: ['BMaj', 'G#min', 'G#m', 'F#Mix', 'C#Dor', 'D#Phr', 'ELyd', 'A#Loc'], stepsFromC: 11 }, |
|
|
|
|
|
'C#': { modes: ['C#Maj', 'A#min', 'A#m', 'G#Mix', 'D#Dor', 'E#Phr', 'F#Lyd', 'B#Loc'], stepsFromC: 1 }, |
|
|
'F#': { modes: ['F#Maj', 'D#min', 'D#m', 'C#Mix', 'G#Dor', 'A#Phr', 'BLyd', 'E#Loc'], stepsFromC: 6 }, |
|
|
'Cb': { modes: ['CbMaj', 'Abmin', 'Abm', 'GbMix', 'DbDor', 'EbPhr', 'FbLyd', 'BbLoc'], stepsFromC: 11 }, |
|
|
} |
|
|
|
|
|
var keyReverse = null |
|
|
|
|
|
function createKeyReverse() { |
|
|
keyReverse = {} |
|
|
var allKeys = Object.keys(keys) |
|
|
for (var i = 0 ; i < allKeys.length; i++) { |
|
|
var keyObj = keys[allKeys[i]] |
|
|
keyReverse[allKeys[i].toLowerCase()] = allKeys[i]; |
|
|
for (var j = 0; j < keyObj.modes.length; j++) { |
|
|
var mode = keyObj.modes[j].toLowerCase() |
|
|
keyReverse[mode] = allKeys[i]; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
function relativeMajor(key) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!keyReverse) { |
|
|
createKeyReverse() |
|
|
} |
|
|
|
|
|
var mode = key.toLowerCase().match(/([a-g][b#]?)(maj|min|mix|dor|phr|lyd|loc|m)?/) |
|
|
if (!mode || !mode[2]) |
|
|
return key; |
|
|
mode = mode[1] + mode[2] |
|
|
var maj = keyReverse[mode] |
|
|
if (maj) |
|
|
return maj; |
|
|
return key; |
|
|
} |
|
|
|
|
|
function relativeMode(majorKey, mode) { |
|
|
|
|
|
|
|
|
var group = keys[majorKey] |
|
|
if (!group) |
|
|
return majorKey; |
|
|
if (mode === '') |
|
|
return majorKey; |
|
|
var match = mode.toLowerCase().match(/^(maj|min|mix|dor|phr|lyd|loc|m)/) |
|
|
if (!match) |
|
|
return majorKey |
|
|
var regMode = match[1] |
|
|
for (var i = 0; i < group.modes.length; i++) { |
|
|
var thisMode = group.modes[i] |
|
|
var ind = thisMode.toLowerCase().indexOf(regMode) |
|
|
if (ind !== -1 && ind === thisMode.length - regMode.length) |
|
|
return thisMode.substring(0, thisMode.length - regMode.length) |
|
|
} |
|
|
return majorKey; |
|
|
} |
|
|
|
|
|
function transposeKey(key, steps) { |
|
|
|
|
|
|
|
|
var match = keys[key] |
|
|
if (!match) |
|
|
return key; |
|
|
while (steps < 0) steps += 12; |
|
|
var fromC = (match.stepsFromC + steps) % 12; |
|
|
for (var i = 0; i < Object.keys(keys).length; i++) { |
|
|
var k = Object.keys(keys)[i] |
|
|
if (keys[k].stepsFromC === fromC) |
|
|
return k; |
|
|
} |
|
|
return key; |
|
|
} |
|
|
|
|
|
module.exports = {relativeMajor: relativeMajor, relativeMode: relativeMode, transposeKey: transposeKey}; |
|
|
|