Typesetting Guitar Tabs

Screen Shot 2015-03-25 at 15.59.17

Windsurfing and guitar playing go well together. So you might think. But in reality, even if there is “no wind” for windsufers, there is still “hell lot of wind” for guitar players on the beach – after all, you went to the windiest spot you could find to surf. So I’m constantly struggeling with “flying pages” when I try to learn a new song on the beach. In addition, everything gets wet all the time…

Something that helps pretty well is laminating the song pages. Since laminating a lot of songs is quite some work – I’d like to laminate as few pages as possible. This is a good idea anyway, since it’s also great to have songs on one page not having to swap pages while playing— although I’d keep a backup of a few multi-page songs in case you want to ask some girl to sit next to you and switch then for you.

Getting songs on one page and highlighting the chords (really helps when the wind moves the paper, right chord, sing lala, everything’s fine..) is quite some work. Thus, is started working on a

Script that typesets guitar chords, e.g. those you can grab from ultimate guitar – from text to a one-page PDF.

Example:

Screen Shot 2015-03-25 at 16.06.35

becomes

Screen Shot 2015-03-25 at 16.07.04

and everything should be nicely fitted in multiple columns on one page.

This is work in progress, feel free to add your improvements… works on my Mac, should work on all *nix systems…

Usage

install wkhtmltopdf

Copy and paste text from e.g. ultimate guitar to a text file, e.g. test.txt, then run makeChords.sh test.txt and open the resulting test.txt.pdf

makeChods.sh

lex lex_head.l
gcc -ll lex.yy.c
mv a.out head.out
lex lex.l
gcc -ll lex.yy.c
mv a.out main.out
./head.out $1 > head.html
./main.out $1 > main.html
sed -n ‘1,61p’ main.html > firstpage.html
sed -n ‘62,122p’ main.html > secondpage.html
cat test_head.html head.html firstpage.html test_middle.html secondpage.html test_tail.html > test_cat.html
wkhtmltopdf -O Landscape test_cat.html $1.pdf
#open $1.pdf

lex_head.l

/* scanner for chords head */

%{
typedef int bool;
#define true 1
#define false 0
bool word;
%}

DIGIT    [0-9]
NOTE     [CDEFGAHBcdefgahb]m?
CHORD    {NOTE}{DIGIT}
WORD     [a-zA-Z0-9]+
TAB      [\t]
SPACE    [ ]
NEWLINES [\n]+

%%

{CHORD}       printf(“<chord>%s</chord>”, yytext );
{WORD}        { printf(“<b>%s</b>”, yytext ); word=true; }
{SPACE}       printf(” “);
{TAB}         printf(“\t”);
{NEWLINES}    { if (word) { printf(“<br>”); return 0; } }
.             // eat

%%

int main( int argc, char **argv )
{
++argv, –argc;  /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], “r” );
else
yyin = stdin;

return yylex();
}

lex.l

/* music chord file scanner */

%{
#include <string.h>
typedef int bool;
int chordline = 0;
int spacesInLine = 0;
int lineContent = 0;
int wordline = 0;
int resultLinePosition=0;
int lineLength=50;
char overlength[1024];
char buffer[1024];
%}

DIGIT    [0-9]
NOTE     [CDEFGAHBcdefgahb]
CHORD    {NOTE}\/?#?b?{DIGIT}?m?{SPACE}?
WORD     [a-zA-Z0-9’\(\)]+
TAB      [\t]
SPACE    [ ]
NEWLINES [\n]+

%%

{SPACE}     { spacesInLine++; //resultLinePosition++;
if (resultLinePosition<lineLength)
{
printf(” “);
} else {
if (resultLinePosition>lineLength)
{
strcat(overlength,” “);
} else {
spacesInLine–; resultLinePosition–; // ignore these space “right in the end of the line wrap”
}
}
}

{CHORD}     {
if (wordline==0) {
lineContent++; chordline = 2;
while (spacesInLine–>0) {
resultLinePosition++;
if (resultLinePosition<lineLength) {
printf(“&nbsp;”);
} else {
strcat(overlength, “&nbsp;”); // store chord in overlength and add later
}
}
resultLinePosition += strlen(yytext);
if (resultLinePosition<lineLength) {
printf(“<chord>%s</chord>”, yytext );
} else {
sprintf(buffer, “<chord>%s</chord>”, yytext );
strcat(overlength, buffer);
}
} else { // Chord in a wordLine. just print it. THIS NEEDS PROPER WRAPPING!
if (chordline>0)printf(“%s”,yytext);
}
}

{WORD}      {
if (chordline != 2) wordline = 1;
lineContent++;
if (chordline==2) {
while (spacesInLine–>0) {
resultLinePosition++;
if (resultLinePosition<lineLength) {
printf(“&nbsp;”);
} else {
strcat(overlength, “&nbsp;”); // store chord in overlength and add later
}
}
resultLinePosition += strlen(yytext);
if (resultLinePosition<lineLength) {
printf(“%s”, yytext );
} else {
sprintf(buffer, “%s”, yytext );
strcat(overlength, buffer);
}
}
if (chordline==1) {
while (spacesInLine–>0) {
resultLinePosition++;
if (resultLinePosition!=lineLength) {
printf(“&nbsp;”);
} else {
printf(“\n<br>”);
printf(“%s”,overlength); printf(“<br>”);
printf(“&nbsp;”);
}
}
resultLinePosition += strlen(yytext);
if (resultLinePosition<lineLength) {
printf(“%s”, yytext );
} else {
if (resultLinePosition-strlen(yytext)>=lineLength) { // was wrapped already
printf(“%s”, yytext );
} else {
printf(“\n<br>”);
printf(“%s”,overlength); printf(“<br>”); // wrap now
printf(“%s”, yytext );
}
}
}
}

{TAB}       {
spacesInLine += 4;
if (chordline>0) {
resultLinePosition += 4;
printf(”    “);
}
}

{NEWLINES}  {
if (lineContent>0) {
wordline=0; chordline–; lineContent=0; spacesInLine=0;
if (chordline>=0) { // Return in chordline or line-after-chordline
printf(“\n<br>”);
if ((chordline==0) && strlen(overlength)>0) {
printf(“%s”,overlength); // flush overlength there are chords without text in OL
printf(“\n<br>”);
overlength[0]=0; // reset overlength string
}
}
resultLinePosition=0;
}
}

.

%%

int main( int argc, char **argv ) {
++argv, –argc;  /* skip over program name */
overlength[0]=0;
wordline=0;
if ( argc > 0 ) {
yyin = fopen( argv[0], “r” );
} else {
yyin = stdin;
}
return yylex();
}

test_head.html

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01//EN”
http://www.w3.org/TR/html4/strict.dtd”&gt;
<html>
<head>
<title>Zweispaltiges Layout – Struktur</title>

<style type=”text/css”>
#wrap {
width:1200px;
margin:0 auto;
}
#left_col {
font-family:monospace;
float:left;
width:600px;
}
#right_col {
font-family:monospace;
float:right;
width:600px;
}
chord {
color: red;
}
</style>

</head>
<body>

<div id=”wrap”>
<div id=”left_col”>

test_middle.html

    </div>
<div id=”right_col”>

test_tail.html

    </div>
</div>

</body>
</html>

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s