# Create a function for transposing musical chords

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)

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"


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 ];
});
}

• 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 – Richard Rodriguez Oct 29 '11 at 4:46
• @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. – nnnnnn Oct 29 '11 at 4:56
• 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! – Richard Rodriguez Oct 29 '11 at 5:07
• 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. – nnnnnn Oct 29 '11 at 5:34
• 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 rimmer@rimmer.sk ... – Richard Rodriguez Oct 29 '11 at 5:37

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.