@interval = qw(0 2 4 5 7 9 11 12 14 16 17 19 21 23 24 26 28 29 31 33 35 36); @chords = ( [ '', [ 4, 7 ] ], [ 'm', [ 3, 7 ] ], [ '+', [ 4, 8 ] ], [ 'mb5', [ 3, 6 ] ], [ '7', [ 4, 7, 10 ] ], [ 'maj7', [ 4, 7, 11 ] ], [ 'm7', [ 3, 7, 10 ] ], [ 'm(maj7)', [ 3, 7, 11 ] ], [ 'm7b5', [ 3, 6, 10 ] ], [ 'dim', [ 3, 6, 9 ] ], [ 'sus', [ 5, 7 ] ], ); for $mode (qw(Ionian Dorian Phrygian Lydian Myxolydian Aeolian Locrian)) { print "\n$mode:\n"; for $degree (0..6) { for $chord (@chords) { $ivs = $$chord[1]; $found = 1; for $i (@$ivs) { $n = $i + $interval[$degree]; unless (grep { $_ == $n } @interval) { $found = 0; last; } } if ($found) { print "[$degree]$$chord[0]\n"; } } } # generate intervals for next mode shift @interval; $diff = $interval[0]; for (@interval) { $_ -= $diff; } }