--- /dev/null
+#!/usr/bin/perl -w
+
+# {{{ header and version
+#
+# Purpose of the script:
+#
+# This is a utility for typesetting guitar chords in chordpro format.
+# It uses TeX typesetting system, namely LaTeX2e macro package for TeX.
+#
+# Author: Daniel Polansky, dan.polansky@seznam.cz
+# Release: 0.8.2
+# Script home page: http://mujweb.cz/www/danielpolansky/chordpack/
+#
+# }}}
+
+# {{{ help message
+
+$help_message="Usage: chordpack [OPTION]... TASK [FILE]...\n".
+ "\n".
+ "Operate on songs for guitar found in FILEs. The songs are supposed\n".
+ "to be in chordpro format. Operation is determined by TASK, most\n".
+ "common is typesetting with TeX. Possible TASKs are tex, html, ascii,\n".
+ "nochord, transpose key-or-shift, pro. Options are\n".
+ "\n".
+ " -f song-list-file \tUse song-list-file\n".
+ " -l language \tUse language\n".
+ " -e encoding \tUse input encoding when typesetting with LaTeX\n".
+ " -b \tTypeset with minimum barre chords\n".
+ " -c chord-style \tSet the style of chord typesetting\n".
+ " -s font-sizes \tSet the font sizes\n".
+ "\n".
+ "For more detailed information see chordpack-documentation.html.\n";
+
+# }}}
+# {{{ support functions
+sub warning {
+ if (not $chordpack_introduced) {
+ $chordpack_introduced=1;
+ printf STDERR "\nChordpack: warning messages:\n\n";
+ }
+ print STDERR $_[0]; }
+
+sub check_for_the_length {
+ my ($line,$file,$maxlength)=@_;
+
+ if (length($line) > $maxlength) {
+ if (not exists($files_warned{$file})) {
+ $files_warned{$file}=1;
+ if ($error_explained==0) {
+ $error_explained=1;
+ warning "Warning >> means too long line ".
+ "(line longer than $maxlength characters).\nFile name where this happened".
+ " follows.\n";}
+ warning ">> $file.\n";}}}
+
+sub insertstring {
+ my ($inserted,$source,$position)=@_;
+
+ # Inset string $inserted into the string $source at position
+ # $position. If the position is farther than than the length of
+ # $source, die.
+
+ if ($position>=length($source)) {
+ die "insertstring: position too far.\n"; }
+
+ return substr($source,0,$position).$inserted.substr($source,$position,length($source)-$position);}
+
+# }}}
+
+# {{{ global variables and constants
+$chordpack_introduced=0;
+$error_explained=0;
+$carriage_return_warned=0;
+
+@tex_font_size = ( "\\tiny" , "\\scriptsize" , "\\footnotesize" ,
+ "\\small" , "\\normalsize" , "\\large", "\\Large" ,
+ "\\LARGE", "\\huge" , "\\Huge" );
+
+# }}}
+# {{{ global options
+
+use Getopt::Std;
+getopts('bf:c:l:s:e:');
+sub option_process {
+ my ($option,$default,$option_letter) = @_;
+ $from_options{$option}=0;
+ eval ("\$$option=\"$default\"");
+ if (eval "defined(\$opt_$option_letter)") {
+ $from_options{$option}=1;
+ eval ("\$$option=\$opt_$option_letter"); }}
+
+
+option_process("language","","l");
+# the only supported languages are Czech and German. The default language is English.
+
+option_process("inputenc","","e");
+# for LaTeX typesetting
+
+option_process("chord_style","m","c");
+# chordstyle string contains mi,m or - and also h if h is required
+
+
+option_process("font_sizes",3,"s");
+# currently available values are 0,1,2,3
+
+option_process("title_style","","");
+
+option_process("columns",2,"");
+
+$nobarre=0; $nobarre=1 if defined($opt_b) and $opt_b==1;
+# This option cannot be set using {} command
+
+# option -f is processed in tex task
+
+$ignore_tablature=0;
+$ignore_tablature=1 if $nobarre;
+
+
+# ------------------------------------
+
+sub finalize_language_dependent_settings {
+ $language=lc($language);
+
+ # This is Czech collation for ISO 8859-2 character encoding.
+ # We do not solve a problem of other encodings, also
+ # we don't know how to tell TeX to understand Codepage1250, for instace.
+ # This collation is not prefect, but working pretty well.
+
+ $collation{"czech"}{"list"}= "\"#$%&'()*+,-.:;<=>[\\]'`{}".
+ "0123456789 AÁBCÈDÏEÉÌFGH".chr(0)."IÍJKLÅ¥MNÒOÓPQRØS©T«UÚÙVWXYÝZ®".
+ "aábcèdïeéìfgh".chr(0)."iíjklåµmnòoópqrøs¹t»uúùvwxyýz¾";
+ $collation{"czech"}{"replace"}={"ch" => chr(0) };
+
+ # english is default
+ $alphabetical_name="Alphabetical index";
+ $transposed_by_1="Transposed by ";
+ $transposed_by_2=" half steps.";
+
+ if ($language eq "czech") {
+ $alphabetical_name="Abecední seznam";
+ $transposed_by_1="Transponováno o ";
+ $transposed_by_2=" pùltonù."; }
+
+ if ($language eq "german") {
+ $alphabetical_name="Alphabetischer index";
+ $transposed_by_1="Transponiert um ";
+ $transposed_by_2=" Halbtöne."; }}
+
+# {{{ finalize_options
+
+sub finalize_options {
+
+ finalize_language_dependent_settings();
+
+ $H_chord=0;
+ $chord_style_string=$chord_style;
+ for ($chord_style_string) {
+ $H_chord=1 if (/h/);
+ $chord_style="-" if (/jazz/ or /-/);
+ $chord_style="mi" if (/mi/);
+ $chord_style="low" if (/low/); }
+
+ if ($columns == 2) {
+ $pagewidth="0.47\\textwidth";
+ $twocolumns="[twocolumn]";
+
+ $hoffset=-1.1;
+ $textwidth=16-2*$hoffset; }
+ else {
+ $pagewidth="0.9\\textwidth";
+ $twocolumns="";
+
+ $hoffset=-0.5;
+ $textwidth=16-2*$hoffset;
+
+ $hoffset-=2; }
+
+
+ $font_sizes=0 if ($font_sizes<0);
+ $font_sizes=3 if ($font_sizes>3);
+
+ $text_font_size=$tex_font_size[$font_sizes+2];
+ $chord_font_size=$tex_font_size[$font_sizes+1];
+ $song_title_font_size=$tex_font_size[$font_sizes+4];
+
+ $tabuline_max=180/(($font_sizes+1)**0.7*$columns**0.7);
+ $tabuline_norm=$tabuline_max*(0.6)."em";
+ $bearable_length=$tabuline_max*(0.85);
+
+
+
+ $songtitles_newpage="";
+ for ($title_style) {
+ $songtitles_newpage="\\newpage" if (/songnewpage/); }
+
+ $album_title_font_size="\\Huge";
+
+ setup_collation();
+
+ #print STDERR %collation_hash;
+}
+
+# }}}
+
+# }}}
+
+# {{{ shared functions
+
+sub min {
+ return $_[0]<$_[1]?$_[0]:$_[1]; }
+
+sub find_chords {
+ my $crdprep = $_[0];
+ for ($crdprep) {
+ s/^[^\]]*\[//;
+ s/\][^\]]*$//; }
+ return split (/][^[]*\[/, $crdprep); }
+
+sub find_text {
+ # parameters: 1 - string of mixed text/chord
+ # 2 - possibly bool indicating whether we sould
+ # fix odd characters for tex
+ @text = split (/\[[^:\]]*\]/,$_[0]);
+ if ($_[1]) {
+ for (@text) {
+ $_=fix_odd_characters($_); }}
+ return @text; }
+
+sub to_nobarre_if_required {
+ if ($nobarre) {
+ my $songstart=0;
+ @tpose=();
+ push @input,"{title:none}"; # Add one false song start at an end
+ my $i=0;
+ while ($i<=$#input) {
+ if ($input[$i] =~ /\x7btitle:/) {
+ $transposition="nobarre";
+ transpose();
+ # warning "I am transposing, sir.\n";
+ splice @input,$songstart,$i-$songstart,@tpose;
+ $i=$songstart+$#tpose+1; # Correct $i so that it points to
+ # position after inserted transposed song
+ @tpose=$input[$i];
+ $songstart=$i; }
+ else {
+ push @tpose,$input[$i]; }
+ ++$i;}
+ pop @input; }} # Pop false song start
+
+%to_xml_text_conversion_table_windows1250 =
+ (
+ "9e" => "17e", # z^
+ "9a" => "161", # s^
+ "e8" => "10d", # c^
+ "f8" => "159", # r^
+ "ef" => "10f", # d^
+ "9d" => "165", # t^
+ "f2" => "148", # n^
+ "ec" => "11b", # e^
+ "f9" => "16f", # u°
+ "e5" => "13a", # l'
+
+ "8e" => "17d", # Z^
+ "8a" => "160", # S^
+ "c8" => "10c", # C^
+ "d8" => "158", # R^
+ "cf" => "10e", # D^
+ "8d" => "164", # T^
+ "d2" => "147", # N^
+ "cc" => "11a", # E^
+ "d9" => "16e", # U°
+ "bc" => "13d" # L'
+ # TODO: make difference between l acute and l caron
+ );
+
+%to_xml_text_conversion_table_isolatin2 =
+ (
+ "be" => "17e", # z^
+ "b9" => "161", # s^
+ "e8" => "10d", # c^
+ "f8" => "159", # r^
+ "ef" => "10f", # d^
+ "bb" => "165", # t^
+ "f2" => "148", # n^
+ "ec" => "11b", # e^
+ "f9" => "16f", # u°
+ "cd" => "13a", # l acute
+ "b5" => "13e", # l caron
+
+ "ae" => "17d", # Z^
+ "a9" => "160", # S^
+ "c8" => "10c", # C^
+ "d8" => "158", # R^
+ "cf" => "10e", # D^
+ "ab" => "164", # T^
+ "d2" => "147", # N^
+ "cc" => "11a", # E^
+ "d9" => "16e", # U°
+ "c5" => "139", # L acute
+ "a5" => "13d" # L caron
+ );
+
+
+sub to_xml_text {
+ $text = $_[0];
+ $text =~ s/&/&/g;
+ $text =~ s/>/>/g;
+ $text =~ s/</</g;
+ $text =~ s/\"/"/g;
+
+ if ($inputenc) {
+ # Convert national character to unicode, Windows 1250 and Iso Latin 2
+ # We convert only those characters which cannot be handled
+ # properly without conversion. For instance, we do not
+ # convert y'.
+
+ if ($inputenc eq "cp1250") {
+ while (($src, $dst) = each %to_xml_text_conversion_table_windows1250) {
+ $text =~ s/\x$src/&#x$dst;/g; }}
+ if ($inputenc eq "latin2") {
+ while (($src, $dst) = each %to_xml_text_conversion_table_isolatin2) {
+ $text =~ s/\x$src/&#x$dst;/g; }}}
+
+ return "$text"; }
+
+sub read_input_into_input_array {
+ # Global interface:
+ # $opt_f
+ # @input
+ # $stdout_opened
+ # $verbatim_lines
+
+ my $output_file_suffix = $_[0];
+
+ if (defined($opt_f)) {
+
+ open(FILE,"$opt_f") or warning("File \"$opt_f\" does not exist."),exit;
+ $mainpath=$opt_f;$mainpath =~ s|/[^/]*$|/|; chdir "$mainpath";
+
+ # $verbatim_lines=0; <- used to be here but I don't know why.
+ while(<FILE>) {
+ if (/^\x23/) {next} # comment
+ if (s/^ //) {push @input,"$_";next} # just one line is verbatim
+ if (/^\s*$/) {next} # whitespace line
+
+ chomp;
+ open(FILE2,"$_") or warning("File \"$_\" does not exist."),exit;
+ my $filename="$_";
+ while(<FILE2>) {
+ #check_for_the_length("$_",$filename,$bearable_length);
+ push @input,"$_"; }
+ close(FILE2);}
+ close(FILE);
+
+ # Open output
+ $output_file=$opt_f;
+ for ($output_file) {
+ if (not s/\.[^.]*$/.$output_file_suffix/) {
+ s/$/.$output_file_suffix/; }}
+
+ # Alphabetical file
+ $output_file_base=$output_file;
+ $output_file_base=~s/\.[^.]*$//; # remove .tex
+
+ open(STDOUT,">".$output_file);
+ $stdout_opened=1; }
+ else {
+ while (<>) {
+ #check_for_the_length("$_",$ARGV,$bearable_length);
+ push @input,"$_"; }}}
+
+# }}}
+# {{{ transposition "class"
+
+# transposition functions and constants are listed
+# here because they are neede not only in transposition
+# but also in tex setting
+
+
+# {{{ constants
+%chord_to_offset = ("C", 0,"C#",1, "Db",1,
+ "D", 2, "D#",3, "Eb",3,
+ "E", 4,
+ "F", 5,"F#",6,"Gb",6,
+ "G", 7,"G#",8,"Ab",8,
+ "A", 9,"A#",10,"Bb",10,
+ "H", 11,
+ "B", 11);
+
+# chord_price
+
+for my $offset (0..11) {
+ for my $minor (0..1) {
+ $chord_price[$offset][$minor]=0; }}
+
+$chord_price[0][0]=-2;
+$chord_price[5][0]=-1;
+$chord_price[7][0]=-1;
+$chord_price[2][1]=-1;
+$chord_price[4][1]=-1;
+$chord_price[9][1]=-2;
+
+# key_norm
+
+@key_norm=("b","b","#","b","#","b","b","#","b","#","b","#");
+
+# chord_barre
+
+for my $offset (0..11) {
+ for my $minor (0..1) {
+ $chord_barre[$offset][$minor]=1; }}
+
+$chord_barre[0][0]=0;
+$chord_barre[2][0]=0;
+$chord_barre[2][1]=0;
+$chord_barre[4][0]=0;
+$chord_barre[4][1]=0;
+$chord_barre[7][0]=0;
+$chord_barre[9][0]=0;
+$chord_barre[9][1]=0;
+
+# barre recognition is simplified
+# e.g. B7 is not barre, but we care only about base note and
+# major/minor.
+
+# }}}
+
+sub transpose_basic {
+ # global $norm, $shift
+
+ # Down shares
+
+ $transposed=$_[0];
+ for (my $i=0; $i<$shift; ++$i) {
+ transpose_basic_one_up();}
+
+ # normalize
+ if ($norm eq "b") {
+ for ($transposed) {
+ s/C\x23/Db/;
+ s/D\x23/Eb/;
+ s/F\x23/Gb/;
+ s/G\x23/Ab/;
+ s/A\x23/Bb/; }}
+ else {
+ for ($transposed) {
+ s/Db/C\x23/;
+ s/Eb/D\x23/;
+ s/Gb/F\x23/;
+ s/Ab/G\x23/;
+ s/Bb/A\x23/; }}
+
+ for ($transposed) {
+ s/mi/m/;
+ s/min/m/;
+ s/H/B/; }
+ return $transposed; }
+
+sub transpose_basic_one_up {
+ # global $transposed
+ # Transpose one chord by one halftone up
+
+ for ($transposed) {
+ s/H/B/;
+ if (s/C\x23/D/) {last;}
+ if (s/D\x23/E/) {last;}
+ if (s/F\x23/G/) {last;}
+ if (s/G\x23/A/) {last;}
+ if (s/A\x23/B/) {last;}
+
+ if (s/Db/D/) {last;}
+ if (s/Eb/E/) {last;}
+ if (s/Gb/G/) {last;}
+ if (s/Ab/A/) {last;}
+ if (s/Bb/B/) {last;}
+
+ if (s/C/C\x23/) {last;}
+ if (s/D/D\x23/) {last;}
+ if (s/E/F/) {last;}
+ if (s/F/F\x23/) {last;}
+ if (s/G/G\x23/) {last;}
+ if (s/A/A\x23/) {last;}
+ if (s/B/C/) {last;}}}
+
+sub transpose {
+ # global @tpose, $transposition
+ # global /*out*/ @tpose
+
+ # $transposition is one of:
+ # . "nobarre"
+ # . an integer (number of halftones to be transposed up)
+ # . destination key
+
+ # @tpose is an array of lines from chordpro songfile to be transposed
+
+ # <i>Normalization</i> is setting either with # or with b depending on
+ # key of the paragraph.
+
+
+
+ # {{{ Count chord frequencies
+
+ # count separately for each paragraph
+
+ $paragraph=0;
+ $was_space=1;
+
+ for (@tpose) {
+ chomp;$_.="\n"; #Every line _really_ has endline character
+
+ # {{{ Chords
+
+ if (/\[/) {
+ enter_paragraph_if_required();
+
+ my @chords = find_chords($_);
+
+ for (@chords) {
+ s/^\((.*)\)$/$1/; #kill brackets
+
+ s/\/.*$//; #kill bass
+ s/maj//;
+ $minor=(/m/);
+ $minor=0 if (not $minor);
+
+ $base=substr($_,0,1);
+ $base.="b" if (/^.b/);
+ $base.="#" if (/^.\x23/);
+ #print "$paragraph\n";
+ ++$chord_count[$paragraph][$chord_to_offset{$base}][$minor]; }
+ next }
+
+ # }}}
+ # {{{ Whitespace
+ if (/^\s*$/) {
+ $was_space=1; next }
+ # }}}
+ # {{{ Text
+ enter_paragraph_if_required();
+ # }}}
+ }
+ $paragraphs=$paragraph;
+
+ # global statistics if nobarre transposition
+
+ if ($transposition eq "nobarre") {
+ for $minor (0..1) {
+ for $offset (0..11) {
+ $song_chord_count[$offset][$minor]=0; }}
+ for $paragraph (1..$paragraphs) {
+ for $minor (0..1) {
+ for $offset (0..11) {
+ $song_chord_count[$offset][$minor]+=
+ $chord_count[$paragraph][$offset][$minor]; }}}}
+
+ # }}}
+ # {{{ Determine best keys
+
+ for ($paragraph=1; $paragraph<=$paragraphs; ++$paragraph) {
+
+ # {{{ debugging print
+ # print $chord_count[$paragraph];print "\n\n";
+
+ #for my $minor (0..1) {
+ # print "min:$minor: ";
+ # for my $chord (0..11) {
+ # print "$chord_count[$paragraph][$chord][$minor] ";
+ # }
+ # print "\n";
+ #}
+ # }}}
+
+ $bestvalue0=10000;
+ $bestkey0=0;
+ for $key (0..11) {
+ $value=0;
+ for my $chord (0..11) {
+ for my $minor (0..1) {
+ $value+=$chord_price[($chord-$key) % 12][$minor] *
+ $chord_count[$paragraph][$chord][$minor]; }}
+ $bestvalue0=$value,$bestkey0=$key if $value<$bestvalue0; }
+ $bestkey[$paragraph]=$bestkey0;
+ $bestvalue[$paragraph]=$bestvalue0; }
+ # }}}
+ # {{{ Determine numeric shift
+
+ if ($transposition eq "nobarre") {
+ $bestshift=0;
+ $bestprice=100000;
+ for $shift (0..11) {
+ $price=0;
+ for $minor (0..1) {
+ for $offset (0..11) {
+ $price+=($song_chord_count[$offset][$minor]
+ * $chord_barre[($offset+$shift)%12][$minor]) }}
+ if ($price<$bestprice) {
+ $bestprice=$price;
+ $bestshift=$shift; }}
+ $shift=$bestshift; }
+ elsif ($transposition =~ /^[-0-9]+$/) {
+ $shift=$transposition % 12; }
+ else {
+ $shift=-1;
+ for $paragraph (1..$paragraphs) {
+ if ($bestvalue[$paragraph]<0) {
+ if (not exists $chord_to_offset{$transposition}) {
+ warning("Key \"$transposition\" is unknown.\n");
+ exit; }
+ $shift=($chord_to_offset{$transposition}-$bestkey[$paragraph]) % 12;
+ last; }}}
+
+ # }}}
+ # {{{ Transpose and normalize
+ $paragraph=0;
+ $was_space=1;
+
+ for (@tpose) {
+ if (/\[/) { # Chord instructions
+ if ($was_space) {
+ $was_space=0;
+ ++$paragraph;
+ $norm=$key_norm[($bestkey[$paragraph]+$shift)%12]; }
+
+ # {{{ Ensure chords contain no spaces
+ if (/\[[^\]]* [^\]]*\]/) {
+ warning "\nSetchord: Chords cannot contain spaces.\n";
+ warning "This was broken at file $ARGV:\n";
+ warning $_;
+ exit; }
+ # }}}
+
+ my @text = split (/\[[^\]]*\]/,$_);
+ my @chords = find_chords($_);
+ # {{{ Transpose
+ for (@chords) {
+ @basses = split (/\//,$_);
+ $tpose=transpose_basic($basses[0]);
+ $tpose.="/".transpose_basic($basses[1]) if ($#basses==1);
+ $_=$tpose; }
+ # }}}
+ # {{{ Print everything out
+ my $out = shift @text;
+ my $textpos=0;
+ for (@chords) {
+ $out.="[$_]$text[$textpos]";
+ ++$textpos; }
+ $_= $out; # Write the result back to array
+ # }}}
+ next; }
+ if (/^\s*$/) { # Whitespace
+ $was_space=1; next; }
+ if ($was_space) { # ext or instruction
+ $was_space=0;
+ ++$paragraph;
+ $norm=$key_norm[($bestkey[$paragraph]+$shift)%12]; }}
+ # }}}
+ # {{{ Inform about cappo (the case of nobarre)
+
+ if ($transposition eq "nobarre" and $shift!=0) {
+ $capo=(12-$shift);
+ if ($capo<6) {
+ $capotext="{c:Cappo $capo}\n"}
+ else {
+ $capotext="{c:".$transposed_by_1.$shift.$transposed_by_2."}\n"}
+
+ splice @tpose,1,0,$capotext; }
+
+ # }}}
+}
+
+sub enter_paragraph_if_required {
+ # initializes @chord_count array by the way
+ if ($was_space) {
+ ++$paragraph; $was_space=0;
+
+ for my $chord (0..11) {
+ for my $minor (0..1) {
+ $chord_count[$paragraph][$chord][$minor]=0;}}}}
+
+
+# }}}
+
+# {{{ collation functions
+sub setup_collation {
+ # global $language,%collation
+ # print STDERR "[".$language."]";
+
+ if (defined($collation{$language})) {
+ #print STDERR "defined";
+ @collation_list=split(//,$collation{$language}{"list"});
+ $i=0;
+ for (@collation_list) {
+ $collation_hash{$_}=$i;
+ ++$i;}}
+ if (defined($collation{$language}{"replace"})) {
+ $collation_replace_ref=$collation{$language}{"replace"};
+ %collation_replace=%$collation_replace_ref; }}
+
+sub by_locale_collation {
+ # global $language,%collation
+ # print STDERR "byloc";
+
+ my $aa=$a;
+ my $bb=$b;
+ while (($old, $new) = each %collation_replace) {
+ $aa=~s/$old/$new/g;
+ $bb=~s/$old/$new/g; }
+
+ $i=0;
+ $min_length=min(length($aa),length($bb));
+ # print STDERR $min_length;
+ while ($i<$min_length) {
+ # print STDERR "[".substr($aa,$i,1)."]";
+ if ($collation_hash{substr($aa,$i,1)} < $collation_hash{substr($bb,$i,1)}) {
+ return -1; }
+ if ($collation_hash{substr($aa,$i,1)} > $collation_hash{substr($bb,$i,1)}) {
+ return 1; }
+ ++$i; }
+ return 0; }
+# }}}
+
+$task = shift @ARGV;
+
+# {{{ undefined task
+if (not defined($task)) {
+ print STDERR $help_message;
+ exit; }
+# }}}
+# {{{ learn os dependecies
+$long_newlines_os=0;
+if ($^O eq "dos" or $^O eq "MSWin32" or $^O eq "os2") {
+ $long_newlines_os=1; }
+# }}}
+# {{{ tex
+
+ # {{{ set_one_chord
+sub set_one_chord {
+ my $set="";
+ $_=$_[0];
+
+ # {{{ Switch B <-> H notation (B is common)
+ if ($H_chord) {
+ s/B([^b])/H$1/g;
+ s/B$/H/g; }
+ else {
+ s/H/B/g; }
+ # }}}
+
+ $set.="\\sf ";
+ # It is nice to represent special sequences with nonprintable characters.
+ s/maj/\001/;s/mi/m/;s/min/m/;s/dim/\002/;s/m75-/z/;
+ s/\0017/\001/;s/7\001/\001/;
+
+ # brackets
+ my $brackets=0;
+ if (/^\(.*\)$/) {
+ s/\(//;s/\)//;
+ $brackets=1;
+ $set.="("; }
+ # basses
+ my $bass="";
+ if (/\//) {
+ @basssplit = split(/\//,"$_");
+ ($bass = $basssplit[1]) =~ s/\043/h/; #043 is octal hash
+ $_ = $basssplit[0]; }
+
+ my $majset;my $dimset;my $minorset;my $minorshiftedbase;
+
+ # {{{ Chord style dependencies
+ for ($chord_style) {
+ if (/^\-$/) {
+ $majset="\$\\triangle\$";
+ $dimset="o";
+ $minorset="\\raisebox{0.26ex}{--}";
+ $minorshiftedbase="F";
+ last}
+ if (/^mi$/) {
+ $majset="maj7";
+ $dimset="dim";
+ $minorset="mi";
+ $minorshiftedbase="?";
+ last}
+ if (/^m$/) {
+ $majset="7maj";
+ $dimset="dim";
+ $minorset="m";
+ $minorshiftedbase="?";}
+ if (/^low$/) {
+ $majset="7maj";
+ $dimset="dim";
+ $minorset="low";
+ $minorshiftedbase="?";}}
+ # }}}
+
+ my $bot=""; my $top="";
+ my $bot0=""; my $top0="";
+ my $puttobot=0;
+ my $numfound=0;
+ my $force_stay_in_upper_index=0;
+ my @CHORD = split (//, $_);
+ $basenote=uc(shift @CHORD); # uc() is upper_case()
+
+
+ # if not reasonable chord, do not try to set indices
+ if (not $basenote=~/[ABCDEFGH]/) {
+ return "\\sf ".$_[0]."\\hskip.7em"; }
+
+ #$set.=$basenote;
+ for (@CHORD) {
+ if ($puttobot) { $bot.=$_; next; }
+ if ($numfound and /[2-9]/ and not $force_stay_in_upper_index) {
+ $bot.=$_; $puttobot=1; next; }
+
+ if (/[-\(]/) {
+ $force_stay_in_upper_index=1; $top.=$_; next; }
+ if (/\)/) {
+ $force_stay_in_upper_index=0; $top.=$_; next; }
+
+ if (/\001/) {
+ my $dest=\$top;
+ if ($numfound) {
+ $puttobot=1;
+ $dest=\$bot;}
+
+ if ($chord_style eq "mi") {
+ $$dest.=7;
+ $bot0.=" " if $bot0;
+ $bot0.="maj";
+ $numfound=1; next; }
+ $$dest.=$majset; $numfound=1; next; } # maj
+
+ if (/[2-9]/) { $top.="$_"; $numfound=1; next; }
+ if (/\002/) { $top.=$dimset; next; } # dim
+ if (/z/) { $top.="\$\\varnothing\$"; next; }
+ if (/b/) { $top0.="\$\\hskip0.1em\\mathbf{\\flat}\$"; next; }
+ if (/\x23/) { $top0.="\$\\hskip0.1em\\mathbf{\\sharp}\$"; next; }
+ # \x23 is octal hash
+
+ if (/m/) { # minor
+ if ($chord_style eq "-" and
+ not $basenote eq $minorshiftedbase) {$bot0.="\\hskip0.1em"}
+ $bot0.=$minorset; next;}
+ if (/\+/) { $bot.="+"; next; } # +
+ $top.="$_"; }
+
+ # Set basenote
+
+ if ($chord_style eq "low" and $bot0) {
+ $set.=lc($basenote);
+ $bot0=""; }
+ else {
+ $set.=$basenote; }
+
+ # Now INDEXES are really nasty
+ INDEXES: {
+ if (not $top0 and not $bot and $bot0 and $top and $chord_style eq "-") {
+ $set.="\\crdx{$top}{$bot0}{}{}"; # Typical case of Fm7
+ last INDEXES; }
+ if (not $top and $bot eq "+") {
+ if ($top0 =~ /flat/) {
+ $set.="\\crdx{$top0}{$bot0}{}{}\\hskip-.3em+";
+ last INDEXES; }
+
+ $set.="\\crdx{$top0}{$bot0}{}{}\\hskip-.1em+";
+ last INDEXES; }
+
+ if ($top =~ /dim/) { #case of dim in "m" and "mi" style setting
+ $set.="\\crdx{$top0}{$bot0}{}{}dim";
+ last INDEXES; }
+
+ $set.="\\crdx{$top0}{$bot0}{$top}{$bot}";
+ }
+ #
+
+ @basses = split(//,$bass);
+ $set.="\\crdbass{$bass}{}" if ($#basses==(1-1));
+ $set.="\\crdbass{$basses[0]}{$basses[1]}" if ($#basses==(2-1));
+
+ $set.=")" if ($brackets);
+
+ $set.="\\hskip.7em";
+ return $set; }
+
+
+# }}}
+ # {{{ set_tex_head
+
+sub set_tex_head {
+
+ finalize_options();
+ if (defined($output_file_base)) {
+ create_alphabetical_toc ($output_file_base); }
+
+ to_nobarre_if_required();
+
+ $head="\\documentclass${twocolumns}{article}\n";
+ if ($language eq "czech") {
+ $head.="\\usepackage{czech}\n"; }
+ if ($inputenc) {
+ $head.="\\usepackage[$inputenc]{inputenc}\n"; }
+ if ($language eq "german") {
+ $head.="\\usepackage{german}\n"; }
+ $head.="\\usepackage{palatino}
+\\usepackage{amsfonts,amssymb}
+\\usepackage{colortbl}
+\\usepackage{verbatim}
+\\usepackage{graphics}
+\\usepackage{exscale}
+\\textwidth=${textwidth}cm
+\\hoffset=${hoffset}cm
+\\textheight=26cm
+\\voffset=-3cm
+\\columnsep=0.07\\columnwidth% This is the size of white space separating two columns
+%
+%
+% ==================================
+% Commands and environments
+% ==================================
+%
+%
+\\newcommand{\\N}{\\\\\\rule{0pt}{0pt}}
+% /\ This is a newline which does not produce underfull box warnings.
+\\newcommand{\\spc}{\\setbox0=\\hbox{x}\\hskip\\wd0}
+\\newcommand{\\largeskip}{\\bigskip\\bigskip}
+% silent \\par not producing undefull hboxes (hack a little)
+\\newcommand{\\spar}{\\rule{0pt}{0pt}\\par}
+
+\\newcommand{\\maxskip}[2]{%
+\\setbox0=\\hbox{#1}\\setbox1=\\hbox{#2}%
+\\ifdim\\wd0<\\wd1\\hskip\\wd1\\else\\hskip\\wd0\\fi}%
+
+\\newdimen\\tempdimen%
+
+\\newcommand{\\filldifrule}[3]{%
+\\setbox0=\\hbox{#1}\\setbox1=\\hbox{#2}%
+\\ifdim\\wd1<\\wd0%
+\\tempdimen=\\wd0%
+\\advance\\tempdimen by - \\wd1%
+\\ifdim\\tempdimen<0.3em\\tempdimen=0.3em\\fi%
+\\advance\\tempdimen by -0.1em%
+\\hskip0.05em%
+\\rule[.5ex]{\\tempdimen}{0.12ex}%
+\\hskip0.05em%
+\\else%
+#3%
+\\fi}
+
+\\newcommand{\\skipdif}[2]{%
+\\setbox0=\\hbox{#1}\\setbox1=\\hbox{#2}%
+\\ifdim\\wd1<\\wd0%
+\\tempdimen=\\wd0%
+\\advance\\tempdimen by - \\wd1%
+\\hskip\\tempdimen%
+\\fi}
+
+\\newcommand{\\leftrepeat}{%
+\\rule[-0.3ex]{0.05em}{2ex}\\hskip0.1em\\rule[-0.3ex]{0.05em}{2ex}%
+\\hskip0.1em\\raisebox{0.1ex}{:} }
+
+\\newcommand{\\rightrepeat}{%
+ \\raisebox{0.1ex}{:}\\hskip0.1em%
+\\rule[-0.3ex]{0.05em}{2ex}\\hskip0.1em\\rule[-0.3ex]{0.05em}{2ex}}
+
+";
+
+$song_title_shared_start=
+"\\newcommand{\\songtitle}[2]{
+\\spar\\vfill
+$songtitles_newpage%
+\\begin{minipage}{\\columnwidth}%
+\\addcontentsline{toc}{subsection}{#1}%
+";
+
+$song_title_shared_end="\\bigskip
+\\end{minipage}\\nopagebreak[4]\\par\\nopagebreak[4]}";
+
+
+
+SONGTITLE: {
+ if ($title_style =~ /norule/) {
+ $head.=$song_title_shared_start.
+"{$song_title_font_size \\sf\\bfseries #1\\\\[0.2ex]}%
+{\\it #2}%
+".$song_title_shared_end;
+ last SONGTITLE; }
+
+ if ($title_style =~ /graybox/) {
+ $head.=$song_title_shared_start.
+"\\begin{tabular}{>{\\columncolor[gray]{0.8}}p{\\textwidth}}%
+$song_title_font_size \\sf\\bfseries\\rule{0pt}{1.6ex}#1%
+\\end{tabular}\\\\[1.5ex]%
+{\\it #2}%
+".$song_title_shared_end;
+ last SONGTITLE; }
+
+ # default style - rule
+
+ $head.=$song_title_shared_start.
+ "\\rule{\\textwidth}{.5ex}\\\\[1.3ex]\n".
+ "{$song_title_font_size \\sf\\bfseries #1\\\\[0.2ex]}%\n".
+ "{\\it #2}%\n".$song_title_shared_end;
+
+}
+
+ $head.="
+\\newcommand{\\albumtitle}[1]{
+%\\spar
+\\vfill
+\\newpage
+\\begin{minipage}{\\columnwidth}
+\\addcontentsline{toc}{section}{#1}
+\\rule{\\textwidth}{.7ex}\\\\
+$album_title_font_size \\sf\\bfseries #1%
+\\bigskip\\bigskip\\bigskip
+\\end{minipage}}
+
+\\newcommand{\\tabuline}[1]{
+\\def\\emptyparameter{}%
+\\def\\currentparameter{#1}%
+\\ifx\\emptyparameter\\currentparameter%
+% This is a case of empty line. Empty line is not as high as nonempty line.
+\\colorbox[gray]{0.87}{\\rule{0pt}{1ex}\\rule{0.95\\textwidth}{0pt}}%
+\\else%
+% This is a case of nonempty line.
+\\colorbox[gray]{0.87}{%
+\\resizebox{0.95\\textwidth}{1.5ex}{%
+\\rule{0pt}{1.5ex}#1\\setbox0=\\hbox{#1}\\hskip-\\wd0\\rule{$tabuline_norm}{0pt}%
+}%
+}%
+\\fi%
+\\\\[-0.3ex]%
+}
+";
+
+ $head.= "
+\\newcommand{\\crdx}[4]{
+\\hskip-0.3em\\lower-0.2ex\\hbox{$chord_font_size\$^\\textsf{#1}_\\textsf{#2}\$}%
+\\hskip0.25em
+\\if:#1:\\if:#2:\\hskip0.1em\\fi\\fi
+\\hskip-0.3em\\lower-0.2ex\\hbox{$chord_font_size\$^\\textsf{#3}_\\textsf{#4}\$}}
+" if ($chord_style eq "-");
+
+ $head.= "
+\\newcommand{\\crdx}[4]{
+\\hskip-0.3em\\lower-0.2ex\\hbox{$chord_font_size\$^\\textsf{#1}\$}%
+\\hskip0.25em%
+\\if:#2:
+\\else\\hskip-0.3em{}#2\\hskip0.3em\\fi
+\\hskip-0.3em\\lower-0.2ex\\hbox{$chord_font_size\$^\\textsf{#3}_\\textsf{#4}\$}}
+" if ($chord_style =~ /m|mi|low/);
+
+ $head.= "
+\\newcommand{\\crdbass}[2]{
+\\hskip-0.4em\\big/#1\\crdx{\$%
+\\if b#2%
+\\flat\\fi\\if h#2%
+\\sharp\\fi\$}{}{}{}}
+
+\\newenvironment{tabbingnb}
+{\\noindent
+\\begin{minipage}{0.4\\textwidth}\\begin{tabbing}}
+{\\end{tabbing}\\end{minipage}\\par\\vskip-\\baselineskip}\n";
+
+$head_after_begin_document="
+%
+%
+% ===========================
+% BEGIN DOCUMENT
+% ===========================
+%
+%
+\\begin{document}
+\\setlength{\\parindent}{0pt}
+\\boldmath
+$text_font_size\n";
+$head_after_begin_document.="\\csprimeson\n" if ($language eq "czech");
+
+#------------------------------------
+
+$table_of_contents.= "
+%
+%
+% =====================
+% TABLE OF CONTENTS
+% =====================
+%
+%
+\\thispagestyle{empty}
+
+\\tableofcontents
+
+%This is macro of Petr Olsak. It inputs the file but
+%does not cry, if file does not exist
+
+\\newread\\testin
+\\def\\softinput #1 {\\let\\next=\\relax \\openin\\testin=#1
+\\ifeof\\testin%
+\\else\\closein\\testin\\def\\next{\\input #1 }\\fi
+\\next}
+
+% Insert alphabetical table of contents,
+% if there is one
+
+\\openin\\testin=\\jobname.atoc
+\\ifeof\\testin\\closein\\testin%
+\\else\\closein\\testin
+\\newpage
+\\section*{$alphabetical_name}
+\\softinput \\jobname.atoc
+\\fi
+
+\\clearpage\n";
+
+$titlepage_head="
+%
+% =======================
+% Titlepage
+% =======================
+%
+\\thispagestyle{empty}
+\\
+\\vskip16\\baselineskip
+{\\Huge
+\\begin{tabular*}{\\textwidth}{c}
+\\hskip\\textwidth\\ \\\\
+\\bfseries ";
+
+$titlepage_tail= "
+\\end{tabular*}}
+\\clearpage";
+
+}
+
+# }}}
+ # {{{ fix_odd_characters
+sub fix_odd_characters {
+ # fix odd characters for normal text and chords
+ # (there is other slightly different fixing process for tabulatures)
+
+ $_=$_[0];
+
+ # Backslashes previously inserted by chordpack
+ # are coded by character with ascii code 01.
+
+ # assumption - there are no nonprintable characters
+ # this assumption may later be explicitly checked
+
+ s/\\/\x00/g; # mark backslashes
+
+ for ($ascii=33;$ascii<=38;++$ascii) {
+ $re="\\x".sprintf "%.2x",$ascii;
+ s/$re/\\char$ascii\x02/g; } #\x02 is reserved for {}
+
+ s/\{/\$\\{\$/g; s/\}/\$\\}\$/g;
+ s/\^/\\char094\x02/g;
+ s/\|/\$\|\$/g;
+ s/</\$<\$/g;
+ s/>/\$>\$/g;
+ s/~/\\~{}/g;
+ s/\[/\$\[\$/g; s/\]/\$\]\$/g;
+
+
+ # backslashes must be done on their own
+ s/\x00/\$\\backslash\$/g;
+ s/\x01/\\/g;
+ s/\x02/\{\}/g;
+ return $_;
+}
+# }}}
+ # {{{ set_songtitle
+sub set_songtitle {
+ # global $songtitle
+ # global @subtitles
+
+ $subtitle_set="";
+ for (@subtitles) {
+ $subtitle_set.=$_."\\\\"; }
+ print "%\n%\n%\n%\n\\songtitle{$songtitle}{$subtitle_set}%\n"; }
+
+# }}}
+ # {{{ previous_block_care
+sub previous_block_care {
+ # global $previous_block
+
+ $pb=$previous_block;
+
+ if ($previous_block==1) {}
+
+ if ($pb==1) {
+ print $_[0]; }
+ if ($pb==2) {
+ print $_[1]; }
+ if ($pb==3) {
+ set_songtitle(); }
+ $previous_block=0; } # global change
+
+# }}}
+ # {{{ create_alphabetical_toc
+sub create_alphabetical_toc {
+ # global $previous_block
+
+ # print STDERR "creating alphabetical";
+
+ $output_file_base=$_[0];
+
+ if (open(TOC,$output_file_base.".toc")) {
+ while (<TOC>) {
+ push @toc,$_; }
+ close (TOC);
+
+ # There may be a problem with sorting for languages. I do not know a solution.
+ # I suppose in that case alphabetical must be edited manually.
+
+ # To be done:
+ # . switch and option producing alphabetical
+ # . discuss languages
+ # . update documentation (not alphabetical, but atoc)
+
+ # print STDERR %collation_hash;
+
+ if (%collation_hash)
+ {
+ # not empty
+ @sorted_toc = sort by_locale_collation @toc;
+ }
+ else
+ {
+ @sorted_toc = sort @toc;
+ }
+
+ @alpha_toc = grep(!/{sect.*}/, @sorted_toc);
+
+ open(ATOC,">".$output_file_base.".atoc");
+ for (@alpha_toc) {
+ print ATOC $_; }
+ close (ATOC); }}
+
+# }}}
+
+
+if ($task eq "tex") {
+
+ my $previous_line=0;
+ $previous_block=0;
+ # previous_line: 0=emptyline, 1=text_line, 2=chord, 3=songtitle, 4=albumtitle
+ # previous_block: 0=we're in block, 1=text_line, 2=chord, 3=songtitle, 4=albumtitle
+
+
+ # Definitions:
+ # White line is a line which contains only whitespace character.
+ # Block is a maximal sequence of lines which are not white.
+ # Lines can be of several kinds, one block can contain lines of
+ # different kinds.
+ # A kind of a block is the kind of last line of that block.
+
+ # Variable Previousblock contains the kind of previous block.
+ # An exception to this is songtitle, which sets previousblock explicitly
+ # as it's current block.
+
+ %files_warned=();
+ $head_printed=0;
+ $verbatim_tex=0;
+ $table_of_contents_printed=0;
+ $tex_prebegin_part=0;
+ $in_tablature=0;
+ $subtitles_enabled=0;
+
+ @input=();
+ $stdout_opened=0;
+
+ # Read input into @input variable
+ read_input_into_input_array("tex");
+
+ for (@input) {
+ # warning "input: $_";
+ chomp;
+ # {{{ Remove carriage return
+ if (not $long_newlines_os) {
+ if (s/\x0d//g) {
+ if (not $carriage_return_warned) {
+ warning "Your chordpro files have DOS carriage return ends of line".
+ " - not a serious problem.\n";
+ $carriage_return_warned=1; }}}
+ # }}}
+
+ # {{{ Parenthesis
+ s/\" /\'\' /g;
+ s/\"$/\'\'/g;
+ s/ \"/ \`\`/g;
+ s/^\"/\`\`/g;
+ # }}}
+
+ # Process line
+
+ # {{{ Head not yet printed
+
+ if (not $head_printed) {
+ # {{{ Remove comment
+ s/\x23.*$//;
+ # }}}
+
+ # {{{ In TeX prebegin
+
+ if ($tex_prebegin_part) {
+ if (/\173tex_prebegin_end/) {
+ $tex_prebegin_part=0;
+ set_tex_head();
+ print "$head";
+ print "$tex_prebegin_text";
+ print "$head_after_begin_document";
+ $head_printed=1;
+ next; }
+ $tex_prebegin_text.="$_\n"; next}
+
+ # }}}
+
+ # {{{ Chordstyle
+ if (/{chordstyle:.*}/) {
+ if ($from_options{"chord_style"}) {
+ next; }
+
+ s/{[^:]*: *//; s/}//;
+ $chord_style=$_;
+ next; }
+ # }}}
+ # {{{ Language
+ if (/{language:.*}/) {
+ if ($from_options{"language"}) {
+ next; }
+
+ s/{[^:]*: *//; s/}//;
+ $language=$_;
+ next; }
+ # }}}
+ # {{{ Fontsize
+ if (/{fontsize:.*}/) {
+ if ($from_options{"font_sizes"}) {
+ next; }
+
+ s/{[^:]*: *//; s/}//;
+
+ $font_sizes=$_;
+ next; }
+ # }}}
+
+ # {{{ Title style
+ if (/{titlestyle:.*}/) {
+ if ($from_options{"title_style"}) {
+ next; }
+
+ s/{[^:]*: *//; s/}//;
+
+ $title_style=$_;
+ next; }
+ # }}}
+ # {{{ Columns
+ if (/{columns:.*}/) {
+ if ($from_options{"columns"}) {
+ next; }
+
+ s/{[^:]*: *//; s/}//;
+
+ $columns=$_;
+ next; }
+ # }}}
+
+ # {{{ Emptyline
+ if (/^\s*$/) {
+ next; }
+ # }}}
+
+
+ # {{{ Songbook title
+ if (/{songbooktitle:.*}/) {
+ s/{[^:]*: *//; s/}//;
+ s/&/\\&/g;
+
+ @titlelist = split (/\^/, $_ );
+
+ set_tex_head();
+ print "$head";
+ print "$head_after_begin_document";
+ print "$titlepage_head";
+
+ for (@titlelist) {
+ print "$_\\\\\n"; }
+
+ print "$titlepage_tail";
+ print "$table_of_contents";
+ $table_of_contents_printed=1;
+
+ $head_printed=1;
+ next; }
+ # }}}
+ # {{{ Songbook title not found
+ if (/{tex_prebegin_start.*}/) {
+ $tex_prebegin_part=1;
+ $tex_prebegin_text=""; next}
+
+ $backup = $_;
+ set_tex_head();
+ print "$head";
+ print "$head_after_begin_document";
+ $head_printed=1;
+ $_ = $backup;
+
+ # }}}
+
+ }
+
+ # }}}
+ # {{{ Command allowed only in before head
+ # warning ("Here is $_.");
+ if (/{fontsize.*}/ or
+ /{language.*}/ or /{titlestyle.*}/ or /{columns.*}/
+ or /{chordstyle.*}/ ) {
+ warning ("Command $_ can be used only before first {album: } or {title: } command is used.\n");
+ next; }
+ # }}}
+ # {{{ In Verbatim TeX
+ if ($verbatim_tex) {
+ if (/{vtexe.*}/ or /{verbatim_tex_end.*}/) {
+ $verbatim_tex=0; next; }
+ print "$_\n"; next; }
+ # }}}
+ # {{{ In tablature
+
+ if ($in_tablature) {
+ if (/{eot.*}/ or /{end_of_tab.*}/) {
+ $in_tablature=0;
+ if (not $ignore_tablature) {
+ # \\rule is here just to prevent underfull hbox messages
+ print "\\rule{0pt}{0pt}\\end{minipage}\n"};
+ next}
+
+ if (not $ignore_tablature) {
+ $_=substr($_,0,$tabuline_max);
+ s/^ +$//g; #no whitespace lines
+
+ # {{{ ascii based translation
+ s/\\/\x00/g; #mark backslashes
+ s/ /\x01/g; #mark spaces
+ for ($ascii=33;$ascii<=47;++$ascii) {
+ $re="\\x".sprintf "%.2x",$ascii;
+ s/$re/\\char$ascii /g; }
+ for ($ascii=93;$ascii<=96;++$ascii) {
+ $re="\\x".sprintf "%.2x",$ascii;
+ s/$re/\\char$ascii /g; }
+ for ($ascii=123;$ascii<=126;++$ascii) {
+ $re="\\x".sprintf "%.2x",$ascii;
+ s/$re/\\char$ascii /g; }
+ # backslashes and spaces must be done on their own
+ s/\x00/\\char92 /g;
+ s/\x01/\\hskip0.602em /g;
+ # }}}
+
+ print "\\tabuline{$_}\n";}
+ next}
+
+ # }}}
+
+ # Line contains
+
+ # {{{ Comment (programmer's kind of)
+ if (/^\043/) { # 043 is octal of hash
+ next}
+ # }}}
+
+ # {{{ Subtitles_on command
+ if (/{subtitles_on.*}/) {
+ $subtitles_enabled=1;
+ next; }
+ # }}}
+ # {{{ Subtitles_off command
+ if (/{subtitles_off.*}/) {
+ $subtitles_enabled=0;
+ next; }
+ # }}}
+
+ # {{{ Start of verbatim TeX
+ if (/{vtexs.*}/ or /{verbatim_tex_start.*}/) {
+ $verbatim_tex=1; next }
+ # }}}
+ # {{{ Start of Tablature
+ if (/{sot.*}/ or /{start_of_tab.*}/) {
+ previous_block_care("\\spar\n","\\spar\\largeskip\n");
+ $in_tablature=1;
+ if (not $ignore_tablature) {
+ print "\n\\begin{minipage}{\\columnwidth}\\tt\n";
+ $previous_line=1; }
+ next; }
+ # }}}
+
+ # {{{ Table of contents
+
+ if (/{toc.*}/ or /{table_of_contents.*}/) {
+ warning ("TOC FOUND\n");
+ if ($table_of_contents_printed) {
+ warning("You ask me to print table of contents though it\n".
+ "has already been printed with songbook's titlepage.\n"); }
+ else {
+ warning ("toc\n");
+ print "$table_of_contents"; }
+ next; }
+
+ # }}}
+
+ # {{{ Title command
+ if (/{t:.*}/ or /{title:.*}/) {
+ s/{[^:]*: *//; s/}//;
+
+ if ($previous_line!=0) {
+ $previous_block=$previous_line }
+ #$previous_line=0;
+
+ # print "\\bigskip" if ($previous_line==0);
+ previous_block_care("\\bigskip","\\bigskip\\bigskip");
+
+ #s/&/\\&/g; # hack, I don't like this
+ #print "%\n%\n%\n%\n\\songtitle{$_}{}%\n";
+ $previous_line=3;
+ $previous_block=3; # explicit previousblock
+
+ $songtitle=fix_odd_characters($_);
+ #$songtitle=$_;
+ @subtitles=();
+ next; }
+ # }}}
+ # {{{ Subtitle command
+ if (/{st:.*}/ or /{subtitle:.*}/) {
+ s/{[^:]*: *//; s/}//;
+
+ if ($subtitles_enabled) {
+ push @subtitles,fix_odd_characters($_); }
+ $previous_block=3; # explicit previous_block
+
+ # ignored, so far
+ #print "\n\\bigskip" if ($previous_line==1);
+ #print "\\bigskip\\bigskip" if ($previous_line==2);
+ #print "\\bigskip" if ($previous_line==0);
+
+ #s/\173[^:]*: *//; s/\175//; # 173 is octal left curly brace 175 is right
+ #s/&/\\&/g;
+ #print "%\n%\n%\n%\n\\songtitle{$_}%\n";
+ #$previous_line=3;
+ next}
+ # }}}
+ # {{{ Album command
+ if (/{album:.*}/) {
+
+ print "\n\\bigskip" if ($previous_line==1);
+ print "\\bigskip\\bigskip" if ($previous_line==2);
+ print "\\bigskip" if ($previous_line==0);
+
+ s/\173[^:]*: *//; s/\175//; # 173 is octal left curly brace 175 is right
+ s/&/\\&/g;
+ print "%\n" .
+ "%\n" .
+ "% ======================\n" .
+ "% $_\n".
+ "% ======================\n" .
+ "%\n" .
+ "%\n\\albumtitle{$_}%\n";
+ $previous_line=4;
+ next}
+ # }}}
+ # {{{ Start of choir
+ if (/{soc.*}/ or /{start_of_chorus.*}/) {
+ print "\\it\n";
+ next}
+ # }}}
+ # {{{ End of choir
+ if (/{eoc.*}/ or /{end_of_chorus.*}/) {
+ print "\\rm\n";
+ next}
+ # }}}
+ # {{{ Comment
+ if (/{c:.*}/ or /{comment:.*}/ or /{comment_italic:.*}/ or /{comment_box:.*}/) {
+ s/{[^:]*: *//; s/}//;
+ s/&/\\&/g;
+
+ previous_block_care("\\spar\n","\\spar\\largeskip\n");
+
+ print "{\\it $_\\rm}\\\\\n";
+ $previous_line=1; #Comment is close to ordinary text
+ next}
+ # }}}
+ # {{{ Chord command (not chordpack)
+
+ if (/{ns.*}/ or /{new_song.*}/ or /{define.*}/ or /{textfont.*}/ or /{textsize.*}/
+ or /{chordfont.*}/ or /{chordsize.*}/ or /{no_grids.*}/ or /{ng.*}/ or
+ /{grid.*}/ or /{g.*}/ or /{new_page.*}/ or /{np.*}/ or /{new_physical_pages.*}/ or
+ /{npp.*}/ or /{columns_break.*}/ or /{colb.*}/) {
+ warning($_.": Here is a command of chord but not of chordpack\n");
+ next}
+
+ # }}}
+
+ # {{{ Other command
+ if (/{.+}/) {
+ warning($_.": unrecognized command\n");
+ next}
+ # }}}
+
+ # {{{ Repeat marks [: :]
+ # Final backslashes are represented by character with code 0
+ # This DEPENDS on behaviour of fix_odd_characters function
+
+ s/\[:/\x01leftrepeat/g; s/:\]/\x01rightrepeat/g;
+ # }}}
+
+ # {{{ Chord instructions
+ if (/\[[^ ].*\]/) {
+ $_.=" ";
+
+ previous_block_care("\\spar\\bigskip\n","\\spar\\largeskip\n");
+ # { Ensure chords contain no spaces
+ if (/\[[^\]]* [^\]]*\]/) {
+ warning "\nSetchord: Chords cannot contain spaces.\n";
+ warning "This was broken at file $ARGV:\n";
+ warning $_;
+ exit;}
+ # }
+
+ s/\]\[/\] \[/g; #no chords tightly follow
+
+ # { Determine chord and text arrays
+ my @text = find_text($_,1);
+ my @chords = find_chords($_);
+ # }
+ # {{{ Print tab stops for chords, chords and text
+
+ my $tabstops=$text[0];
+ my $text_line=$text[0];
+ my $chord_line="";
+ my $i=1;
+ for (@chords) {
+ $crd = set_one_chord("$_");
+
+ $text[$i] =~ s/^ /\\hskip.7em /; #chord is preshifted to the left of the text
+ #$tabstops.="\\=\\maxskip{$crd}{$text[$i]}";
+ $chord_line.="\\>$crd";
+ #$text_line.="\\>$text[$i]";
+ # Join two broken parts of word, if needed
+ $text=$text[$i];
+ if ($i<$#text) {
+ $last_char=substr($text[$i],length($text[$i])-1,1);
+ $first_char=substr($text[$i+1],0,1);
+ if (($last_char =~ /^[^ .,]$/) and ($first_char =~ /^[^ .,]$/)) {
+ for ($text) {
+ if (s/ ([^ ])/ \\skipdif{$crd}{$text}$1/) {last;}
+ if (s/ / \\skipdif{$crd}{$text}/) {last;}
+
+ $present_dash="";
+ if(s/-+$//) {$present_dash="-"} # Remove dashes already present in adjacent
+ if($text[$i+1] =~ s/^-+([a-zA-Z])/$1/) {$present_dash="-"} # texts
+ s/$/\\filldifrule{$crd}{$text}{$present_dash}/;}}}
+
+ $text_line.="\\>$text";
+ $tabstops.="\\=\\maxskip{$crd}{$text}";
+
+ $text[$i] =~ s/^ /\\hskip.7em /g; #chord is preshifted to the left of the text
+ ++$i;}
+
+ print "\\begin{tabbingnb}\n";
+ print "$tabstops\\kill\n";
+ print "$chord_line\\\\\n";
+ print "$text_line\\\\\n";
+ print "\\end{tabbingnb}\n";
+
+ # }}}
+
+ $previous_line=2;
+ next}
+ # }}}
+ # {{{ Spaces only
+ if (/^ *$/) {
+ $previous_block=$previous_line if ($previous_line!=0);
+ $previous_line=0;
+ next}
+ # }}}
+ # {{{ Text without chords
+ previous_block_care("\\spar\n","\\spar\\largeskip\n");
+
+ print fix_odd_characters($_)."\\N\n";
+ $previous_line=1;
+ # }}}
+ }
+
+ print "\\spar\\end{document}\n";
+ exit; }
+
+# }}}
+# {{{ ascii
+if ($task eq "ascii") {
+
+ my $first_song = 1;
+
+ @input = ();
+ $stdout_opened = 0;
+
+ read_input_into_input_array("txt");
+
+ finalize_language_dependent_settings();
+ to_nobarre_if_required();
+
+ for (@input) {
+ chomp;
+
+ # Process line
+
+ # Line contains:
+ # {{{ Title command
+ if (/{t:.*}/ or /{title:.*}/) {
+
+ if ($first_song) {
+ $first_song = 0; }
+ else {
+ printf "\n\n"; }
+
+ s/{[^:]*: *//; s/}//;
+ printf "$_\n----------------------------------------\n";
+ next; }
+ # }}}
+ # {{{ Comment
+ if (/{c:.*}/ or /{comment:.*}/) {
+ s/\173[^:]*: *//; s/\175//; # 173 is octal left curly brace 175 is right
+ print "\n$_\n\n";
+ next; }
+ # }}}
+ # {{{ Other command
+ if (/{.*}/) {
+ next;}
+ # }}}
+
+ # {{{ Comment (programmer's kind of)
+ if (/^\x23/) { # \x23 is hash
+ next; }
+ # }}}
+ # {{{ Chord instructions
+ if (/\[[^:]/) {
+ $_.=" ";
+
+ # {{{ Ensure chords contain no spaces
+ if (/\[[^\]]* [^\]]*\]/) {
+ warning "\nSetchord: Chords cannot contain spaces.\n";
+ warning "This was broken at file $ARGV:\n";
+ warning $_;
+ exit; }
+ # }}}
+
+ s/\]\[/\] \[/g; #no chords tightly follow
+
+ # {{{ Determine chord and text arrays
+ my @text = find_text($_);
+ my @chords = find_chords($_);
+ # }}}
+ # {{{ Print chords and text
+
+ my $chord_line=$text[0]; $chord_line =~ s/./ /g;
+ my $textpos=1;
+ my $text_line=$text[0];
+ for (@chords) {
+ $crd=$_;
+ $chord_line.=$_ . (' ' x (length($text[$textpos])-length($crd)));
+ $text_line.=$text[$textpos] . ' ' x (length($crd)-length($text[$textpos]));
+ $textpos++; }
+
+ print "$chord_line\n$text_line\n";
+
+ # }}}
+
+ next; }
+ # }}}
+ # {{{ Spaces only
+ if (/^ *$/) {
+ print "\n";
+ next;}
+ # }}}
+ # {{{ Text without chords
+ print "$_\n";
+ # }}}
+ }
+exit;
+}
+# }}}
+# {{{ fmm - freemind mind map
+
+if ($task eq "fmm") {
+
+ $song_opened = 0;
+ $album_opened = 0;
+
+ @input = ();
+ $stdout_opened = 0;
+
+ read_input_into_input_array("mm");
+
+ printf "<map>\n<node text=\"Songbook\" color=\"#996600\"><node text=\" \">\n";
+
+ my $closing_of_song = "\">\n".
+ "<font name=\"Courier New\" size=\"12\"/>\n".
+ "</node>\n</node>\n";
+
+ my $closing_of_album = "</node>\n";
+
+ for (@input) {
+ chomp;
+
+ # Process line
+
+ # Line contains:
+ # {{{ Title command
+ if (/{t:.*}/ or /{title:.*}/) {
+
+ if ($song_opened) {
+ printf $closing_of_song;
+ $song_opened = 0; }
+
+ s/{[^:]*: *//; s/}//;
+ printf "<node text=\"".to_xml_text("$_")."\" color=\"#669900\" folded=\"true\">\n";
+ printf "<node text=\"";
+
+ $song_opened = 1;
+ next; }
+ # }}}
+ # {{{ Album command
+ if (/{album:.*}/) {
+
+ if ($song_opened) {
+ printf $closing_of_song;
+ $song_opened = 0; }
+
+ if ($album_opened) {
+ printf $closing_of_album;
+ $album_opened = 0; }
+
+ s/{[^:]*: *//; s/}//;
+ printf "<node text=\"".to_xml_text("$_")."\" color=\"#006633\" folded=\"true\">\n";
+ $album_opened = 1;
+ next; }
+ # }}}
+ # {{{ Other command
+ if (/{.*}/) {next;}
+ # }}}
+
+ if (not $song_opened) {
+ next; }
+
+ # {{{ Comment (programmer's kind of)
+ if (/^\x23/) { # \x23 is hash
+ next; }
+ # }}}
+ # {{{ Chord instructions
+
+ if (/\[[^:]/) {
+ $_.=" ";
+
+ # {{{ Ensure chords contain no spaces
+
+ if (/\[[^\]]* [^\]]*\]/) {
+ warning "\nSetchord: Chords cannot contain spaces.\n";
+ defined($opt_f) or
+ warning "Chords with spaces occured in file $ARGV:\n";
+ warning $_;
+ next; }
+
+ # }}}
+
+ s/\]\[/\] \[/g; #no chords tightly follow
+
+ # {{{ Determine chord and text arrays
+ my @text = find_text($_);
+ my @chords = find_chords($_);
+ # }}}
+ # {{{ Print chords and text
+
+ my $chord_line=$text[0]; $chord_line =~ s/./ /g;
+ my $textpos=1;
+ my $text_line=$text[0];
+ for (@chords) {
+ $crd=$_;
+ $chord_line.=$_ . (' ' x (length($text[$textpos])-length($crd)));
+ $text_line.=$text[$textpos] . ' ' x (length($crd)-length($text[$textpos]));
+ $textpos++; }
+
+ print to_xml_text("$chord_line\n$text_line\n");
+ # }}}
+
+ next; }
+
+ # }}}
+ # {{{ Spaces only
+ if (/^ *$/) {
+ print "\n";
+ next;}
+ # }}}
+ # {{{ Text without chords
+ print to_xml_text("$_")."\n";
+ # }}}
+ }
+
+ if ($song_opened) {
+ printf $closing_of_song;
+ $song_opened = 0; }
+
+ if ($album_opened) {
+ printf $closing_of_album;
+ $album_opened = 0; }
+
+ printf "</node>\n</node>\n</map>";
+exit;
+}
+
+# }}}
+# {{{ nochord
+if ($task eq "nochord") {
+ $in_tablature=0;
+while (<>) {
+ chomp;
+
+ # Process line
+
+ # {{{ In tablature
+ if ($in_tablature) {
+ if (/\x7beot/ or /\x7bend_of_tab/) {
+ $in_tablature=0;
+ next}
+ next}
+ # }}}
+
+ # Line contains
+
+ # {{{ Title command
+ if (/{t:.*}/ or /{title:.*}/) {
+
+ s/\173[^:]*: *//; s/\175//; # 173 is octal left curly brace 175 is right
+ printf "$_\n";
+ next; }
+ # }}}
+ # {{{ Start of Tablature
+ if (/\x7bsot/ or /\x7bstart_of_tab/) {
+ $in_tablature=1;
+ next; }
+ # }}}
+ # {{{ Other command
+ if (/{.*}/) {next;}
+ # }}}
+
+ # {{{ Comment (programmer's kind of)
+ if (/^\043/) { # 043 is octal of hash
+ next; }
+ # }}}
+ # {{{ Chord instructions
+
+ if (/\[/) {
+ $_.="\n";
+
+ my @text = find_text($_);
+
+ for (@text) {
+ print; }
+
+ next; }
+
+ # }}}
+ # {{{ Spaces only
+ if (/^ *$/) {
+ print "\n";
+ next;}
+ # }}}
+ # {{{ Text without chords
+ print "$_\n";
+ # }}}
+}
+exit;
+}
+# }}}
+# {{{ pro
+
+# Assumption: chord lines do not contain any tabulator characters.
+
+$in_tabulature=0;
+
+if ($task eq "pro") {
+ $previous_was_chord_line=0;
+while (<>) {
+ chomp; $_.="\n";
+ if ($previous_was_chord_line) {
+ $previous_was_chord_line=0;
+
+ chomp;
+ $chord_line =~ s/\s+$//;
+ $_.=" " x (length($chord_line)-length($_));
+
+ $chord_end=length($chord_line)-1;
+ $chord_curr=$chord_end;
+ $looking_for_chord_end=1;
+ while (1) {
+ if ($looking_for_chord_end) {
+ last if $chord_curr==-1;
+ if (not substr($chord_line,$chord_curr,1) eq " ") {
+ $chord_end=$chord_curr;
+ $looking_for_chord_end=0; }}
+ else {
+ if ((substr($chord_line,$chord_curr,1) eq " ") or $chord_curr==-1) {
+ $looking_for_chord_end=1;
+ $chord=substr($chord_line,$chord_curr+1,$chord_end-$chord_curr);
+ $_=insertstring("[$chord]",$_,$chord_curr+1); }
+ last if $chord_curr==-1; }
+ --$chord_curr; }
+
+ s/\+*$//;
+ print "$_\n"; }
+ else {
+ if ($in_tabulature) { # In tabulature
+ if (/{eot.*}/ or /{end_of_tab.*}/) {
+ $in_tabulature=0; }
+ print "$_"; }
+ else { # Not in tabulature
+ if (/{sot.*}/ or /{start_of_tab.*}/) {
+ $in_tabulature=1; }
+
+ if (/^[ \/\+\x23()12345679A-Hbmajindsu]+$/ and not /^\s*$/) {
+ # ^ Is this a chord line?
+ $previous_was_chord_line=1;
+ $chord_line=$_; }
+ else {
+ print "$_"; }}}}
+exit; }
+# }}}
+# {{{ html
+
+$chord_color_command="<font color=\"#aa4422\">";
+# chord_color_command must be <font> tag. Atributes are optional
+
+ # {{{ set_one_chord_html
+sub set_one_chord_html {
+ $tdxs="<td><small>$chord_color_command";
+ $tdxe="</font></small></td>";
+
+ my $table_s="<table border=0 cellpadding=0 cellspacing=0>";
+
+ my $set="";
+ $_=$_[0];
+
+ # {{{ Switch B <-> H notation (B is common)
+ if ($H_chord) {
+ s/B([^b])/H$1/g;
+ s/B$/H/g; }
+ else {
+ s/H/B/g; }
+ # }}}
+
+ #$set.="\\sf ";
+ # It is nice to represent special sequences with nonprintable characters.
+ s/maj/\001/;s/mi/m/;s/min/m/;s/dim/\002/;s/m75-/z/;
+ s/\0017/\001/;s/7\001/\001/;
+
+ # {{{ brackets
+ my $brackets=0;
+ if (/^\(.*\)$/) {
+ s/\(//;s/\)//;
+ $brackets=1;
+ $set.="(";
+ }
+ # }}}
+ # {{{ basses
+ my $bass="";
+ if (/\//) {
+ @basssplit = split(/\//,"$_");
+ $bass = $basssplit[1];
+ $_ = $basssplit[0];
+ }
+ # }}}
+
+ my $majset;my $dimset;my $minorset;my $minorshiftedbase;
+
+ # {{{ Chord style dependencies
+# if ($chord_style==0) {
+# $majset="\$\\triangle\$";
+# $dimset="o";
+# $minorset="\\raisebox{0.26ex}{--}";
+# $minorshiftedbase="F"; }
+# else {
+ $majset="7maj";
+ $dimset="dim";
+ $minorset="m";
+ $minorshiftedbase="?";
+# }
+ # }}}
+
+ my $bot=""; my $top="";
+ my $bot0=""; my $top0="";
+ my $puttobot=0;
+ my $numfound=0;
+ my @CHORD = split (//, $_);
+ $basenote=uc(shift @CHORD);
+ for (@CHORD) {
+ if ($puttobot) { $bot.="$_"; next; }
+ if ($numfound and /[2-9]/) { $bot.="$_"; $puttobot=1; next; }
+ if ($numfound and /\001/) { $bot.=$majset; $puttobot=1; next; }
+
+ if (/[2-9]/) { $top.="$_"; $numfound=1; next; }
+
+ if (/\001/) { $top.=$majset; $numfound=1; next; } # maj
+ if (/\002/) { $top.=$dimset; next; } # dim
+ if (/z/) { $top.="\$\\varnothing\$"; next; }
+ if (/b/) { $top0.="b"; next; }
+ if (/\043/) { $top0.="#"; next; }
+ # \043 is octal hash
+
+ if (/m/) {
+ #if (not $basenote eq $minorshiftedbase) {$bot0.="\hskip0.1em"}
+ $bot0.=$minorset; next;
+ } # minor
+ if (/\+/) { $bot.="+"; next; } # +
+ $top.="$_";
+ }
+
+
+ $start_with_basenote="$table_s <tr><td>$chord_color_command$basenote</font></td>";
+
+ # Now this really is nasty
+ PRINT: {
+ if (not ($top0 or $bot0 or $top or $bot)) { # No indices at all
+ $set.="$start_with_basenote";
+ $set.="$tdxs <br> $tdxe";
+ last PRINT; }
+
+ if ($top =~ /dim/) {
+ $bot0=" " if not $bot0;
+ $set.="$start_with_basenote";
+ $set.="$tdxs$top0<br>$bot0$tdxe"
+ if ($top0 or not $bot0 eq " ");
+ $set.="<td>${chord_color_command}dim</font></td>";
+ last PRINT }
+
+# if (not $bot0 and not $bot) { # No bottom indices
+# $set.="$table_s<tr><td>$chord_color_command$basenote<td>";
+# $set.="<td>$table_s $idxs$top0$top$idxe$idxs $idxe</table></td>" if ($top0 or $top);
+# last PRINT; }
+
+ if ($bot0) {
+ $bot=" " if not $bot;
+ $set.="$start_with_basenote";
+ $set.="$tdxs$top0<br> $tdxe" if ($top0);
+ $set.="$tdxs$bot0$tdxe";
+ $set.="$tdxs$top<br>$bot$tdxe";
+ last PRINT }
+
+
+ $bot0=" ";
+ $bot=" " unless ($bot);
+
+ $set.="$start_with_basenote";
+ $set.="$tdxs$top0<br>$bot0$tdxe" if ($top0 or $bot0);
+ $set.="$tdxs$top<br>$bot$tdxe" if ($top or not $bot eq " ");
+
+ }
+ #
+
+ $set.="<td>$chord_color_command";
+ @basses = split(//,$bass);
+ $set.="/$bass" if ($#basses==(1-1));
+ if ($#basses==(2-1)) {
+ $set.="/$basses[0]</font></td>";
+ $set.="<td>$chord_color_command$basses[1]<br> </font></td>";
+ $set.="<td>$chord_color_command";
+ }
+
+ $set.=")" if ($brackets);
+ $set.=" </font></td></tr></table>";
+
+ return $set;
+}
+
+# }}}
+
+if ($task eq "html") {
+ # {{{ set head variable
+ $head="<!doctype html public \"-//W3C//DTD HTML 4.0 Transitional//EN\">
+<html>
+<head>
+<title>Songbook</title>
+</head>
+<body bgcolor=\"#eeeeee\">";
+ # }}}
+
+ # Process input files
+
+ my $previous_line=0; my $previous_block=0;
+ # previous_line: 0=emptyline, 1=text_line, 2=chord, 3=title
+ # previousblock: 0=we're in block, 1=text_line, 2=chord, 3=title
+
+ $bearable_length=50;
+ %files_warned=();
+ $head_printed=0;
+ $verbatim_tex=0;
+ $table_of_contents_printed=0;
+ $tex_prebegin_part=0;
+ $it="";
+
+ @input=();
+ $stdout_opened=0;
+
+ # Read input into @input variable
+ read_input_into_input_array("html");
+
+ print $head;
+
+ finalize_language_dependent_settings();
+ to_nobarre_if_required();
+
+ for (@input) {
+ chomp;
+ # {{{ Parenthesis
+ s/\" /\'\' /g;
+ s/\"$/\'\'/g;
+ s/ \"/ \`\`/g;
+ s/^\"/\`\`/g;
+ # }}}
+
+ # Process line
+ # {{{ In Verbatim TeX
+ if ($verbatim_tex) {
+ if (/{texe.*}/ or /{verbatim_tex_end.*}/) {
+ $verbatim_tex=0; next; }
+ print "$_\n"; next; }
+ # }}}
+ # {{{ In tablature
+ if ($in_tablature) {
+ if (/{eot.*}/ or /{end_of_tab.*}/) {
+ $in_tablature=0;
+ if (not $ignore_tablature) {
+ print "</pre></font></td></tr></table>\n"};
+ next;}
+
+ if (not $ignore_tablature) {
+ print "$_\n";}
+ next;}
+ # }}}
+
+ # Line contains:
+ # {{{ Start of verbatim TeX
+ if (/{texs.*}/ or /{verbatim_tex_start.*}/) {
+ $verbatim_tex=1; next; }
+ # }}}
+ # {{{ Start of Tablature
+ if (/{sot.*}/ or /{start_of_tab.*}/) {
+ # {{{ Care about previous block
+ if ($previous_block!=0) {
+ print "<br>\n" if ($previous_block==1);
+ print "<br><br>\n" if ($previous_block==2);
+ $previous_block=0;
+ }
+ # }}}
+ $in_tablature=1;
+ if (not $ignore_tablature) {
+ print "<table><tr><td bgcolor=\"#dddddd\"><font size=\"-1\"><pre>\n";
+ $previous_line=1;
+ }
+ next}
+ # }}}
+ # {{{ Table of contents
+ if (/{toc.*}/ or /{table_of_contents.*}/) {
+ if ($table_of_contents_printed) {
+ warning("You ask me to print table of contents though it\n".
+ "has already been printed with songbook's titlepage.\n"); }
+ else {
+ print "$table_of_contents"; }}
+ # }}}
+
+ # {{{ Title command
+ if (/{t:.*}/ or /{title:.*}/) {
+
+ print "\n<br>" if ($previous_line==1);
+ print "<br><br>" if ($previous_line==2);
+ print "<br>" if ($previous_line==0);
+
+ s/\173[^:]*: *//; s/\175//; # 173 is octal left curly brace 175 is right
+ s/&/&/g;
+ print "<br><br><br><br>\n<H3>$_</H3>\n";
+ $previous_line=3;
+ next;
+ }
+ # }}}
+ # {{{ Album command
+ if (/{album:.*}/) {
+
+ print "\n<br>" if ($previous_line==1);
+ print "<br><br>\n" if ($previous_line==2);
+ print "<br>\n" if ($previous_line==0);
+
+ s/\173[^:]*: *//; s/\175//; # 173 is octal left curly brace 175 is right
+ s/&/\\&/g;
+ print "<H2> $_</H2>\n";
+ $previous_line=3;
+ next;
+ }
+ # }}}
+ # {{{ Start of choir
+ if (/{soc.*}/ or /{start_of_chorus.*}/) {
+ $it="<i>";
+ #print "<it>\n";
+ next;
+ }
+ # }}}
+ # {{{ End of choir
+ if (/{eoc.*}/ or /{end_of_chorus.*}/) {
+ $it="";
+ #print "\\rm\n";
+ next;
+ }
+
+ # }}}
+ # {{{ Comment
+ if (/{c:.*}/ or /{comment:.*}/) {
+ s/\173[^:]*: *//; s/\175//; # 173 is octal left curly brace 175 is right
+ s/&/\\&/g;
+
+ # {{{ Care about previous block
+ if ($previous_block!=0) {
+ print "<br>\n" if ($previous_block==1);
+ print "<br><br>\n" if ($previous_block==2);
+ $previous_block=0;
+ }
+ # }}}
+
+ print "<i>$_</i><br>\n";
+ $previous_line=1; #Comment is close to ordinary text
+ next;
+ }
+
+ # }}}
+ # {{{ Other command
+ if (/{.*}/) {next;}
+ # }}}
+
+ # {{{ Comment (programmer's kind of)
+ if (/^\043/) { # 043 is octal of hash
+ next; }
+ # }}}
+ # {{{ Chord instructions
+
+ if (/\[[^:]/) {
+ $_.=" ";
+
+ # {{{ Care about previous block
+ if ($previous_block!=0) {
+ print "<br><br>\n" if ($previous_block==1);
+ print "<br><br><br>\n" if ($previous_block==2);
+ $previous_block=0;
+ }
+ # }}}
+ # {{{ Ensure chords contain no spaces
+ if (/\[[^\x5d]* [^\x5d]*\]/) {
+ warning "\nSetchord: Chords cannot contain spaces.\n";
+ warning "This was broken at file $ARGV:\n";
+ warning $_;
+ exit; }
+ # }}}
+
+ s/&/&/g; #care about html-dangerous characters
+
+ s/\]\[/\] \[/g; #no chords tightly follow
+
+ s/\] /\] /g; #chord is preshifted to the left of the text
+
+ my @text = find_text($_);
+ my @chords = find_chords($_);
+
+ # {{{ Print tab stops for chords and chords
+
+ my $chord_line="<tr><td>";
+ my $text_line="<tr><td>$it$text[0]";
+ my $textpos=1;
+ for (@chords) {
+ $crd = set_one_chord_html("$_");
+ $chord_line.="</td><td>$crd";
+ $text_line.="</td><td>$it$text[$textpos]";
+ $textpos++; }
+
+ $chord_line.="</td></tr>\n";
+ $text_line.="</td></tr>\n";
+
+ $text_line=~s, </td>, </td>,g; # space at the end of a cell must be hard
+
+ print "<table border=0 cellpadding=0 cellspacing=0>\n";
+ print "$chord_line";
+ print "$text_line";
+ # }}}
+
+ print "</table>\n";
+ $previous_line=2;
+ next; }
+ # }}}
+
+ # {{{ Spaces only
+ if (/^ *$/) {
+ $previous_block=$previous_line if ($previous_line!=0);
+ $previous_line=0;
+ next; }
+ # }}}
+ # {{{ Text without chords
+ do {
+ # {{{ Care about previous block
+ if ($previous_block!=0) {
+ print "<br>\n" if ($previous_block==1);
+ print "<br><br>\n" if ($previous_block==2);
+ $previous_block=0; }
+ # }}}
+
+ print "$_<br>\n";
+ $previous_line=1; }
+ # }}}
+ }
+
+ print "</html>\n";
+ exit; }
+# }}}
+# {{{ transpose
+
+if ($task eq "transpose") {
+ $transposition=shift @ARGV;
+ @tpose=<>;
+
+ if ($nobarre) {
+ $transposition="nobarre"; }
+
+ transpose($transposition);
+
+ for (@tpose) {
+ print; }
+ exit; }
+
+# }}}
+# {{{ unknown
+print STDERR "Task \"$task\" is unknown.\n".$help_message;
+exit;
+# }}}
+
+if ($stdout_opened) {
+ close (STDOUT); }
+
+# {{{ emacs
+#
+# Local Variables:
+# compile-command:"chordpack tex chordpack-testing-song.pro >testing.tex"
+# compile-function:(save-excursion (compile compile-command)(sleep-for 2)(to-buffer "testing.tex")(TeX-compile-to-ps))
+# end:
+#
+# }}}
--- /dev/null
+<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>Chordpack Documentation</title>
+
+<style type="text/css">
+body { background: #eeeee8; }
+div.contents {
+ margin: 0em 3em 0em 3em;
+/* padding: 0.5em 0.5em 0.5em 0.5em; */
+ border-style: none;
+ border-width: 1;
+/* background: #ccddcc; */
+}
+h3.contents { color: green; }
+div.myframe {
+ margin: 0em 0em 1em 1em;
+ padding: 0.05em 1em 1em 1em;
+/* border-style: none; */
+ border-width: 1;
+ border-color: #848478;
+ background: #e4e4d8;
+}
+
+
+ H1 { color: green }
+ h3 { color: #aa6611; }
+ TT { color: #aa3300; font-weight: bold; }
+ PRE { color: #aa4444; }
+</style>
+</head>
+<body bgcolor="#eeeeee">
+<table width=600 align=center><tr><td>
+
+<center><h1>Chordpack Documentation</h1>
+<small> For version 0.8.2</small></center>
+<br>
+<br>
+
+<div class=contents>
+<h3 class=contents>Table of contents</h3>
+<a href="#intro">What users for what purpose</a><br>
+<a href="#quick">Quick introduction to chordpro format</a><br>
+<a href="#insta">Installation requirements</a><br>
+<a href="#comma">Command line usage</a><br>
+<a href="#pro">Chordpro commands</a><br>
+<a href="#under">Chordpack specific commands</a><br>
+<a href="#versus">Chordpack versus Chord</a><br>
+<a href="#credi">Credits and Copyrights</a><br>
+</div>
+<div class=contents>
+<h3 class=contents>Links</h3>
+<a href="http://www.fi.muni.cz/~xpolansk/chordpack">Chordpack home page</a><br>
+</div>
+<br>
+<br>
+
+<div class=myframe>
+<a name="intro"><h3>What users for what purpose</h3></a>
+
+<p>You are a technical user of computers, willing to install tools like Perl
+or TeX; you are willing to work with tools without graphical interface. You
+want to typeset guitar songs with chords, and you want a good-looking
+postscript or pdf result, or maybe only HTML result.
+
+<p><b>Chordpack</b> is a utility for typesetting and manipulating
+<em>chordpro</em> chord files. These are files used by <em>chord</em>
+utility. The main functionality provided by Chordpack is typesetting
+song-books using TeX typesetting system and its LaTeX macro
+package. However, Chordpack can perform variety of tasks on chordpro
+files.<br><br>
+
+
+
+Chordpack can do the following tasks:
+
+<ul>
+<li>Generate LaTeX source of songs/songbook</li>
+<li>Generate HTML version of songs/songbook</li>
+<li>Generate ASCII version of songs/songbook</li>
+<li>Generate ASCII version of songs/songbook omitting chords</li>
+<li>Transpose chordpro song to desired key</li>
+<li>Take ordinary ASCII notation of song with chords and output almost
+chordpro version.</li>
+</ul>
+</div>
+<div class=myframe>
+<a name="quick"><h3>Quick introduction to chordpro format</h3></a>
+
+Chordpack understands extension of chordpro format.<br><br>
+
+Chordpro is an ASCII format for marking chords. Chords are denoted in square
+brackets. For instance
+
+<pre>
+ [G]Always [Em]look at the [Am7]bright [D7]side of [G]life [Em] [Am7] [D7]
+</pre>
+
+is a notation for
+
+<pre>
+ G Em Am7 D7 G Em Am7 D7
+ Always look at the bright side of life
+</pre>
+
+Repetition marks are denoted by <tt>[:</tt> and <tt>:]</tt> (<em>repetition
+marks are only part of extension of chordpro format</em>).<br><br>
+
+Besides this, chordpro format defines braced instructions (commands), most
+important of which is <tt> {title:I am a Title of the Song} </tt>.
+
+Other commands include <tt>{subtitle:...}</tt>, <tt>{start_of_choir}</tt>,
+<tt>{end_of_choir}</tt> etc.<br><br><br>
+
+You should use at most one command per line.<br><br>
+
+<em>
+The important thing about chordpro format is that there are already lots of songs
+on the web (see <a href="http://www.olga.net/">Online Guitar Archive -
+OLGA</a> for instance) in this format.
+</em>
+</div>
+<div class=myframe>
+<a name="insta"><h3>Installation requirements</h3></a>
+Chordpack consists of one script written in Perl. If you want to use
+Chordpack, you need to have <a href="http://www.perl.com/pub/language/info/software.html">
+Perl installed</a>. If you want to use chordpack for its main purpose
+i.e. typesetting in TeX, you need to
+<a href="http://www.tug.org/interest.html#free"> install TeX </a> as well.
+We are using teTeX distribution for Linux but there's a high chance that you
+will want to use some Windows distribution.
+</div>
+
+<!--
+ Command line usage of chordpack
+-->
+
+<div class=myframe>
+<a name="comma"><h3>Command line usage of chordpack</h3></a>
+
+<p>The first thing to note is that the best printing result is achieved if you
+use chordpack to produce LaTeX source. This however requires installation of
+TeX and LaTeX2e macro package which some of you may find inconvenient. In
+that case, you should generate HTML instead.<br><br>
+
+The usage is
+<pre>
+ chordpack <SWITCHES> <TASK> FILE ...
+</pre>
+<b>TASK</b> is one of the following
+
+<ul>
+<li>tex - create LaTeX source</li>
+<li>html - create HTML page</li>
+<li>ascii - create plain ascii output with chords</li>
+<li>nochord - create plain ascii output without chords</li>
+<li>transpose <em>key-or-shift</em></li>
+<li>pro - create chordpro out of plain ascii with chords</li>
+<li>fmm - create <a href="http://freemind.sourceforge.net/">FreeMind</a>'s mind map</li>
+</ul>
+
+Task transpose has one parameter; either destination key of the song,
+or the number of half-steps by which song has to be transposed up.
+
+<p>Chordpack reads input from FILEs or from standard input and produces the
+result on standard output. An exception to this is option -f, as described below.
+
+<p><b>SWITCHES</b>, most of them applies to tex task only, are one of
+
+<ul>
+<li>-f song-list-file</li>
+<li>-l language</li>
+<li>-b</li>
+<li>-c chord-style</li>
+<li>-s font-sizes</li>
+<li>-e enonding: input encoding to be used with LaTeX and FreeMind</li>
+</ul>
+
+<p>For most of the settings, it is better to set them directly in the input
+file. The use of switch -f in combination with tex task is recommended.
+
+<a name=optionf><h4>-f song-list-file</h4></a>
+
+<p>Use song-list-file and output the result to file created from song-list-file
+by removing its suffix and adding tex suffix. Song-list-file is a file
+containing the list of song files as well as lines that are directly passed
+to Chordpack. The lines directly passed to Chordpack differ from filenames
+in that they start with space. For example:<br>
+
+Let file songbook.list contain
+
+<pre>
+ {toc}
+ {album:Two is Enough}
+
+song-one.pro
+second-song.pro
+</pre>
+
+Let file song-one.pro contain only
+
+<pre>
+{title:Just a Small Song}
+[A]Hey [Gm]hey
+</pre>
+
+and file second-song.pro contain only
+
+<pre>
+{title:Not a Big One}
+[G#m]Day is [G97maj]long and
+[D#]Girls are [F]sweet
+</pre>
+
+Then the result of using <tt>chordpack -f songbook.list tex</tt> is the same as
+the result of <tt>chordpack tex songbookfile >songbook.tex</tt> given that file
+<tt>songbookfile</tt> contains
+
+<pre>
+{toc}
+{album:Two is Enough}
+{title:Just a Small Song}
+[A]Hey [Gm]hey
+{title:Not a Big One}
+[G#m]Day is [G97maj]long and
+[D#]Girls are [F]sweet
+</pre>
+
+<a name="optionl"><h4>-l language</h4></a>
+
+Sets language. Currently, this has effect on TeX typesetting and the only
+supported language is Czech. If you make support for more languages, send me
+one.
+
+<a name="optionb"><h4>-b</h4></a>
+
+<p>With this option set, Chordpack transposes all the songs being set to
+such a key that there are as few barre chords as possible. All tablatures
+(text inside <tt>{start_of_tab}</tt> and <tt>{end_of_tab}</tt>) are ignored
+in this case, because transposition of tablatures in virtually impossible,
+unless you have a very smart artificial intelligence program.
+
+<p>This options is working with the tasks tex, html, ascii and transpose.
+
+<h4>-c chord-style</h4>
+
+Set the style of chord setting. There are four styles available:
+<tt>jazz</tt>, <tt>m</tt>, <tt>mi</tt> and low. The default is m.
+Also, the presence of <tt>h</tt> letter in chord-style string turns on
+Central-European (or at least German and Czech) style of denoting
+last tone of C major key (English denote it B while German H).
+
+<a name="options"><h4>-s font_sizes</h4></a>
+
+Sets the sizes of fonts. These can be 0,1,2,3.
+
+</div>
+<div class=myframe>
+<a name="pro"><h3>Chordpro commands</h3></a>
+
+Here are listed chordpro commands understood by Chordpack. Chord utility
+however understands more commands.<br><br>
+
+<p><b>{title:...}</b> or <b>{t:...}</b>. Title of the song.
+
+<p><b><a name="subtitle">{subtitle:...}</a></b> or <b>{st:...}</b>.
+Subtitle of the song. It is typically author of the song. You may specify
+more subtitles. By default, chordpack does not set these subtitles. You can
+turn setting of subtitles on by <a href="#subtitles_on">{subtitles_on}</a>
+command and later turn setting of them of by <a
+href="#subtitles_off">{subtitles_off}</a>.
+
+<p><b>{comment:...}</b> or <b>{c:...}</b>. Commentary on
+something. Typically set in italics.
+
+<p><b>{start_of_choir}</b> or <b>{soc}</b>. Marks the beginning of
+choir. Choir is set by italics to distinguish from verse.
+
+<p><b>{end_of_choir}</b> or <b>{eoc}</b>. Marks the end of choir.
+
+<p><b>{start_of_tab}</b> or <b>{sot}</b>. Marks the start of tablature. The
+important thing about tablature is that is is set in non-proportional
+(fixed-width if you wish) font. The result is this marking does not say that
+there is a tablature inside. It says set me in non-proportional font. This
+is however mainly useful for tablatures or other tone notation.
+
+<p><b>{end_of_tab}</b> or <b>{eot}</b>. Marks the end of tablature.
+
+</div>
+<div class=myframe>
+<a name="under"><h3>Chordpack specific commands</h3></a>
+
+Chordpack has abilities that surpass those of Chord and as such it defines
+new commands of its own. These have to do with organization of song-book and
+with setting typesetting parameters as well. <em>You should not use these
+commands as a part of single song files, rather they should be used to
+finalize the look of the song-book being set.</em> They are best used as a
+part of song-list-file (see <a href="#optionf">option -f</a>).<br><br>
+
+<p><b>{album: ... }</b>. This is analogical to <tt>{title: ...}</tt>
+command. It marks the start of a new album. Album title is typeset. The
+commands has also effect on the table of contents.
+
+<p><b><a name="subtitles_on">{subtitles_on}</a></b>. Turn setting of <a
+href="#subtitle">subtitles</a> on. <p><b><a
+name="subtitles_off">{subtitles_off}</a></b>. Turn setting of <a
+href="#subtitle">subtitles</a> off. This is the default.
+
+<p><b>{chordstyle: ... }</b>. Sets the style of chord setting (see <a
+href="#optionb">option -b</a>).
+
+<p><b>{language: ... }</b>. Sets language (see <a href="#optionl">option
+-l</a>).
+
+<p><b>{fontsize: ... }</b>. Sets fontsizes (see <a href="#options">option
+-s</a>).
+
+<p><b>{titlestyle: ... }</b>. Sets the style of song titles. In default
+style song titles are set in sans serif with a rule above the song
+title. Style <tt>norule</tt> differs only in that there is no rule. Finally
+style <tt>graybox</tt> sets gray box in the background of the song title.
+If you add <tt>songnewpage</tt> to titlestyle, every song will be set on a
+new page (or column in two column mode). For example, you can write
+<tt>{titlestyle:graybox songnewpage}</tt>.
+
+<p><b>{columns: ... }</b>. Sets the number of columns. Possible values are 1
+and 2, the later being default.
+
+<p><b>{songbooktitle: ... }</b>. Songbooktitle is a string of lines
+separated by ^. It determines the look of title page of the song-book. Each
+line is set on a new line and is centered. The first line is bold. For
+example, if you write <tt>{songbooktitle:The Beatles^With the Beatles^Yellow
+Submarine}</tt>, you will get something close to
+ <center>
+ <b>The Beatles</b><br> With the Beatles<br> Yellow Submarine
+ </center>
+Next to the title page will be set the table of contents together with
+alphabetical table of contents.
+
+<p><b>{toc}</b>. Typesets the table of contents. This is useful if you don't
+want to have title page or you are user of LaTeX and want to design your own
+title page using LaTeX.
+
+<p><b>{verbatim_tex_start: ... }</b> or <b>{vtexs: ... }</b>. Enters
+verbatim TeX mode. In this mode every line is passed directly to TeX
+unchanged. These lines are ignored if you do not use task <tt>tex</tt>.
+
+<p><b>{verbatim_tex_end: ... }</b> or <b>{vtexe: ... }</b>. Quits verbatim
+TeX mode.
+
+</div>
+<div class=myframe>
+<a name="versus"><h3>Chordpack versus Chord</h3></a>
+
+Chordpack was written to surpass the <em>Chord</em> program which generates
+postscript from chordpro format. The main drawback was the setting of
+chords.
+
+Consider example typesetting of chord which looks like
+
+<blockquote>
+<table border=0 cellpadding=0 cellspacing=0>
+<tr><td></td><td><i>Eb7+ </i></td><td><i>Eb75- </i></td><td><i>Eb74sus </i></td><td><i>Eb97maj </i></td><td><i>Ebm97maj </i></td><td><i>Ebm9 </i></td><td></td></tr>
+<tr><td></td><td>Finally </td><td>he </td><td>closed </td><td> his </td><td>eyes </td><td>shut. </td></tr>
+</table>
+</blockquote>
+
+and compare it to chordpack's
+
+<blockquote>
+<table border=0 cellpadding=0 cellspacing=0>
+<tr><td></td><td><table border=0 cellpadding=0 cellspacing=0> <tr><td><font color="#aa4422">E</font></td><td><small><font color="#aa4422">b<br> </font></small></td><td><small><font color="#aa4422">7<br>+</font></small></td><td><font color="#aa4422"> </font></td></tr></table></td><td><table border=0 cellpadding=0 cellspacing=0> <tr><td><font color="#aa4422">E</font></td><td><small><font color="#aa4422">b<br> </font></small></td><td><small><font color="#aa4422">7<br>5-</font></small></td><td><font color="#aa4422"> </font></td></tr></table></td><td><table border=0 cellpadding=0 cellspacing=0> <tr><td><font color="#aa4422">E</font></td><td><small><font color="#aa4422">b<br> </font></small></td><td><small><font color="#aa4422">7<br>4sus</font></small></td><td><font color="#aa4422"> </font></td></tr></table></td><td><table border=0 cellpadding=0 cellspacing=0> <tr><td><font color="#aa4422">E</font></td><td><small><font color="#aa4422">b<br> </font></small></td><td><small><font color="#aa4422">9<br>7maj</font></small></td><td><font color="#aa4422"> </font></td></tr></table></td><td><table border=0 cellpadding=0 cellspacing=0> <tr><td><font color="#aa4422">E</font></td><td><small><font color="#aa4422">b<br> </font></small></td><td><small><font color="#aa4422">m</font></small></td><td><small><font color="#aa4422">9<br>7maj</font></small></td><td><font color="#aa4422"> </font></td></tr></table></td><td><table border=0 cellpadding=0 cellspacing=0> <tr><td><font color="#aa4422">E</font></td><td><small><font color="#aa4422">b<br> </font></small></td><td><small><font color="#aa4422">m</font></small></td><td><small><font color="#aa4422">9<br> </font></small></td><td><font color="#aa4422"> </font></td></tr></table></td></tr>
+<tr><td></td><td>Finally </td><td>he </td><td>closed </td><td> his </td><td>eyes </td><td>shut. </td></tr>
+</table>
+</blockquote>
+
+
+This just touches on the quality of chord typesetting of chordpack. However,
+chordpack has its weak spots as well when compared to Chord:
+
+<ul>
+ <li>Generates LaTeX source and not postsript (less convenient)</li>
+ <li>Does not generate chord pickings
+</ul>
+
+and maybe other.The main purpose was to set <em>chords nicely</em> and
+enable easy setting of song-books. We believe that the result going out of
+chordpack is close to perfect and I ain't going to spell out every little
+annoyance I had to solve to get things looking well.
+</div>
+<div class=myframe>
+<a name="credi"><h3>Credits and Copyrights</h3></a>
+
+<p>The Chordpack was written by <a
+href="http://mujweb.cz/www/danielpolansky/">Daniel Polansky</a> in
+September 2000; with some tips provided by David Necas aka <a
+href="http://trific.ath.cx/">Yeti</a>.
+
+<p>Chordpack is distributed under GNU General Public Licence - GPL.
+</div>
+
+</td></tr></table>
+</body>
+</html>