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


in reply to Transpose guitar chords

Your code doesn't look inelegant to me. However, you've made a very significant simplifying assumption in your code sample, namely that each tone in the 12 tone scale has exactly one letter note value.

As you know, many notes in the 12 scale have in fact two letter representations (Bb=A#, E#=F, E=Fb, and so on). After you have transposed the note, converting it back into letter values (natural, sharp, flat) requires knowing not just the shift, but also the intended key signature. Otherwise you have no way of knowing if you need D# or Eb. Therefore the "amount" parameter is not enough to print out transposed chords. My own attempt taking into account key signatures might look something like this:

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

Note: I only eyeballed the chords - I'm not super good with purely written chords and didn't check my work on the keyboard, so if you see a mistake I apologize in advance.