File size: 2,751 Bytes
af6912c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
var sharpChords = ['C', 'C♯', 'D', "D♯", 'E', 'F', "F♯", 'G', 'G♯', 'A', 'A♯', 'B'];
var flatChords = ['C', 'D♭', 'D', 'E♭', 'E', 'F', 'G♭', 'G', 'A♭', 'A', 'B♭', 'B'];
var sharpChordsFree = ['C', 'C#', 'D', "D#", 'E', 'F', "F#", 'G', 'G#', 'A', 'A#', 'B'];
var flatChordsFree = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];

function transposeChordName(chord, steps, preferFlats, freeGCchord) {
	if (!steps || (steps % 12 === 0)) // The chords are the same if it is an exact octave change.
		return chord;

	// There are two things in the chord that might need to be transposed:
	// The chord will start with a letter from A-G, and might have one accidental after it.
	// That accidental might be an actual sharp or flat char, or it might be a pound sign or lower case "b".
	// Then there is a bunch of stuff that isn't transposed and should just be copied. That is stuff like "7" and more complicated chords.
	// But there is one other exception: right after a slash there will be a bass note and possibly an accidental. That should also be transposed.

	while (steps < 0) steps += 12;
	if (steps > 11) steps = steps % 12;

	// (chord name w/accidental) (a bunch of stuff) (/) (bass note) (anything else)
	var match = chord.match(/^([A-G][b#♭♯]?)([^\/]+)?\/?([A-G][b#♭♯]?)?(.+)?/)
	if (!match)
		return chord; // We don't recognize the format of the chord, so skip it.
	var name = match[1]
	var extra1 = match[2]
	var bass = match[3]
	var extra2 = match[4]
	var index = sharpChords.indexOf(name)
	if (index < 0)
		index = flatChords.indexOf(name)
	if (index < 0)
		index = sharpChordsFree.indexOf(name)
	if (index < 0)
		index = flatChordsFree.indexOf(name)
	if (index < 0)
		return chord; // This should never happen, but if we can't find the chord just bail.	

	index += steps
	index = index % 12

	if (preferFlats) {
		if (freeGCchord) chord = flatChordsFree[index]
		else chord = flatChords[index]
	} else {
		if (freeGCchord) chord = sharpChordsFree[index]
		else chord = sharpChords[index]
	}

	if (extra1)
		chord += extra1

	if (bass) {
		var index = sharpChords.indexOf(bass)
		if (index < 0)
			index = flatChords.indexOf(bass)
		if (index < 0)
			index = sharpChordsFree.indexOf(bass)
		if (index < 0)
			index = flatChordsFree.indexOf(bass)
		chord += '/'
		if (index >= 0) {
			index += steps
			index = index % 12
			if (preferFlats) {
				if (freeGCchord) chord += flatChordsFree[index]
				else chord += flatChords[index]
			} else {
				if (freeGCchord) chord += sharpChordsFree[index]
				else chord += sharpChords[index]
			}
		} else
			chord += bass; // Don't know what to do so do nothing
	}

	if (extra2)
		chord += extra2

	return chord;
}

module.exports = transposeChordName