From 31781c84bb15996316411b9ada2a2969eb23c58a Mon Sep 17 00:00:00 2001 From: Merijn Date: Wed, 19 Nov 2025 09:19:12 +0100 Subject: [PATCH 1/2] Transposes minor keys to relative major When transcoding to Nashville or Roman notation, correctly transposes minor keys to their relative major for accurate representation. Fixes #526 --- lib/ChordPro/Song.pm | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/ChordPro/Song.pm b/lib/ChordPro/Song.pm index e6c4db26..26702003 100644 --- a/lib/ChordPro/Song.pm +++ b/lib/ChordPro/Song.pm @@ -2659,15 +2659,24 @@ sub parse_chord { } } - if ( $xc && $info ) { - my $key_ord; - $key_ord = $self->{chordsinfo}->{$self->{meta}->{key}->[-1]}->{root_ord} - if $self->{meta}->{key}; - if ( $xcmov && !defined $key_ord ) { - do_warn("Warning: Transcoding to $xc without key may yield unexpected results\n"); - undef $xcmov; - } - my $i = $info->transcode( $xc, $key_ord ); + if ( $xc && $info ) { + my $key_ord; + if ( $self->{meta}->{key} ) { + my $key_info = $self->{chordsinfo}->{$self->{meta}->{key}->[-1]}; + $key_ord = $key_info->{root_ord}; + # For Nashville/Roman notation, convert minor keys to relative major + if ( $xcmov && $key_info->{qual_canon} && $key_info->{qual_canon} eq "-" ) { + # Minor key: transpose up 3 semitones to get relative major + my $p = ChordPro::Chords::get_parser(); + $key_ord = ( $key_ord + 3 ) % $p->intervals; + } + } + if ( $xcmov && !defined $key_ord ) { + do_warn("Warning: Transcoding to $xc without key may yield unexpected results\n"); + undef $xcmov; + } + my $i = $info->transcode( $xc, $key_ord ); + # Prevent self-references. $i->{xc} = $info unless $i eq $info; $info = $i; From b6dd5959c372d8180d45ff5af36f51b37349b1cb Mon Sep 17 00:00:00 2001 From: Merijn Date: Wed, 19 Nov 2025 23:26:22 +0100 Subject: [PATCH 2/2] Handles transcoded keys in Nashville notation Ensures that the original key is used for Nashville notation calculations when the key has already been transcoded, preventing incorrect chord transformations. Fixes #526 --- lib/ChordPro/Song.pm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/ChordPro/Song.pm b/lib/ChordPro/Song.pm index 26702003..ce2f4c34 100644 --- a/lib/ChordPro/Song.pm +++ b/lib/ChordPro/Song.pm @@ -2662,7 +2662,14 @@ sub parse_chord { if ( $xc && $info ) { my $key_ord; if ( $self->{meta}->{key} ) { - my $key_info = $self->{chordsinfo}->{$self->{meta}->{key}->[-1]}; + my $key_name = $self->{meta}->{key}->[-1]; + my $key_info = $self->{chordsinfo}->{$key_name}; + + # If the key was already transcoded, get the original + if ( $key_info->{xc} ) { + $key_info = $key_info->{xc}; + } + $key_ord = $key_info->{root_ord}; # For Nashville/Roman notation, convert minor keys to relative major if ( $xcmov && $key_info->{qual_canon} && $key_info->{qual_canon} eq "-" ) {