#!/usr/bin/perl $Version = "1.1.1"; printf "ABC2Tab Version $Version, Copyright (C) 1998,2001,2003 Lyle Melick,\n Mandolin tab by Jake Edge\n"; ############################################################################ # # abc2tab: Program to convert tunes in abc format to ASCII Tablature. # Copyright (C) 1998,2001,2003 Lyle Melick # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # The author can be contacted as follows: # # Lyle Melick # lyle@melick.net # # Minor mods made by Jake Edge (jake@edge2.net) to produce mandolin tab # 24 October 2001 # ############################################################################ # #----- # # parse command line # #----- print "ARGV = ", join(" ", @ARGV), "\n" if $verbose; &Getopts('d:u:x:fghmsv'); if ($opt_h || $opt_err) { print "Usage: $0 [-d[#]] [-f] [-g] [-h] [-s] [-u[#]] [-v] [-x[xref]] [abcfile.abc]\n"; print " -d -- adjust DOWN by this many octaves (Example: -d1)\n"; print " -f -- suppress footer annotations\n"; print " -g -- guitar style tab (High string on top)\n"; print " -m -- mandolin tab\n"; print " -h -- print this help\n"; print " -s -- suppress interline spaces, add column for spaces in source\n"; print " -u -- adjust UP by this many octaves (Example: -u1)\n"; print " -v -- verbose\n"; print " -x -- single x reference to print\n"; exit 0; } $Footers = 1; $Footers = 0 if $opt_f; $GuitarTab = 0; $GuitarTab = 1 if $opt_g; $MandoTab = 0; $MandoTab = 1 if $opt_m; $Melody_Only = 0; #$Melody_Only = 1 if $opt_m; # this would appear to be unimplemented and I # grabbed $opt_m for mando $Spaces = 1; $Spaces = 0 if $opt_s; $verbose = 0; $verbose = 1 if $opt_v; $Xref_List = $opt_x if ($opt_x ne ""); printf "\tVERBOSE:Footers=%s,GuitarTab=%s,MandoTab=%s,RegKey=%s,verbose=%s,Xref_List=%s\n", $Footers, $GuitarTab, $MandoTab, $opt_r, $verbose, $Xref_List if $verbose; #----- # # Setup # #----- printf "\tVERBOSE:Initializing\n" if $verbose; $NoteXlt = ('CDEFGABcdefgab zZ'); @NoteNum = ('40','42','44','45','47','49','51','52','54','56','57','59','61','63',' ','99','99'); @Frets = ('-0-','-%-','-1-','-1%','-2-','-3-','-3%','-4-','-4%','-5-','-6-','-6%','-7-','-7%','-8-','-8%','-9-','-10','10%','-11','11%','-12','-13','13%','-14') if !$GuitarTab; @Frets = ('-0-','-1-','-2-','-3-','-4-','-5-','-6-','-7-','-8-','-9-','-10','-11','-12','-13','-14','-15','-16','-17','-18','-19','-20','-21','-22','-23','-24') if $GuitarTab || $MandoTab; @NoteLnth8 = (' t','dt',' s',' e',' q','dq',' h','5X','dh','7X',' w',' '); @NoteLnth16 = (' x','dx',' t',' s',' e','de',' q','5X','dq','7X',' h',' '); $startabcline = 0; $endabcline = 0; $abcline = 0; $abcnote = 0; printf "\tVERBOSE:All set...\n" if $verbose; #----- # # Open the File # #----- printf "\tVERBOSE:Opening input file\n" if $verbose; open(FILE, "@ARGV") || die "Can't open file - @ARGV: $!\n"; #----- # # Begin Processing the file # #----- while () { chop; # checking for and handling blank line between songs. if ($_ eq "") { if ($InSong eq "Yes") { $endabcline = $abcline; SWITCH: for ($X_Number) { if ($X_Number == $Xref_List || $Xref_List == "") { &Process($startabcline,$endabcline); }; }; $startabcline = $endabcline + 1; $InSong = "No"; } else { next; } } (@inline0) = split(/\!/, $_); $inline0 = $inline0[0]; (@inline1) = split(/\\/, $inline0); $inline1 = $inline1[0]; (@inline2) = split(/\*/, $inline1); $inline2 = $inline2[0]; (@inline) = split(/%/, $inline2); $inline = $inline[0]; (@Field) = split(/\:/,$inline[0]); (@RDef) = split(/\:/,$inline[2]); if ($inline[0] eq "" && $inline[1] eq "" && $RDef[0] eq "ABC2TAB") { printf "\tVERBOSE:$RDef[1], $RDef[2]\n" if $verbose; &ReadDefinitions($RDef[1], $RDef[2]); } #-------------------- # # Process Fields # #-------------------- if (length($Field[0]) eq 1) { $InHistory = "No"; if (substr($Field[1],0,1) eq " ") { $Field[1] = substr($Field[1],1,length($Field[1])-1); } #-------------------- # # Handle fields # #-------------------- printf "\tVERBOSE:Parsing Header...\n" if $verbose; SWITCH: for ($Field[0]) { /[Aa]/ && do { $information[1] = $Field[1]; last SWITCH; }; /[Bb]/ && do { $information[2] = "From The Book $Field[1]"; last SWITCH; }; /[Cc]/ && do { $information[3] = $Field[1]; last SWITCH; }; /[Dd]/ && do { $information[4] = "Recorded on $Field[1]"; last SWITCH; }; /[Ee]/ && do { $information[5] = "Elemskip = $Field[1]"; last SWITCH; }; /[Ff]/ && do { $information[6] = "Processed from File $Field[1]"; last SWITCH; }; /[Gg]/ && do { $information[7] = "Group: $Field[1]"; last SWITCH; }; /[Hh]/ && do { $information[8] = "History: $Field[1]"; $InHistory = "Yes"; last SWITCH; }; /[Ii]/ && do { $information[9] = "Information: $Field[1]"; last SWITCH; }; /[Jj]/ && do { $information[10] = $Field[1]; last SWITCH; }; /[Kk]/ && do { if ($InHeader eq "No") { @part[$abcline+1] = "Key of $Field[1]"; &SetKey($Field[1]); } else { printf OUT "\tKey of %s %s\n\n ", $Field[1], $information[3]; &SetKey($Field[1]); if ($HaveStringDef eq "No") { $RDef[1] = "D A d"; $RDef[2] = "Default Dulcimer Tuning"; &ReadDefinitions($RDef[1],$RDef[2]); } if ($HaveTimeSig eq "No") { $TimeSig[0] = 4; $TimeSig[1] = 4; } $InHeader = "No"; printf "\tVERBOSE:Header complete, starting notes\n" if $verbose; } last SWITCH; }; /[Ll]/ && do { (@DefLnth) = split(/\//,$Field[1]); $DefNoteLnth = @DefLnth[1]; $LnthExpl = 1; last SWITCH; }; /[Mm]/ && do { $HaveTimeSig = "Yes"; (@TimeSig) = split(/\//,$Field[1]); if (@TimeSig[0] eq "C" || @TimeSig[0] eq "c") { $TimeSig[0] = 4; $TimeSig[1] = 4; } if (@TimeSig[0] eq "C|" || @TimeSig[0] eq "c|") { $TimeSig[0] = 2; $TimeSig[1] = 4; } if ($LnthExpl = 0) { if (($TimeSig[0] / $TimeSig[1]) >= .75) { $DefNoteLnth = 8; } else { $DefNoteLnth = 16; } } last SWITCH; }; /[Nn]/ && do { $information[14] = "Notes: $Field[1]"; last SWITCH; }; /[Oo]/ && do { $information[15] = "Origin: $Field[1]"; last SWITCH; }; /[Pp]/ && do { if ($InHeader eq "No") { @part[$abcline+1] = "($Field[1])"; } else { printf OUT "\n\tPlay parts in following order: %s\n\n", $Field[1]; } last SWITCH; }; /[Qq]/ && do { printf OUT "\t%s\n", $Field[1]; last SWITCH; }; /[Rr]/ && do { printf OUT "\t%s\n", $Field[1]; last SWITCH; }; /[Ss]/ && do { $information[19] = "Source: $Field[1]"; last SWITCH; }; /[Tt]/ && do { if ($NoTitle eq "TRUE") { $LnthTitle = length($Field[1]); printf OUT ' ' x (40 - ($LnthTitle / 2)); printf OUT "%s\n\n ", $Field[1]; $NoTitle = "FALSE"; } else { $LnthTitle = length($Field[1]); printf OUT ' ' x (35 - ($LnthTitle / 2)); printf OUT "%s\n ", $Field[1]; } last SWITCH; }; /[Uu]/ && do { $information[21] = $Field[1]; last SWITCH; }; /[Vv]/ && do { $information[22] = "Voice: $Field[1]"; last SWITCH; }; /[Ww]/ && do { $information[23] = "Lyrics: $Field[1]"; last SWITCH; }; /[Xx]/ && do { &Initialize(); $X_Number = $Field[1]; $information[24] = "Song #$Field[1]"; SWITCH: for ($X_Number) { close(OUT); if ($X_Number == $Xref_List || $Xref_List == "") { printf "Creating %s.tab from %s\n", $Field[1], @ARGV; open(OUT,">$Field[1].tab") || die "Can't open file - $Field[1].tab: $!\n"; }; }; $NoTitle = "TRUE"; $InHeader = "Yes"; $InSong = "Yes"; $HaveStringDef = "No"; last SWITCH; }; /[Yy]/ && do { $information[25] = $Field[1]; last SWITCH; }; /[Zz]/ && do { $information[26] = "Transcription Note: $Field[1]"; last SWITCH; }; }; } else { next if ($InSong ne "Yes"); #-------------------- # # process music # #-------------------- chop; if ($InHistory eq "Yes") {$information[8] .= "\n $inline"; next;}; #-------------------- # # abc2ps comment handling # #-------------------- if ($inline[0] eq "" && $inline[1] eq "" && $RDef[0] eq "begintext") { $InComment = "Yes"; } if ($inline[0] eq "" && $inline[1] eq "" && $RDef[0] eq "endtext") { $InComment = "No"; } next if ($InComment eq "Yes"); #-------------------- # # end of abc2ps comment handling # #-------------------- $NumChars = length($inline); printf "\tVERBOSE:INPUT LINE:$inline\n" if $verbose; printf "\tVERBOSE:NumChars=$NumChars.\n" if $verbose; for ($nt=0; $nt <= $NumChars; $nt++) { @Chord{join('.',$abcline,$abcnote)} = ""; $InTuple = "No"; $Gracing = "No"; $Lnth = 1; $Note = substr($inline,$nt,1); printf "\tVERBOSE:Processing NOTE:$Note-nt=$nt\n" if $verbose; # # Handle Guitar Chords # if (($InChord eq "Yes") && ( $Note ne '"')) { @Chord{join('.',$abcline,$abcnote)} .= $Note; }; next if (($InChord eq "Yes") && ( $Note ne '"')); # #Handle Notes & modifiers # if ($nt < $NumChars - 1) { SWITCH: for (substr($inline,$nt+1,1)) { /\(/ && do { $ProcessNow = "Yes"; }; /\|/ && do { $ProcessNow = "Yes"; }; /\:/ && do { $ProcessNow = "Yes"; }; /\[/ && do { $ProcessNow = "Yes"; }; / / && do { $ProcessNow = "Yes"; }; /[A-Ga-gZz]/ && do { $ProcessNow = "Yes"; }; }; } if ($nt == $NumChars - 1) { $ProcessNow = "Yes"; }; SWITCH: for ($Note) { #Notes /[A-Ga-g]/ && do { $CurrentNote = $Note; printf "1-%s ", $Note if $verbose; last SWITCH; }; #Accidentals /\^/ && do { $Accidental++; printf "2-%s ", $Note if $verbose; last SWITCH; }; /\_/ && do { $Accidental--; printf "2-%s ", $Note if $verbose; last SWITCH; }; /\=/ && do { $Accidental = 0; printf "2-%s ", $Note if $verbose; last SWITCH; }; #Octave Modifiers /\,/ && do { $Octave = $Octave - 12; printf "3-%s ", $Note if $verbose; last SWITCH; }; /\'/ && do { $Octave = $Octave + 12; printf "3-%s ", $Note if $verbose; last SWITCH; }; #Rests /[zZ]/ && do { $CurrentNote = $Note; printf "4-%s ", $Note if $verbose; last SWITCH; }; #Spaces / / && do { $Lnth = 9; $CurrentNote = $Note; printf "5-%s ", $Note if $verbose; last SWITCH; }; #Barlines /\|/ && do { $Lnth = 9; &CheckEnding; $CurrentNote = $Note; printf "5-%s ", $Note if $verbose; last SWITCH; }; /\:/ && do { $Lnth = 9; $CurrentNote = $Note; printf "5-%s ", $Note if $verbose; last SWITCH; }; #Slurs /\(/ && do { $InSlur = "Yes"; SWITCH: for (substr($inline,$nt+1,1)) { /[1-9]/ && do { $InTuple = "Yes"; $TupleLength = "tp"; $TupleLength .= substr($inline,$nt+1,1); printf "6a-%s ", $Note if $verbose; $nt++; last SWITCH; }; } printf "6-%s ", $Note if $verbose; last SWITCH; }; /\)/ && do { $InSlur = "No"; printf "6-%s ", $Note if $verbose; last SWITCH; }; #Ties /\-/ && do { printf "6-%s ", $Note if $verbose; last SWITCH; }; #Stacatto /\./ && do { printf "6-%s ", $Note if $verbose; last SWITCH; }; #Bowings /u/ && do { printf "6-%s ", $Note if $verbose; last SWITCH; }; /v/ && do { printf "6-%s ", $Note if $verbose; last SWITCH; }; #Misc Decorations - Ignored /J/ && do { printf "6-%s ", $Note if $verbose; last SWITCH; }; /M/ && do { printf "6-%s ", $Note if $verbose; last SWITCH; }; /H/ && do { printf "6-%s ", $Note if $verbose; last SWITCH; }; /R/ && do { printf "6-%s ", $Note if $verbose; last SWITCH; }; /T/ && do { printf "6-%s ", $Note if $verbose; last SWITCH; }; #Length Modifiers />/ && do { $Lnth++; printf "7-%s ", $Note if $verbose; last SWITCH; }; / 3) { $NumSpaces{join('.',$abcline,$abcnote)} = length(@Chord{join('.',$abcline,$abcnote)}) - 3; } if (length(@Chord{join('.',$abcline,$abcnote)}) < 3) { @Chord{join('.',$abcline,$abcnote)} .= " " x (3 - length(@Chord{join('.',$abcline,$abcnote)})); } } else { $InChord = "Yes"; $NumSpaces{join('.',$abcline,$abcnote)} = 0; }; printf "B-%s ", $Note if $verbose; last SWITCH; }; #Misc Ignored /h-twyIK-LN-SU-Y/ && do { printf "C-%s ", $Note if $verbose; last SWITCH; }; }; #Put it all together next if ($ProcessNow ne "Yes"); @note{join('.',$abcline,$abcnote)} = $CurrentNote; if ($InTuple eq "Yes") { $Lnth = $TupleLength; }; @lnth{join('.',$abcline,$abcnote)} = $Lnth; @Grace{join('.',$abcline,$abcnote)} = $Gracing; @accd{join('.',$abcline,$abcnote)} = $Accidental; $Octave = $Octave + ($opt_u*12) - ($opt_d*12); @octv{join('.',$abcline,$abcnote)} = $Octave; @Ending{join('.',$abcline,$abcnote)} = $EndingNo; $abcnote++; $Accidental = 0; $Octave = 0; $ProcessNow = "No"; } } #----- # # End of an ABC text file line # #----- printf "\tVERBOSE:There were $abcnote notes in line $abcline\n" if $verbose; $abcnote{$abcline} = $abcnote; $abcline++; $abcnote=0; } #------------------- # # Handle missing blank line at end of file # #------------------- if ($InSong eq "Yes") { $endabcline = $abcline; SWITCH: for ($X_Number) { if ($X_Number == $Xref_List || $Xref_List == "") { &Process($startabcline,$endabcline); }; }; } printf "\tVERBOSE:End of File\n" if $verbose; close(FILE); exit 0; # #----- # # End of Song - Begin processing output # #----- sub Process { printf "\tVERBOSE:Song Parsed...Starting processing\n" if $verbose; for ($abcline=$startabcline; $abcline < $endabcline; $abcline++) { printf "\tVERBOSE:Processing line %s\n", $abcline if $verbose; for ($tabline=0; $tabline <= (2*$NumStrings)+4; $tabline++) { &CheckTabline($tabline,$TabLineStatus); $String_Note = $StringNoteNumber[$StringNumber]; printf "\tVERBOSE: This string is number: %s, Note: %s\n", $StringNumber, $StringNote if $verbose; next if (($TabLineStatus eq "Space") && ($Spaces == 0)); for ($abcnote=0; $abcnote < $abcnote{$abcline}; $abcnote++) { #-------------------- # # Initialize & load data for current pass # #-------------------- $Note = @note{join('.',$abcline,$abcnote)}; next if ($Note eq " " && $Spaces == 0); $Accidental = $accd{join('.',$abcline,$abcnote)}; $Octave = $octv{join('.',$abcline,$abcnote)}; $EndingNo = @Ending{join('.',$abcline,$abcnote)}; $Gracing = $Grace{join('.',$abcline,$abcnote)}; $Lnth = @lnth{join('.',$abcline,$abcnote)}; #-------------------- # # Collect Used Notes # #-------------------- @UsedNotes[($NoteNum[index($NoteXlt,$Note)] + $Octave + $Accidental + $KeyNotes[index($NoteXlt,$Note)] - 1)] = 1; #-------------------- # # Handle Misc Templates # #-------------------- printf "\tVERBOSE:Handling note between periods .$Note." if $verbose; SWITCH: for ($Note) { /\|/ && do { $Tab = @MsrTmplat[$tabline]; $Tab =~ s/E/$EndingNo/g; last SWITCH; }; /\:/ && do { $Tab = @RptTmplat[$tabline]; last SWITCH; }; / / && do { $Tab = @SpcTmplat[$tabline]; last SWITCH; }; /[Zz]/ && do { $Tab = @RestTmplat[$tabline]; last SWITCH; }; $Tab = @TabTmplat[$tabline]; }; #-------------------- # # Handle Note Lengths # #-------------------- if ($TabLineStatus eq "Time") { if (substr(@lnth{join('.',$abcline,$abcnote)},0,2) eq "tp") { $baT = substr(@lnth{join('.',$abcline,$abcnote)},2,1); $Tab =~ s/TT /.T./g; $Tab =~ s/T/$baT/g; } else { if ($DefNoteLnth eq "16") { $Tab =~ s/TT/@NoteLnth16[(@lnth{join('.',$abcline,$abcnote)}) + $DefLnthOff]/g; } else { $Tab =~ s/TT/@NoteLnth8[(@lnth{join('.',$abcline,$abcnote)}) + $DefLnthOff]/g; } } } #-------------------- # # Handle Notes # #-------------------- if ($TabLineStatus eq "Space") { } if ($TabLineStatus eq "Line") { $Absolute_Note = ($NoteNum[index($NoteXlt,$Note)] + $Octave + $Accidental + $KeyNotes[index($NoteXlt,$Note)] - 1); $Diff_Note = $Absolute_Note - $String_Note; if ($Gracing eq "Yes") { $Tab =~ s/-/~/g; } SWITCH: for ($Diff_Note) { (($Diff_Note < 0) && ($tabline == $BottomLine)) && do { $Tab =~ s/W/-*-/g; last SWITCH; }; (($Diff_Note < 0) && ($tabline != $BottomLine)) && do { $Tab =~ s/W/---/g; last SWITCH; }; (($Diff_Note >= 0) && ($Diff_Note < $StringDelt[$StringNumber + 1])) && do { $Tab =~ s/W/$Frets[$Diff_Note]/g; last SWITCH; }; (($Diff_Note >= 0) && ($Diff_Note >= $StringDelt[$StringNumber + 1])) && do { $Tab =~ s/W/---/g; last SWITCH; }; }; } @tab{join('.',$tabline,$abcline,$abcnote)} = $Tab; } } } #----- # # Print out the used notes. # #----- printf "\tVERBOSE:Used Notes:\n" if $verbose; for ($i=1; $i<=88; $i++) { if ($UsedNotes[$i] == 1) { printf "%s-%s,", $i,$UsedNotes[$i] if $verbose; } } #printf ":End of Used Notes:\n" if $verbose; #----- # # Print it out. # #----- SWITCH: for ($X_Number) { if ($X_Number == $Xref_List || $Xref_List == "") { &PrintOut($startabcline,$endabcline); }; }; } # Process # #-------------------- # # Print song # #-------------------- sub PrintOut { for ($abcline=$startabcline; $abcline < $endabcline; $abcline++) { next if $abcnote{$abcline} eq "0"; for ($tabline=0; $tabline <= ((2*$NumStrings)+4); $tabline++) { &CheckTabline($tabline,$TabLineStatus); next if (($TabLineStatus eq "Space") && ($Spaces == 0)); # # Time Signature # $Tab = @TimeTmplat[$tabline]; if ($tabline == 2) { $Tab =~ s/V/@TimeSig[0]/g; } if ($tabline == (2*$NumStrings - 2)) { $Tab =~ s/V/@TimeSig[1]/g; } if ($tabline == $NumStrings) { $Tab =~ s/V/\//g; } $Tab =~ s/V/ /g; # # String Names # if ($TabLineStatus eq "Line") { SWITCH: for (length(@StringDef[$StringNumber])) { /1/ && do { $tString = "t"; last SWITCH; }; /2/ && do { $tString = " t"; last SWITCH; }; /3/ && do { $tString = " t"; last SWITCH; }; /4/ && do { $tString = " t"; last SWITCH; }; /5/ && do { $tString = " t"; last SWITCH; }; /6/ && do { $tString = " t"; last SWITCH; }; /7/ && do { $tString = " t"; last SWITCH; }; /8/ && do { $tString = " t"; last SWITCH; }; /9/ && do { $tString = " t"; last SWITCH; }; }; $Tab =~ s/$tString/@StringDef[$StringNumber]/g; } # # Part/Letter numbers above staff # if (@part[$abcline] ne "") { $ShortPart = "("; $ShortPart .= substr(@part[$abcline],1,1); $ShortPart .= ")"; $Tab =~ s/www/$ShortPart/g; } else { $Tab =~ s/www/ /g; } printf OUT "%s", $Tab; for ($abcnote=0; $abcnote <= $abcnote{$abcline}; $abcnote++) { $Tab = @tab{join('.',$tabline,$abcline,$abcnote)}; if ($tabline eq "1") { printf "\tVERBOSE:Printing Note: $abcnote $Tab\n" if $verbose; } next if $Tab eq ""; if (@Chord{join('.',$abcline,$abcnote)} eq "" ) { @Chord{join('.',$abcline,$abcnote)} = " "; } $Tab =~ s/C/@Chord{join('.',$abcline,$abcnote)}/g; printf OUT "%s", $Tab; if (($NumSpaces{join('.',$abcline,$abcnote)} > 0) && ($tabline != 0)) { if ($TabLineStatus eq "Line") { printf OUT "-" x ($NumSpaces{join('.',$abcline,$abcnote)}); } else { printf OUT " " x ($NumSpaces{join('.',$abcline,$abcnote)}); } } } printf OUT "\n "; } } SWITCH: for ($X_Number) { if ($X_Number == $Xref_List || $Xref_List == "") { &PrintFoot(); }; }; } # PrintOut # #-------------------- # # Print Footer # #-------------------- sub PrintFoot { printf OUT "\nTAB for %s\nProcessed by ABC2TAB Version %s, Copyright 1998,2001 Lyle Melick, Mandolin tab by Jake Edge\n\n", $InstDesc, $Version; if ($Footers == 1) { printf "\tVERBOSE:Printing Footer\n" if $verbose; printf OUT "The rhythmic notation used works as follows :\n"; printf OUT "w = whole note (semibreve) h = half note (minim)\n"; printf OUT "q = quarter note (crotchet) e = eigth note (quaver)\n"; printf OUT "s = sixteenth note (semiquaver) t = thirtysecond note (demisemiquaver)\n"; printf OUT "dh = dotted half note dq = dotted quarter note\n"; printf OUT "de = eighth note\n\n"; printf OUT "Other Notation (In tab with fret numbers) :\n"; printf OUT "h = hammer on / = slide up\n"; printf OUT "p = pull off \\ = slide down\n"; printf OUT "b = bend up v = vibrato\n"; printf OUT "r = release bend t = Right Hand tap\n"; printf OUT " = Harmonic on N fret x = Heavy Damp\n\n"; printf OUT "A percent sign beside a fret number signifies a half fret.\n\n"; printf OUT "An Asterisk (*) on a string line signifies the note is too low\n"; printf OUT " or too high for the instrument\n\n"; } printf OUT "Other stuff from abc header:\n"; for ($info=1; $info <= 26; $info++) { if ($information[$info] ne "") { printf OUT "%s\n", $information[$info]; } } printf OUT "\f"; } # PrintFoot # #-------------------- # # Misc routines # #---------------------- # #-------------------- # # Check for Endings # #---------------------- sub CheckEnding { $EndingNo = " "; SWITCH: for (substr($inline,$nt+1,1)) { /[1-9]/ && do { $EndingNo = substr($inline,$nt+1,1); }; }; return 1; } # CheckEnding # #-------------------- # # Check tabline for line/space/chord/time/text # #---------------------- sub CheckTabline { SWITCH: for ($tabline) { if ($tabline == (0)) { $TabLineStatus = "Chord"; $StringNumber = -1; last SWITCH; }; if ($tabline == (2*$NumStrings)) { $TabLineStatus = "Time"; last SWITCH; }; if ($tabline > (2*$NumStrings)) { $TabLineStatus = "Text"; last SWITCH; }; if (($tabline < (2*$NumStrings)) && ($tabline == 1 || $tabline == 3 || $tabline == 5 || $tabline == 7 || $tabline == 9 || $tabline == 11)) { $TabLineStatus = "Line"; $StringNumber++; last SWITCH; } else { $TabLineStatus = "Space"; last SWITCH; }; }; } # CheckTabline # #-------------------- # # Set up tablature Templates # #---------------------- sub SetTab { printf "\tVERBOSE:Setting up TAB Templates\n" if $verbose; for ($ns=0; $ns < ($NumStrings*2)+4; $ns++) { SWITCH: for ($ns) { ($ns eq "0") && do { @TabTmplat[$ns] = (' C'); @TimeTmplat[$ns] = (' www'); @SpcTmplat[$ns] = (' '); @RestTmplat[$ns] = (' '); @MsrTmplat[$ns] = ('E'); @RptTmplat[$ns] = (' '); last SWITCH; }; ($ns eq "1" || $ns eq "3" || $ns eq "5" || $ns eq "7" || $ns eq "9" || $ns eq "11") && do { @TabTmplat[$ns] = ('-W'); @TimeTmplat[$ns] = (' t|'); @SpcTmplat[$ns] = ('-'); @RestTmplat[$ns] = ('---'); @MsrTmplat[$ns] = ('|'); @RptTmplat[$ns] = ('--'); last SWITCH; }; ($ns eq "2" || $ns eq "4" || $ns eq "6" || $ns eq "8" || $ns eq "10") && do { @TabTmplat[$ns] = (' '); @TimeTmplat[$ns] = (' V |'); @SpcTmplat[$ns] = (' '); @RestTmplat[$ns] = (' '); @MsrTmplat[$ns] = ('|'); @RptTmplat[$ns] = (' *'); last SWITCH; }; } if ($ns == ($NumStrings*2)-4) { @RestTmplat[$ns] = (' R '); } if ($ns == ($NumStrings*2)-3) { @RestTmplat[$ns] = ('-e-'); } if ($ns == ($NumStrings*2)-2) { @RestTmplat[$ns] = (' s '); } if ($ns == ($NumStrings*2)-1) { @RestTmplat[$ns] = ('-t-'); } if ($ns == ($NumStrings*2)) { @TabTmplat[$ns] = (' TT '); @TimeTmplat[$ns] = (' '); @SpcTmplat[$ns] = (' '); @RestTmplat[$ns] = ('TT '); @MsrTmplat[$ns] = (' '); @RptTmplat[$ns] = (' '); } if ($ns > ($NumStrings*2)) { @TabTmplat[$ns] = (' '); @TimeTmplat[$ns] = (' '); @SpcTmplat[$ns] = (' '); @RestTmplat[$ns] = (' '); @MsrTmplat[$ns] = (' '); @RptTmplat[$ns] = (' '); } } } # SetTab # #-------------------- # # Routines listed # from here to end are # run once per song # #---------------------- # #-------------------- # # Set up Key Signature Related Stuff # #---------------------- sub SetKey { printf "\tVERBOSE:Handling Key Signature\n" if $verbose; #This table is setup for addition in the line 5,3,1 translations that handle octaves & accidentals. #I am subtracting one from the note number in the translation, so that a natural is a plus one here. SWITCH: for ($Field[1]) { /C#|C#Maj|D#Dor|E#Phr|F#Lyd|G#Mix|A#m|A#Min|A#Aeo|B#Loc/ && do { @KeyNotes = ('2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', ' ',' ',' '); last SWITCH; }; /F#|F#Maj|G#Dor|A#Phr|B#Lyd|C#Mix|D#m|D#Min|D#Aeo|E#Loc/ && do { @KeyNotes = ('2', '2', '2', '2', '2', '2', '1', '2', '2', '2', '2', '2', '2', '1', ' ',' ',' '); last SWITCH; }; /B|BMaj|C#Dor|D#Phr|ELyd|F#Mix|G#m|G#Min|G#Aeo|A#Loc/ && do { @KeyNotes = ('2', '2', '1', '2', '2', '2', '1', '2', '2', '1', '2', '2', '2', '1', ' ',' ',' '); last SWITCH; }; /E|EMaj|F#Dor|G#Phr|ALyd|BMix|C#m|C#Min|C#Aeo|D#Loc/ && do { @KeyNotes = ('2', '2', '1', '2', '2', '1', '1', '2', '2', '1', '2', '2', '1', '1', ' ',' ',' '); last SWITCH; }; /A|AMaj|BDor|C#Phr|DLyd|EMix|F#m|F#Min|F#Aeo|G#Loc/ && do { @KeyNotes = ('2', '1', '1', '2', '2', '1', '1', '2', '1', '1', '2', '2', '1', '1', ' ',' ',' '); last SWITCH; }; /D|DMaj|EDor|F#Phr|GLyd|AMix|Bm|BMin|BAeo|C#Loc|HP|Hp/ && do { @KeyNotes = ('2', '1', '1', '2', '1', '1', '1', '2', '1', '1', '2', '1', '1', '1', ' ',' ',' '); last SWITCH; }; /G|GMaj|ADor|BPhr|CLyd|DMix|Em|EMin|EAeo|F#Loc/ && do { @KeyNotes = ('1', '1', '1', '2', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', ' ',' ',' '); last SWITCH; }; /C|CMaj|DDor|EPhr|FLyd|GMix|Am|AMin|AAeo|BLoc/ && do { @KeyNotes = ('1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', ' ',' ',' '); last SWITCH; }; /F|FMaj|GDor|APhr|BbLyd|CMix|Dm|DMin|DAeo|ELoc/ && do { @KeyNotes = ('1', '1', '1', '1', '1', '1', '0', '1', '1', '1', '1', '1', '1', '0', ' ',' ',' '); last SWITCH; }; /Bb|BbMaj|CDor|DPhr|EbLyd|FMix|Gm|GMin|GAeo|ALoc/ && do { @KeyNotes = ('1', '1', '0', '1', '1', '1', '0', '1', '1', '0', '1', '1', '1', '0', ' ',' ',' '); last SWITCH; }; /Eb|EbMaj|FDor|GPhr|AbLyd|BbMix|Cm|CMin|CAeo|DLoc/ && do { @KeyNotes = ('1', '1', '0', '1', '1', '0', '0', '1', '1', '0', '1', '1', '0', '0', ' ',' ',' '); last SWITCH; }; /Ab|AbMaj|BbDor|CPhr|DbLyd|EbMix|Fm|FMin|FAeo|GLoc/ && do { @KeyNotes = ('1', '0', '0', '1', '1', '0', '0', '1', '0', '0', '1', '1', '0', '0', ' ',' ',' '); last SWITCH; }; /Db|DbMaj|EbDor|FPhr|GbLyd|AbMix|Bbm|BbMin|BbAeo|CLoc/ && do { @KeyNotes = ('1', '0', '0', '1', '0', '0', '0', '1', '0', '0', '1', '0', '0', '0', ' ',' ',' '); last SWITCH; }; /Gb|GbMaj|AbDor|BbPhr|CbLyd|DbMix|Ebm|EbMin|EbAeo|FLoc/ && do { @KeyNotes = ('0', '0', '0', '1', '0', '0', '0', '0', '0', '0', '1', '0', '0', '0', ' ',' ',' '); last SWITCH; }; /Cb|CbMaj|DbDor|EbPhr|FbLyd|GbMix|Abm|AbMin|AbAeo|BbLoc/ && do { @KeyNotes = ('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', ' ',' ',' '); last SWITCH; }; }; } # SetKey # #-------------------- # # Configure String Handling # #---------------------- sub ReadDefinitions { printf "\tVERBOSE:Handling String Definitions\n" if $verbose; # # Over-ride if guitar switch thrown # $RDef[1] = "E B, G, D, A,, E,," if $GuitarTab; $RDef[2] = "Guitar" if $GuitarTab; $RDef[1] = "e A D G," if $MandoTab; $RDef[2] = "Mando" if $MandoTab; $InstDesc = $RDef[2]; $DefaultStrings = $RDef[1]; (@StringDef) = split(/ /,$DefaultStrings); $NumStrings = $#StringDef + 1; printf "\tVERBOSE:Number of Strings:%s\n", $NumStrings if $verbose; for ($StringGrp=0; $StringGrp <= $NumStrings - 1; $StringGrp++) { $StrDef = @StringDef[$StringGrp]; $NumChar = length($StrDef); for ($sg=0; $sg < $NumChar; $sg++) { $StringNote = substr($StrDef,$sg,1); SWITCH: for ($StringNote) { /\^/ && do { $StringNoteNumber[$StringGrp]++; last SWITCH; }; /\_/ && do { $StringNoteNumber[$StringGrp]--; last SWITCH; }; /\=/ && do { $StringNoteNumber[$StringGrp] = 0; last SWITCH; }; /\,/ && do { $StringNoteNumber[$StringGrp] = $StringNoteNumber[$StringGrp] - 12; last SWITCH; }; /\'/ && do { $StringNoteNumber[$StringGrp] = $StringNoteNumber[$StringGrp] + 12; last SWITCH; }; /[A-Ga-g]/ && do { $StringNoteNumber[$StringGrp] = $NoteNum[index($NoteXlt,$StringNote)]; last SWITCH; }; }; } printf "\tVerbose:StringNoteNumber %s = %s\n", $StringGrp, $StringNoteNumber[$StringGrp] if $verbose; } for ($StringGrp=1; $StringGrp <= $NumStrings-1; $StringGrp++) { $StringDelt[$StringGrp] = $StringNoteNumber[$StringGrp] - $StringNoteNumber[$StringGrp - 1]; $StringDelt[$StringGrp] = $StringNoteNumber[$StringGrp - 1] - $StringNoteNumber[$StringGrp] if $GuitarTab || $MandoTab; printf "\tVERBOSE:This Note:$StringNoteNumber[$StringGrp - 1] Next Note:$StringNoteNumber[$StringGrp] Difference:$StringDelt[$StringGrp]\n" if $verbose; if ($StringDelt[$StringGrp] < 0) { printf "\n***WARNING***String Definition problem in strings.cfg\nCheck for proper note definition (Capitalization??)\n\n"; } } #$StringDelt[$NumStrings] = 24; $HaveStringDef = "Yes"; &SetTab($NumStrings); } # ReadDefinitions # #-------------------- # # Clean up Variables # #---------------------- sub Initialize { printf "\tVERBOSE:Initializing Variables\n" if $verbose; $BottomLine = 1; $BottomLine = 11 if $GuitarTab || $MandoTab; $DefLnthOff = 2; $LnthExpl = 0; $InChord = No; $Gracing = No; $Tie = 0; $NoTitle = "TRUE"; $InHeader = "No"; $InSong = "No"; $HaveStringDef = "No"; $HaveTimeSig = "No"; $InComment = "No"; $Accidental = 0; $Octave = 0; for ($i=0; $i<=26; $i++) { $information[$i] = ""; } } # Initialize # #-------------------- # # Once per execution # #---------------------- # #-------------------- # # Handle Command Line Options # #---------------------- ;# getopts.pl - a better getopt.pl ;# Usage: ;# do Getopts('a:bc'); # -a takes arg. -b & -c not. Sets opt_* as a ;# # side effect. sub Getopts { local($argumentative) = @_; local(@args,$_,$first,$rest); local($errs) = 0; local($[) = 0; @args = split( / */, $argumentative ); while(@ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) { ($first,$rest) = ($1,$2); $pos = index($argumentative,$first); if($pos >= $[) { if($args[$pos+1] eq ':') { shift(@ARGV); if($rest eq '') { ++$errs unless @ARGV; $rest = shift(@ARGV); } eval "\$opt_$first = \$rest;"; } else { eval "\$opt_$first = 1"; if($rest eq '') { shift(@ARGV); } else { $ARGV[0] = "-$rest"; } } } else { print STDERR "Unknown option: $first\n"; ++$errs; if($rest ne '') { $ARGV[0] = "-$rest"; } else { shift(@ARGV); } } } $errs == 0; } # Getopts