Music: What's the name of this chord?

9

3

This is the reverse of Music: what's in this chord?, which is to print the notes in a given chord. This time the input is a list of notes in a chord, and your task is to output which chord it is.

Your program should support the following triadic chords. Examples are given with root C. Chords with other roots are the same chords with all notes rotated so C will become that root note, e.g. Dmaj consists of D, F# and A.

        C C#D D#E F F#G G#A A#B
          Db  Eb    Gb  Ab  Bb
Cmaj    C       E     G
Cm      C     D#      G
Caug    C       E       G#
Cdim    C     D#    F#
Csus4   C         F   G
Csus2   C   D         G

Note that Caug is the same as Eaug and G#aug, and Csus4 is the same as Fsus2. You can output either one but there is a bonus if you output them all.

And the seventh chords for the bonus are listed in the follow table:

        C C#D D#E F F#G G#A A#B
          Db  Eb    Gb  Ab  Bb
C7      C       E     G     A#
Cm7     C     D#      G     A#
Cmmaj7  C     D#      G       B
Cmaj7   C       E     G       B
Caug7   C       E       G#  A#
Cdim7   C     D#    F#    A

Rules

  • You can write either a complete program or a function.
  • The input is a list of notes, separated by a space or another convenient character. It can also be an array of strings (if it take input from function argument) or the string representation of such array.
  • Input doesn't have to be in specific order.
  • There may be duplicated notes in the input. They must be treated the same way as there is only one of them.
  • The output is the name of the chord. In case it will output multiple names, the same rule for input applies.
  • If the input isn't a supported chord, you should print the notes as-is. Your program can also support other chords not listed in the tables above (which is valid but has no bonus).
  • You can use other notations listed in the Wikipedia article. But if you choose C for C major, you should add a human readable prefix in either case to distinguish a chord with a single note.
  • You cannot use built-in functions for this task (if there is any).
  • This is code-golf. Shortest code in bytes wins.

Examples

  • Input: C D# G Output: Cm.
  • Input: C Eb G Output: Cm.
  • Input: C Eb F# Output: Cdim.
  • Input: F A C# Output: Faug, Aaug, C#aug, Dbaug or Faug Aaug C#aug, Faug Aaug Dbaug in any order.
  • Input: F D F F F F A A F Output: Dm.
  • Input: C D Output: C D.

Bonuses

  • -30 if it prints them all if there are more than one interpretations (for aug, sus4/sus2 and dim7).
  • -70 if it also supports seventh chords.
  • -200 if it accepts MIDI input and prints each chord it have received. Note that the notes doesn't have to begin or end at the same time. You decide what happens in the intermediate states (as long as it doesn't crash or stop working). You may assume there are no notes in percussion channels (or there is only one channel if that's convenient). It is recommended to also provide a text (or array) version for testing, especially if it is platform-dependent.

jimmy23013

Posted 2015-01-07T16:04:28.837

Reputation: 34 042

Can the input have flats or is it using sharp only? Should notes such as B# be handled? – feersum – 2015-01-07T20:50:14.687

@feersum It can have flats (unless you claim the -200 bonus). Added some examples. You don't need to handle B#, Cb, etc. – jimmy23013 – 2015-01-08T04:28:33.770

You say Csus4 is the same as Gsus2. I think you mean Csus2 is the same as Gsus4 don't you? – Gareth – 2015-01-08T11:14:48.470

@Gareth ...Yes. Fixed. – jimmy23013 – 2015-01-08T11:32:10.880

Answers

2

Pyth 190 character - 30 - 70 = 90

=Q{cQdL+x"C D EF G A B"hb&tlbt%hx" #b"eb3FZQJx[188 212 199 213 200 224 2555 2411 2412 2556 2567 2398)u+*G12hHSm%-dyZ12mykQ0IhJ+Z@c"sus2 maj dim aug m sus4 7 m7 mmaj7 maj7 aug7 dim7"dJ=T0;ITQ

Not really happy with it. Used hard-coded chords.

Usage:

Try it here: Pyth Compiler/Executor. Disable debug mode and use "C D# G" as input.

Explanation:

First some preparation:

=Q{cQd
   cQd  split chord into notes "C D# G" -> ["C", "D#", "G"]
  {     set (eliminate duplicates)
=Q      Q = ...

Then a function that converts notes into integer

L+x"C D EF G A B"hb&tlbt%hx" #b"eb3
defines a function g(b),
  returns the sum of 
     index of "D" in "C D EF G A B"
     and the index of "#" in " #b" 
       (if b than use -1 instead of 2)

Then for each note, shift the coord and look it up in a table

FZQJx[188 ...)u+*G12hHSm%-dyZ12mykQ0IhJ+Z@c"sus2 ..."dJ=T0;ITQ
               implicit T=10
FZQ            for note Z in chord Q:
   mykQ         map each note of Q to it's integer value
   m%-dyZ12     shift it by the integer value of Z modulo 12 
   S            sort it
   u+*G12hH 0   convert it to an integer in base 12
   x[188 ...)   look it up in the list (-1 if not in list)
   J            and store the value in J

   IhJ               if J>=0:
   +Z@c"sus2 ..."dJ   print the note Z and the chord in the list
=T0                   and set T=0
;            end loop
ITQ          if T:print chord (chord not in list)

Jakube

Posted 2015-01-07T16:04:28.837

Reputation: 21 462

2

Perl 5: 183 - 100 = 83

Edit: I managed to cut some extra characters so I also altered the chord names like in the Python solution, so I can pretend for a moment that I am leading.

#!perl -pa
for$z(0..11){$x=0;$x|=1<<((/#/-/b/+$z+1.61*ord)%12or$o=$_)for@F;$x-/\d+_?/-$_*4||push@r,$o.$'
for qw(36M 34- 68+ 18o 40sus2 33sus4 292_7 290-7 546-M7 548M7 324+7 146o7)}$_="@r
"if@r

Example:

$ perl chord.pl <<<"C D# G"
C-

nutki

Posted 2015-01-07T16:04:28.837

Reputation: 3 634

0

Python 2, 335 bytes - 30 - 70 = 235

First attempt at a slightly longer golf, so I may be missing some obvious tricks.

def f(s,N="C D EF G A B",r=range,u=1):
 for i in r(12):
  for t in r(12):
   if(set((N.find(n[0])+" #".find(n[1:]))%12for n in s.split())==set(map(lambda n:(int(n,16)+i)%12,"0"+"47037048036057027047A37A37B47B48A369"[3*t:3*t+3]))):print(N[i],N[i+1]+"b")[N[i]==" "]+"M - + o sus4 sus2 7 -7 -M7 M7 +7 o7".split()[t];u=0
 if(u):print s

Comments:

  • I used alternative chord names from the Wiki page (see the end of the long line) to save space.
  • Chords are represented by 3 hex offsets each (0 is not required but included for triads to make them line up).
  • " #".find(n[1:]) works since " #".find("b") is -1 and " #".find("") is 0.

Sample output

>>> f("C D# G")
C-
>>> f("C Eb G")
C-
>>> f("C Eb F#")
Co
>>> f("F A C#")
Db+
F+
A+
>>> f("F D F F F F A A F")
D-
>>> f("C D")
C D
>>> f("C Eb Gb A")
Co7
Ebo7
Gbo7
Ao7

Uri Granta

Posted 2015-01-07T16:04:28.837

Reputation: 2 675