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)
}
Interesting challenge. Is it just coincidence or why do we actually talk the same topic in music class? – GiantTree – 2015-02-05T21:20:43.973
2I like the challenge, but I felt for people like me, who can barely read music, the explanation in the link was rather difficult to follow. I've gone ahead and added integer notation to the question, which is much easier to follow for non-musicians. Roll it back if you don't like it. Also '-M7' should be minor/major. C major minor 7th would just be C dominant. – Level River St – 2015-02-05T22:04:50.157
Isn't this essentially a duplicate of this earlier question?
– Peter Taylor – 2015-02-05T23:10:17.7201
@PeterTaylor I would say not, because the bonus for the 7th chords on the question you linked was quite low, so nobody did it. Also the fact that this question only requires an output of black/white will lead to very different strategies, such as the one I introduced in this question http://codegolf.stackexchange.com/q/36497/15599
– Level River St – 2015-02-05T23:33:20.0601Is "Bb-M7" a Major or Major/Minor chord? – aditsu quit because SE is EVIL – 2015-02-05T23:56:08.503
1Is the example a typo meant to be "BbM7"? – dennisdeems – 2015-02-06T00:24:35.833
@steveverrill like a keytar? – Bryan Devaney – 2015-02-06T10:13:55.733
@steveverrill I remember a Super simplified version of this with an electric keyboard from moog in the early ninties. there was a "meta pedal" when pressed it changed the key layout to one you could define. did not change any keys that were pressed when the pedal was pushed. there may be an implementation out there somewhere thats does what you want. – Bryan Devaney – 2015-02-06T12:57:18.190
1@dennisdeems No, it really is
Bb-M7
- it's the Minor/Major chord, denoted by-M7
. – Petr Pudlák – 2015-02-06T14:43:33.0101@PetrPudlák In that case
^---
is wrong. – aditsu quit because SE is EVIL – 2015-02-06T15:56:09.117Petr, I think @dennisdeems 's point is, that if it is a Minor/Major chord, it should have a Db in it Bb-Db-F-A. If that is what you mean, please correct. Also note that the question still says "Major-minor" where I believe you mean minor-major" – Level River St – 2015-02-06T15:56:45.663
Yes, that's what I meant. Either the chord is named incorrectly or spelled incorrectly. – dennisdeems – 2015-02-06T17:11:28.333
@dennisdeems You're right, I corrected the answer. – Petr Pudlák – 2015-02-07T08:52:06.900
@steveverrill have a virtual medal for picking up after Petr :) – aditsu quit because SE is EVIL – 2015-02-07T15:18:58.447
@aditsu haha thanks. I'll have another one for my 155-byte C answer which I'm going to post soon, if I may. – Level River St – 2015-02-07T20:50:13.883