diff --git a/Changes b/Changes index 1a8e7e69..cfb9abda 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,26 @@ +6.042 2024-01-09 + + - !This is a bugfix release. + + - !Important + + - To trace problems, the ChordPro 'about' information is included + in the PDF. This should not reveal sensitive information, but in + case this bothers you, you can disable this by setting + debug.runtimeinfo to 0 in the config. + + - !Functionality + - Report XDG_CONFIG_HOME in runtime info. + - Include 'about' info as PDF metadata. + - !Bug fixes + - Post-release typo fixes. + - (Stringdiagram) Fix font size of base fret numeral (issue 337). + - (Stringdiagram) Fix fret number colours. + - Fix handling of XDG_CONFIG_HOME. + - Fix 'spread' images. + - Fix problem finding notes:german et al. + - (MMA) Fix test fail with perl >= 5.39.6. + 6.040 2023-12-26 - !Highlights @@ -6,13 +29,13 @@ They can be placed relative to the paper, the page, the column, and the lyrics. - - Images can be [embedded[(https://chordpro.org/chordpro/directives-image/#inline-images) in text (lyrics) lines, either as part of + - Images can be [embedded](https://chordpro.org/chordpro/directives-image/#inline-images) in text (lyrics) lines, either as part of the text similar to a glyph, or somewhere else on the page relative to a particular place in the text. The latter is most interesting for annotations. - - Delegates are images too. Annotate your lyrics with SVG images, - or with musical notes using ABC or Lilypond. + - Delegates are images too. Annotate your lyrics with SVG images + and musical notes using ABC or Lilypond. - Chord and keyboard diagrams are images too. And you can use string and keyboard diagrams simultaneously. diff --git a/Design/ChordDiagram.odg b/Design/ChordDiagram.odg new file mode 100644 index 00000000..7984f449 Binary files /dev/null and b/Design/ChordDiagram.odg differ diff --git a/Design/ChordPro_Component_Support.odg b/Design/ChordPro_Component_Support.odg new file mode 100644 index 00000000..adadfeed Binary files /dev/null and b/Design/ChordPro_Component_Support.odg differ diff --git a/Design/StructuredChordPro.org b/Design/StructuredChordPro.org new file mode 100644 index 00000000..c13e861d --- /dev/null +++ b/Design/StructuredChordPro.org @@ -0,0 +1,23 @@ +songbook ::= song+ + +song ::= directive-or-part+ + +directive-or-part ::= directive | part + +directive ::= '{' keyword [ ':' value ] '}' + +part ::= verse | chorus | tab + +verse ::= one or more consequetive songlines + +chorus ::= start-of-chorus verse+ end-of-chorus + +start-of-chorus ::= '{' 'start-of-chorus' | 'soc' '}' + +end-of-chorus ::= '{' 'end-of-chorus' | 'eoc' '}' + +tab ::= start-of-tab lines+ end-of-tab + +start-of-tab ::= '{' 'start-of-tab' | 'sot' '}' + +end-of-tab ::= '{' 'end-of-tab' | 'eot' '}' diff --git a/Design/capo.txt b/Design/capo.txt new file mode 100644 index 00000000..f9a2a93d --- /dev/null +++ b/Design/capo.txt @@ -0,0 +1,23 @@ + Key Capo Chord Display +Mod Down D - D D +Mod Up D - D D +Ignore D - D D + +Key = Concert key + + Key Capo Chord Display +Mod Down D 2 D C +Mod Up D 2 D E +Ignore D 2 D D + +Key = Relative + + Key Capo Chord Display +Mod Down C 2 D C +Mod Up E 2 D E +Ignore D 2 D D + +Note: MuseScore would display D(C) (sounding D, play C). + +While other will prefer D(E). + diff --git a/Design/design.xcf b/Design/design.xcf new file mode 100644 index 00000000..bc4f35c3 Binary files /dev/null and b/Design/design.xcf differ diff --git a/Design/pagelayout.odg b/Design/pagelayout.odg new file mode 100644 index 00000000..2e9f3815 Binary files /dev/null and b/Design/pagelayout.odg differ diff --git a/MANIFEST b/MANIFEST index b68f1685..54df73d0 100644 --- a/MANIFEST +++ b/MANIFEST @@ -135,6 +135,7 @@ lib/ChordPro/res/config/songbook_latex.json lib/ChordPro/res/config/ukulele-ly.json lib/ChordPro/res/config/ukulele.json lib/ChordPro/res/examples/bgdemo.pdf +lib/ChordPro/res/examples/mollymalone.cho lib/ChordPro/res/examples/swinglow.cho lib/ChordPro/res/fonts/ChordProSymbols.ttf lib/ChordPro/res/icons/chordpro-doc.icns diff --git a/Makefile.PL b/Makefile.PL index e7667049..5778edcd 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -43,7 +43,7 @@ WriteMakefile 'Text::Layout' => 0.032, 'JSON::PP' => 2.27203, 'String::Interpolate::Named' => 1.030, - 'File::LoadLines' => 1.042, + 'File::LoadLines' => 1.044, 'File::HomeDir' => 1.004, 'Image::Info' => 1.41, 'List::Util' => 1.46, diff --git a/docs/content/ChordPro-Configuration-Overview.md b/docs/content/ChordPro-Configuration-Overview.md index 81b1e9d2..49ba3935 100644 --- a/docs/content/ChordPro-Configuration-Overview.md +++ b/docs/content/ChordPro-Configuration-Overview.md @@ -108,9 +108,9 @@ Instrument definitions, in particular the settings `"tuning"`, `"notes"` and `"c For example, assume `"chords_italian.json"` defines a number of chords using italian (latin) note names and `"chords_german.json"` defines some chords using german note names. Then the following sequence of configuration files will work as expected: - notes::latin (built-in, enable latin note names) + notes:latin (built-in, enable latin note names) chords_italian.json (defines chords with latin note names) - notes::german (built-in, enable german note names) + notes:german (built-in, enable german note names) chords_german.json (defines chords with german note names) ### Merging hash valued items diff --git a/docs/content/ChordPro-Reference-RelNotes.md b/docs/content/ChordPro-Reference-RelNotes.md index 844f1f3f..64f354b5 100644 --- a/docs/content/ChordPro-Reference-RelNotes.md +++ b/docs/content/ChordPro-Reference-RelNotes.md @@ -1,5 +1,37 @@ # Release info +## 6.042 + +Released: 2024-01-09 + + +### This is a bugfix release. + + +### Important + +* To trace problems, the ChordPro 'about' information is included in the PDF. This should not reveal sensitive information, but in case this bothers you, you can disable this by setting debug.runtimeinfo to 0 in the config. + +### Functionality + +* Report XDG_CONFIG_HOME in runtime info. +* Include 'about' info as PDF metadata. + +### Bug fixes + +* Post-release typo fixes. +* (Stringdiagram) Fix font size of base fret numeral (issue 337). +* (Stringdiagram) Fix fret number colours. +* Fix handling of XDG_CONFIG_HOME. +* Fix 'spread' images. +* Fix problem finding notes:german et al. +* (MMA) Fix test fail with perl >= 5.39.6. + +### Social and support + +[User community](https://groups.io/g/ChordPro) for feedback and help. +Please use the [issue tracker](https://github.com/ChordPro/chordpro/issues) for bugs reports. + ## 6.040 Released: 2023-12-26 @@ -8,8 +40,8 @@ Released: 2023-12-26 ### Highlights * Images can be [placed everywhere](https://chordpro.org/chordpro/directives-image/). They can be placed relative to the paper, the page, the column, and the lyrics. -* Images can be [embedded[(https://chordpro.org/chordpro/directives-image/#inline-images) in text (lyrics) lines, either as part of the text similar to a glyph, or somewhere else on the page relative to a particular place in the text. The latter is most interesting for annotations. -* Delegates are images too. Annotate your lyrics with SVG images, or with musical notes using ABC or Lilypond. +* Images can be [embedded](https://chordpro.org/chordpro/directives-image/#inline-images) in text (lyrics) lines, either as part of the text similar to a glyph, or somewhere else on the page relative to a particular place in the text. The latter is most interesting for annotations. +* Delegates are images too. Annotate your lyrics with SVG images and musical notes using ABC or Lilypond. * Chord and keyboard diagrams are images too. And you can use string and keyboard diagrams simultaneously. * Resources like configs, tasks and images are now more logically searched using [resource libraries](https://chordpro.org/chordpro/resources/). @@ -52,11 +84,6 @@ Released: 2023-12-26 * (PDF) Enhance assets (wip), labels; move grid to separate module. * Experimental ##include facility. -### Social and support - -[User community](https://groups.io/g/ChordPro) for feedback and help. -Please use the [issue tracker](https://github.com/ChordPro/chordpro/issues) for bugs reports. - ## 6.030 Released: 2023-09-18 diff --git a/lib/ChordPro.pm b/lib/ChordPro.pm index 5c2128fa..da089b19 100644 --- a/lib/ChordPro.pm +++ b/lib/ChordPro.pm @@ -1059,6 +1059,11 @@ sub ::runtimeinfo { push( @p, $cp->display($_) ); } } + for ( qw( XDG_CONFIG_HOME ) ) { + if ( defined($ENV{$_}) && $ENV{$_} ne "" ) { + $msg .= sprintf( $fmt, $_, $cp->display($ENV{$_}) ); + } + } push( @p, map { $cp->display($_) } @{ $cp->resdirs } ); $tag = "Resource path"; for ( uniq(@p) ) { diff --git a/lib/ChordPro/Config.pm b/lib/ChordPro/Config.pm index 541422d2..5d17448d 100644 --- a/lib/ChordPro/Config.pm +++ b/lib/ChordPro/Config.pm @@ -733,6 +733,7 @@ sub hmerge( $left, $right, $path = "" ) { || $path =~ /^pdf\.(?:info|fonts)\./ || $path =~ /^meta\./ || $path =~ /^delegates\./ + || $path =~ /^parser\.preprocess\./ || $path =~ /^debug\./ || $key =~ /^_/; @@ -1127,6 +1128,7 @@ sub default_config () { "preamble" : [ // Use ChordPro fonts for lyrics and chords. "%%textfont pdf.fonts.text", + "%%vocalfont pdf.fonts.text", "%%gchordfont pdf.fonts.chord", ], "preprocess" : { "abc" : [] }, @@ -1643,6 +1645,7 @@ sub default_config () { // For (debugging (internal use only)). "debug" : { + "runtimeinfo" : 1, "a2crd" : 0, "assets" : 0, "chords" : 0, diff --git a/lib/ChordPro/Output/MMA.pm b/lib/ChordPro/Output/MMA.pm index 978fabe5..ba92efe0 100644 --- a/lib/ChordPro/Output/MMA.pm +++ b/lib/ChordPro/Output/MMA.pm @@ -37,7 +37,7 @@ my $chords_under = 0; # chords under lyrics sub safemeta { my ( $s, $meta, $default ) = @_; - return $default undef unless defined $meta && defined $s->{meta}->{$meta}; + return $default unless defined $meta && defined $s->{meta}->{$meta}; return $s->{meta}->{$meta}->[0]; } diff --git a/lib/ChordPro/Output/PDF.pm b/lib/ChordPro/Output/PDF.pm index 3a018480..d4a0e8da 100644 --- a/lib/ChordPro/Output/PDF.pm +++ b/lib/ChordPro/Output/PDF.pm @@ -544,11 +544,14 @@ sub generate_song { }; my $col; + my $spreadimage; my $col_adjust = sub { if ( $ps->{columns} <= 1 ) { warn("L=", $ps->{__leftmargin}, ", R=", $ps->{__rightmargin}, + ", T=", $ps->{_top}, + ", S=", $spreadimage//"", "\n") if $config->{debug}->{spacing}; return; } @@ -559,17 +562,19 @@ sub generate_song { + $ps->{columnoffsets}->[$col+1]; $ps->{__rightmargin} -= $ps->{columnspace} if $col < $ps->{columns}-1; + $y = $ps->{_top}; warn("C=$col, L=", $ps->{__leftmargin}, ", R=", $ps->{__rightmargin}, + ", T=", $ps->{_top}, + ", S=", $spreadimage//"", "\n") if $config->{debug}->{spacing}; - $y = $ps->{_top}; $x += $ps->{_indent}; + $y -= $spreadimage if defined($spreadimage) && !ref($spreadimage); }; my $vsp_ignorefirst; my $startpage = $opts->{startpage} || 1; my $thispage = $startpage - 1; - my $spreadimage; # Physical newpage handler. my $newpage = sub { @@ -651,12 +656,8 @@ sub generate_song { $x = $ps->{__leftmargin}; $y = $ps->{_margintop}; $y += $ps->{headspace} if $ps->{'head-first-only'} && $class == 2; - - if ( $spreadimage ) { - $y -= imagespread( $spreadimage, $x, $y, $ps ); - undef $spreadimage; - } $x += $ps->{_indent}; + undef $spreadimage unless ref($spreadimage); $ps->{_top} = $y; $col = 0; $vsp_ignorefirst = 1; @@ -859,13 +860,7 @@ sub generate_song { # prepare_assets( $s, $pr ); - if ( $s->{spreadimage} ) { - $spreadimage = $assets->{$s->{spreadimage}->{id}}; -# { type => "image", -# id => $s->{spreadimage}->{id}, -# opts => { spread => $s->{spreadimage}->{space} } -# }; - } + $spreadimage = $s->{spreadimage}; # Get going. $newpage->(); @@ -905,6 +900,13 @@ sub generate_song { $chorddiagrams->() unless $dctl->{show} eq "below"; # Prepare the assets now we know the page width. prepare_assets( $s, $pr ); + + if ( $spreadimage ) { + if (ref($spreadimage) eq 'HASH' ) { + $spreadimage = imagespread( $spreadimage, $x, $y, $ps ); + } + $y -= $spreadimage; + } showlayout($ps) if $ps->{showlayout} || $config->{debug}->{spacing}; } @@ -1403,21 +1405,22 @@ sub generate_song { # margin* are offsets from the edges of the paper. # _*margin are offsets taking even/odd pages into account. - # _margin* are physical coordinates, taking ... if ( $rightpage ) { $ps->{_leftmargin} = $ps->{marginleft}; - $ps->{_marginleft} = $ps->{marginleft}; $ps->{_rightmargin} = $ps->{marginright}; - $ps->{_marginright} = $ps->{papersize}->[0] - $ps->{marginright}; } else { $ps->{_leftmargin} = $ps->{marginright}; - $ps->{_marginleft} = $ps->{marginright}; $ps->{_rightmargin} = $ps->{marginleft}; - $ps->{_marginright} = $ps->{papersize}->[0] - $ps->{marginleft}; } + + # _margin* are physical coordinates, taking even/odd pages into account. + $ps->{_marginleft} = $ps->{_leftmargin}; + $ps->{_marginright} = $ps->{papersize}->[0] - $ps->{_rightmargin}; $ps->{_marginbottom} = $ps->{marginbottom}; $ps->{_margintop} = $ps->{papersize}->[1] - $ps->{margintop}; + + # Bottom margin, taking bottom chords into account. $ps->{_bottommargin} = $ps->{marginbottom}; # Physical coordinates; will be adjusted to columns if needed. @@ -2015,20 +2018,19 @@ sub imageline { } sub imagespread { - my ( $elt, $x, $y, $ps ) = @_; - ::dump($elt); - my $opts = $elt->{opts}; + my ( $si, $x, $y, $ps ) = @_; my $pr = $ps->{pr}; - my $tag = "id=" . $elt->{opts}->{id}; + my $tag = "id=" . $si->{id}; return "Unknown asset: $tag" - unless exists( $assets->{$elt->{opts}->{id}} ); - my $img = $assets->{$elt->{opts}->{id}}->{data}; + unless exists( $assets->{$si->{id}} ); + my $img = $assets->{$si->{id}}->{data}; return "Unhandled asset: $tag" unless $img; + my $opts = {}; # Available width and height. - my $pw = $ps->{__rightmargin} - $ps->{_leftmargin}; + my $pw = $ps->{_marginright} - $ps->{_marginleft}; my $ph = $ps->{_margintop} - $ps->{_marginbottom}; my $scale = 1; @@ -2090,7 +2092,7 @@ sub imagespread { align => $align, ); - return $h + $elt->{opts}->{spread}; # vertical size + return $h + $si->{space}; # vertical size } sub tocline { @@ -2651,9 +2653,9 @@ sub prepare_assets { # So we first scan the list for SVG and delegate items and turn these # into simple display items. - my $pw = $ps->{__rightmargin} - $ps->{__leftmargin} + my $pw = $ps->{_marginright} - $ps->{_marginleft}; + my $cw = ( $pw - ( $ps->{columns} - 1 ) * $ps->{columnspace} ) /$ps->{columns} - $ps->{_indent}; - my $cw = ( $pw - ( $ps->{columns} - 1 ) * $ps->{columnspace} ) /$ps->{columns}; warn("PDF: Preparing ", scalar(keys %sa), " image", keys(%sa) == 1 ? "" : "s", ", pw=$pw, cw=$cw\n") if $config->{debug}->{images} || $config->{debug}->{assets}; @@ -2665,7 +2667,9 @@ sub prepare_assets { if ( $elt->{type} eq "image" && $elt->{subtype} eq "delegate" ) { my $delegate = $elt->{delegate}; warn("PDF: Preparing delegate $delegate, handler ", - $elt->{handler}, "\n") if $config->{debug}->{images}; + $elt->{handler}, + ( map { " $_=" . $elt->{opts}->{$_} } keys(%{$elt->{opts}//{}})), + "\n") if $config->{debug}->{images}; my $pkg = __PACKAGE__; $pkg =~ s/::Output::[:\w]+$/::Delegate::$delegate/; @@ -2678,18 +2682,20 @@ sub prepare_assets { # Determine actual width. my $w = defined($elt->{opts}->{spread}) ? $pw : $cw; -# $w -= $ps->{_indent}; $w = $elt->{opts}->{width} if $elt->{opts}->{width} && $elt->{opts}->{width} < $w; my $res = $hd->( $s, $w, $elt ); if ( $res ) { + $res->{opts} = { %{ $res->{opts} // {} }, + %{ $elt->{opts} // {} } }; warn( "PDF: Preparing delegate $delegate, handler ", $elt->{handler}, " => ", - $res->{type}, "/", $res->{subtype}, "\n" ) + $res->{type}, "/", $res->{subtype}, + ( map { " $_=" . $res->{opts}->{$_} } keys(%{$res->{opts}//{}})), + " w=$w", + "\n" ) if $config->{debug}->{images}; - $res->{opts} = { %{ $res->{opts} // {} }, - %{ $elt->{opts} // {} } }; $s->{assets}->{$id} = $res; } @@ -2828,7 +2834,8 @@ sub prepare_assets { }; warn("Created asset $id ($elt->{subtype}, ", $res->{width}, "x", $res->{height}, ")", - map { " $_=" . $res->{opts}->{$_} } keys( %{$res->{opts}//{}} ), + ( map { " $_=" . $res->{opts}->{$_} } + keys( %{$res->{opts}//{}} ) ), "\n") if $config->{debug}->{images}; } diff --git a/lib/ChordPro/Output/PDF/StringDiagram.pm b/lib/ChordPro/Output/PDF/StringDiagram.pm index 43dd1971..b95dc1de 100644 --- a/lib/ChordPro/Output/PDF/StringDiagram.pm +++ b/lib/ChordPro/Output/PDF/StringDiagram.pm @@ -139,10 +139,12 @@ method diagram_xo( $info ) { if ( $basefretno > 1 ) { $basefont = $ps->{fonts}->{diagram_base}->{fd}->{font}; - $basesize = $ps->{spacing}->{diagramchords}*$gh; - $bb[0] -= $basefont->width("$basefretno ") * $basesize; + $basesize = $gh/0.85; + $basefretno = sprintf( "%2d", $basefretno ); + $bb[0] -= $basefont->width("xx$basefretno") * $basesize; } else { + $basefretno = ""; $bb[0] -= $dot/2; } if ( $fsh eq "below" && $info->{fingers} ) { @@ -180,12 +182,12 @@ method diagram_xo( $info ) { } # Draw first fret number, if > 1. - if ( $basefretno > 1 ) { - my $i = sprintf("%2d ", $basefretno ); + if ( $basefretno ) { $xo->textstart; $xo->font( $basefont, $basesize ); - $xo->translate( 0, -$nw - ($baselabeloffset+0.85)*$gh ); - $xo->text( "$basefretno ", align => "right" ); + $xo->translate( -$basefont->width("x") * 0.85 * $basesize, + -$nw - ($baselabeloffset+0.85)*$gh ); + $xo->text( $basefretno, align => "right" ); $xo->textend; } @@ -231,6 +233,19 @@ method diagram_xo( $info ) { my $oflo; # to detect out of range frets + # Color of the dots and numbers. + my $fbg = ""; # numbers + my $ffg = ""; # dots + unless ( $fsh eq "below" ) { + # The numbercolor property of the chordfingers is used for the + # color of the dot numbers. + my $fcf = $ps->{fonts}->{chordfingers}; + $fbg = $pr->_bgcolor($fcf->{numbercolor}); + $ffg = $pr->_bgcolor($fcf->{color}); + # However, if none we should really use white. + $fbg = "white" if $fbg eq "none"; + } + $x = -$gw; for my $sx ( 0 .. $strings-1 ) { $x += $gw; @@ -249,6 +264,7 @@ method diagram_xo( $info ) { "Fret position $fret exceeds diagram size $vc\n"); next; } + $xo->fill_color($ffg); $xo->circle( $x, -$nw - ($fret-0.5)*$gh, $dot/2 )->fill; } @@ -270,17 +286,6 @@ method diagram_xo( $info ) { my $size = $dot; my $asc; # space if "below" - # Color of the numbers. - my $fbg = ""; - unless ( $fsh eq "below" ) { - # The numbercolor property of the chordfingers is used for the - # color of the dot numbers. - my $fcf = $ps->{fonts}->{chordfingers}; - $fbg = $pr->_bgcolor($fcf->{numbercolor}); - # However, if none we should really use white. - $fbg = "white" if $fbg eq "none"; - } - $x = -$gw; my $did = 0; for my $sx ( 0 .. $strings-1 ) { diff --git a/lib/ChordPro/Output/PDF/Writer.pm b/lib/ChordPro/Output/PDF/Writer.pm index 657f6f91..2c9b2a1c 100644 --- a/lib/ChordPro/Output/PDF/Writer.pm +++ b/lib/ChordPro/Output/PDF/Writer.pm @@ -61,6 +61,9 @@ sub info { for ( keys(%info) ) { $self->{pdf}->info_metadata( $_, demarkup($info{$_}) ); } + if ( $config->{debug}->{runtimeinfo} ) { + $self->{pdf}->info_metadata( "RuntimeInfo", ::runtimeinfo() ); + } } else { $self->{pdf}->info(%info); diff --git a/lib/ChordPro/Paths.pm b/lib/ChordPro/Paths.pm index 36041b4d..5b31723f 100644 --- a/lib/ChordPro/Paths.pm +++ b/lib/ChordPro/Paths.pm @@ -60,11 +60,13 @@ BUILD { # -d ~/.$app_lc # -d my_dist_config my @try; - if ( defined( $ENV{XDG_CONFIG_HOME} ) ) { + if ( defined( $ENV{XDG_CONFIG_HOME} ) && $ENV{XDG_CONFIG_HOME} ne "" ) { push( @try, - catdir( $ENV{XDG_CONFIG_HOME}, ".config", $app_lc ), - catdir( $ENV{XDG_CONFIG_HOME}, ".config" ), - catdir( $ENV{XDG_CONFIG_HOME}, ".$app_lc" ) ); + # See https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + # catdir( $ENV{XDG_CONFIG_HOME}, ".config", $app_lc ), + # catdir( $ENV{XDG_CONFIG_HOME}, ".config" ), + # catdir( $ENV{XDG_CONFIG_HOME}, ".$app_lc" ) ); + catdir( $ENV{XDG_CONFIG_HOME}, "$app_lc" ) ); } else { push( @try, @@ -230,6 +232,7 @@ method findcfg ( $p ) { @p = ( $p ); } else { + $p =~ s/:+/\//g; @p = ( "$p.prp", "$p.json" ); } unless ( $found ) { diff --git a/lib/ChordPro/Song.pm b/lib/ChordPro/Song.pm index 12c8bf50..4bf3aa27 100644 --- a/lib/ChordPro/Song.pm +++ b/lib/ChordPro/Song.pm @@ -335,15 +335,17 @@ sub parse_song { warn(sprintf("==[%3d]=> %s\n", $diag->{line}, $diag->{orig} ) ); } - if ( $prep->{all} ) { - # warn("PRE: ", $_, "\n"); - $prep->{all}->($_); - # warn("POST: ", $_, "\n"); - if ( /\n/ ) { - my @a = split( /\n/, $_ ); - $_ = shift(@a); - unshift( @$lines, @a ); - $skipcnt += @a; + for my $pp ( "all", "env-$in_context" ) { + if ( $prep->{$pp} ) { + # warn("PRE: ", $_, "\n"); + $prep->{$pp}->($_); + # warn("POST: ", $_, "\n"); + if ( /\n/ ) { + my @a = split( /\n/, $_ ); + $_ = shift(@a); + unshift( @$lines, @a ); + $skipcnt += @a; + } } } @@ -1266,7 +1268,7 @@ sub directive { $xpose + ($config->{settings}->{transpose}//0 ); } my $kv = {}; - if ( $arg =~ /\b(id|label|scale|split|align|center)=(.+)/ ) { + if ( $arg =~ /\b(id|label|scale|split|spread|width|align|center)=(.+)/ ) { $kv = parse_kv($arg); } else { diff --git a/lib/ChordPro/Version.pm b/lib/ChordPro/Version.pm index acbca98f..54906e37 100644 --- a/lib/ChordPro/Version.pm +++ b/lib/ChordPro/Version.pm @@ -1,4 +1,4 @@ # This file is generated. Do not edit! package ChordPro::Version; -our $VERSION = "6.040"; +our $VERSION = "6.042"; print "$VERSION\n" unless caller; diff --git a/lib/ChordPro/res/config/chordpro.json b/lib/ChordPro/res/config/chordpro.json index 8e7757da..a91a1268 100644 --- a/lib/ChordPro/res/config/chordpro.json +++ b/lib/ChordPro/res/config/chordpro.json @@ -245,6 +245,7 @@ "preamble" : [ // Use ChordPro fonts for lyrics and chords. "%%textfont pdf.fonts.text", + "%%vocalfont pdf.fonts.text", "%%gchordfont pdf.fonts.chord", ], "preprocess" : { "abc" : [] }, @@ -761,6 +762,7 @@ // For (debugging (internal use only)). "debug" : { + "runtimeinfo" : 1, "a2crd" : 0, "assets" : 0, "chords" : 0, diff --git a/lib/ChordPro/res/examples/mollymalone.cho b/lib/ChordPro/res/examples/mollymalone.cho new file mode 100644 index 00000000..acb4dcaf --- /dev/null +++ b/lib/ChordPro/res/examples/mollymalone.cho @@ -0,0 +1,40 @@ +{title: Molly Malone} +{subtitle: Irish Traditional} +{artist: Traditional} +{columns 2} +{start_of_abc spread=32 width="700"} +X: 1 +M: 3/4 +L: 1/4 +K: G +D | "G"GGG | "Em"GG"D7"A|"G"G2D| +w: “Cock-les_ and Mus-sels,_ a-live a-live O!” A- +P:Chorus +"G"G>GG|"Em"G/B/-BG|"Am"A>AA|"D7"A/c/-cA/A/|"G"G/d/-dc|"Em"B/d/-d c|"A7"B>G"D7"A|"G"G2z |] +w: live, a-live O!_* A-live a-live O!_* Cry-ing “Cock-les* and Mus-sels* a-live a-live-O!” + +{end_of_abc} +{image anchor="page" x="100%" y="100%" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Dublin_-_Molly_Malone.jpg/270px-Dublin_-_Molly_Malone.jpg"} +{start_of_verse} +She [G]was a fish [Em]monger +but [Am]sure, 'twas no [D7]wonder +For [G]so were her [Em]father and [A7]mother be[D7]fore +They [G]both wheeled their [Em]barrows +through [Am]streets broad and [D7]narrow +Crying [G]“Cockles and Mus[Em]sels, a[A7]live a[D7]live-[G]o” +{end_of_verse} + +{column_break} +{start_of_verse} +She died of the fever, +and nothing could save her +And that was the end of sweet Molly Malone +But her ghost wheels a barrow +through streets broad and narrow +Crying “Cockles and Mussels, alive alive-o” +{end_of_verse} + diff --git a/lib/ChordPro/res/pod/Config.pod b/lib/ChordPro/res/pod/Config.pod index 3cb0e69f..a5f4a97c 100644 --- a/lib/ChordPro/res/pod/Config.pod +++ b/lib/ChordPro/res/pod/Config.pod @@ -272,6 +272,7 @@ extensive details and examples. "preamble" : [ // Use ChordPro fonts for lyrics and chords. "%%textfont pdf.fonts.text", + "%%vocalfont pdf.fonts.text", "%%gchordfont pdf.fonts.chord", ], "preprocess" : { "abc" : [] }, @@ -788,6 +789,7 @@ extensive details and examples. // For (debugging (internal use only)). "debug" : { + "runtimeinfo" : 1, "a2crd" : 0, "assets" : 0, "chords" : 0,