C, 154 151 bytes
Rev 1 eliminated variable f
by doubling with p
, and placed formula search inside for
bracket.
char c[9],s[]="d7m+mM-";n;main(p){gets(c);n=*c*2%7+(c[p]&4?0:5+c[p++]%2*2);for(p=strchr(s,c[p])-s<<!!c[p+3]|8;p;p/=2)putchar(45+n%12/7*49),n+=9-p%2*5;}
Rev 0
char c[9],s[]="d7m+mM-";n;f;main(p){gets(c);n=*c*2%7+(c[p]&4?0:5+c[p++]%2*2);f=strchr(s,c[p])-s<<!!c[p+3]|8;for(;f;f/=2)putchar(45+n%12/7*49),n+=9-f%2*5;}
EXPLANTATION
I've used a bit of music theory to help reduce my score.
Terminology
A seventh chord is composed of the 1st, 3rd, 5th and 7th notes of a diatonic scale. These names are also used to describe intervals.
A "3rd" is an interval of 3 or 4 semitones, known as "minor" and "major" 3rds respectivelty.
A "5th" is made by stacking two "3rds", and a "7th" is made by stacking a "5th" and a "3rd."
The standard 5th is the "perfect 5th" (of 3+4 or 4+3 = 7 semitones.) "Diminished" (3+3=6) and "augmented" (4+4=8) 5ths are also possible.
There are two standard 7ths: "minor" (7+3=10) and "major" (7+4=11) and one nonstandard 7th: "diminished" (6+3=9.)
Note that there is no "augmented" 7th interval, because 8+4=12 sums to a whole octave.
Stacked Thirds
All of the seventh chords required in this question are based on stacked thirds. That is, the inteval between one note and the next is always three or four semitones. Therefore we can encode the formula for the chord type as a 3-bit binary number as below. (The increments are coded into binary from right to left and the 4th bit is set to 1 to signal the end of the information.)
Symbol Name Formula Increments Binary
dim7 Diminished 0,3,6,9 3,3,3 1 000
7 Dominant 0,4,7,10 4,3,3 1 001
m7 Minor 0,3,7,10 3,4,3 1 010
+M7 Augmented/Major* 0,4,8,11 4,4,3 1 011
m7b5 Half-Diminished 0,3,6,10 3,3,4 1 100
M7 Major 0,4,7,11 4,3,4 1 101
-M7 Minor/Major 0,3,7,11 3,4,4 1 110
*The augmented major seventh chord is not required by the question, nor is it implemented correctly, because it clashes with the #/b correction.
The binary is obtained from the first character of the chord type by finding its position in the string "d7m+mM-"
. There is a problem with the m7b5 chord, because there are two m
's in the string and strchr
will always find the first one. To fix this, the binary is leftshifted one place whenever the chord type has more than 3 characters.
Circle of fifths
Instead of organising the notes as A A#/Bb B C
etc, I use an imporant alternate representation called the Circle of fifths. In this we start at F and count 7 semitones each time, giving the following sequence:
F C G D A E B F#/Gb C#Db G#/Ab D#/Eb A#/Bb
As can be seen, all the white notes come first, followed by all the black notes. This is no coincidence: the fifth (7 semitones, frequency ratio 3/2) is the most important musical interval after the octave (12 semitones, ratio 2/1). The familiar scale of 7 out of the 12 available notes is constructed by stacking these "fifths."
The input note letter can be converted to its position in the circle of 5ths by ASCII code*2%7
, then 5 is added for a flat or 7 for a sharp.
In the domain of fifths, a minor third is nine fifths (minus five octaves): 9*7=63, 63%12=3
and a major third is four fifths (minus two octaves): 4*7=28, 28%12=4
.
For output, any number below 7 is a white note, any number 7 and above is a black note.
REV 0 UNGOLFED CODE
char c[9],s[]="d7m+mM-";n;f; //array c is filled with zeroes
main(p){ //if no arguments are given, p initialised to 1
gets(c);
n=*c*2%7 //convert character zero to its position in cycle of fifths, then correct for #/b in the next line
+(c[p]&4?0:5+c[p++]%2*2); //# and b are the only characters in position 1 whose ASCII codes have the 4's bit clear.
f=strchr(s,c[p])-s<<!!c[p+3]|8; //find binary representation of stacked 3rds, correct for m7b5, and OR with 8
for(;f;f/=2) //at end of iteration, rightshift f. loop will end when f=0 (when 8's bit shifted out)
putchar(45+n%12/7*49), //if n%2<7, put ASCII 45='-', else put ASCII 45+49='^'
n+=9-f%2*5; //increment n by a minor third (9 fifths) or major third (4 fifths)
}
Bb-M7
- it's the Minor/Major chord, denoted by-M7
. \$\endgroup\$ – Petr Feb 6 '15 at 14:43