http://qs321.pair.com?node_id=890437


in reply to Re: Transpose guitar chords
in thread Transpose guitar chords

This is only correct for major mode. Minor key signatures reverse the use of sharps and flats.

Replies are listed 'Best First'.
Re^3: Transpose guitar chords
by ELISHEVA (Prior) on Feb 27, 2011 at 18:58 UTC

    Good point. You are right that the code above is only for major keys.

    Minor keys are a bit more complex though than "reverse the use of sharps and flats". For the minor scales, only D,G switch from flats to sharps. F and all flat keys (Ab,Bb, etc) uses flats in both major and minor modes. B,E and all sharp keys (A#,B#,etc) use sharps for both major and minor modes. A goes from sharps to all naturals, and C goes from all naturals to flats. See Key signature.

    So here is the script revised to take into account minor keys as well as major keys (changes marked with <== ):

    use strict; use warnings; my %Tone =( A => 0, B => 2, C => 3, D => 5, E => 7, F => 8, G=>10); my @Notes; foreach my $natural ('A'..'G') { my $i = $Tone{$natural}; my $iFlat = $i ? $i-1 : 11; $Tone{$natural.'#'} = $i+1; $Tone{$natural.'b'} = $iFlat; $Notes[$iFlat][0]=$natural.'b'; $Notes[$i][0] = $natural; $Notes[$i][1] = $natural; $Notes[$i+1][1]=$natural.'#'; } #print "Tone: ". Dumper(\%Tone); #print "Notes: ". Dumper(\@Notes); sub transpose { my ($key, $aChord, $toKey) = @_; my @aTransposed; my $bMinor = $key =~ /m$/ ? 1 : 0; # <== $key= $key =~ /^(.*)m$/ ? $1 : $key; # <== $toKey= $toKey =~ /^(.*)m$/ ? $1 : $toKey; # <== my $iShift = $Tone{$toKey} - $Tone{$key}; my $iIndex = $bMinor # <== ? ($toKey =~ /^(?:C|D|F|G|.b)$/ ? 0 : 1) # minor key : ($toKey =~ /^(?:F|.b)$/ ? 0 : 1); # F uses flats in major push @aTransposed, $Notes[($Tone{$_}+$iShift) % 12][$iIndex] for @$aChord; return \@aTransposed; } # demo local $"='-'; print "Major modes\n"; for ('A'..'G','Eb','Bb', 'D', 'E') { print "C-E-G => $_ : @{transpose('C',[qw(C E G)],$_)}\n"; } print "Minor modes\n"; for ('A'..'G','Eb','Bb', 'D', 'E') { print "C-Eb-G => $_ : @{transpose('Cm',[qw(C Eb G)],qq{${_}m})}\n"; } # outputs Major modes C-E-G => A : A-C#-E C-E-G => B : B-D#-F# C-E-G => C : C-E-G C-E-G => D : D-F#-A C-E-G => E : E-G#-B C-E-G => F : F-A-C C-E-G => G : G-B-D C-E-G => Eb : Eb-G-Bb C-E-G => Bb : Bb-D-F C-E-G => D : D-F#-A C-E-G => E : E-G#-B Minor modes C-Eb-G => A : A-C-E C-Eb-G => B : B-D-F# C-Eb-G => C : C-Eb-G C-Eb-G => D : D-F-A C-Eb-G => E : E-G-B C-Eb-G => F : F-Ab-C C-Eb-G => G : G-Bb-D C-Eb-G => Eb : Eb-Gb-Bb C-Eb-G => Bb : Bb-Db-F C-Eb-G => D : D-F-A C-Eb-G => E : E-G-B

    And should anyone else see room for improvement, please post!

      Right, sorry, I should have said, sometimes reverse the use of sharps and flats. Another nice improvement would be to handle chord names in full generality, including minor chords, augmented, diminished, etc . This is mostly a matter of allowing suffixes after the sharp or flat notation, in the typical form, e.g. G sharp minor half diminished seventh is G#m7(b5). I think you'd just have to take everything after the A-G(#|b)? and just carry it through the transposition.