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! |