Scale from key and mode

Most of you probably know the C major scale:

C D E F G A B C


The major scale is characterised by the intervals between adjacent notes, which measured in semitones are:

2 2 1 2 2 2 1


From these intervales, we can construct any major scale starting in any note (the key of the scale). The 12 notes in our 12-tone equal temperament tuning system are:

C C♯ D D♯ E F F♯ G G♯ A A♯ B


equivalently (substituting some enharmonic equivalents):

C D♭ D E♭ E F G♭ G Ab A B♭ B


with a semitone between each pair of adjacent notes.

Each scale has to have the seven notes in order, starting from the key. Otherwise, you could have two notes in the same line of the pentagram, which would be confusing. So, in G# major/ionian, you have F## instead of G; musicians will just look at where in the pentagram is the note, they already have learned the accidentals for each scale. Indeed, in G# major, F## is represented in the line of F## without accidentals, the accidentals are in the key signature - but since that key signature would require 2 sharps for F, usually this is notated as Ab major.

Shifting the 2 2 1 2 2 2 1 intervals, we arrive at seven different modes of the diatonic scale:

• Ionian: 2 2 1 2 2 2 1 - corresponds to the major scale
• Dorian: 2 1 2 2 2 1 2
• Phrygian: 1 2 2 2 1 2 2
• Lydian: 2 2 2 1 2 2 1
• Mixolydian: 2 2 1 2 2 1 2
• Aeolian: 2 1 2 2 1 2 2 - corresponds to the natural minor scale, and to the melodic minor scale when descending (when ascending, the melodic minor scale has raised 6th and 7th degrees. There is also a harmonic minor scale, with a raised 7th degree compared to the natural minor).
• Locrian: 1 2 2 1 2 2 2

So, the challenge is to write a program that takes as input (via stdin) a key and a mode and outputs (via stdout) the corresponding scale. Some test cases (stdin(key mode) => stdout(scale)):

Input:              Output:
C mixolydian   =>   C D E F G A Bb
F mixolydian   =>   F G A Bb C D Eb
G mixolydian   =>   G A B C D E F
G# ionian      =>   G# A# B# C# D# E# F##
Bb aeolian     =>   Bb C Db Eb F Gb Ab


Further references:
How many (major and minor) keys are there? Why?

• The examples feature notation which isn't described above - flats and double-sharps. Is it acceptable to output equivalents using only the base notes and simple majors? (For what it's worth, my preference would be that you say "No" and expand the specification a bit - looks like this question could have quite a bit of hidden depth). – Peter Taylor Nov 17 '12 at 22:59
• @PeterTaylor: Right. I hope the edit is enough. I expect output to be as shown, with the seven note names and their corresponding accidentals. This is a relatively large program. – ninjalj Nov 18 '12 at 0:34

GolfScript, 96 characters

" "/~5<{+}*7%"v]nwm[{"=2*2base(;\(" #"@?]{.1>))["b""""#"..+]=+\[~@(@+@(7%65+\1\$7%4%0>-]}7*;]" "*


Golfscript solution which can be tested online.

Note: As in the examples the key has to be upper case while mode has to be given in lower case.

Examples:

>C lydian
C D E F# G A B

>C mixolydian
C D E F G A Bb