5
\$\begingroup\$

Your mission is to create a function for transposing music chords.

Copied from SO with permission of the original asker, I just really wanted to see what you guys could do with this one:

Since I don't expect everyone to be a musician here, I'll try to explain how it works in music theory. I hope I don't forget something. If yes, musicians, please, correct me.

1) The simple chords

The simple chords are almost as simple as an alphabet and it goes like this:

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

From B it loops all over again to C. Therefore, If the original chord is E and we want to transpose +1, the resulting chord is F. If we transpose +4, the resulting chord is G#.

2) Expanded chords

They work almost like the simple chords, but contain a few more characters, which can safely be ignored when transposing. For example:

Cmi, C#7, Dsus7, Emi, Fsus4, F#mi, G ...

So again, as with the simple chords, if we transpose Dsus7 + 3 = Fsus7

3) Non-root bass tone

A problem arises when the bass plays a different tone than the chord root tone. This is marked by a slash after the chord and also needs to be transposed. Examples:

C/G, Dmi/A, F#sus7/A#

As with examples 1 and 2, everything is the same, but the part after the slash needs transpose too, therefore:

C/G + 5 = F/C

F#sus7/A# + 1 = Gsus7/B

I think this should be all, unless I forgot something.

So basically, imagine you have a javascript variable called chord and the transpose value transpose. What code would transpose the chord?

Example:

var chord = 'F#sus7/C#';
var transpose = 3; // remember this value also may be negative, like "-4"
... code here ...
var result; // expected result = 'Asus7/E';

original question here: https://stackoverflow.com/questions/7936843/how-do-i-transpose-music-chords-using-javascript (note that he's asking for JS, for this challenge I don't care what language its in)

\$\endgroup\$

4 Answers 4

2
\$\begingroup\$

Haskell, 146

c=zip(words"C C# D D# E F F# G G# A A# B")[0..]
x#n=maybe x(\i->fst$c!!mod(i+n)12)$lookup x c
(x:'#':y)%n=(x:"#")#n++y%n
(x:y)%n=[x]#n++y%n
x%_=x

This defines an operator % that transposes a chord by a given amount, so you'd use it like this:

*Main> "E"%1
"F"
*Main> "E"%4
"G#"
*Main> "Dsus7"%3
"Fsus7"
*Main> "C/G"%5
"F/C"
*Main> "F#sus7/A#"%1
"Gsus7/B"
\$\endgroup\$
2
\$\begingroup\$

OK, within the limitations of the question as asked and not catering for a lot of things you'd need to allow for if using with real music (flats being the most obvious):

function t(c,a) {
  var s=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],i;
  return c.replace(/[A-G]#?/g,function(m){return s[(i=(s.indexOf(m)+a)%s.length)<0?i+s.length:i];});
}

This is my first attempt at code-golf, so I hope I've taken the right approach. Following is the readable version that I originally posted at stackoverflow.com:

function transposeChord(chord, amount) {
  var scale = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
  return chord.replace(/[CDEFGAB]#?/g,
                       function(match) {
                         var i = (scale.indexOf(match) + amount) % scale.length;
                         return scale[ i < 0 ? i + scale.length : i ];
                       });
}
\$\endgroup\$
8
  • \$\begingroup\$ I think flats and stuff like E# etc isn't really useful when simply "sharing" chords with friends and playing music this way. Of course they are very important in sheet music etc, but for people transposing music to play for their own pleasure, this seems like a very satisfying solution. +1 \$\endgroup\$
    – Frantisek
    Oct 29, 2011 at 4:46
  • \$\begingroup\$ @RIMMER - Even with a simple chord chart I find it much harder to follow when the author has ignored flats. Do you never play in the key of F (which has a Bb, not an A#)? I'd like to see a full solution (using my function or not) that transposes a whole chord chart and not just one chord. Thanks for the up-vote. \$\endgroup\$
    – nnnnnn
    Oct 29, 2011 at 4:56
  • \$\begingroup\$ Oh OK, I see what you mean now. Well, I play the piano and I know the scales perfectly, so even if the chords say A# and I'm in the F scale, I always know that I can play A in that scale and that the A# notation is actually Bb. Anyway, maybe you can re-define the problem to consider all this in the equation? I don't know how to explain the whole theory to reach the full solution, but I'd be happy to see the code! \$\endgroup\$
    – Frantisek
    Oct 29, 2011 at 5:07
  • \$\begingroup\$ A full solution is beyond me (and would probably be incomprehensible in a code-golf setting). I agree that yes, if I see an A# chord in the key of F I know that it should be a Bb, but it's a distraction so I'd rather correct the chart before I play from it. \$\endgroup\$
    – nnnnnn
    Oct 29, 2011 at 5:34
  • \$\begingroup\$ If I write down all the chords and exactly specify which scale has what sharps and what flats and would offer you a money reward, how much would it cost to code the full solution? (this is rather a reply for your stackoverflow comment, but I didn't want to put it there). anyway, my mail is [email protected] ... \$\endgroup\$
    – Frantisek
    Oct 29, 2011 at 5:37
0
\$\begingroup\$

As a preliminary effort, I'd like to flesh-out some of what "the full solution" should take into account.

Sharps and Flats

When transposing a musical key, one adds sharps or flats to the key signature according to the distance traversed in the "circle of fourths" (or fifths, depending on the direction you're going).

fifths from C up to the enharmonic
key: C G  D  A  E  B  F# C# G#  D#  A#  E#  B#
add:   F# C# G# D# A# E# B# F## C## G## D## A##

fourths from C down to the enharmonic
key: C F  Bb Eb Ab Db Gb Cb Fb  Bbb Ebb Abb Dbb
add:   Bb Eb Ab Db Gb Cb Fb Bbb Ebb Abb Dbb Gbb

So the key of C can be written with zero sharps or flats, or with twelve sharps, or with twelve flats. The first options is clearly superior.

But we only really need the middle of the table above because all those double-sharps and double-flats mean that some note is being given an overly-complicated name. So extracting the middle and arranging in sequence gives us this list of keys.

C  Db(5 'b's) D(2#) Eb(3b) E(4#) F(1b) F#(6#)[or Gb(6b)]
G(1#) Ab(4b) A(3#) Bb(2b) B(5#) C

And, dropping the counts and picking between F# and Gb (all flats looks prettier than one lonely sharp) gives:

C Db D Eb F Gb G Ab A Bb B C

But for named chords, the situation is less clear because the names carry accidentals with them.

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

Javascript, 249

This code handles bemol input:

let N=["A","A#","B","C","C#","D","D#","E","F","F#","G","G#"]
let t=(r,n)=>r.split("/").map((i)=>{
let a=i[1]
let m=a=="#"||a=="b"?2:1
let c=i.slice(0,m)
c=a=="b"?t(c[0],-1):c
let x=(N.indexOf(c)+n)%12
x=x<0?12+x:x
return N[x]+i.slice(m)
}).join("/")

Limitations:

  1. No double flat or double sharp support.
  2. No validation of the chord's bass note or modifiers.
  3. Output always uses sharps for accidents. i.e: G#/C instead of Ab/C.

To solve the 'full' problem, you need the program to understand the chord modifiers and calculate each note that the chord uses, then match that with the transposed chord to get the right answer. While possible I see it unpractical to code that in a code golf setting.

'Readable' version:

let Notes=["A","A#","B","C","C#","D","D#","E","F","F#","G","G#"]
let transpose=(input,n)=>input.split("/").map((splittedInput)=>{
let accident=splittedInput[1]
let modifierIndex=accident=="#"||accident=="b"?2:1
let note=splittedInput.slice(0,modifierIndex)
note=accident=="b"?transpose(note[0],-1):note
let transposedIndex=(Notes.indexOf(note)+n)%12
transposedIndex=transposedIndex<0?12+transposedIndex:transposedIndex
return Notes[transposedIndex]+splittedInput.slice(modifierIndex)
}).join("/")
\$\endgroup\$
2
  • 4
    \$\begingroup\$ Welcome to the site! Answers should include code in the body of the question (rather than an external link), and the code should aim to be competitive (i.e. golfed as this is a code-golf challenge). \$\endgroup\$ Jan 17, 2021 at 21:24
  • \$\begingroup\$ Thanks for letting me know. I wasn't familiar with the code golf concept. \$\endgroup\$
    – corlaez
    Jan 18, 2021 at 6:14

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.