From: Hugo Villeneuve Date: Wed, 9 Mar 2022 22:17:43 +0000 (-0500) Subject: Importation de chordpack-0.8.2 X-Git-Url: http://gitweb.hugovil.com/?a=commitdiff_plain;h=7979771d2da925e47f58cdf2c4f985605b9b70a0;p=musique%2Fhvchordpack.git Importation de chordpack-0.8.2 --- 7979771d2da925e47f58cdf2c4f985605b9b70a0 diff --git a/chordpack b/chordpack new file mode 100755 index 0000000..f087f95 --- /dev/null +++ b/chordpack @@ -0,0 +1,2453 @@ +#!/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/) { + 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() { + #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 + + # Normalization 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; + + + # 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 () { + 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 "\n\n"; + + my $closing_of_song = "\">\n". + "\n". + "\n\n"; + + my $closing_of_album = "\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 "\n"; + printf "\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 "\n\n"; +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=""; +# chord_color_command must be tag. Atributes are optional + + # {{{ set_one_chord_html +sub set_one_chord_html { + $tdxs="$chord_color_command"; + $tdxe=""; + + my $table_s=""; + + 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 "; + + # 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 
 $tdxe"; + last PRINT; } + + if ($top =~ /dim/) { + $bot0=" " if not $bot0; + $set.="$start_with_basenote"; + $set.="$tdxs$top0
$bot0$tdxe" + if ($top0 or not $bot0 eq " "); + $set.=""; + last PRINT } + +# if (not $bot0 and not $bot) { # No bottom indices +# $set.="$table_s
$chord_color_command$basenote${chord_color_command}dim
$chord_color_command$basenote"; +# $set.="$table_s $idxs$top0$top$idxe$idxs $idxe
" if ($top0 or $top); +# last PRINT; } + + if ($bot0) { + $bot=" " if not $bot; + $set.="$start_with_basenote"; + $set.="$tdxs$top0
 $tdxe" if ($top0); + $set.="$tdxs$bot0$tdxe"; + $set.="$tdxs$top
$bot$tdxe"; + last PRINT } + + + $bot0=" "; + $bot=" " unless ($bot); + + $set.="$start_with_basenote"; + $set.="$tdxs$top0
$bot0$tdxe" if ($top0 or $bot0); + $set.="$tdxs$top
$bot$tdxe" if ($top or not $bot eq " "); + + } + # + + $set.="$chord_color_command"; + @basses = split(//,$bass); + $set.="/$bass" if ($#basses==(1-1)); + if ($#basses==(2-1)) { + $set.="/$basses[0]
"; + $set.="$chord_color_command$basses[1]
 
"; + $set.="$chord_color_command"; + } + + $set.=")" if ($brackets); + $set.=" "; + + return $set; +} + +# }}} + +if ($task eq "html") { + # {{{ set head variable + $head=" + + +Songbook + +"; + # }}} + + # 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 "\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 "
\n" if ($previous_block==1); + print "

\n" if ($previous_block==2); + $previous_block=0; + } + # }}} + $in_tablature=1; + if (not $ignore_tablature) { + print "\n"; + $text_line.="\n"; + + $text_line=~s, , ,g; # space at the end of a cell must be hard + + print "
\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
" if ($previous_line==1); + print "

" if ($previous_line==2); + print "
" if ($previous_line==0); + + s/\173[^:]*: *//; s/\175//; # 173 is octal left curly brace 175 is right + s/&/&/g; + print "



\n

$_

\n"; + $previous_line=3; + next; + } + # }}} + # {{{ Album command + if (/{album:.*}/) { + + print "\n
" if ($previous_line==1); + print "

\n" if ($previous_line==2); + print "
\n" if ($previous_line==0); + + s/\173[^:]*: *//; s/\175//; # 173 is octal left curly brace 175 is right + s/&/\\&/g; + print "

$_

\n"; + $previous_line=3; + next; + } + # }}} + # {{{ Start of choir + if (/{soc.*}/ or /{start_of_chorus.*}/) { + $it=""; + #print "\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 "
\n" if ($previous_block==1); + print "

\n" if ($previous_block==2); + $previous_block=0; + } + # }}} + + print "$_
\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 "

\n" if ($previous_block==1); + print "


\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="
"; + my $text_line="
$it$text[0]"; + my $textpos=1; + for (@chords) { + $crd = set_one_chord_html("$_"); + $chord_line.="$crd"; + $text_line.="$it$text[$textpos]"; + $textpos++; } + + $chord_line.="
\n"; + print "$chord_line"; + print "$text_line"; + # }}} + + print "
\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 "
\n" if ($previous_block==1); + print "

\n" if ($previous_block==2); + $previous_block=0; } + # }}} + + print "$_
\n"; + $previous_line=1; } + # }}} + } + + print "\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: +# +# }}} diff --git a/chordpack-documentation.html b/chordpack-documentation.html new file mode 100644 index 0000000..bbf2c08 --- /dev/null +++ b/chordpack-documentation.html @@ -0,0 +1,404 @@ + + + +Chordpack Documentation + + + + +
+ +

Chordpack Documentation

+ For version 0.8.2
+
+
+ + + +
+
+ +
+

What users for what purpose

+ +

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. + +

Chordpack is a utility for typesetting and manipulating +chordpro chord files. These are files used by chord +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.

+ + + +Chordpack can do the following tasks: + +

    +
  • Generate LaTeX source of songs/songbook
  • +
  • Generate HTML version of songs/songbook
  • +
  • Generate ASCII version of songs/songbook
  • +
  • Generate ASCII version of songs/songbook omitting chords
  • +
  • Transpose chordpro song to desired key
  • +
  • Take ordinary ASCII notation of song with chords and output almost +chordpro version.
  • +
+
+
+

Quick introduction to chordpro format

+ +Chordpack understands extension of chordpro format.

+ +Chordpro is an ASCII format for marking chords. Chords are denoted in square +brackets. For instance + +
+   [G]Always [Em]look at the [Am7]bright [D7]side of [G]life [Em] [Am7] [D7]
+
+ +is a notation for + +
+   G       Em          Am7    D7      G    Em Am7 D7
+   Always look at the bright side of life           
+
+ +Repetition marks are denoted by [: and :] (repetition +marks are only part of extension of chordpro format).

+ +Besides this, chordpro format defines braced instructions (commands), most +important of which is {title:I am a Title of the Song} . + +Other commands include {subtitle:...}, {start_of_choir}, +{end_of_choir} etc.


+ +You should use at most one command per line.

+ + +The important thing about chordpro format is that there are already lots of songs +on the web (see Online Guitar Archive - +OLGA for instance) in this format. + +
+
+

Installation requirements

+Chordpack consists of one script written in Perl. If you want to use +Chordpack, you need to have +Perl installed. If you want to use chordpack for its main purpose +i.e. typesetting in TeX, you need to + install TeX as well. +We are using teTeX distribution for Linux but there's a high chance that you +will want to use some Windows distribution. +
+ + + +
+

Command line usage of chordpack

+ +

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.

+ +The usage is +

+   chordpack <SWITCHES> <TASK> FILE ...
+
+TASK is one of the following + +
    +
  • tex - create LaTeX source
  • +
  • html - create HTML page
  • +
  • ascii - create plain ascii output with chords
  • +
  • nochord - create plain ascii output without chords
  • +
  • transpose key-or-shift
  • +
  • pro - create chordpro out of plain ascii with chords
  • +
  • fmm - create FreeMind's mind map
  • +
+ +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. + +

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. + +

SWITCHES, most of them applies to tex task only, are one of + +

    +
  • -f song-list-file
  • +
  • -l language
  • +
  • -b
  • +
  • -c chord-style
  • +
  • -s font-sizes
  • +
  • -e enonding: input encoding to be used with LaTeX and FreeMind
  • +
+ +

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. + +

-f song-list-file

+ +

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:
+ +Let file songbook.list contain + +

+ {toc}                      
+ {album:Two is Enough}      
+                            
+song-one.pro                
+second-song.pro             
+
+ +Let file song-one.pro contain only + +
+{title:Just a Small Song}   
+[A]Hey [Gm]hey              
+
+ +and file second-song.pro contain only + +
+{title:Not a Big One}       
+[G#m]Day is [G97maj]long and
+[D#]Girls are [F]sweet      
+
+ +Then the result of using chordpack -f songbook.list tex is the same as +the result of chordpack tex songbookfile >songbook.tex given that file +songbookfile contains + +
+{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      
+
+ +

-l language

+ +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. + +

-b

+ +

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 {start_of_tab} and {end_of_tab}) are ignored +in this case, because transposition of tablatures in virtually impossible, +unless you have a very smart artificial intelligence program. + +

This options is working with the tasks tex, html, ascii and transpose. + +

-c chord-style

+ +Set the style of chord setting. There are four styles available: +jazz, m, mi and low. The default is m. +Also, the presence of h 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). + +

-s font_sizes

+ +Sets the sizes of fonts. These can be 0,1,2,3. + +
+
+

Chordpro commands

+ +Here are listed chordpro commands understood by Chordpack. Chord utility +however understands more commands.

+ +

{title:...} or {t:...}. Title of the song. + +

{subtitle:...} or {st:...}. +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 {subtitles_on} +command and later turn setting of them of by {subtitles_off}. + +

{comment:...} or {c:...}. Commentary on +something. Typically set in italics. + +

{start_of_choir} or {soc}. Marks the beginning of +choir. Choir is set by italics to distinguish from verse. + +

{end_of_choir} or {eoc}. Marks the end of choir. + +

{start_of_tab} or {sot}. 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. + +

{end_of_tab} or {eot}. Marks the end of tablature. + +

+
+

Chordpack specific commands

+ +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. 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. They are best used as a +part of song-list-file (see option -f).

+ +

{album: ... }. This is analogical to {title: ...} +command. It marks the start of a new album. Album title is typeset. The +commands has also effect on the table of contents. + +

{subtitles_on}. Turn setting of subtitles on.

{subtitles_off}. Turn setting of subtitles off. This is the default. + +

{chordstyle: ... }. Sets the style of chord setting (see option -b). + +

{language: ... }. Sets language (see option +-l). + +

{fontsize: ... }. Sets fontsizes (see option +-s). + +

{titlestyle: ... }. Sets the style of song titles. In default +style song titles are set in sans serif with a rule above the song +title. Style norule differs only in that there is no rule. Finally +style graybox sets gray box in the background of the song title. +If you add songnewpage to titlestyle, every song will be set on a +new page (or column in two column mode). For example, you can write +{titlestyle:graybox songnewpage}. + +

{columns: ... }. Sets the number of columns. Possible values are 1 +and 2, the later being default. + +

{songbooktitle: ... }. 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 {songbooktitle:The Beatles^With the Beatles^Yellow +Submarine}, you will get something close to +

+ The Beatles
With the Beatles
Yellow Submarine +
+Next to the title page will be set the table of contents together with +alphabetical table of contents. + +

{toc}. 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. + +

{verbatim_tex_start: ... } or {vtexs: ... }. 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 tex. + +

{verbatim_tex_end: ... } or {vtexe: ... }. Quits verbatim +TeX mode. + +

+
+

Chordpack versus Chord

+ +Chordpack was written to surpass the Chord program which generates +postscript from chordpro format. The main drawback was the setting of +chords. + +Consider example typesetting of chord which looks like + +
+ + + +
Eb7+ Eb75- Eb74sus Eb97maj Ebm97maj Ebm9 
Finally he closed  his eyes shut.
+
+ +and compare it to chordpack's + +
+ + + +
Eb
 
7
+
 
Eb
 
7
5-
 
Eb
 
7
4sus
 
Eb
 
9
7maj
 
Eb
 
m9
7maj
 
Eb
 
m9
 
 
Finally he closed   his eyes shut.
+
+ + +This just touches on the quality of chord typesetting of chordpack. However, +chordpack has its weak spots as well when compared to Chord: + +
    +
  • Generates LaTeX source and not postsript (less convenient)
  • +
  • Does not generate chord pickings +
+ +and maybe other.The main purpose was to set chords nicely 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. +
+
+

Credits and Copyrights

+ +

The Chordpack was written by Daniel Polansky in +September 2000; with some tips provided by David Necas aka Yeti. + +

Chordpack is distributed under GNU General Public Licence - GPL. +

+ +
+ + diff --git a/chordpro-mode.el b/chordpro-mode.el new file mode 100644 index 0000000..102e7a5 --- /dev/null +++ b/chordpro-mode.el @@ -0,0 +1,39 @@ +;;; Chordpro mode +;; Chordpro is a format of songs with guitar chords. +;; +;; Instalation: 1) copy this file to emacs load path +;; 2) add to your .emacs (load "chordpro-mode.el") +;; 3) add to mode to file extensions you want + +(defun chordpro-mode-choir-around () + (interactive) + "Surround region with start and end of choir marks..." + (vim-filter "echo \"{soc}\";cat;echo \"{eoc}\"")) + +(defun call-key (key) + "Call the command KEY is bound to. Example of usage in lisp: (call-key [f2])." + (interactive) + (command-execute (key-binding key) t)) + +(defvar chordpro-font-lock-keywords + ;; Here \n is for endline! + '(("\\(\\[[^]]*\\]\\)" 1 'font-lock-string-face) + ("^\\(#.*\\)" 1 'font-lock-comment-face) + ("\\({subtitle[^}]*}\\)" 1 'font-lock-type-face) + ("\\({title[^}]*}\\)" 1 'font-lock-keyword-face) + ("\\({[^}]*}\\)" 1 'font-lock-variable-name-face) + )) + +(define-derived-mode chordpro-mode fundamental-mode "chordpro" + "Major mode for editing pro files with guitra chords." + (set (make-local-variable 'font-lock-defaults) + '(chordpro-font-lock-keywords + t ;; bool - t = Do not fontify using also syntax table. + t ;; bool - t = Do case insensitive matching when fontifying. + )) + (font-lock-mode t) + (font-lock-fontify-buffer) + (setq case-fold-search nil) + (setq fill-column 71)) + +(provide 'chordpro-mode)