How to transfer musical chords using JavaScript?

I was wondering how to create a javascript function to transfer musical chords.

Since I do not expect everyone to be a musician here, I will try to explain how this works in music theory. I hope I don’t forget anything. If yes, musicians, please correct me.

1) Simple chords

Simple chords are almost as simple as the alphabet, and it looks like this:

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

From B, it again moves to C. Therefore, if the original chord is E , and we want to transfer +1, the resulting chord will be F If we transpose +4, the resulting chord will be G# .

2) Extended chords

They work almost like simple chords, but contain a few more characters that you can safely ignore when transposing. For example:

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

So, as in the case of simple chords, if we transpose Dsus7 + 3 = Fsus7

3) Low frequency bass tone

The problem arises when the bass reproduces a different tone than the root tone of the chord. This is indicated by a slash after the chord, and must also be transposed. Examples:

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

As in the case of examples 1 and 2, everything is the same, but the part after the slash also requires transposition, therefore:

C/G + 5 = F/C

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

I think that everything should be if I have not forgotten anything.

So basically, imagine that you have a javascript variable called chord and a transpose value of transpose . Which code will 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'; 
+8
javascript music
source share
6 answers

How about a little something like this:

 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 ]; }); } alert(transposeChord("Dm7/G", 2)); // gives "Em7/A" alert(transposeChord("Fmaj9#11", -23)); // gives "F#maj9#11" 

Please note that I added the example "F # maj9 # 11" to give you more information about what constitutes a valid chord name: you can find the "#" is a sharp character that does not follow the letter (in this case it refers to " eleven" ).

And, obviously, my function only understands sharp objects, not apartments, and doesn't understand the keys, so for example, transposeChord("C/E", 1) will give "C # / F" when it really should be "C # / E # ".

+8
source share
 function transpose(chord, increment) { var cycle = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]; var el = chord.charAt(0); if(chord.length > 1 && chord.charAt(1) == '#') { el += "#"; } var ind = cycle.indexOf(el); var newInd = (ind + increment + cycle.length) % cycle.length; var newChord = cycle[newInd]; return newChord + chord.substring(el.length); } 

I'll let you figure out the bass part, as it just calls the function twice.

Alternatively, you can add the code here before the function for older browsers that do not support indexOf .

I put the demo on jsFiddle.

EDIT: The problem was the negative module. The above will work as long as the negative result does not exceed the length (for example, you cannot transpose 100 steps down).

+2
source share

Define your keys with an object:

 var keys = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]; 

Break down your chord with a regular expression:

 var matches = /([AG]#?)([^\/]*)(?:\/([AG]#?))?/.exec(chord); var key = matches[1]; var descriptor = matches[2]; var bass = matches[3]; 

Do a little math to get a new key:

 var newKey = keys[(keys.indexOf(key) + transpose) % keys.length]; var newBass = keys[(keys.indexOf(bass) + transpose) % keys.length]; 

Combine it all again:

 var newChord = newKey + descriptor; if (newBass) { newChord += "/" + newBass; } return newChord; 
+1
source share
 function transposechord(chord, amount){ var scale = ["C","Cb","C#","D","Db","D#","E","Eb","E#","F","Fb","F#","G","Gb","G#", "A","Ab","A#","B","Bb","B#"]; var transp = ["Cb","C","C#","Bb","Cb","C","C","C#","D","Db","D","D#","C","Db","D", "D","D#","E","Eb","E","F","D","Eb","E", "E","E#","F#", "E","F","F#", "Eb","Fb","F","F","F#","G","Gb","G","G#","F","Gb","G", "G","G#","A", "Ab","A","A#","G","Ab","A","A","A#","B","Bb","B","C","A","Bb","B", "B","B#","C#"]; var subst = chord.match(/[^b#][#b]?/g); for(var ax in subst){ if(scale.indexOf(subst[ax])!==-1){ if(amount>0){ for(ix=0;ix<amount;ix++){ var pos = scale.indexOf(subst[ax]); var transpos = 3*pos-2+3; subst[ax] = transp[transpos+1]; } } if(amount<0){ for(ix=0;ix>amount;ix--){ var pos = scale.indexOf(subst[ax]); var transpos = 3*pos-2+3; subst[ax] = transp[transpos-1]; } } } } chord=subst.join(""); } 

chord = C / B, amount = 1: C # / C or chord = Gm7, quantity 2: Am7

0
source share

Ok, so I thought about it honestly now, and I have a functional answer. This is on a standard western scale (sorry northern Europeans).

To truly transfer the chord, you need 3 pieces of information: 1) the name CHORD, 2) OLDKEY and 3) NEWKEY. This is not always enough to modulate AMOUNT (is it UP-2 from the EF # or Gb key?).

Basically you need to save two distances β€” the distance between steps between CHORD and OLDKEY and the β€œletter” distance between CHORD and OLDKEY β€” when displaying CHORD in NEWKEY.

 function transposeChord(chord, oldKey, newKey) {} 

To simplify (?) This, I have predetermined each scale and all possible notes (and some impossible) in relation to this scale.

  var scales = { // scale_form = [1-7, #1-7, b1-7, *1-7, bb1-7] "CScale": ["C", "D", "E", "F", "G", "A", "B", "C#", "D#", "E#", "F#", "G#", "A#", "B#", "Cb", "Db", "Eb", "Fb", "Gb", "Ab", "Bb", "C*", "D*", "E*", "F*", "G*", "A*", "B*", "Cbb", "Dbb", "Ebb", "Fbb", "Gbb", "Abb", "Bbb"], "GScale": ["G", "A", "B", "C", "D", "E", "F#", "G#", "A#", "B#", "C#", "D#", "E#", "F*", "Gb", "Ab", "Bb", "Cb", "Db", "Eb", "F", "G*", "A*", "B*", "C*", "D*", "E*", "F#*", "Gbb", "Abb", "Bbb", "Cbb", "Dbb", "Ebb", "Fb"], "DScale": ["D", "E", "F#", "G", "A", "B", "C#", "D#", "E#", "F*", "G#", "A#", "B#", "C*", "Db", "Eb", "F", "Gb", "Ab", "Bb", "C", "D*", "E*", "F#*", "G*", "A*", "B*", "C#*", "Dbb", "Ebb", "Fb", "Gbb", "Abb", "Bbb", "Cb"], "AScale": ["A", "B", "C#", "D", "E", "F#", "G#", "A#", "B#", "C*", "D#", "E#", "F*", "G*", "Ab", "Bb", "C", "Db", "Eb", "F", "G", "A*", "B*", "C#*", "D*", "E*", "F#*", "G#*", "Abb", "Bbb", "Cb", "Dbb", "Ebb", "Fb", "Gb"], "EScale": ["E", "F#", "G#", "A", "B", "C#", "D#", "E#", "F*", "G*", "A#", "B#", "C*", "D*", "Eb", "F", "G", "Ab", "Bb", "C", "D", "E*", "F#*", "G#*", "A*", "B*", "C#*", "D#*", "Ebb", "Fb", "Gb", "Abb", "Bbb", "Cb", "Db"], "BScale": ["B", "C#", "D#", "E", "F#", "G#", "A#", "B#", "C*", "D*", "E#", "F*", "G*", "A*", "Bb", "C", "D", "Eb", "F", "G", "A", "B*", "C#*", "D#*", "E*", "F#*", "G#*", "A#*", "Bbb", "Cb", "Db", "Ebb", "Fb", "Gb", "Ab"], "F#Scale": ["F#", "G#", "A#", "B", "C#", "D#", "E#", "F*", "G*", "A*", "B#", "C*", "D*", "E*", "F", "G", "A", "Bb", "C", "D", "E", "F#*", "G#*", "A#*", "B*", "C#*", "D#*", "E#*", "Fb", "Gb", "Ab", "Bbb", "Cb", "Db", "Eb"], "C#Scale": ["C#", "D#", "E#", "F#", "G#", "A#", "B#", "C*", "D*", "E*", "F*", "G*", "A*", "B*", "C", "D", "E", "F", "G", "A", "B", "C#*", "D#*", "E#*", "F#*", "G#*", "A#*", "B#*", "Cb", "Db", "Eb", "Fb", "Gb", "Ab", "Bb"], "G#Scale": ["G#", "A#", "B#", "C#", "D#", "E#", "F*", "G*", "A*", "B*", "C*", "D*", "E*", "F#*", "G", "A", "B", "C", "D", "E", "F#", "G#*", "A#*", "B#*", "C#*", "D#*", "E#*", "F**", "Gb", "Ab", "Bb", "Cb", "Db", "Eb", "F"], "D#Scale": ["D#", "E#", "F*", "G#", "A#", "B#", "C*", "D*", "E*", "F#*", "G*", "A*", "B*", "C#*", "D", "E", "F#", "G", "A", "B", "C#", "D#*", "E#*", "F**", "G#*", "A#*", "B#*", "C**", "Db", "Eb", "F", "Gb", "Ab", "Bb", "C"], "A#Scale": ["A#", "B#", "C*", "D#", "E#", "F*", "G*", "A*", "B*", "C#*", "D*", "E*", "F#*", "G#*", "A", "B", "C#", "D", "E", "F#", "G#", "A#*", "B#*", "C**", "D#*", "E#*", "F**", "G**", "Ab", "Bb", "C", "D#", "Eb", "F", "G"], // E#Scale: // B#Scale: "FScale": ["F", "G", "A", "Bb", "C", "D", "E", "F#", "G#", "A#", "B", "C#", "D#", "E#", "Fb", "Gb", "Ab", "Bbb", "Cb", "Db", "Eb", "F*", "G*", "A*", "B#", "C*", "D*", "E*", "Fbb", "Gbb", "Abb", "Bbbb", "Cbb", ,"Dbb", ,"Ebb"], "BbScale": ["Bb", "C", "D", "Eb", "F", "G", "A", "B", "C#", "D#", "E", "F#", "G#", "A#", "Bbb", "Cb", "Db", "Ebb", "Fb", "Gb", "Ab", "B#", "C*", "D*", "E#", "F*", "G*", "A*", "Bbbb", "Cbb", "Dbb", "Ebbb", "Fbb", "Gbb", "Abb"], "EbScale": ["Eb", "F", "G", "Ab", "Bb", "C", "D", "E", "F#", "G#", "A", "B", "C#", "D#", "Ebb", "Fb", "Gb", "Abb", "Bbb", "Cb", "Db", "E#", "F*", "G*", "A#", "B#", "C*", "D*", "Ebbb", "Fbb", "Gbb", "Abbb", "Bbbb", "Cbb", "Dbb"], "AbScale": ["Ab", "Bb", "C", "Db", "Eb", "F", "G", "A", "B", "C#", "D", "E", "F#", "G#", "Abb", "Bbb", "Cb", "Dbb", "Ebb", "Fb", "Gb", "A#", "B#", "C*", "D#", "E#", "F*", "G*", "Abbb", "Bbbb", "Cbb", "Dbbb", "Ebbb", "Fbb", "Gbb"], "DbScale": ["Db", "Eb", "F", "Gb", "Ab", "Bb", "C", "D", "E", "F#", "G", "A", "B", "C#", "Dbb", "Ebb", "Fb", "Gbb", "Abb", "Bbb", "Cb", "D#", "E#", "F*", "G#", "A#", "B#", "C*", "Dbbb", "Ebbb", "Fbb", "Gbbb", "Abbb", "Bbbb", "Cbb"], "GbScale": ["Gb", "Ab", "Bb", "Cb", "Db", "Eb", "F", "G", "A", "B", "C", "D", "E", "F#", "Gbb", "Abb", "Bbb", "Cbb", "Dbb", "Ebb", "Fb", "G#", "A#", "B#", "C#", "D#", "E#", "F*", "Gbbb", "Abbb", "Bbbb", "Cbbb", "Dbbb", "Ebbb", "Fbb"] // CbScale: // FbScale: // BbbFlatScale: // ... } 

Then you assign your scales based on OLDKEY and NEWKEY:

 var oldKeyScale = scales[key + "Scale"] var newKeyScale = scales[newKey + "Scale"] 

Finally, some regex for finding and replacing all of these chord roots / planes / sharp / double flags / etc. with their corresponding position in the NEWKEY scale.

 var transposedChord transposedChord = chord.replace(/(([CDEFGAB]#\*)|([CDEFGAB]#)|([CDEFGAB]b+)|([CDEFGAB]\**))/g, function(match) { var i = oldKeyScale.indexOf(match) return newKeyScale[i] }) return transposedChord 

There is definitely a better, more thinking-computer way to do this, but it will take

 transposeChord("Am7/G", "C", "A#") 

and return

 "F*m7/E#" 
0
source share

Just to continue nnnnnn's answer. We can take his code and add a little more code to make it work with apartments.

 transposeChord("F#sus7/A#", 1) > "Gsus7/B" transposeChord("Bb", 1) > "B" ... works like a charm 

 function transposeChord(chord, amount) { var scale = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] var normalizeMap = {"Cb":"B", "Db":"C#", "Eb":"D#", "Fb":"E", "Gb":"F#", "Ab":"G#", "Bb":"A#", "E#":"F", "B#":"C"} return chord.replace(/[CDEFGAB](b|#)?/g, function(match) { var i = (scale.indexOf((normalizeMap[match] ? normalizeMap[match] : match)) + amount) % scale.length; return scale[ i < 0 ? i + scale.length : i ]; }) } 
 <!-- Example Page --> Chord: <input id="chord" type="text" value="C#" style="width:70px"> transposed by <input id="amount" type="number" value="0" style="width:30px"> = <input id="new-chord" type="text" style="width:70px"> <button onclick="document.getElementById('new-chord').value = transposeChord(document.getElementById('chord').value,parseInt(document.getElementById('amount').value))">Calculate</button> 
0
source share

All Articles