diff --git a/lib/scale.js b/lib/scale.js index cf0cc95..ead78a8 100644 --- a/lib/scale.js +++ b/lib/scale.js @@ -97,6 +97,22 @@ Scale.prototype = { return this.tonic.interval(interval).interval(new Interval([octaves, 0])); }, + getTriadChord: function(index) { + if (this.scale.length !== 7) { + throw new Error('Chord degrees are only supported for diatonic scales'); + } + var root = this.get(index); + var third = root.interval(this.get(index + 2)).toString(); + var fifth = root.interval(this.get(index + 4)).toString(); + var quality; + if (third === 'M3') { + quality = fifth === 'P5' ? 'M' : 'aug'; + } else { + quality = fifth === 'P5' ? 'm' : 'dim'; + } + return root.chord(quality); + }, + solfege: function(index, showOctaves) { if (index) return this.get(index).solfege(this, showOctaves); diff --git a/test/scales.js b/test/scales.js index 2d91a02..092ddcf 100644 --- a/test/scales.js +++ b/test/scales.js @@ -120,5 +120,33 @@ vows.describe('Scales').addBatch({ '-13 is two octaves down': function(topic) { assert.deepEqual(topic.get(-13), teoria.note('A2')); } + }, + + 'Chord Degrees': { + 'D major': function() { + var scale = teoria.note('D').scale('major'); + var expected = ['DM', 'Em', 'F#m', 'GM', 'AM', 'Bm', 'C#dim']; + var actual = scale.notes().map((n, i) => scale.getTriadChord(i+1).name); + assert.deepEqual(actual, expected); + }, + + 'Bb minor': function() { + var scale = teoria.note('Bb').scale('minor'); + var expected = ['Bbm', 'Cdim', 'DbM', 'Ebm', 'Fm', 'GbM', 'AbM']; + var actual = scale.notes().map((n, i) => scale.getTriadChord(i + 1).name); + assert.deepEqual(actual, expected); + }, + + 'G mixolydian': function () { + var scale = teoria.note('G').scale('mixolydian'); + var expected = ['GM', 'Am', 'Bdim', 'CM', 'Dm', 'Em', 'FM']; + var actual = scale.notes().map((n, i) => scale.getTriadChord(i + 1).name); + assert.deepEqual(actual, expected); + }, + + 'only supports diatonic scales': function() { + var scale = teoria.note('C').scale('minorpentatonic'); + assert.throws(() => scale.getTriadChord(1), Error); + } } }).export(module);