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 $iShift = $Tone{$toKey} - $Tone{$key}; my $iIndex = ($toKey =~ /^F|.b$/) ? 0 : 1; # F uses flats push @aTransposed, $Notes[($Tone{$_}+$iShift) % 12][$iIndex] for @$aChord; return \@aTransposed; } # demo local $"='-'; for ('A'..'G','Eb','Bb') { print "C-E-G => $_ : @{transpose('C',[qw(C E G)],$_)}\n"; } # which outputs 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