in the spirit of "release early, release often"...
i've been learning perl for the sole purpose of creating what's
below. excited by the fact that it's working and it's a start, i
wanted to get it out tonight for people to look at before i go crash.
i intend to ultimately put this on our lug's box, linux.umbc.edu
(which doesn't yet exist). for now, i have it running on my machine
if you want to take a look at it. two caveats, though:
1. my machine's on a dialup modem connection, so:
a. it's slow.
b. it's not connected 24/7. i'll leave it on tonight in case
anyone sees this and wants to play with it, but eventually you
may find it's not on.
2. i haven't thought a lot yet about how to handle the fact that doing
this can potentially chew up a ton of disk space. i'm just
handling it at the moment with a cron job that wipes out all the
jobs every half hour. so,
a. don't clobber me by sending 20 jobs in 15 minutes that each
result in 1 meg postscript files.
b. don't start a job at 1:29. :-)
anyway, here's where it is:
http://plaything.smart.net/cgi-bin/lilypond_cgi.pl
feel free to play around with it, keeping in mind the above. i've
copied-and-pasted some of my own scores and some from mutopia to it,
and it seems to do the job like a champ.
see you tomorrow!
#!/usr/bin/perl -w
#==============================================================================*
# *
# lilypond_cgi.pl -- a web interface for gnu lilypond *
# *
# started: 98/10/15 jeff covey <[EMAIL PROTECTED]> *
# Time-stamp: <lilypond_cgi.pl was last updated on Thu, 15 Oct 1998 11:30pm> *
# *
# 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. *
#==============================================================================*
# installation is simple: *
# *
# 1. install lilypond, put this file in a cgi-bin directory. *
# 2. as necessary, change the paths of the programs lilypond uses in *
# the variables below. *
# 3. create $tmpdir somewhere within your webspace (so people can link *
# to the output files), and chmod it 777 (so user nobody can create *
# files and directories in it. *
# 4. find where it's broken, gather together the pieces, and use them *
# in assorted arts & crafts projects. *
# (also send email about it to me.) *
#==============================================================================*
use strict;
use CGI qw(:standard);
use File::Basename;
# locations of programs to use:
my $ly2dvi="/usr/bin/ly2dvi --separate";
my $dvips="/usr/bin/dvips";
my $ps_to_gifs="/home/jeff/bin/ps-to-gifs.sh";
# change these to reflect your situation.
my $servername="http://localhost";
my $tmpdir_base="/home/httpd/html/lilypond_cgi";
# you probably don't need to touch these.
my $tmpdir="${tmpdir_base}/$$"; # name the directory after the pid so
# it's unique
my $tmpdir_url ="${servername}/" . basename("$tmpdir_base") . "/$$";
my $scorename="score";
my $tmpscore="${scorename}.ly";
my $score="\\score { \\melodic { c d e f g } \\paper {} }";
my $ps="off"; my $gif="off";
my $query;
print header();
print start_html("LilyPond Web Interface");
print "<center>", h1("LilyPond Web Interface"), "</center>";
if (param()) { # the form has already been filled out
$score=param("score");
$ps=param("postscript_requested");
$gif=param("gif_requested");
print h1("results of your lilypond job");
print p("<a href=\"\#output\">go straight to the output...</a>");
print p("you entered a score of:");
print "<pre>$score</pre>";
print p("let's see what i can do about that...");
print hr, h2("setting things up...");
setup();
print hr, h2("working...");
run_lilypond();
make_postscript() if ($ps eq "on" || $gif eq "on");
make_gifs() if ($gif eq "on");
show_output();
}
else {
print <<EOF;
<p>
(<a href="#input">Click here</a> to go straight to the input box.)
<p>
This is a web front-end for <a
href="http://www.cs.ruu.nl/people/hanwen/lilypond/index.html">LilyPond</a>,
The GNU Project Music Typesetter. To quote the LilyPond webpage,
<blockquote>
This program can print beautiful sheet music from a music definition
file. It can also play mechanical performances to a MIDI
file. Features include multiple staffs, meters, clefs, keys, lyrics,
versatile input language, cadenzas, beams, slurs, triplets, formatting
scores, part extraction. It includes a nice font of musical symbols.
</blockquote>
<p>
LilyPond makes it easy to create very high quality musical
manuscripts. LilyPond source files consist of nothing more than ASCII
text, making it possible for anyone to manipulate them without special
software; if you've got a text editor, you can notate or edit scores.
This perl script makes it possible to use LilyPond even if you don't
have it installed on your system. From this webpage, you can edit
your scores and see, listen to, or print out the results.
<p>
I hope this will be a useful tool for the following purposes:
<ul>
<li>It makes LilyPond platform-independent; anyone with a web
browser can use it.
<li>It allows people to work on their scores from wherever they are;
they don't have to go to a machine that has LilyPond installed.
<li>It could be used in an online music archive to allow people to
modify scores in the archive. For example, if you came across a
score you wanted but you disagreed with some of the fingerings
or other notations, you could copy and paste the script into
this page, make your desired changes, and have it generate a new
copy just the way you want it.
</ul>
<p>
The first thing to do is start learning Mudela, the Music Definition
Language, which is the language in which Lilypond source files are
written. Head over to the <a
href="http://www.cs.ruu.nl/people/hanwen/lilypond/index.html">LilyPond
homepage</a>, and take a look at the tutorial on how to use it. If
you open another window, you can go back-and-forth typing in the
examples here and looking at the results, and you'll be on your way in
no time.
<hr>
<p>
<a href="mailto:jeff.covey\@pobox.com">I'd like to hear</a> all your
thoughts on what features should be added. The following are turning
around in my mind right now:
<ul>
<li>Three modes of operation:
<ol>
<li>As it is now, letting people type in their scores here
directly (or copy and paste it from a <a
href="http://www.gnu.org/software/emacs/">real editor</a>).
<li>Using file upload buttons to let them specify files on
their hard drives to process.
<li>An interactive mode, more friendly to new people. This
would have separate boxes for "title", "author", "midi
tempo", etc. It would take all of these, create a source
file out of them, then process it.
</ol>
<li>A tutorial consisting of people typing in scores and seeing the
results.
<li>An option to mail the Lilypond source file to yourself after
you're done with it, or to send it to the curator of an archive
as a new submission.
</ul>
EOF
print "<a name=\"input\">";
print hr, start_form;
print p("Please enter your score in the box below. for example:");
print p("<pre>${score}</pre>");
print p(textarea("score","",40,80));
print p(
checkbox("postscript_requested",1,"on","Generate postscript images"), br,
checkbox("gif_requested",1,"on","Generate gif images")
);
print p(submit("Submit this score for processing"), reset("Reset the score box"));
print end_form, hr;
}
print end_html();
sub setup {
unless (-r $tmpdir && -w $tmpdir && -d $tmpdir) {
mkdir("$tmpdir",0777) || quit("couldn't create ${tmpdir}");
}
if (open (SCORE,">$tmpdir/$tmpscore")) {
print SCORE $score;
if (close (SCORE)) { print p("wrote the score to ${tmpdir}/${tmpscore}..."); }
else { quit("couldn't close ${tmpdir}/${tmpscore}"); }
}
else { quit("couldn't open ${tmpdir}/${tmpscore} for writing"); }
if (chdir $tmpdir) { print p("changed to $tmpdir..."); }
else { quit("couldn't change to ${tmpdir}"); }
}
sub run_lilypond {
print p("running ${ly2dvi} ${tmpscore}...");
print "<pre>";
my $lily_output=`${ly2dvi} ${tmpscore}`;
print $lily_output;
print "</pre>";
}
sub make_postscript {
print p("converting dvi files to postscript files...");
while (defined(my $dvi_file=<$tmpdir/*.dvi>)) {
my $dvi_file_basename = basename("$dvi_file", "\.dvi");
my $dvips_output=`${dvips} -o ${dvi_file_basename}.ps $dvi_file`;
print p("dvips output for ${dvi_file}:");
print "<pre>";
print $dvips_output;
print "</pre>";
}
}
sub make_gifs {
print p("converting postscript files to gifs...");
while (defined(my $ps_file=<$tmpdir/*.ps>)) {
my $ps_to_gifs_output=`${ps_to_gifs} ${ps_file}`;
print p("ps-to-gifs output for ${ps_file}:");
print "<pre>";
print $ps_to_gifs_output;
print "</pre>";
}
}
sub show_output {
print hr;
print "<a name=\"output\">";
print h2("the output files were:");
print "<ul>";
print "<li>source files:";
print "<ul>";
while (defined(my $output_file=<$tmpdir/*ly>)) {
$output_file = basename("$output_file");
print "<li><a href=\"$tmpdir_url/$output_file\">$output_file</a>";
}
print "</ul>";
print "<li>postscript images:";
print "<ul>";
while (defined(my $output_file=<$tmpdir/*ps>)) {
$output_file = basename("$output_file");
print "<li><a href=\"$tmpdir_url/$output_file\">$output_file</a>";
}
print "</ul>";
print "<li>gif images:";
print "<ul>";
while (defined(my $output_file=<$tmpdir/*gif>)) {
$output_file = basename("$output_file");
print "<li><a href=\"$tmpdir_url/$output_file\">$output_file</a>";
}
print "</ul>";
print "<li>midi sound files:";
print "<ul>";
while (defined(my $output_file=<$tmpdir/*midi>)) {
$output_file = basename("$output_file");
print "<li><a href=\"$tmpdir_url/$output_file\">$output_file</a>";
}
print "</ul>";
print "</ul>";
}
sub quit {
print p("whoops! $_[0]:<br> $!");
print end_html(); die;
}