|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #! perl  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package main;  | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $config;  | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $options;  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package ChordPro::Chords;  | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
10
 | 
81
 | 
 
 | 
 
 | 
  
81
  
 | 
 
 | 
1044
 | 
 use v5.26;  | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
291
 | 
    | 
| 
11
 | 
81
 | 
 
 | 
 
 | 
  
81
  
 | 
 
 | 
529
 | 
 use utf8;  | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
190
 | 
    | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
470
 | 
    | 
| 
12
 | 
81
 | 
 
 | 
 
 | 
  
81
  
 | 
 
 | 
1848
 | 
 use Carp;  | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
170
 | 
    | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4496
 | 
    | 
| 
13
 | 
81
 | 
 
 | 
 
 | 
  
81
  
 | 
 
 | 
508
 | 
 use feature qw( signatures );  | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
240
 | 
    | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6663
 | 
    | 
| 
14
 | 
81
 | 
 
 | 
 
 | 
  
81
  
 | 
 
 | 
588
 | 
 no warnings "experimental::signatures";  | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
173
 | 
    | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3352
 | 
    | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
16
 | 
81
 | 
 
 | 
 
 | 
  
81
  
 | 
 
 | 
44463
 | 
 use ChordPro::Chords::Parser;  | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
260
 | 
    | 
| 
 
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
493906
 | 
    | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Chords defined by the configs.  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %config_chords;  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Names of chords loaded from configs.  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my @chordnames;  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Additional chords, defined by the user.  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %song_chords;  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Current tuning.  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my @tuning;			# names, e.g. E2  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my @t_ord;			# ordinals, e.g. 4  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $t_oct;			# octave, usually 12  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Assert that an instrument is loaded.  | 
| 
33
 | 
199
 | 
 
 | 
 
 | 
  
199
  
 | 
  
0
  
 | 
497
 | 
 sub assert_tuning () {  | 
| 
 
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
408
 | 
    | 
| 
34
 | 
199
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
829
 | 
     Carp::croak("FATAL: No instrument?") unless @tuning;  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ################ Section Dumping Chords ################  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Returns a list of all chord names in a nice order.  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: ChordPro, Output/ChordPro.  | 
| 
41
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 sub chordnames () {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
42
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     assert_tuning();  | 
| 
43
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     [ sort chordcompare @chordnames ];  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Chord order ordinals, for sorting.  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %chordorderkey; {  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $ord = 0;  | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     for ( split( ' ', "C C# Db D D# Eb E F F# Gb G G# Ab A A# Bb B" ) ) {  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	$chordorderkey{$_} = $ord;  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	$ord += 2;  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Compare routine for chord names.  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Used by: Song.  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub chordcompare {  | 
| 
58
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ( $a0, $arest ) = $a =~ /^([A-G][b#]?)(.*)/;  | 
| 
59
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my ( $b0, $brest ) = $b =~ /^([A-G][b#]?)(.*)/;  | 
| 
60
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
     $a0 = $chordorderkey{$a0//"\x{ff}"}//return 0;  | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
61
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
     $b0 = $chordorderkey{$b0//"\x{ff}"}//return 0;  | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
62
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $a0 <=> $b0 if $a0 != $b0;  | 
| 
63
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $a0++ if $arest =~ /^m(?:in)?(?!aj)/;  | 
| 
64
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $b0++ if $brest =~ /^m(?:in)?(?!aj)/;  | 
| 
65
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     for ( $arest, $brest ) {  | 
| 
66
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	s/11/:/;		# sort 11 after 9  | 
| 
67
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	s/13/;/;		# sort 13 after 11  | 
| 
68
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	s/\((.*?)\)/$1/g;	# ignore parens  | 
| 
69
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	s/\+/aug/;		# sort + as aug  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
71
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $a0 <=> $b0 || $arest cmp $brest;  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Dump a textual list of chord definitions.  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Should be handled by the ChordPro backend?  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
76
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 sub list_chords ( $chords, $origin, $hdr ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
77
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     assert_tuning();  | 
| 
78
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my @s;  | 
| 
79
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if ( $hdr ) {  | 
| 
80
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $t = "-" x (((@tuning - 1) * 4) + 1);  | 
| 
81
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	substr( $t, (length($t)-7)/2, 7, "strings" );  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	push( @s,  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	      "# CHORD CHART",  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	      "# Generated by ChordPro " . $ChordPro::VERSION,  | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	      "# https://www.chordpro.org",  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	      "#",  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	      "#            " . ( " " x 35 ) . $t,  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	      "#       Chord" . ( " " x 35 ) .  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	      join("",  | 
| 
90
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		   map { sprintf("%-4s", $_) }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		   @tuning ),  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    );  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
95
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     foreach my $chord ( @$chords ) {  | 
| 
96
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $info;  | 
| 
97
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if ( eval{ $chord->{name} } ) {  | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
98
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $info = $chord;  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	elsif ( $origin eq "chord" ) {  | 
| 
101
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    push( @s, sprintf( "{%s:  %s}", "chord", $chord ) );  | 
| 
102
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    next;  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	else {  | 
| 
105
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $info = known_chord($chord);  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
107
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	next unless $info;  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	my $s = sprintf( "{%s %-15.15s base-fret %2d    ".  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			 "frets   %s",  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			 $origin eq "chord" ? "chord: " : "define:",  | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			 $info->{name}, $info->{base},  | 
| 
112
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 			 @{ $info->{frets} // [] }  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			 ? join("",  | 
| 
114
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				map { sprintf("%-4s", $_) }  | 
| 
115
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				map { $_ < 0 ? "X" : $_ }  | 
| 
116
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 				@{ $info->{frets} } )  | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 			 : ("    " x strings() ));  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	$s .= join("", "    fingers ",  | 
| 
119
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		   map { sprintf("%-4s", $_) }  | 
| 
120
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		   map { $_ < 0 ? "X" : $_ }  | 
| 
121
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		   @{ $info->{fingers} } )  | 
| 
122
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	  if $info->{fingers} && @{ $info->{fingers} };  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	$s .= join("", "    keys ",  | 
| 
124
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		   map { sprintf("%2d", $_) }  | 
| 
125
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		   @{ $info->{keys} } )  | 
| 
126
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	  if $info->{keys} && @{ $info->{keys} };  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
127
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$s .= "}";  | 
| 
128
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	push( @s, $s );  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
130
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     \@s;  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
133
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 sub dump_chords ( $mode ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
134
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     assert_tuning();  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     print( join( "\n",  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		 $mode && $mode == 2  | 
| 
137
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		 ? @{ json_chords(\@chordnames ) }  | 
| 
138
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 		 : @{ list_chords(\@chordnames, "__CLI__", 1) } ), "\n" );  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
141
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 sub json_chords ( $chords ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
142
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     assert_tuning();  | 
| 
143
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my @s;  | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     push( @s, "// ChordPro instrument definition.",  | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  "",  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  qq<{ "instrument" : "> .  | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  ($::config->{instrument} || "Guitar, 6 strings, standard tuning") .  | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  qq<",>,  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  "",  | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  qq<  "tuning" : [ > .  | 
| 
152
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	  join(", ", map { qq{"$_"} } @tuning) . " ],",  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  "",  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  qq{  "chords" : [},  | 
| 
155
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  "",  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	 );  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
158
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $maxl = -1;  | 
| 
159
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     foreach my $chord ( @$chords ) {  | 
| 
160
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $t = length( $chord );  | 
| 
161
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$maxl < $t and $maxl = $t;  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
163
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $maxl += 2;  | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
165
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     foreach my $chord ( @$chords ) {  | 
| 
166
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $info;  | 
| 
167
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if ( eval{ $chord->{name} } ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
168
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $info = $chord;  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	else {  | 
| 
171
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $info = known_chord($chord);  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
173
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	next unless $info;  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
175
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $name = '"' . $info->{name} . '"';  | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	my $s = sprintf( qq[    { "name" : %-${maxl}.${maxl}s,] .  | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                          qq[ "base" : %2d,],  | 
| 
178
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 			 $name, $info->{base} );  | 
| 
179
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if ( @{ $info->{frets} } ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    $s .= qq{ "frets" : [ } .  | 
| 
181
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      join( ", ", map { sprintf("%2s", $_) } @{ $info->{frets} } ) .  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		qq{ ],};  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
184
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	if ( $info->{fingers} && @{ $info->{fingers} } ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    $s .= qq{ "fingers" : [ } .  | 
| 
186
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      join( ", ", map { sprintf("%2s", $_) } @{ $info->{fingers} } ) .  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		qq{ ],};  | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
189
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	if ( $info->{keys} && @{ $info->{keys} } ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    $s .= qq{ "keys" : [ } .  | 
| 
191
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      join( ", ", map { sprintf("%2d", $_) } @{ $info->{keys} } ) .  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		qq{ ],};  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
194
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	chop($s);  | 
| 
195
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$s .= " },";  | 
| 
196
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	push( @s, $s );  | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
198
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     chop( $s[-1] );  | 
| 
199
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     push( @s, "", "  ]," );  | 
| 
200
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if ( $::config->{pdf}->{diagrams}->{vcells} ) {  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	push( @s, qq<  "pdf" : { "diagrams" : { "vcells" : > .  | 
| 
202
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      $::config->{pdf}->{diagrams}->{vcells} . qq< } },> );  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
204
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     chop( $s[-1] );  | 
| 
205
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     push( @s, "}" );  | 
| 
206
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     \@s;  | 
| 
207
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
208
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ################ Section Tuning ################  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Return the number of strings supported.  | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: Songbook, Output::PDF.  | 
| 
213
 | 
50112
 | 
 
 | 
 
 | 
  
50112
  
 | 
  
0
  
 | 
67979
 | 
 sub strings () {  | 
| 
 
 | 
50112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
65783
 | 
    | 
| 
214
 | 
50112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
133888
 | 
     scalar(@tuning);  | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $parser;# = ChordPro::Chords::Parser->default;  | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Set tuning, discarding chords.  | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: Config.  | 
| 
221
 | 
199
 | 
 
 | 
 
 | 
  
199
  
 | 
  
0
  
 | 
673
 | 
 sub set_tuning ( $cfg ) {  | 
| 
 
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
533
 | 
    | 
| 
 
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
486
 | 
    | 
| 
222
 | 
199
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
1185
 | 
     my $t = $cfg->{tuning} // [];  | 
| 
223
 | 
199
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1287
 | 
     return "Invalid tuning (not array)" unless ref($t) eq "ARRAY";  | 
| 
224
 | 
199
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
1289
 | 
     $options //= { verbose => 0 };  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
226
 | 
199
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1095
 | 
     if ( @tuning ) {  | 
| 
227
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1822
 | 
 	( my $t1 = "@$t" ) =~ s/\d//g;  | 
| 
228
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1184
 | 
 	( my $t2 = "@tuning" ) =~ s/\d//g;  | 
| 
229
 | 
118
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
667
 | 
 	if ( $t1 ne $t2 ) {  | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    warn("Tuning changed, chords flushed\n")  | 
| 
231
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      if $options->{verbose} > 1;  | 
| 
232
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    @chordnames = ();  | 
| 
233
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    %config_chords = ();  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     else {  | 
| 
237
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
344
 | 
 	@chordnames = ();  | 
| 
238
 | 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
313
 | 
 	%config_chords = ();  | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
240
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1209
 | 
     @tuning = @$t;  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Get ordinals for tuning.  | 
| 
243
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3047
 | 
     my $p = ChordPro::Chords::Parser->get_parser("common");  | 
| 
244
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
583
 | 
     $t_oct = keys %{ $p->{ns_tbl} };  | 
| 
 
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1034
 | 
    | 
| 
245
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
761
 | 
     for ( @tuning ) {  | 
| 
246
 | 
1194
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5385
 | 
 	return "Invalid tuning (should be note + octave): $_"  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  unless /(^.*?)(\d+)$/;	# split off octave  | 
| 
248
 | 
1194
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
4365
 | 
 	my $n = $p->{ns_tbl}->{$1} // $p->{nf_tbl}->{$1};  | 
| 
249
 | 
1194
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
2897
 | 
 	return "Invalid tuning (unknown note): $1" unless defined $n;  | 
| 
250
 | 
1194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3902
 | 
 	push( @t_ord, $2 * $t_oct + $n );  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
253
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1713
 | 
     assert_tuning();  | 
| 
254
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
797
 | 
     return;  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Get tuning.  | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: String substitution.  | 
| 
260
 | 
2139
 | 
 
 | 
 
 | 
  
2139
  
 | 
  
0
  
 | 
3364
 | 
 sub get_tuning () {  | 
| 
 
 | 
2139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2959
 | 
    | 
| 
261
 | 
2139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2945
 | 
     @{[@tuning]};  | 
| 
 
 | 
2139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15328
 | 
    | 
| 
262
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Set target parser.  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: ChordPro.  | 
| 
266
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
  
0
  
 | 
12437
 | 
 sub set_parser ( $p ) {  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
268
 | 
7
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
68
 | 
     $p = ChordPro::Chords::Parser->get_parser($p)  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       unless ref($p) && $p->isa('ChordPro::Chords::Parser');  | 
| 
270
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     $parser = $p;  | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     warn( "Parser: ", $parser->{system}, "\n" )  | 
| 
272
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
30
 | 
       if $options->{verbose} > 1;  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
274
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
     return;  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Parser stack.  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
279
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my @parsers;  | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Reset current parser.  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: Config.  | 
| 
283
 | 
210
 | 
 
 | 
 
 | 
  
210
  
 | 
  
0
  
 | 
559
 | 
 sub reset_parser () {  | 
| 
 
 | 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
398
 | 
    | 
| 
284
 | 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
622
 | 
     undef $parser;  | 
| 
285
 | 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
767
 | 
     @parsers = ();  | 
| 
286
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
288
 | 
72
 | 
 
 | 
 
 | 
  
72
  
 | 
  
0
  
 | 
117
 | 
 sub get_parser () {  | 
| 
 
 | 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
113
 | 
    | 
| 
289
 | 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
248
 | 
     $parser;  | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
292
 | 
199
 | 
 
 | 
 
 | 
  
199
  
 | 
  
0
  
 | 
577
 | 
 sub push_parser ( $p ) {  | 
| 
 
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
757
 | 
    | 
| 
 
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
469
 | 
    | 
| 
293
 | 
199
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
1706
 | 
     $p = ChordPro::Chords::Parser->get_parser($p)  | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       unless ref($p) && $p->isa('ChordPro::Chords::Parser');  | 
| 
295
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
968
 | 
     push( @parsers, $p );  | 
| 
296
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
729
 | 
     $parser = $p;  | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
299
 | 
199
 | 
 
 | 
 
 | 
  
199
  
 | 
  
0
  
 | 
463
 | 
 sub pop_parser () {  | 
| 
 
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
458
 | 
    | 
| 
300
 | 
199
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
737
 | 
     Carp::croak("Parser stack underflow") unless @parsers;  | 
| 
301
 | 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5463
 | 
     $parser = pop(@parsers);  | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
304
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ################ Section Config & User Chords ################  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
306
 | 
2317
 | 
 
 | 
 
 | 
  
2317
  
 | 
  
0
  
 | 
3271
 | 
 sub known_chord ( $name ) {  | 
| 
 
 | 
2317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3640
 | 
    | 
| 
 
 | 
2317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3005
 | 
    | 
| 
307
 | 
2317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3207
 | 
     my $info;  | 
| 
308
 | 
2317
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
7149
 | 
     if ( ref($name) =~ /^ChordPro::Chord::/ ) {  | 
| 
309
 | 
1132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1963
 | 
 	$info = $name;  | 
| 
310
 | 
1132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3216
 | 
 	$name = $info->name;  | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
312
 | 
2317
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
8827
 | 
     my $ret = $song_chords{$name} // $config_chords{$name};  | 
| 
313
 | 
2317
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
9275
 | 
     $ret->{_via} = $ret->{origin} . " chords", return $ret if $ret;  | 
| 
314
 | 
480
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1216
 | 
     return unless $info;  | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Retry agnostic. Not all can do that.  | 
| 
317
 | 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
459
 | 
     $name = eval { $info->agnostic };  | 
| 
 
 | 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
803
 | 
    | 
| 
318
 | 
248
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
731
 | 
     return unless $name;  | 
| 
319
 | 
230
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
842
 | 
     $ret = $song_chords{$name} // $config_chords{$name};  | 
| 
320
 | 
230
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
537
 | 
     if ( $ret ) {  | 
| 
321
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
 	$ret = $info->new($ret);  | 
| 
322
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37
 | 
 	for ( qw( name display  | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  root root_canon root_mod  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  qual qual_canon ext ext_canon  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  bass bass_canon  | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		  system parser ) ) {  | 
| 
327
 | 
117
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
229
 | 
 	    next unless defined $info->{$_};  | 
| 
328
 | 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
172
 | 
 	    $ret->{$_} = $info->{$_};  | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
330
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
 	$ret->{_via} = "agnostic" . " " . $ret->{origin} . " chords";  | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
332
 | 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1157
 | 
     $ret;  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
335
 | 
49885
 | 
 
 | 
 
 | 
  
49885
  
 | 
  
0
  
 | 
68403
 | 
 sub check_chord ( $ii ) {  | 
| 
 
 | 
49885
 | 
 
 | 
 
 | 
 
 | 
 
 | 
67754
 | 
    | 
| 
 
 | 
49885
 | 
 
 | 
 
 | 
 
 | 
 
 | 
65226
 | 
    | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my ( $name, $base, $frets, $fingers, $keys )  | 
| 
337
 | 
49885
 | 
 
 | 
 
 | 
 
 | 
 
 | 
114052
 | 
       = @$ii{qw(name base frets fingers keys)};  | 
| 
338
 | 
49885
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
205007
 | 
     if ( $frets && @$frets && @$frets != strings() ) {  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
339
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return scalar(@$frets) . " strings";  | 
| 
340
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
341
 | 
49885
 | 
  
 50
  
 | 
  
100
  
 | 
 
 | 
 
 | 
146055
 | 
     if ( $fingers && @$fingers && @$fingers != strings() ) {  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
342
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return scalar(@$fingers) . " strings for fingers";  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
344
 | 
49885
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
160031
 | 
     unless ( $base > 0 && $base < 24 ) {  | 
| 
345
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return "base-fret $base out of range";  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
347
 | 
49885
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
132939
 | 
     if ( $keys && @$keys ) {  | 
| 
348
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
 	for ( @$keys ) {  | 
| 
349
 | 
24
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
106
 | 
 	    return "invalid key \"$_\"" unless /^\d+$/ && $_ < 24;  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
351
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
352
 | 
49885
 | 
 
 | 
 
 | 
 
 | 
 
 | 
93374
 | 
     return;  | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
354
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Add a config defined chord.  | 
| 
356
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: Config.  | 
| 
357
 | 
49823
 | 
 
 | 
 
 | 
  
49823
  
 | 
  
0
  
 | 
75160
 | 
 sub add_config_chord ( $def ) {  | 
| 
 
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
73488
 | 
    | 
| 
 
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64956
 | 
    | 
| 
358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
359
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
76993
 | 
     my $res;  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $name;  | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
362
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
106837
 | 
     my @extprops = qw( display format );  | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Handle alternatives.  | 
| 
365
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69531
 | 
     my @names;  | 
| 
366
 | 
49823
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
152147
 | 
     if ( $def->{name} =~ /.\|./ ) {  | 
| 
367
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$def->{name} = [ split( /\|/, $def->{name} ) ];  | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
369
 | 
49823
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
226446
 | 
     if ( UNIVERSAL::isa( $def->{name}, 'ARRAY' ) ) {  | 
| 
370
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
 	$name = shift( @{ $def->{name} } );  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
371
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
 	push( @names, @{ $def->{name} } );  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
372
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
373
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     else {  | 
| 
374
 | 
49822
 | 
 
 | 
 
 | 
 
 | 
 
 | 
91264
 | 
 	$name = $def->{name};  | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
377
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # For derived chords.  | 
| 
378
 | 
49823
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
147924
 | 
     if ( $def->{copy} || $def->{"copyall"} ) {  | 
| 
379
 | 
30940
 | 
 
 | 
 
 | 
 
 | 
 
 | 
54620
 | 
 	my $src = $def->{copy};  | 
| 
380
 | 
30940
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
65481
 | 
 	if ( $def->{copyall} ) {  | 
| 
381
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    return "Cannot copy and copyall at the same time"  | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	      if $src;  | 
| 
383
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $src = $def->{copyall};  | 
| 
384
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
385
 | 
30940
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52918
 | 
 	$res = $config_chords{$src};  | 
| 
386
 | 
30940
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
60409
 | 
 	return "Cannot copy $src" unless $res;  | 
| 
387
 | 
30940
 | 
 
 | 
 
 | 
 
 | 
 
 | 
347178
 | 
 	$def = bless { %$res, %$def } => ref($res);  | 
| 
388
 | 
30940
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
89721
 | 
 	if ( $def->{copy} ) {  | 
| 
389
 | 
30940
 | 
 
 | 
 
 | 
 
 | 
 
 | 
85295
 | 
 	    delete $def->{$_} for @extprops;  | 
| 
390
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	else {  | 
| 
392
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $def->{copy} = $def->{copyall};  | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
395
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
99769
 | 
     delete $def->{name};  | 
| 
396
 | 
49823
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
99830
 | 
     $def->{base} ||= 1;  | 
| 
397
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my ( $base, $frets, $fingers, $keys ) =  | 
| 
399
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
116208
 | 
       ( $def->{base}, $def->{frets}, $def->{fingers}, $def->{keys} );  | 
| 
400
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
95549
 | 
     $res = check_chord($def);  | 
| 
401
 | 
49823
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
88378
 | 
     return $res if $res;  | 
| 
402
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
403
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68528
 | 
     my $dpinfo;  | 
| 
404
 | 
49823
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
95719
 | 
     if ( $def->{display} ) {  | 
| 
405
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$dpinfo = parse_chord($def->{display});  | 
| 
406
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	if ( $dpinfo ) {  | 
| 
407
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $def->{display} = $dpinfo;  | 
| 
408
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	else {  | 
| 
410
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    delete $def->{display};  | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
413
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
87780
 | 
     for $name ( $name, @names ) {  | 
| 
414
 | 
49824
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
199106
 | 
 	next if $name =~ /^(\||\s*)$/;  | 
| 
415
 | 
49824
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
99467
 | 
 	my $info = parse_chord($name)  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  // ChordPro::Chord::Common->new({ name => $name });  | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
418
 | 
49824
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
138477
 | 
 	if ( $info->is_chord && $def->{copy} && $def->is_chord ) {  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
419
 | 
19873
 | 
 
 | 
 
 | 
 
 | 
 
 | 
41975
 | 
 	    for ( qw( root bass ext qual ) ) {  | 
| 
420
 | 
79492
 | 
 
 | 
 
 | 
 
 | 
 
 | 
129162
 | 
 		delete $def->{$_};  | 
| 
421
 | 
79492
 | 
 
 | 
 
 | 
 
 | 
 
 | 
133293
 | 
 		delete $def->{$_."_mod"};  | 
| 
422
 | 
79492
 | 
 
 | 
 
 | 
 
 | 
 
 | 
145102
 | 
 		delete $def->{$_."_canon"};  | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    }  | 
| 
424
 | 
19873
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32916
 | 
 	    for ( qw( ext qual ) ) {  | 
| 
425
 | 
39746
 | 
 
 | 
 
 | 
 
 | 
 
 | 
55653
 | 
 		delete $def->{$_};  | 
| 
426
 | 
39746
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68302
 | 
 		delete $def->{$_."_canon"};  | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    }  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
429
 | 
49824
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
120303
 | 
 	Carp::confess(::dump($parser)) unless $parser->{target};  | 
| 
430
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	$config_chords{$name} = bless  | 
| 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  { origin  => "config",  | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    system  => $parser->{system},  | 
| 
433
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    %$info,  | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    %$def,  | 
| 
435
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    base    => $base,  | 
| 
436
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    baselabeloffset => $def->{baselabeloffset}||0,  | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    frets   => [ $frets && @$frets ? @$frets : () ],  | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    fingers => [ $fingers && @$fingers ? @$fingers : () ],  | 
| 
439
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    keys    => [ $keys && @$keys ? @$keys : () ]  | 
| 
440
 | 
49824
 | 
  
 50
  
 | 
  
 50
  
 | 
 
 | 
 
 | 
1376348
 | 
 	  } => $parser->{target};  | 
| 
 
 | 
 
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
441
 | 
49824
 | 
 
 | 
 
 | 
 
 | 
 
 | 
169160
 | 
 	push( @chordnames, $name );  | 
| 
442
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
443
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Also store the chord info under a neutral name so it can be  | 
| 
444
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# found when other note name systems are used.  | 
| 
445
 | 
49824
 | 
 
 | 
 
 | 
 
 | 
 
 | 
75004
 | 
 	my $i;  | 
| 
446
 | 
49824
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
120577
 | 
 	if ( $info->is_chord ) {  | 
| 
447
 | 
38318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94518
 | 
 	    $i = $info->agnostic;  | 
| 
448
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
449
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	else {  | 
| 
450
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    # Retry with default parser.  | 
| 
451
 | 
11506
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33596
 | 
 	    $i = ChordPro::Chords::Parser->default->parse($name);  | 
| 
452
 | 
11506
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
31420
 | 
 	    if ( $i && $i->is_chord ) {  | 
| 
453
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$info->{root_ord} = $i->{root_ord};  | 
| 
454
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 		$config_chords{$name}->{$_} = $i->{$_}  | 
| 
455
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		  for qw( root_ord root_mod ext_canon qual_canon );  | 
| 
456
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$i = $i->agnostic;  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    }  | 
| 
458
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
459
 | 
49824
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
125076
 | 
 	if ( $info->is_chord ) {  | 
| 
460
 | 
38318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
340870
 | 
 	    $config_chords{$i} = $config_chords{$name};  | 
| 
461
 | 
38318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
155940
 | 
 	    $config_chords{$i}->{origin} = "config";  | 
| 
462
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
464
 | 
49823
 | 
 
 | 
 
 | 
 
 | 
 
 | 
195625
 | 
     return;  | 
| 
465
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
466
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
467
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Add a user defined chord.  | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: Song.  | 
| 
469
 | 
62
 | 
 
 | 
 
 | 
  
62
  
 | 
  
0
  
 | 
101
 | 
 sub add_song_chord ( $ii ) {  | 
| 
 
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
109
 | 
    | 
| 
 
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
89
 | 
    | 
| 
470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
471
 | 
62
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
185
 | 
     return if $ii->name =~ /^(\||\s*)$/;  | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
473
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
202
 | 
     my $res = check_chord($ii);  | 
| 
474
 | 
62
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
199
 | 
     return $res if $res;  | 
| 
475
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
476
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Need a parser anyway.  | 
| 
477
 | 
62
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
163
 | 
     $parser //= ChordPro::Chords::Parser->get_parser;  | 
| 
478
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
479
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $c =  | 
| 
480
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       { system  => $parser->{system},  | 
| 
481
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
773
 | 
 	parser  => $parser,  | 
| 
482
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	%$ii,  | 
| 
483
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       };  | 
| 
484
 | 
62
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
229
 | 
     $c->{origin} //= "user";  | 
| 
485
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
486
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Cleanup.  | 
| 
487
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
154
 | 
     for ( qw( display ) ) {  | 
| 
488
 | 
62
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
199
 | 
 	delete $c->{$_} unless defined $c->{$_};  | 
| 
489
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
490
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
135
 | 
     for ( qw( frets fingers keys ) ) {  | 
| 
491
 | 
186
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
457
 | 
 	delete $c->{$_} unless $c->{$_} && @{ $c->{$_} };  | 
| 
 
 | 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
340
 | 
    | 
| 
492
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
493
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
494
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
230
 | 
     $song_chords{$c->{name}} = bless $c => $parser->{target};  | 
| 
495
 | 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
185
 | 
     return;  | 
| 
496
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
497
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
498
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Add an unknown chord.  | 
| 
499
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: Song.  | 
| 
500
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 sub add_unknown_chord ( $name ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
501
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
     $parser //= ChordPro::Chords::Parser->get_parser;  | 
| 
502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $song_chords{$name} = bless  | 
| 
503
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       { origin  => "user",  | 
| 
504
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	name    => $name,  | 
| 
505
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	base    => 0,  | 
| 
506
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	frets   => [],  | 
| 
507
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	fingers => [],  | 
| 
508
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         keys    => []  | 
| 
509
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       } => $parser->{target};  | 
| 
510
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
511
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
512
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Reset user defined songs. Should be done for each new song.  | 
| 
513
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: Songbook, Output::PDF.  | 
| 
514
 | 
172
 | 
 
 | 
 
 | 
  
172
  
 | 
  
0
  
 | 
432
 | 
 sub reset_song_chords () {  | 
| 
 
 | 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
312
 | 
    | 
| 
515
 | 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1290
 | 
     %song_chords = ();  | 
| 
516
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
517
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
518
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Return some chord statistics.  | 
| 
519
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 sub chord_stats () {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
520
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $res = sprintf( "%d config chords", scalar(keys(%config_chords)) );  | 
| 
521
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $res .= sprintf( ", %d song chords", scalar(keys(%song_chords)) )  | 
| 
522
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       if %song_chords;  | 
| 
523
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $res;  | 
| 
524
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
525
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
526
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ################ Section Chords Parser ################  | 
| 
527
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
528
 | 
53309
 | 
 
 | 
 
 | 
  
53309
  
 | 
  
0
  
 | 
4043861
 | 
 sub parse_chord ( $chord ) {  | 
| 
 
 | 
53309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
84251
 | 
    | 
| 
 
 | 
53309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
67621
 | 
    | 
| 
529
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
530
 | 
53309
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
104063
 | 
     $parser //= ChordPro::Chords::Parser->get_parser;  | 
| 
531
 | 
53309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
148684
 | 
     return $parser->parse($chord);  | 
| 
532
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
533
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
534
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ################ Section Keyboard keys ################  | 
| 
535
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
536
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %keys =  | 
| 
537
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   ( ""       => [ 0, 4, 7 ],	             # major  | 
| 
538
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-"      => [ 0, 3, 7 ],	             # minor  | 
| 
539
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"7"      => [ 0, 4, 7, 10 ],             # dominant 7th  | 
| 
540
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-7"     => [ 0, 3, 7, 10 ],             # minor seventh  | 
| 
541
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"maj7"   => [ 0, 4, 7, 11 ],             # major 7th  | 
| 
542
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-maj7"  => [ 0, 3, 7, 11 ],             # minor major 7th  | 
| 
543
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"6"      => [ 0, 4, 7, 9 ],              # 6th  | 
| 
544
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-6"     => [ 0, 3, 7, 9 ],              # minor 6th  | 
| 
545
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"6add9"  => [ 0, 4, 7, 9, 14],           # 6/9  | 
| 
546
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"5"      => [ 0, 7 ],                    # 6th  | 
| 
547
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"9"      => [ 0, 4, 7, 10, 14 ],         # 9th  | 
| 
548
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-9"     => [ 0, 3, 7, 10, 14 ],         # minor 9th  | 
| 
549
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"maj9"   => [ 0, 4, 7, 11, 14 ],         # major 9th  | 
| 
550
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"11"     => [ 0, 4, 7, 10, 14, 17 ],     # 11th  | 
| 
551
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-11"    => [ 0, 3, 7, 10, 14, 17 ],     # minor 11th  | 
| 
552
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"13"     => [ 0, 4, 7, 10, 14, 17, 21 ], # 13th  | 
| 
553
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-13"    => [ 0, 3, 7, 10, 14, 17, 21 ], # minor 13th  | 
| 
554
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"maj13"  => [ 0, 4, 7, 11, 14, 21 ],     # major 13th  | 
| 
555
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"add2"   => [ 0, 2, 4, 7 ],              # add 2  | 
| 
556
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"add9"   => [ 0, 4, 7, 14 ],             # add 9  | 
| 
557
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-add2"  => [ 0, 2, 3, 7 ],              # minor add 2  | 
| 
558
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-add9"  => [ 0, 2, 3, 7, 11 ],          # minor add 9  | 
| 
559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-add11" => [ 0, 3, 5, 7, 11 ],          # minor add 11  | 
| 
560
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"7-5"    => [ 0, 4, 6, 10 ],             # 7 flat 5 altered chord  | 
| 
561
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"7+5"    => [ 0, 4, 8, 10 ],             # 7 sharp 5 altered chord  | 
| 
562
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"sus4"   => [ 0, 5, 7 ],                 # sus 4  | 
| 
563
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"sus2"   => [ 0, 2, 7 ],                 # sus 2  | 
| 
564
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"7sus2"  => [ 0, 2, 7, 10 ],             # 7 sus 2  | 
| 
565
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"7sus4"  => [ 0, 5, 7, 10 ],             # 7 sus 4  | 
| 
566
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-7sus2" => [ 0, 2, 3, 7, 10 ],          # minor 7 sus 2  | 
| 
567
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-7sus4" => [ 0, 3, 5, 7, 10 ],          # minor 7 sus 4  | 
| 
568
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"0"      => [ 0, 3, 6 ],	             # diminished  | 
| 
569
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"07"     => [ 0, 3, 6, 9 ],              # diminished 7  | 
| 
570
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"-7b5"   => [ 0, 3, 6, 10 ],             # minor 7 flat 5  | 
| 
571
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"+"      => [ 0, 4, 8 ],	             # augmented  | 
| 
572
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"+7"     => [ 0, 4, 8, 10 ],             # augmented 7  | 
| 
573
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	"h"      => [ 0, 3, 6, 10 ],             # half-diminished seventh  | 
| 
574
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
575
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
576
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
 sub get_keys ( $info ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
577
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
578
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Has keys defined.  | 
| 
579
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
     return $info->{keys} if $info->{keys} && @{$info->{keys}};  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
580
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
581
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my @keys;  | 
| 
582
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
583
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
     if ( defined $info->{qual_canon}  | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
584
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	 && defined $info->{ext_canon}  | 
| 
585
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	 && defined $keys{$info->{qual_canon}.$info->{ext_canon}} ) {  | 
| 
586
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Known chord extension.  | 
| 
587
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	@keys = @{ $keys{$info->{qual_canon}.$info->{ext_canon}} };  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
588
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
589
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     else {  | 
| 
590
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Try to derive from guitar chord.  | 
| 
591
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
 	return [] unless $info->{frets} && @{$info->{frets}};  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
592
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
593
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Get ordinals for tuning.  | 
| 
594
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my @t_ord = map { $_ % $t_oct } @t_ord;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
595
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
596
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my %keys;  | 
| 
597
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $i = -1;  | 
| 
598
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $base = $info->{base} - 1;  | 
| 
599
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$base = 0 if $base < 0;  | 
| 
600
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	for ( @{ $info->{frets} } ) {  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
601
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $i++;  | 
| 
602
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    next if $_ < 0;  | 
| 
603
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    my $c = $t_ord[$i] + $_ + $base;  | 
| 
604
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    if ( $info->{root_ord} ) {  | 
| 
605
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$c += $t_oct if $c < $info->{root_ord};  | 
| 
606
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 		$c -= $info->{root_ord};  | 
| 
607
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    }  | 
| 
608
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $keys{ $c % $t_oct }++;  | 
| 
609
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
610
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	@keys = sort keys %keys;  | 
| 
611
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
612
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
613
 | 
  
0
  
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
     if ( defined $info->{bass} && $info->{bass} ne '' ) {  | 
| 
614
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	# Handle inversions.  | 
| 
615
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my @k;  | 
| 
616
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $bass = $info->{bass_ord} - $info->{root_ord};  | 
| 
617
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	my $oct = 12;		# yes  | 
| 
618
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	$bass += $oct if $bass < 0;  | 
| 
619
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	for ( @keys ) {  | 
| 
620
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    next if $_ == $bass;  | 
| 
621
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    push( @k, $_ < $bass ? $_+$oct : $_ );  | 
| 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
623
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	unshift( @k, $bass );  | 
| 
624
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	@keys = @k;  | 
| 
625
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
626
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     \@keys;  | 
| 
627
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
628
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
629
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ################ Section Transposition ################  | 
| 
630
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
631
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # API: Transpose a chord.  | 
| 
632
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Used by: Songbook.  | 
| 
633
 | 
123
 | 
 
 | 
 
 | 
  
123
  
 | 
  
0
  
 | 
191
 | 
 sub transpose ( $c, $xpose, $xcode = "" ) {  | 
| 
 
 | 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
222
 | 
    | 
| 
 
 | 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
184
 | 
    | 
| 
 
 | 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
206
 | 
    | 
| 
 
 | 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
169
 | 
    | 
| 
634
 | 
123
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
310
 | 
     return $c unless $xpose || $xcode;  | 
| 
635
 | 
123
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
274
 | 
     return $c if $c =~ /^ .+/;  | 
| 
636
 | 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
270
 | 
     my $info = parse_chord($c);  | 
| 
637
 | 
123
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
363
 | 
     unless ( $info ) {  | 
| 
638
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	assert_tuning();  | 
| 
639
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	for ( \%song_chords, \%config_chords ) {  | 
| 
640
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    # Not sure what this is for...  | 
| 
641
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    # Anyway, it causes unknown but {defined} chords to silently  | 
| 
642
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    # bypass the trans* warnings.  | 
| 
643
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    # return if exists($_->{$c});  | 
| 
644
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
645
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	$xpose  | 
| 
646
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  ? warn("Cannot transpose $c\n")  | 
| 
647
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  : warn("Cannot transcode $c\n");  | 
| 
648
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	return;  | 
| 
649
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
650
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
651
 | 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
394
 | 
     my $res = $info->transcode($xcode)->transpose($xpose)->canonical;  | 
| 
652
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
653
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #    Carp::cluck("__XPOSE = ", $xpose, " __XCODE = $xcode, chord $c => $res\n");  | 
| 
654
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
655
 | 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3605
 | 
     return $res;  | 
| 
656
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
657
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
658
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  |