42
\$\begingroup\$

Input

The symbol of any triadic chord (see http://en.wikipedia.org/wiki/Chord_(music)#Triads).

Output

The notes constituting the given chord.

Examples

Input: AM Output: A C# E

Input: C#m Output: C# E G#

Input: Db+ Output: C# F A

Input: C0 Output: C D# F#

Bonuses

-50 if you can also deal with seventh chords

-150 for actually playing the sound of the chord

-150 for using printable characters to show how to play the chord on a piano; example for AM:

┌─┬─┬┬─┬─┬─┬─┬┬─┲┱─┬─┬─┲━┱┬─┲━┱─┬─┬┬─┬┬─┬─┐
│ │ ││ │ │ │ ││ ┃┃ │ │ ┃ ┃│ ┃ ┃ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ┃┃ │ │ ┃ ┃│ ┃ ┃ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ┃┃ │ │ ┃ ┃│ ┃ ┃ │ ││ ││ │ │
│ └┬┘└┬┘ │ └┬┘└┲┛┗┱┘ │ ┗┯┛└┲┛ ┃ └┬┘└┬┘└┬┘ │
│  │  │  │  │  ┃  ┃  │  │  ┃  ┃  │  │  │  │
└──┴──┴──┴──┴──┺━━┹──┴──┴──┺━━┹──┴──┴──┴──┘

-100 for using printable characters to show how to play the chord on a guitar; example for AM:

x   o   o   o   o   o
┌───┬───┬───┬───┬───┐
│   │   │   │   │   │
├───┼───┼───┼───┼───┤
│   │   │   │   │   │
├───┼───┼───┼───┼───┤
│   │   █   █   █   │
├───┼───┼───┼───┼───┤
│   │   │   │   │   │

(see https://en.wikipedia.org/wiki/Box-drawing_character)

Rules

  • The result must be a command-line program or script.

  • The input and output can be in any form, as long as it follows a music notation standard.

  • A guitar or piano representation is considered valid if and only if it contains the three (triadic) or four (seventh) required notes and nothing else. The same note can be present several times in the chord.

  • External libraries are not allowed, except for sound generation (in which case the #include, import... directives are not added to the character count).

  • This is code golf, the shortest code wins!

A little bit of music theory...

In modern Western tonal music, every octave is made of twelve successive notes, often noted:

A A# B C C# D D# E F F# G G#

Or:

La La# Si Do Do# Re Re# Mi Fa Fa# Sol Sol#

In this system, we consider that two successive notes (e.g. A and A#, or E and F) are separated by one semitone. Also, the notes are kind of "looping": what immediately follows G# is A.

Pitch constellation

A chord is constituted by a few (2, 3, 4, sometimes more) notes that "sound good together". For instance, triadic chords contain three different notes, and seventh chords contain four different notes.

Let's define the four triadic chords as:

  • Major triad: contains the root of the chord (in this question, the note given as input), the major third for the root (4 semitones higher than the root), and the perfect fifth for the root (7 semitones higher than the root); this can be symbolized 0-4-7

  • Minor triad, symbolized 0-3-7

  • Augmented triad, symbolized 0-4-8

  • Diminished triad, symbolized 0-3-6

Pitch constellations: triads

So for example, if you want to make a C major triad, noted C, CM, Cmaj, you will need three noted:

  • 0: the root, in this case a C
  • 4: the minor third, 4 semitones higher than the root; that's an E
  • 7: the perfect fifth, 7 semitones higher than the root: a G

This is what the 0-4-7, 0-3-7, 0-4-8 and 0-3-6 notations used above mean! For the seventh chords, use the following pattern:

Pitch constallations: seventh chords

That's it for today! Now, amaze me with amazing code... If you have any question, add some comments below.

\$\endgroup\$
18
  • 1
    \$\begingroup\$ It might be worth adding an explanation including the formulas for the chords in integer notation for non musicians. Integer notation refers to everything in semitones. Major chord (Example AM): 0,4,7. Minor chord (example C#m): 0,3,7. C diminished (Example Co, or as you call it C0) 0,3,6 (note that the correct representation is C Eb Gb, but for this challenge I guess we can assume both this and C D# F# are acceptable.) The formula for an augmented chord (Example Db+) is 0,4,8 and your example is wrong as it doesn't even contain a Db. As written it is a B+ which is equivalent to a D#+ or G+ \$\endgroup\$ Mar 24, 2014 at 17:12
  • 3
    \$\begingroup\$ Also, shortest code will result from use of the same chord shape for all guitar chords of the same type, barred. So Ab will be an A shape barred at the 11th fret. Is it Ok to put a number or do we have to draw 11 frets? All in all, it's a lot of things to think about. You may want to simplify the bonuses. \$\endgroup\$ Mar 24, 2014 at 17:29
  • 1
    \$\begingroup\$ Hmm.. your augmented chord is still wrong. C# is enharmonic to Db, but Db+ is Db F A there's no D# or G in there. That's perhaps a little more theory than necessary, the formulas were the important part. If you really want to include all eight of the seventh chords listed in wikipedia you should specify the input. I assume the ascii-art output of piano and guitar is flexible. \$\endgroup\$ Mar 24, 2014 at 22:04
  • 3
    \$\begingroup\$ I feel like I've learned more about music theory here than I've learned from lessons. \$\endgroup\$ Mar 28, 2014 at 22:37
  • 4
    \$\begingroup\$ The coolest problem on this site ! \$\endgroup\$
    – Ray
    Mar 31, 2014 at 17:16

12 Answers 12

9
\$\begingroup\$

As you can tell, I didn't try to golf this at all. I'm a music geek, and a pet peeve of mine is when people write things using the wrong enharmonics (e.g. saying that a C diminished chord is C D# F# instead of C Eb Gb), so I wrote this program that gets the enharmonics right. It does so by representing each note as the number of perfect fifths above F.

For what it's worth, if you want to distinguish enharmonics, any musical interval can be represented nicely in a computer program as a number of perfect fifths and a number of octaves. An augmented fourth, for example, is 6 perfect fifths and -3 octaves, and a diminished fifth is -6 perfect fifths and 4 octaves.

Haskell, 441 characters

import Data.List

notes = "FCGDAEB"

fromNum x = [notes !! (mod x 7)] ++ if x < 0 then replicate (-(div x 7)) 'b' else replicate (div x 7) '#'

toNum (x:xs) = y + 7 * if isPrefixOf "b" xs then -length xs else length xs
    where Just y = elemIndex x notes

chord xs = unwords . map (fromNum . \x -> toNum (init xs) + x) $ case last xs of 'A' -> [0,4,8]; 'M' -> [0,4,1]; 'm' -> [0,-3,1]; 'd' -> [0,-3,-6]

main = getLine >>= putStrLn . chord

Some example invocations:

jaspers:junk tswett$ ./chord
AM
A C# E
jaspers:junk tswett$ ./chord
C#m
C# E G#
jaspers:junk tswett$ ./chord
DbA
Db F A
jaspers:junk tswett$ ./chord
Cd
C Eb Gb
jaspers:junk tswett$ ./chord
A#M
A# C## E#
jaspers:junk tswett$ ./chord
Dbm
Db Fb Ab
\$\endgroup\$
0
5
+50
\$\begingroup\$

BBC BASIC

Emulator at bbcbasic.co.uk

Rev 1, 340 - 150 keyboard - 150 playing = 40

Here's the latest version, in which I managed to include the following enhancements while lengthening by only a few more characters.

Input can be edited comfortably on the screen before pressing return (I was using GET$ before to get single keypresses, because BBC Basic does not let you access a single character from a string as if the string was an array. Now I use the rather bulky MID$ function to extract a string of one character from within the string.

Both sides of keyboard displayed as well as the full line between E and F.

To compensate for the characters added by the above, I rearranged the program to eliminate unnecessary print statements, and deleted some white space which at first sight looked like it couldnt be deleted. IN BBC Basic all built in functions are reserved words, and you can put a variable name right before them with no space in between. Variable names are not allowed to start with a reserved word. In order to make the program less confusing to read I changed all variables to lower case.

Although the presentation looks much better, the following program is actually fully golfed already. (See correction below.) Generally newlines and colons are interchangeable, except when an IF statement is used. In that case all statements on the same line (separated by colons) with be executed conditionally. Statements after the newline are not controlled by the IF and will always be executed.

Program rev 1 340 characters

  a$="C#D#EF#G#A#B0Mm+"
  INPUTx$
  r=INSTR(a$,LEFT$(x$,1))-1
  c=INSTR(a$,MID$(x$,2,1))
  IFc=2c=INSTR(a$,MID$(x$,3)):r=r+1
  t=(r+4-c MOD2)MOD12
  f=(r+c DIV2)MOD12
  v=1
  FORn=-1TO11
  c=1-(n<0ORn=4ORn=11)*5
  b$=MID$(a$,n+1,1)
  IFb$="#"c=11:b$=MID$(a$,n,1)+b$
  c$=MID$("   _______--|__",c,5)
  IFr=n ORt=n ORf=n c$=c$+b$:SOUNDv,-15,100+n*4,99:v=v+1
  PRINTc$
  NEXT

CORRECTION: RT Russell's BBC BASIC for Windows allows you to eliminate some newlines and colons, bringing the total down to 327, see below. Also it tokenises the keywords into single characters before saving, bringing it down to 279.

  a$="C#D#EF#G#A#B0Mm+"INPUTx$
  r=INSTR(a$,LEFT$(x$,1))-1c=INSTR(a$,MID$(x$,2,1))IFc=2c=INSTR(a$,MID$(x$,3))r=r+1
  t=(r+4-c MOD2)MOD12f=(r+c DIV2)MOD12v=1FORn=-1TO11c=1-(n<0ORn=4ORn=11)*5b$=MID$(a$,n+1,1)IFb$="#"c=11b$=MID$(a$,n,1)+b$
  c$=MID$("   _______--|__",c,5)IFr=n ORt=n ORf=n c$=c$+b$SOUNDv,-15,100+n*4,99v=v+1
  PRINTc$
  NEXT

Output rev 1

enter image description here

Rev 0, 337 - 150 keyboard - 150 playing = 37

A$="C#D#EF#G#A#B0Mm+":X$=GET$:R=INSTR(A$,X$)-1:X$=GET$:IF X$="#"R=R+1:X$=GET$
C=INSTR(A$,X$):T=(R+4-C MOD2)MOD12:F=(R+C DIV2)MOD12:V=1:PRINT"______"
FORN=0 TO 11
C=1-(N=4)*12:B$=MID$(A$,N+1,1): IF B$="#" C=7: B$=MID$(A$,N,1)+B$
PRINT MID$("    __---|________",C,6);:IF(R-N)*(T-N)*(F-N)=0 PRINT B$;:SOUND V,-15,100+N*4,99:V=V+1
PRINT
NEXT

This is a similar concept to my Arduino answer, but I always knew I could beat that byte count with BBC basic. Only recognises sharps, but considers B# invalid,you must put C. This could be fixed if it was really considered important.

I abandoned the idea of guitar and concentrated on improving the keyboard. It now runs from C to B, and I've added in the left side of the keyboard and the line between E and F. That costs 28 characters. The right hand side wouldn't be much more.

Here's some sample output, an A# diminished chord (which has a pretty freaky sound in this inversion) and a B major chord. Note that the input is not echoed to the screen. As per the Arduino answer, turn the screen anticlockwise to view.

enter image description here

Ungolfed version

A$="C#D#EF#G#A#B0Mm+"                              :REM Note names and chord type names fit very conveniently in the same string.
X$=GET$                                            :REM Get a character 
R=INSTR(A$,X$)-1                                   :REM Root note = position of that char in A$. INSTR starts counting at 1, but we want 0, so subtract.
X$=GET$                                            :REM If the root note is natural, the next character will be the chord type. But...
IF X$="#"R=R+1:X$=GET$                             :REM If this char is # we need to increment the root, and get another char for chord type. 
C=INSTR(A$,X$)                                     :REM C encodes for chord type
T=(R+4-C MOD2)MOD12                                :REM even C means major third, odd C means minor third
F=(R+C DIV2)MOD12                                  :REM "Mm" gives C=14,15 meaning C DIV2=7 (perfect fifth.) C=13,16 give diminished and augmented: 6,8.
V=1                                                :REM V is the sound channel number ("voice")                             
PRINT"______"                                      :REM left side of keyboard for cosmetic reasons
FORN=0 TO 11                                       :REM at the start of each iteration initialise C to 1, to point to the 4 spaces/2 underscores in the string below for drawing white notes. 
  C=1-(N=4)*12                                     :REM if the note is E, add 12 so it points to the 6 underscores to draw the line between E and F. 
  B$=MID$(A$,N+1,1)                                :REM load B$ with the name of the current note.
  IF B$="#" C=7: B$=MID$(A$,N,1)+B$                :REM if the character encountered is a sharp, update C to point the characters for drawing a sharp. Find the previous character in A$ and join it to the beginning of B$ to complete the note name.
  PRINT MID$("    __---|________",C,6);            :REM print the key (6 characters.)
  IF(R-N)*(T-N)*(F-N)=0 PRINT B$;:SOUND V,-15,100+N*4,99:V=V+1  :REM if N is equal to R,T or F, print the note name beside the key, play the note and increment the channel number for the next note.  
  PRINT                                            :REM print a carriage return. It may be possible to golf this line out.
NEXT
\$\endgroup\$
9
  • \$\begingroup\$ How is the program supposed to be used from command line? (I installed BBC BASIC on my Ubuntu machine) \$\endgroup\$ Apr 3, 2014 at 14:27
  • \$\begingroup\$ Wow, I didn't know there was a version of BBC basic for Ubuntu. I can't find one on the site I got my emulator from, and I don't use Ubuntu. Original BBC basic only had one program in memory at a time so you typed RUN. With the emulator I use you have to start the emulator environment then it runs within it. It has a text editor, then you click to run, then when the program terminates you can either type RUN to run the program again, or type individual Basic commands within the environment. You can produce a command-line executable with my emulator, but only if you buy the full version. \$\endgroup\$ Apr 3, 2014 at 17:32
  • \$\begingroup\$ If you want to test the program, the best way I could help you is if you could find a Windows machine and download the exact version I'm using. Alternatively, if you could tell me where you got your Ubuntu version from I could have a little read of that. \$\endgroup\$ Apr 3, 2014 at 17:48
  • \$\begingroup\$ BBC Basic runs on Linux too, they provide many distributions on their home page depending on the host OS. I just didn't manage to get the program running, neither from passing the code or pasting it in the prompt... \$\endgroup\$ Apr 3, 2014 at 21:27
  • \$\begingroup\$ I just downloaded Napoleon Brandy Basic, and it is indeed, difficult to get started! You need save the code as text file called chords.nap, then type LOAD"chords.nap" at the command prompt. It adds line numbers to the code (more authentic to the original BBC Basic, would add a few more characters) Then you type RUN and the program crashes at the line with the SOUND statement in it, with the error message "Unsupported Basic V feature found." You could actually write a serious program with RT Russell's implementation if you really wanted to. But with Brandy basic I wouldn't even think about it. \$\endgroup\$ Apr 3, 2014 at 22:27
5
\$\begingroup\$

Python3 - 315 char

First time in codegolf! Only supports minor, major, diminished and augmented chords right now.

z=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"];y=[1,2,4,5,6]
def q(a):print(z[a%12])
a=input();k=(ord(a[0])+3)%7;j=k;m=4;s=0;f=7;
for i in y:
    if(k>=i):j+=1
if('#'in a):j+=1
if('b'in a):j-=1
if('m'in a or'0'in a):m=3
if('+'in a or"aug"in a):f=8
if('0'in a or"dim"in a):f=6;m=3
if('ma'in a):m=4
q(j);q(j+m);q(j+f);
\$\endgroup\$
5
  • 2
    \$\begingroup\$ Use 'C C# D D# E F F# G G# A A# B'.split(' ') instead of your literal array to save some bytes. \$\endgroup\$
    – wchargin
    Mar 25, 2014 at 0:36
  • 2
    \$\begingroup\$ if('#'in a):j+=1 -> if'#'in a:j+=1 = 2 chars less for every statement. Also changing y to a range() expression saves something too. Welcome! (and remember that newlines also count ;)) \$\endgroup\$
    – gcq
    Mar 25, 2014 at 1:17
  • 2
    \$\begingroup\$ @wch More bytes can be saved with 'C C# D D# E F F# G G# A A# B'.split() ;) \$\endgroup\$ Mar 25, 2014 at 1:25
  • 1
    \$\begingroup\$ How did you count your score? I think you have to count new lines as one char each as well. By the way, since this answer works only in Python3, I'll edit your answer to explicitly state that. Also, instead of using y to store [1,2,4,5,6], why don't you just skip the y and replace line 4 with for i in[1,2,4,5,6]:? Anyway, welcome to codegolf and I hope you have fun here. \$\endgroup\$
    – user12205
    Mar 25, 2014 at 3:56
  • 1
    \$\begingroup\$ You can also save 3 more chars by indenting with only one space instead of four in line 5. \$\endgroup\$
    – user12205
    Mar 25, 2014 at 4:03
5
\$\begingroup\$

Arduino

Input/output is sent to / received from the Arduino via a COM port. A user can interact with this via a terminal, or the serial monitor in the Arduino IDE. As you may have guessed from my choice of platform, I am planning to include the actual playing of the chord (though I haven't done it yet.)

I have tackled the keyboard bonus successfully, and I have tried to tackle the guitar, with limited success.

The chord box comes in at 130 bytes, which is too long to be worth it. Therefore I have tried another way, just printing the fret numbers Tab style. Currently this is 81 bytes for a bonus of 81-100=-19. If this approach is deemed valid I can try and improve on it.

The chords used are all D-type shapes with the root on the 2nd string, fifth on the 3rd string, and third on the 1st and 4th strings. The 5th and 6th strings are not used and I mark this with X's on the right of the chord box (the left would be more usual, but examples marked on the right can be found.)

Because the program considers F to be the lowest note (for compatability with the keyboard while avoiding excessively high frets with this chord shape) the highest chord is an E (with root on the 17th fret.) See example output.

The keyboard is more successful in terms of golfing. It runs from F-E rather than C-B for the reasons described above. It must be viewed by turning the screen 90% anticlockwise, when you can clearly see the outlines of the black notes, and the demarcation between the white notes with ---. The line between B an C could be extended with some ____ for a few more bytes.

I will try playing the notes next. This will be interesting because, although I believe the Arduino Uno has 3 internal timers, only one note at a time can be played using the built in tone command. There is an external library function which uses all the hardware timers (which will mess up the serial, but it won't be needed at that stage anyway.) Alternatively I may try to produce the tones in softare.

If I am successful with that, I will golf it down but I don't think it will be the overall winner.

Ungolfed code

String p="F#G#A#BC#D#E -Mm+",y,d[]=
{"    ","---|"},n="\n";

void setup() {
  Serial.begin(9600);
  Serial.setTimeout(99999);
}

void loop(){
  char x[9]; int r,t,f,i,c=1;
  Serial.readBytesUntil(13,x,9);
  Serial.println(x);  
  r=p.indexOf(x[0]);
  if (x[1]==35|x[1]==98){c=2;r+=x[1]==35?1:-1;}
  f=p.indexOf(x[c])/2;
  t=4-p.indexOf(x[c])%2;

  //chord box
  y=n;for(i=24;i--;)y+=d[1]+(i%4?"":" \n");
  y[89]=y[107]='X'; y[t*4-10]=y[t*4+52]=y[f*4+14]=y[28]='O';
  Serial.print("\t "+String(r+6)+y);
  
  f+=r;t+=r;

  //tab style
  Serial.println(String(t+1)+n+String(r+6)+n
  +String(f-2)+n+String(t+3)+"\nX\nX\n");
  
  f%=12;t%=12;

  //piano
  for(i=0;i<12;i++){
    c=0;
    y=String(p[i]);
    if(y=="#") {c=1;y=p[i-1]+y;}      
    Serial.println(d[c]+"__"+((r-i&&t-i&&f-i)?"":y));
  }  
}

Sample output The lower the spacing between the lines of text, the better this looks. Therefore it looks great when I am actually editing the post, but horrible in the grey box after posting. Instead I've posted a screenshot of the Arduino serial monitor which is of intermediate line spacing (and hence display quality.)

enter image description here

\$\endgroup\$
5
  • \$\begingroup\$ Can't wait for the actual sound! \$\endgroup\$ Mar 31, 2014 at 7:20
  • \$\begingroup\$ The notes for EM are correct (E G# B), but they aren't aligned correctly on your keyboard. It looks like you're on the right track though! \$\endgroup\$ Mar 31, 2014 at 15:36
  • \$\begingroup\$ @CameronTinker Please tilt your screen 90 deg anticlockwise and look again. Note that the keyboard runs from F to E, not from C to B for the reasons described in my post. Choosing F as the internal "zero note" was a compromise for both guitar and keyboard output. There are 3 black notes on the left, 2 on the right and the output notes are correctly aligned. Extending the division between B and C would make it clearer, but would cost about 20 extra bytes. Crude it is, but I still think my keyboard is more readable than Pandubear's. \$\endgroup\$ Mar 31, 2014 at 17:30
  • \$\begingroup\$ I don't know how I missed that! Sorry about that. I'm a pianist and my first inclination when I saw this was that the keyboard didn't look right ;). \$\endgroup\$ Mar 31, 2014 at 17:37
  • \$\begingroup\$ @MathieuRodic I've got sounds out of the Arduino now, but they are so poor I'm not sure I'd call them a recognisable chord. I will have another try, but there are a few things happening with the Arduino that I don't understand. Anyway I just posted an answer in BBC Basic with keyboard and sound that's looking much better. So I will update this post later \$\endgroup\$ Apr 3, 2014 at 1:29
5
\$\begingroup\$

Python 506(unicode as 1 char)-150(sound)-150(keyboard) = 206

For sound playing, it uses pygame.midi. Note that the pygame.midi.get_default_output_id() method don't work very well. So you may try changing the line o=Output(get_default_output_id()) to o=Output(1), o=Output(2), etc. Usually the correct value is between 0 and 5.

c=input()
s='C D EF G A B'.index(c[0])+{'#':1,'b':-1,'':0}[c[1:-1]]
m='0mM+'.index(c[-1])
t=s+3+m//2
R=[list(x)for x in['┌─'+'─┬─'*13+'─┐']+['│'+'  │'*14]*5+['└─'+'─┴─'*13+'─┘']]
i=3
for d in[3,6,3,3,6]*2:q=slice(i-1,i+2);R[0][q]='┬─┬';R[1][q]=R[2][q]=R[3][q]='│ │';R[4][q]='└┬┘';i+=d
X=[2]+[1,2,1,2,3,1,2,1,2,1,2,3]*2
from pygame.midi import*
init()
o=Output(get_default_output_id())
for s in[s,t,t+3+m%2]:R[[5,3][s%12 in[1,3,6,8,10]]][sum(X[:s+1])]='o';o.note_on(s+60,127,1)
for r in R:print(''.join(r))

Results

goooolf> python chords2.py
CM
┌─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┬─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┐
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │
│ o│  │ o│  │ o│  │  │  │  │  │  │  │  │  │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
goooolf> python chords2.py
Cm
┌─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┬─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┐
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││o│ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │
│ o│  │  │  │ o│  │  │  │  │  │  │  │  │  │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
goooolf> python chords2.py
Dm
┌─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┬─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┐
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │
│  │ o│  │ o│  │ o│  │  │  │  │  │  │  │  │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
goooolf> python chords2.py
D+
┌─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┬─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┐
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │o││ ││o│ │ │ ││ │ │ │ ││ ││ │ │
│ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │
│  │ o│  │  │  │  │  │  │  │  │  │  │  │  │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
G+
┌─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┬─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┐
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││o│ │ │ ││ ││ │ │
│ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │
│  │  │  │  │ o│  │ o│  │  │  │  │  │  │  │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
goooolf> python chords2.py
Am
┌─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┬─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┐
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │
│  │  │  │  │  │ o│  │ o│  │ o│  │  │  │  │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
goooolf> python chords2.py
C#0
┌─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┬─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┐
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │o││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │
│  │  │ o│  │ o│  │  │  │  │  │  │  │  │  │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
goooolf> python chords2.py
EbM
┌─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┬─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┐
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││ │ │ │ ││ ││ │ │ │ ││ │ │ │ ││ ││ │ │
│ │ ││o│ │ │ ││ ││o│ │ │ ││ │ │ │ ││ ││ │ │
│ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │
│  │  │  │  │ o│  │  │  │  │  │  │  │  │  │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
\$\endgroup\$
3
\$\begingroup\$

J - 82 char

Self-contained, reads from console input. If you need stdin, change the final 1 to a 3. Claiming no bonuses, and only covering the triads.

+/&(0 3 6++/\_3{.#:'0mM+'i.{:e)&.((,~C`Db`D`Eb`E`F`Gb`G`Ab`A`Bb`B)i.;:)}:e=.1!:1]1

Instead of a sharp note e.g. C# you must use the equivalent flat name Db. (Correcting for this would inflate the code by more than a bit.) The four types of chords are 0 for diminishing, m for minor, M for major, and + for augmented.

The logic is as follows: we use the last character to add an offset to the base 0-3-6, which selects the kind of third and fifth. Meanwhile, we use the note to find where in the scale to pull the notes from. The ;: both makes the note compatible with indexing into the scale at the start, and later (by &.) turns the pulled notes into a space separated string.

Example usage:

   +/&(0 3 6++/\_3{.#:'0mM+'i.{:e)&.((,~C`Db`D`Eb`E`F`Gb`G`Ab`A`Bb`B)i.;:)}:e=.1!:1]1
AM
A Ch E
   +/&(0 3 6++/\_3{.#:'0mM+'i.{:e)&.((,~C`Db`D`Eb`E`F`Gb`G`Ab`A`Bb`B)i.;:)}:e=.1!:1]1
Ab0
Ab B D
   +/&(0 3 6++/\_3{.#:'0mM+'i.{:e)&.((,~C`Db`D`Eb`E`F`Gb`G`Ab`A`Bb`B)i.;:)}:e=.1!:1]1
B+
B Eb G
   +/&(0 3 6++/\_3{.#:'0mM+'i.{:e)&.((,~C`Db`D`Eb`E`F`Gb`G`Ab`A`Bb`B)i.;:)}:e=.1!:1]1
Em
E G B
\$\endgroup\$
2
  • \$\begingroup\$ Does the suffix 'h' follow one of the "music notation standards"? \$\endgroup\$ Mar 25, 2014 at 1:18
  • \$\begingroup\$ @MathieuRodic I suppose it's a grey area, so I bumped them all up to flats. No change in functionality. Don't know why I didn't do this earlier. \$\endgroup\$ Mar 25, 2014 at 1:24
2
\$\begingroup\$

Javascript, 224 char

n=prompt();a="A0A#0B0C0C#0D0D#0E0F0F#0G0G#".split(0);x=1;r=a.indexOf(n[0]);n[1]=="#"&&(r++,x++);n[1]=="b"&&(r--,x++);s=r+4;l=r+7;(n[x]=="m"||n[x]==0)&&s++;s%=12;n[x]=="+"&&l++;n[x]==0&&l--;l%=12;alert(a[r]+" "+a[s]+" "+a[l])

This is my first code golf. I think it can be shorter, but I can't find any bytes to save.

Supports major, m for minor, 0 for diminished, + for augmented, or 37 more bytes for dim, aug.

\$\endgroup\$
3
  • \$\begingroup\$ n[m]==0 can be simply !n[m]. Same applies at another place. Total you can cut off 6 chars easily. \$\endgroup\$ Mar 25, 2014 at 15:52
  • \$\begingroup\$ @GaurangTandon Since n is string, n[m]==0 will cast 0 to "0", so it equals to n[m]=="0". "0" == 0 is true, but !"0" is false. \$\endgroup\$
    – Snack
    Mar 26, 2014 at 2:11
  • \$\begingroup\$ I was just pointing out because I got the same output when I inputted AM. I might be wrong also. \$\endgroup\$ Mar 26, 2014 at 5:59
2
\$\begingroup\$

Python (143 134 chars)

n,a='A A# B C C# D D# E F F# G G#'.split(),input();m,i=ord(a[-1])-42,n.index(a[:-1])
print(n[i],n[(i+4-m//2)%12],n[(i-4+(-m//2))%12]) 

My first golf challenge :), don't know if some more bytes can be shaved off.
The notation used here is * aug / + maj / , min / - dim
I deserve a bonus point for having the constant 42 in the code :P

\$\endgroup\$
1
  • \$\begingroup\$ You can gain a few bytes like this: n,q,a='A A# B C C# D D# E F F# G G#'.split(),[4,4,3,3],input();m,i=ord(a[-1])-42,n.index(a[:-1]) \$\endgroup\$ Mar 30, 2014 at 22:18
2
\$\begingroup\$

Scala 537 chars - 50

import java.util.Scanner
object C extends App{
val c=Map("M"->145,"m"->137,"+"->273,"0"->73,"7"->1169,"M7"->2193,"m7"->1161,"Mm7"->2185,"+7"->1297,"+M7"->2321,"07"->585,"7b5"->1097)
val n=List("A","A#","B","C","C#","D","D#","E","F","F#","G","G#")
val o=List("","Bb","Cb","B#","Db","","Eb","Fb","E#","Gb","","Ab")
val s=new Scanner(System.in).nextLine
val v=s indexWhere{c=>c!='#'&&c!='b'&&(c<'A'||c>'G')}
val (u,m)=s splitAt v
val x=n.indexOf(u)max o.indexOf(u)
val k=c(m)
for(i<-0 to 11)if((k&(1<<i))!=0)print(n((i+x)%12)+" ")
println}
\$\endgroup\$
1
\$\begingroup\$

Python 3: 257 - 150 = 107

Just 25 chars too long to beat the J solution! Oh well. There are some neat ideas here, I think.

I='AaBCcDdEFfGg'*2
Q='0123456789.,'*2
K="""-1#_2
-,#_0
-9#_.
____8
-6#_7
-4#_5
____3"""
r,*R,q=input()
r=I.find(r)+bool(R)
p=str.replace
for x in[0]+[8,4,7,3,6]['+Mm0'.find(q):][:2]:K=p(K,Q[x+r],I[x+r].upper())
for x in Q:K=p(K,x,' ')
print(p(K,' #','  '))

Input is like the examples, though you must use sharp names instead of flat names. (e.g. Gb must be F#)

Output is a single octave of a piano, seen from above and to the left, with note names superimposed. Should be just a tiny stretch of the imagination.

$ echo C#m | python3 chords.py
-  _ 
-G#_ 
-  _ 
____ 
-  _E
-C#_ 
____ 
\$\endgroup\$
7
  • \$\begingroup\$ Nice job! Although, I don't see the notes to play in the output? For CM, we should be able to read C E G... \$\endgroup\$ Mar 28, 2014 at 12:53
  • \$\begingroup\$ Oh, I misinterpreted the question I suppose. Let's see if I can work that in... \$\endgroup\$
    – Pandu
    Mar 28, 2014 at 16:27
  • \$\begingroup\$ Fixed! Too long... ): \$\endgroup\$
    – Pandu
    Mar 28, 2014 at 18:21
  • \$\begingroup\$ Can't you replace bool(R) with R|0? \$\endgroup\$ Mar 31, 2014 at 7:19
  • \$\begingroup\$ Nah, the point is that R is a list and bool(R) is 1 (true) if nonempty, and 0 (false) if empty. The | operator doesn't work with lists... \$\endgroup\$
    – Pandu
    Mar 31, 2014 at 7:25
1
\$\begingroup\$

Raku, 216 bytes

Shorter than my original Scala solution and spells pitches correctly to boot.

for $*IN.lines {m:P5/([A-G])(\#*)(b*)([Mm+0])/;my \r=4613502.comb[$0.ord-65]+7*($1.comb-$2.comb);put %(:M<0 4 1>,:m<0 -3 1>,"+",<0 4 8>,0,<0 -3 -6>){$3}.map({"FCGDAEB".comb[($/=r+$_)%7]~(<b #>)[$/>0]x abs($/div 7)})}

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Haskell, 273 chars

n(s,a)="CCDDEFFGGAABB"!!(s+1-a):["b#"!!a|" b b  b b b "!!s/=' ']
t p=[(s,a)|s<-[11,10..0],a<-[0,1],n(s,a)==p]!!0
m(s,d)=n(mod s 12,d-3)
c q=[n(a,x),m(a+d,d),m(a+d+e,e)]where
 (a,x)=t$init q;f=lookup(last q).zip"0mM+";Just d=f[3,3,4,4];Just e=f[3,4,3,4]
main=print.c=<<getLine

Results

C0 ->["C","Eb","Gb"]   Cm ->["C","Eb","G"]    CM ->["C","E","G"]     C+ ->["C","E","G#"]    
C#0->["C#","F","G"]    C#m->["C#","F","G#"]   C#M->["C#","F","Ab"]   C#+->["C#","F","A"]    
D0 ->["D","F","Ab"]    Dm ->["D","F","A"]     DM ->["D","F#","A"]    D+ ->["D","F#","A#"]   
D#0->["D#","Gb","A"]   D#m->["D#","Gb","A#"]  D#M->["D#","G","Bb"]   D#+->["D#","G","B"]    
E0 ->["E","G","Bb"]    Em ->["E","G","B"]     EM ->["E","G#","B"]    E+ ->["E","G#","C"]    
F0 ->["F","Ab","B"]    Fm ->["F","Ab","C"]    FM ->["F","A","C"]     F+ ->["F","A","C#"]    
F#0->["F#","A","C"]    F#m->["F#","A","C#"]   F#M->["F#","A#","Db"]  F#+->["F#","A#","D"]   
G0 ->["G","Bb","Db"]   Gm ->["G","Bb","D"]    GM ->["G","B","D"]     G+ ->["G","B","D#"]    
G#0->["G#","B","D"]    G#m->["G#","B","D#"]   G#M->["G#","C","Eb"]   G#+->["G#","C","E"]    
A0 ->["A","C","Eb"]    Am ->["A","C","E"]     AM ->["A","C#","F"]    A+ ->["A","C#","F"]    
A#0->["A#","Db","F"]   A#m->["A#","Db","F"]   A#M->["A#","D","F"]    A#+->["A#","D","F#"]   
B0 ->["B","D","F"]     Bm ->["B","D","F#"]    BM ->["B","D#","Gb"]   B+ ->["B","D#","G"]    
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.