UNPKG

abcjs

Version:

Renderer for abc music notation

93 lines (86 loc) 4.02 kB
// All these keys have the same number of accidentals 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 }, // Enharmonic keys '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) { // Translate a key to its relative major. If it doesn't exist, do the best we can // by just returning the original key. // There are alternate spellings of these - so the search needs to be case insensitive. // To make this efficient, the first time this is called the "keys" object is reversed so this search is fast in the future if (!keyReverse) { createKeyReverse() } // get the key portion itself - there might be other stuff, like extra sharps and flats, or the mode written out. 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) { // The reverse of the relativeMajor. Translate it back to the original mode. // If it isn't a recognized mode or it is already major, then just return the major key. 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) { // This takes a major key and adds the desired steps. // It assigns each key a number that is the number of steps from C so that there can just be arithmetic. 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};