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;
}

Reply via email to