changeset 6060:0247125e995d

lilypondcairo: bump to 2.13.46, include windows and midi2ly patches.
author Jan Nieuwenhuizen <janneke@gnu.org>
date Mon, 24 Jan 2011 15:23:33 +0100
parents 2b278c103efd
children 71bcdbdd76e7
files gub/specs/lilypondcairo.py patches/0001-Midi2ly-grok-midi-files-with-up-to-256-tracks-was-32.patch patches/0001-Use-g_spawn_sync-instead-of-system-.-Fixes-1429.patch patches/lilypond-midi2ly-preview.patch
diffstat 4 files changed, 1201 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/gub/specs/lilypondcairo.py	Mon Jan 24 21:36:43 2011 +0100
+++ b/gub/specs/lilypondcairo.py	Mon Jan 24 15:23:33 2011 +0100
@@ -6,11 +6,14 @@
 # in.  Hmm.
 
 class Lilypondcairo (lilypond.Lilypond):
-    source = 'http://lilypond.org/download/source/v2.13/lilypond-2.13.42.tar.gz'
+    source = 'http://lilypond.org/download/source/v2.13/lilypond-2.13.46.tar.gz'
     dependencies = [x.replace ('pango', 'pangocairo')
                     for x in lilypond.Lilypond.dependencies]
     patches = [
         '0003-Start-OTF-font-from-E800-avoids-hardcoded-linux-unic.patch',
+        '0001-Use-g_spawn_sync-instead-of-system-.-Fixes-1429.patch',
+        '0001-Midi2ly-grok-midi-files-with-up-to-256-tracks-was-32.patch',
+        'lilypond-midi2ly-preview.patch',
         ]
     def get_conflict_dict (self):
         return {'': ['lilypond']}
@@ -21,7 +24,9 @@
                 for x in lilypond.Lilypond__mingw.dependencies]
     patches = [
         '0003-Start-OTF-font-from-E800-avoids-hardcoded-linux-unic.patch',
-        '0001-MINGW32-Prepend-cwd-to-PATH.-Fixes-invoking-as-lilyp.patch',
+        '0001-Use-g_spawn_sync-instead-of-system-.-Fixes-1429.patch',
+        '0001-Midi2ly-grok-midi-files-with-up-to-256-tracks-was-32.patch',
+        'lilypond-midi2ly-preview.patch',
         ]
     def get_conflict_dict (self):
         return {'': ['lilypond']}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/0001-Midi2ly-grok-midi-files-with-up-to-256-tracks-was-32.patch	Mon Jan 24 15:23:33 2011 +0100
@@ -0,0 +1,51 @@
+From 85c0ce205e1a9b5fad4ac79d02292ac1231db532 Mon Sep 17 00:00:00 2001
+From: Jan Nieuwenhuizen <janneke@gnu.org>
+Date: Tue, 18 Jan 2011 15:31:58 +0100
+Subject: [PATCH] Midi2ly: grok midi files with up to 256 tracks, was 32.  Fixes #1479.
+
+---
+ scripts/midi2ly.py |   13 +++++++++++--
+ 1 files changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/scripts/midi2ly.py b/scripts/midi2ly.py
+index 86c32ba..b03e1a8 100644
+--- a/scripts/midi2ly.py
++++ b/scripts/midi2ly.py
+@@ -712,11 +712,20 @@ def dump_channel (thread, skip):
+ 
+     return '\n  '.join (lines) + '\n'
+ 
++def number2ascii (i):
++    s = ''
++    i += 1
++    while i > 0:
++        m = (i - 1) % 26
++        s = '%c' % (m + ord ('A')) + s
++        i = (i - m)/26
++    return s
++
+ def track_name (i):
+-    return 'track%c' % (i + ord ('A'))
++    return 'track' + number2ascii (i)
+ 
+ def channel_name (i):
+-    return 'channel%c' % (i + ord ('A'))
++    return 'channel' + number2ascii (i)
+ 
+ def dump_track (channels, n):
+     s = '\n'
+diff --git a/python/midi.c b/python/midi.c
+index 972410f..4e6368a 100644
+--- a/python/midi.c
++++ b/python/midi.c
+@@ -388,7 +388,7 @@ midi_parse (unsigned char **midi,unsigned  char *midi_end)
+   format = get_number (midi, *midi + 2, 2);
+   tracks = get_number (midi, *midi + 2, 2);
+ 
+-  if (tracks > 32)
++  if (tracks > 256)
+     return midi_error (__FUNCTION__,  ": too many tracks: ", compat_itoa (tracks));
+   
+   division = get_number (midi, *midi + 2, 2) * 4;
+-- 
+1.7.1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/0001-Use-g_spawn_sync-instead-of-system-.-Fixes-1429.patch	Mon Jan 24 15:23:33 2011 +0100
@@ -0,0 +1,290 @@
+From 11d5b22d4eb69696b43e576db3d16793dd166d93 Mon Sep 17 00:00:00 2001
+From: Jan Nieuwenhuizen <janneke@gnu.org>
+Date: Fri, 21 Jan 2011 15:02:31 +0100
+Subject: [PATCH] Use g_spawn_sync () instead of system ().  Fixes #1429.
+
+Avoid the opening of a DOS box, console window, command window or
+power shell during PostScript to PDF conversion on some versions of
+Microsoft Windows [with GUB 6976be5 or newer].
+
+Bypass the shell, thus avoiding quoting (think spaces or other special
+characters in a file name), mangling and shell-incompatibilities.
+---
+ lily/general-scheme.cc     |   62 ++++++++++++++++++++++++++++
+ lily/include/lily-guile.hh |    2 +-
+ lily/lily-guile.cc         |    6 +--
+ scm/backend-library.scm    |   98 ++++++++++++++------------------------------
+ scm/framework-ps.scm       |    8 ++-
+ scm/ps-to-png.scm          |    2 +
+ 6 files changed, 103 insertions(+), 75 deletions(-)
+
+diff --git a/lily/general-scheme.cc b/lily/general-scheme.cc
+index 14ef697..5989350 100644
+--- a/lily/general-scheme.cc
++++ b/lily/general-scheme.cc
+@@ -23,6 +23,7 @@
+ #include <cstdio>
+ #include <ctype.h>
+ #include <cstring>  /* memset */
++#include <glib.h>
+ using namespace std;
+ 
+ #include "dimensions.hh"
+@@ -663,3 +664,64 @@ LY_DEFINE (ly_format, "ly:format",
+ 
+   return scm_take_locale_stringn (result, len);
+ }
++
++int
++ly_run_command (char *argv[], char **standard_output, char **standard_error)
++{
++  GError *error = 0;
++  int exit_status = 0;
++  int flags = G_SPAWN_SEARCH_PATH;
++  if (!standard_output)
++    flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
++  if (!standard_error)
++    flags |= G_SPAWN_STDERR_TO_DEV_NULL;
++  if (!g_spawn_sync (0, argv, 0, GSpawnFlags (flags),
++		     0, 0, 
++		     standard_output, standard_error,
++		     &exit_status, &error))
++    {
++      fprintf (stderr, "failed (%d): %s: %s\n", exit_status, argv[0], error->message);
++      g_error_free (error);
++      if (!exit_status)
++	exit_status = -1;
++    }
++
++  return exit_status;
++}
++
++LY_DEFINE (ly_spawn, "ly:spawn",
++	   1, 0, 1, (SCM command, SCM rest),
++	   "Simple interface to g_spawn_sync"
++	   " @var{str}."
++	   "  The error is formatted with @code{format} and @var{rest}.")
++
++{
++  LY_ASSERT_TYPE (scm_is_string, command, 1);
++
++  int argc = scm_is_pair (rest) ? scm_ilength (rest) : 0;
++  char **argv = new char*[argc + 2];
++
++  int n = 0;
++  argv[n++] = ly_scm2str0 (command);
++  for (SCM s = rest; scm_is_pair (s); s = scm_cdr (s))
++    argv[n++] = ly_scm2str0 (scm_car (s));
++  argv[n] = 0;
++
++  char *standard_output = 0;
++  char *standard_error = 0;
++  int exit_status = be_verbose_global
++    ? ly_run_command (argv, &standard_output, &standard_error)
++    : ly_run_command (argv, 0, 0);
++
++  if (be_verbose_global)
++    {
++      fprintf (stderr, "\n%s", standard_output);
++      fprintf (stderr, "%s", standard_error);
++    }
++  
++  for (int i = 0; i < n; i++)
++    free (argv[i]);
++  delete[] argv;
++
++  return scm_from_int (exit_status);
++}
+diff --git a/lily/include/lily-guile.hh b/lily/include/lily-guile.hh
+index 6dcc050..3fefd5d 100644
+--- a/lily/include/lily-guile.hh
++++ b/lily/include/lily-guile.hh
+@@ -66,7 +66,7 @@ Interval ly_scm2interval (SCM);
+ Drul_array<Real> ly_scm2realdrul (SCM);
+ Slice int_list_to_slice (SCM l);
+ SCM ly_interval2scm (Drul_array<Real>);
+-char *ly_scm2newstr (SCM str, size_t *lenp);
++char *ly_scm2str0 (SCM str);
+ 
+ Real robust_scm2double (SCM, double);
+ int robust_scm2int (SCM, int);
+diff --git a/lily/lily-guile.cc b/lily/lily-guile.cc
+index f0ff8ca..1763a5c 100644
+--- a/lily/lily-guile.cc
++++ b/lily/lily-guile.cc
+@@ -138,12 +138,10 @@ ly_string2scm (string const &str)
+ 				  str.length ());
+ }
+ 
+-
+ char *
+-ly_scm2newstr (SCM str, size_t *lenp)
++ly_scm2str0 (SCM str)
+ {
+-  char* p = scm_to_locale_stringn(str, lenp);
+-  return p;
++  return scm_to_locale_string (str);
+ }
+ 
+ /*
+diff --git a/scm/backend-library.scm b/scm/backend-library.scm
+index ec81b2f..f21decd 100644
+--- a/scm/backend-library.scm
++++ b/scm/backend-library.scm
+@@ -23,23 +23,12 @@
+ 	     (scm paper-system)
+ 	     (ice-9 optargs))
+ 
+-(define-public (ly:system command . rest)
+-  (let* ((status 0)
+-	 (dev-null "/dev/null")
+-	 (silenced (if (or (ly:get-option 'verbose)
+-			   (not (access? dev-null W_OK)))
+-		       command
+-		       (format #f "~a > ~a 2>&1 " command dev-null))))
+-    (if (ly:get-option 'verbose)
+-	(begin
+-	  (ly:message (_ "Invoking `~a'...") command))
+-	  (ly:progress "\n"))
+-
+-    (set! status
+-	  (if (pair? rest)
+-	      (system-with-env silenced (car rest))
+-	      (system silenced)))
+-	
++(define-public (ly:system command)
++  (if (ly:get-option 'verbose)
++      (begin
++	(ly:message (_ "Invoking `~a'...") (string-join command)))
++      (ly:progress "\n"))
++  (let ((status (apply ly:spawn command)))
+     (if (> status 0)
+ 	(begin
+ 	  (ly:message (_ "`~a' failed (~a)") command status)
+@@ -47,22 +36,6 @@
+ 	  ;; hmmm.  what's the best failure option? 
+ 	  (throw 'ly-file-failed)))))
+ 
+-(define-public (system-with-env cmd env)
+-
+-  "Execute CMD in fork, with ENV (a list of strings) as the environment"
+-  (let*
+-      ;; laziness: should use execle?
+-      
+-      ((pid (primitive-fork)))
+-    (if (= 0 pid)
+-	;; child
+-	(begin
+-	  (environ env)
+-	  (system cmd))
+-	
+-	;; parent
+-	(cdr (waitpid pid)))))
+-
+ (define-public (sanitize-command-option str)
+   "Kill dubious shell quoting"
+   
+@@ -91,41 +64,32 @@
+ 		    (dir-basename name ".ps" ".eps")
+ 		    ".pdf"))
+ 	 (is-eps (string-match "\\.eps$" name))
+-	 (paper-size-string (if is-eps
+-				"-dEPSCrop"
+-				(ly:format "-dDEVICEWIDTHPOINTS=~$\
+- -dDEVICEHEIGHTPOINTS=~$"
+-					paper-width paper-height)))
+-
+-	 (cmd (ly:format
+-		      "~a\
+- ~a\
+- ~a\
+- ~a\
+- -dCompatibilityLevel=1.4\
+- -dNOPAUSE\
+- -dBATCH\
+- -r1200\
+- -sDEVICE=pdfwrite\
+- -sOutputFile=~S\
+- -c .setpdfwrite\
+- -f ~S\
+-"
+-		      (search-gs)
+-		      (if (ly:get-option 'verbose) "" "-q")
+-		      (if (or (ly:get-option 'gs-load-fonts)
+-			      (ly:get-option 'gs-load-lily-fonts))
+-			  "-dNOSAFER"
+-			  "-dSAFER")
+-		      paper-size-string
+-		      pdf-name
+-		      name)))
+-    ;; The wrapper on windows cannot handle `=' signs,
+-    ;; gs has a workaround with #.
+-    (if (eq? PLATFORM 'windows)
+-	(begin
+-	  (set! cmd (string-regexp-substitute "=" "#" cmd))
+-	  (set! cmd (string-regexp-substitute "-dSAFER " "" cmd))))
++	 (*unspecified* (if #f #f))
++	 (cmd
++	  (remove (lambda (x) (eq? x *unspecified*))
++	  (list
++	       (search-gs)
++	       (if (ly:get-option 'verbose) *unspecified* "-q")
++	       (if (or (ly:get-option 'gs-load-fonts)
++		       (ly:get-option 'gs-load-lily-fonts)
++		       (eq? PLATFORM 'windows))
++		   "-dNOSAFER"
++		   "-dSAFER")
++
++	       (if is-eps
++		   "-dEPSCrop"
++		   (ly:format "-dDEVICEWIDTHPOINTS=~$" paper-width))
++	       (if is-eps
++		   *unspecified*
++		   (ly:format "-dDEVICEHEIGHTPOINTS=~$" paper-height))
++	       "-dCompatibilityLevel=1.4"
++	       "-dNOPAUSE"
++	       "-dBATCH"
++	       "-r1200"
++	       "-sDEVICE=pdfwrite"
++	       (string-append "-sOutputFile=" pdf-name)
++	       "-c.setpdfwrite"
++	       (string-append "-f" name)))))
+ 
+     (ly:message (_ "Converting to `~a'...") pdf-name)
+     (ly:progress "\n")
+diff --git a/scm/framework-ps.scm b/scm/framework-ps.scm
+index b79c1a3..c4d1d01 100644
+--- a/scm/framework-ps.scm
++++ b/scm/framework-ps.scm
+@@ -267,10 +267,12 @@
+     (let* ((dir-name (tmpnam))
+ 	   (files '())
+ 	   (status 0)
+-	   (embed #f))
++	   (embed #f)
++	   (cwd (getcwd)))
+       (mkdir dir-name #o700)
+-      (set! status (ly:system
+-		    (format "cd ~a && fondu -force '~a'" dir-name filename)))
++      (chdir dir-name)
++      (set! status (ly:system (list "fondu" "-force" file-name)))
++      (chdir cwd)
+       (set! files (dir-listing dir-name))
+       (for-each
+        (lambda (f)
+diff --git a/scm/ps-to-png.scm b/scm/ps-to-png.scm
+index 4436ea3..17f8222 100644
+--- a/scm/ps-to-png.scm
++++ b/scm/ps-to-png.scm
+@@ -27,6 +27,8 @@
+  (lily)
+  )
+ 
++;; FIXME: use backend-library for duplicates and stubs; lilypond-ps2png.scm is no more
++
+ (define-public _ gettext)
+ 
+ (define PLATFORM
+-- 
+1.7.1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/lilypond-midi2ly-preview.patch	Mon Jan 24 15:23:33 2011 +0100
@@ -0,0 +1,853 @@
+From 2005e201323314c8439d6aca062386c70c784294 Mon Sep 17 00:00:00 2001
+From: Jan Nieuwenhuizen <janneke@gnu.org>
+Date: Mon, 24 Jan 2011 14:15:36 +0100
+Subject: [PATCH 1/5] Midi2ly: Whitespace nits.
+
+---
+ scripts/midi2ly.py |  213 ++++++++++++++++++++++++++--------------------------
+ 1 files changed, 107 insertions(+), 106 deletions(-)
+
+diff --git a/scripts/midi2ly.py b/scripts/midi2ly.py
+index b03e1a8..43000c1 100644
+--- a/scripts/midi2ly.py
++++ b/scripts/midi2ly.py
+@@ -5,7 +5,7 @@
+ # This file is part of LilyPond, the GNU music typesetter.
+ #
+ # Copyright (C) 1998--2011  Han-Wen Nienhuys <hanwen@xs4all.nl>
+-#                 Jan Nieuwenhuizen <janneke@gnu.org>
++#                           Jan Nieuwenhuizen <janneke@gnu.org>
+ #
+ # LilyPond is free software: you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+@@ -87,7 +87,7 @@ def warranty ():
+ 
+ %s
+ %s
+-''' % ( _ ('Copyright (c) %s by') % '2001--2011',
++''' % ( _ ('Copyright (c) %s by') % '1998--2011',
+         '\n  '.join (authors),
+         _ ('Distributed under terms of the GNU General Public License.'),
+         _ ('It comes with NO WARRANTY.')))
+@@ -97,7 +97,7 @@ def progress (s):
+ 
+ def warning (s):
+     progress (_ ("warning: ") + s)
+-        
++
+ def error (s):
+     progress (_ ("error: ") + s)
+     raise Exception (_ ("Exiting... "))
+@@ -119,7 +119,7 @@ class Duration:
+         if clocks <= 0:
+             self.clocks = duration_quant_clocks
+         (self.dur, self.num, self.den) = self.dur_num_den (clocks)
+-        
++
+     def dur_num_den (self, clocks):
+         for i in range (len (allowed_tuplet_clocks)):
+             if clocks == allowed_tuplet_clocks[i]:
+@@ -143,7 +143,7 @@ class Duration:
+                 s = '%d*%d' % (self.dur, self.num)
+         else:
+             s = '%d*%d/%d' % (self.dur, self.num, self.den)
+-            
++
+         global reference_note
+         reference_note.duration = self
+ 
+@@ -246,10 +246,10 @@ class Note:
+             n = 6; a = 1; o = o - 1
+ 
+         return (o, n, a)
+-        
++
+     def __repr__ (self):
+         s = chr ((self.notename + 2)  % 7 + ord ('a'))
+-        return 'Note(%s %s)' % (s, self.duration.dump())
++        return 'Note(%s %s)' % (s, self.duration.dump ())
+ 
+     def dump (self, dump_dur = 1):
+         global reference_note
+@@ -260,25 +260,25 @@ class Note:
+         else:
+             delta = self.pitch - reference_note.pitch
+             commas = sign (delta) * (abs (delta) / 12)
+-            if ((sign (delta) \
+-              * (self.notename - reference_note.notename) + 7) \
+-              % 7 >= 4) \
+-              or ((self.notename == reference_note.notename) \
+-                and (abs (delta) > 4) and (abs (delta) < 12)):
++            if (((sign (delta)
++                  * (self.notename - reference_note.notename) + 7)
++                 % 7 >= 4)
++                or ((self.notename == reference_note.notename)
++                    and (abs (delta) > 4) and (abs (delta) < 12))):
+                 commas = commas + sign (delta)
+-            
++
+         if commas > 0:
+             s = s + "'" * commas
+         elif commas < 0:
+             s = s + "," * -commas
+ 
+         ## FIXME: compile fix --jcn
+-        if dump_dur and (global_options.explicit_durations \
+-         or self.duration.compare (reference_note.duration)):
++        if (dump_dur and (global_options.explicit_durations
++                          or self.duration.compare (reference_note.duration))):
+             s = s + self.duration.dump ()
+ 
+         reference_note = self
+-        
++
+         # TODO: move space
+         return s + ' '
+ 
+@@ -294,7 +294,7 @@ class Time:
+ 
+     def __repr__ (self):
+         return 'Time(%d/%d)' % (self.num, self.den)
+-    
++
+     def dump (self):
+         global time
+         time = self
+@@ -307,12 +307,12 @@ class Tempo:
+ 
+     def __repr__ (self):
+         return 'Tempo(%d)' % self.bpm ()
+-    
++
+     def bpm (self):
+         return 4 * 60 / self.seconds_per_1
+-    
++
+     def dump (self):
+-        return '\n  ' + '\\tempo 4 = %d ' % (self.bpm()) + '\n  '
++        return '\n  ' + '\\tempo 4 = %d ' % (self.bpm ()) + '\n  '
+ 
+ class Clef:
+     clefs = ('"bass_8"', 'bass', 'violin', '"violin^8"')
+@@ -321,7 +321,7 @@ class Clef:
+ 
+     def __repr__ (self):
+         return 'Clef(%s)' % self.clefs[self.type]
+-    
++
+     def dump (self):
+         return '\n  \\clef %s\n  ' % self.clefs[self.type]
+ 
+@@ -346,7 +346,7 @@ class Key:
+                 k = (ord ('cfbeadg'[self.flats % 7]) - ord ('a') - 2 -2 * self.minor + 7) % 7
+             else:
+                 k = (ord ('cgdaebf'[self.sharps % 7]) - ord ('a') - 2 -2 * self.minor + 7) % 7
+- 
++
+             if not self.minor:
+                 name = chr ((k + 2) % 7 + ord ('a'))
+             else:
+@@ -386,7 +386,7 @@ class Text:
+         'LYRIC',
+         'MARKER',
+         'CUE_POINT',)
+-    
++
+     def __init__ (self, type, text):
+         self.clocks = 0
+         self.type = type
+@@ -397,8 +397,8 @@ class Text:
+         if self.type == midi.LYRIC:
+             s = '"%s"' % self.text
+             d = Duration (self.clocks)
+-            if global_options.explicit_durations \
+-             or d.compare (reference_note.duration):
++            if (global_options.explicit_durations
++                or d.compare (reference_note.duration)):
+                 s = s + Duration (self.clocks).dump ()
+             s = s + ' '
+         else:
+@@ -412,9 +412,9 @@ class Text:
+ 
+ def split_track (track):
+     chs = {}
+-    for i in range(16):
++    for i in range (16):
+         chs[i] = []
+-        
++
+     for e in track:
+         data = list (e[1])
+         if data[0] > 0x7f and data[0] < 0xf0:
+@@ -452,7 +452,7 @@ def end_note (pitches, notes, t, e):
+         (lt, vel) = pitches[e]
+         del pitches[e]
+ 
+-        i = len (notes) - 1 
++        i = len (notes) - 1
+         while i > 0:
+             if notes[i][0] > lt:
+                 i = i -1
+@@ -484,20 +484,20 @@ def events_on_channel (channel):
+             t = quantise_clocks (t, start_quant_clocks)
+ 
+ 
+-        if e[1][0] == midi.NOTE_OFF \
+-         or (e[1][0] == midi.NOTE_ON and e[1][2] == 0):
++        if (e[1][0] == midi.NOTE_OFF
++            or (e[1][0] == midi.NOTE_ON and e[1][2] == 0)):
+             end_note (pitches, notes, t, e[1][1])
+-            
++
+         elif e[1][0] == midi.NOTE_ON:
+             if not pitches.has_key (e[1][1]):
+                 pitches[e[1][1]] = (t, e[1][2])
+-                
++
+         # all include ALL_NOTES_OFF
+-        elif e[1][0] >= midi.ALL_SOUND_OFF \
+-          and e[1][0] <= midi.POLY_MODE_ON:
++        elif (e[1][0] >= midi.ALL_SOUND_OFF
++          and e[1][0] <= midi.POLY_MODE_ON):
+             for i in pitches:
+                 end_note (pitches, notes, t, i)
+-                
++
+         elif e[1][0] == midi.META_EVENT:
+             if e[1][1] == midi.END_OF_TRACK:
+                 for i in pitches:
+@@ -511,7 +511,7 @@ def events_on_channel (channel):
+                 events.append ((t, Tempo (seconds_per_1)))
+             elif e[1][1] == midi.TIME_SIGNATURE:
+                 (num, dur, clocks4, count32) = map (ord, e[1][2])
+-                den = 2 ** dur 
++                den = 2 ** dur
+                 events.append ((t, Time (num, den)))
+             elif e[1][1] == midi.KEY_SIGNATURE:
+                 (alterations, minor) = map (ord, e[1][2])
+@@ -530,16 +530,16 @@ def events_on_channel (channel):
+                 # Better do Note.calc () at dump time?
+                 global_options.key = k
+ 
+-            elif e[1][1] == midi.LYRIC \
+-              or (global_options.text_lyrics and e[1][1] == midi.TEXT_EVENT):
++            elif (e[1][1] == midi.LYRIC
++                  or (global_options.text_lyrics and e[1][1] == midi.TEXT_EVENT)):
+                 if last_lyric:
+                     last_lyric.clocks = t - last_time
+                     events.append ((last_time, last_lyric))
+                 last_time = t
+                 last_lyric = Text (midi.LYRIC, e[1][2])
+ 
+-            elif e[1][1] >= midi.SEQUENCE_NUMBER \
+-              and e[1][1] <= midi.CUE_POINT:
++            elif (e[1][1] >= midi.SEQUENCE_NUMBER
++                  and e[1][1] <= midi.CUE_POINT):
+                 events.append ((t, Text (e[1][1], e[1][2])))
+             else:
+                 if global_options.verbose:
+@@ -556,7 +556,7 @@ def events_on_channel (channel):
+         last_lyric.clocks = clocks_per_4
+         events.append ((last_time, last_lyric))
+         last_lyric = 0
+-        
++
+     i = 0
+     while len (notes):
+         if i < len (events) and notes[0][0] >= events[i][0]:
+@@ -575,17 +575,17 @@ def unthread_notes (channel):
+         todo = []
+         for e in channel:
+             t = e[0]
+-            if e[1].__class__ == Note \
+-             and ((t == start_busy_t \
+-                and e[1].clocks + t == end_busy_t) \
+-              or t >= end_busy_t):
++            if (e[1].__class__ == Note
++                and ((t == start_busy_t
++                      and e[1].clocks + t == end_busy_t)
++                     or t >= end_busy_t)):
+                 thread.append (e)
+                 start_busy_t = t
+                 end_busy_t = t + e[1].clocks
+-            elif e[1].__class__ == Time \
+-              or e[1].__class__ == Key \
+-              or e[1].__class__ == Text \
+-              or e[1].__class__ == Tempo:
++            elif (e[1].__class__ == Time
++                  or e[1].__class__ == Key
++                  or e[1].__class__ == Text
++                  or e[1].__class__ == Tempo):
+                 thread.append (e)
+             else:
+                 todo.append (e)
+@@ -598,12 +598,12 @@ def gcd (a,b):
+     if b == 0:
+         return a
+     c = a
+-    while c: 
++    while c:
+         c = a % b
+         a = b
+         b = c
+     return a
+-    
++
+ def dump_skip (skip, clocks):
+     return skip + Duration (clocks).dump () + ' '
+ 
+@@ -629,7 +629,7 @@ def dump_chord (ch):
+             s = s + i.dump (dump_dur = 0 )
+         s = s + '>'
+ 
+-        s = s + notes[0].duration.dump() + ' '
++        s = s + notes[0].duration.dump () + ' '
+         reference_note = r
+     return s
+ 
+@@ -638,17 +638,17 @@ def dump_bar_line (last_bar_t, t, bar_count):
+     bar_t = time.bar_clocks ()
+     if t - last_bar_t >= bar_t:
+         bar_count = bar_count + (t - last_bar_t) / bar_t
+-        
++
+         if t - last_bar_t == bar_t:
+             s = '|\n  %% %d\n  ' % bar_count
+             last_bar_t = t
+         else:
+             # urg, this will barf at meter changes
+             last_bar_t = last_bar_t + (t - last_bar_t) / bar_t * bar_t
+-            
++
+     return (s, last_bar_t, bar_count)
+ 
+-            
++
+ def dump_channel (thread, skip):
+     global reference_note, time
+ 
+@@ -668,9 +668,9 @@ def dump_channel (thread, skip):
+         else:
+             if ch:
+                 chs.append ((last_e[0], ch))
+-                
++
+             ch = [e[1]]
+-            
++
+         last_e = e
+ 
+     if ch:
+@@ -679,9 +679,9 @@ def dump_channel (thread, skip):
+     last_t = 0
+     last_bar_t = 0
+     bar_count = 1
+-    
++
+     lines = ['']
+-    for ch in chs: 
++    for ch in chs:
+         t = ch[0]
+ 
+         i = lines[-1].rfind ('\n') + 1
+@@ -696,16 +696,16 @@ def dump_channel (thread, skip):
+         (s, last_bar_t, bar_count) = dump_bar_line (last_bar_t,
+                               t, bar_count)
+         lines[-1] = lines[-1] + s
+-        
++
+         lines[-1] = lines[-1] + dump_chord (ch[1])
+ 
+         clocks = 0
+         for i in ch[1]:
+             if i.clocks > clocks:
+                 clocks = i.clocks
+-                
++
+         last_t = t + clocks
+-        
++
+         (s, last_bar_t, bar_count) = dump_bar_line (last_bar_t,
+                               last_t, bar_count)
+         lines[-1] = lines[-1] + s
+@@ -771,10 +771,10 @@ def dump_track (channels, n):
+ def thread_first_item (thread):
+     for chord in thread:
+         for event in chord:
+-            if (event[1].__class__ == Note 
+-              or (event[1].__class__ == Text 
++            if (event[1].__class__ == Note
++              or (event[1].__class__ == Text
+                 and event[1].type == midi.LYRIC)):
+-                
++
+               return event[1]
+     return None
+ 
+@@ -802,20 +802,20 @@ def guess_clef (track):
+         return Clef (3)
+     else:
+         return Clef (2)
+-    
++
+ 
+ def convert_midi (in_file, out_file):
+     global clocks_per_1, clocks_per_4, key
+     global start_quant_clocks
+-    global  duration_quant_clocks
++    global duration_quant_clocks
+     global allowed_tuplet_clocks
+ 
+     str = open (in_file, 'rb').read ()
+     midi_dump = midi.parse (str)
+-    
++
+     clocks_per_1 = midi_dump[0][1]
+     clocks_per_4 = clocks_per_1 / 4
+-    
++
+     if global_options.start_quant:
+         start_quant_clocks = clocks_per_1 / global_options.start_quant
+ 
+@@ -833,19 +833,19 @@ def convert_midi (in_file, out_file):
+ 
+     tag = '%% Lily was here -- automatically converted by %s from %s' % ( program_name, in_file)
+ 
+-    
++
+     s = ''
+     s = tag + '\n\\version "2.7.38"\n\n'
+     for i in range (len (tracks)):
+         s = s + dump_track (tracks[i], i)
+ 
+     s = s + '\n\\score {\n  <<\n'
+-    
++
+     i = 0
+     for t in tracks:
+         track = track_name (i)
+         item = track_first_item (t)
+-        
++
+         if item and item.__class__ == Note:
+             s = s + '    \\context Staff=%s \\%s\n' % (track, track)
+         elif item and item.__class__ == Text:
+@@ -872,44 +872,44 @@ def get_option_parser ():
+ 
+     p.add_option ('-a', '--absolute-pitches',
+            action='store_true',
+-           help=_ ("print absolute pitches"))
++           help=_ ('print absolute pitches'))
+     p.add_option ('-d', '--duration-quant',
+-           metavar= _("DUR"),
+-           help=_ ("quantise note durations on DUR"))
++           metavar=_ ('DUR'),
++           help=_ ('quantise note durations on DUR'))
+     p.add_option ('-e', '--explicit-durations',
+            action='store_true',
+-           help=_ ("print explicit durations"))
+-    p.add_option("-h", "--help",
+-                 action="help",
+-                 help=_ ("show this help and exit"))
+-    p.add_option('-k', '--key', help=_ ("set key: ALT=+sharps|-flats; MINOR=1"),
+-          metavar=_ ("ALT[:MINOR]"),
++           help=_ ('print explicit durations'))
++    p.add_option('-h', '--help',
++                 action='help',
++                 help=_ ('show this help and exit'))
++    p.add_option('-k', '--key', help=_ ('set key: ALT=+sharps|-flats; MINOR=1'),
++          metavar=_ ('ALT[:MINOR]'),
+           default='0'),
+-    p.add_option ('-o', '--output', help=_ ("write output to FILE"),
+-           metavar=_("FILE"),
++    p.add_option ('-o', '--output', help=_ ('write output to FILE'),
++           metavar=_('FILE'),
+            action='store')
+-    p.add_option ('-s', '--start-quant',help= _ ("quantise note starts on DUR"),
+-           metavar=_ ("DUR"))
++    p.add_option ('-s', '--start-quant',help= _ ('quantise note starts on DUR'),
++           metavar=_ ('DUR'))
+     p.add_option ('-t', '--allow-tuplet',
+-           metavar=_ ("DUR*NUM/DEN"),
+-           action = "append",
+-           dest="allowed_tuplets",
+-           help=_ ("allow tuplet durations DUR*NUM/DEN"),
++           metavar=_ ('DUR*NUM/DEN'),
++           action = 'append',
++           dest='allowed_tuplets',
++           help=_ ('allow tuplet durations DUR*NUM/DEN'),
+            default=[])
+-    p.add_option ('-V', '--verbose', help=_ ("be verbose"),
++    p.add_option ('-V', '--verbose', help=_ ('be verbose'),
+            action='store_true'
+            ),
+-    p.version = "midi2ly (LilyPond) @TOPLEVEL_VERSION@"
+-    p.add_option("--version",
+-                 action="version",
+-                 help=_ ("show version number and exit"))
+-    p.add_option ('-w', '--warranty', help=_ ("show warranty and copyright"),
++    p.version = 'midi2ly (LilyPond) @TOPLEVEL_VERSION@'
++    p.add_option ('--version',
++                 action='version',
++                 help=_ ('show version number and exit'))
++    p.add_option ('-w', '--warranty', help=_ ('show warranty and copyright'),
+            action='store_true',
+            ),
+-    p.add_option ('-x', '--text-lyrics', help=_ ("treat every text as a lyric"),
++    p.add_option ('-x', '--text-lyrics', help=_ ('treat every text as a lyric'),
+            action='store_true')
+ 
+-    p.add_option_group (ly.display_encode (_ ("Examples")),
++    p.add_option_group (ly.display_encode (_ ('Examples')),
+               description = r'''
+   $ midi2ly --key=-2:1 --duration-quant=32 --allow-tuplet=4*2/3 --allow-tuplet=2*4/3 foo.midi
+ ''')
+@@ -923,13 +923,13 @@ def get_option_parser ():
+ 
+ 
+ def do_options ():
+-    opt_parser = get_option_parser()
++    opt_parser = get_option_parser ()
+     (options, args) = opt_parser.parse_args ()
+ 
+     if not args or args[0] == '-':
+         opt_parser.print_help ()
+-        ly.stderr_write ('\n%s: %s %s\n' % (program_name, _ ("error: "),
+-                         _ ("no files specified on command line.")))
++        ly.stderr_write ('\n%s: %s %s\n' % (program_name, _ ('error: '),
++                         _ ('no files specified on command line.')))
+         sys.exit (2)
+ 
+     if options.duration_quant:
+@@ -949,20 +949,20 @@ def do_options ():
+ 
+         options.key = Key (sharps, flats, minor)
+ 
+-        
++
+     if options.start_quant:
+         options.start_quant = int (options.start_quant)
+-        
++
+     options.allowed_tuplets = [map (int, a.replace ('/','*').split ('*'))
+                 for a in options.allowed_tuplets]
+-    
++
+     global global_options
+     global_options = options
+ 
+     return args
+ 
+-def main():
+-    files = do_options()
++def main ():
++    files = do_options ()
+ 
+     for f in files:
+         g = f
+@@ -990,5 +990,6 @@ def main():
+                 pass
+ 
+         convert_midi (f, o)
++
+ if __name__ == '__main__':
+-    main()
++    main ()
+-- 
+1.7.1
+
+From 7b3a9b122d7ef1eb70fdabaac466b7b0c23a1df2 Mon Sep 17 00:00:00 2001
+From: Jan Nieuwenhuizen <janneke@gnu.org>
+Date: Mon, 24 Jan 2011 14:29:37 +0100
+Subject: [PATCH 2/5] Midi2ly: add --preview option.
+
+---
+ scripts/midi2ly.py |   23 +++++++++++++++++------
+ 1 files changed, 17 insertions(+), 6 deletions(-)
+
+diff --git a/scripts/midi2ly.py b/scripts/midi2ly.py
+index 43000c1..1b3723e 100644
+--- a/scripts/midi2ly.py
++++ b/scripts/midi2ly.py
+@@ -62,7 +62,7 @@ start_quant_clocks = 0
+ 
+ duration_quant_clocks = 0
+ allowed_tuplet_clocks = []
+-
++bar_max = 0
+ 
+ ################################################################
+ 
+@@ -689,14 +689,20 @@ def dump_channel (thread, skip):
+             lines.append ('')
+ 
+         if t - last_t > 0:
+-            lines[-1] = lines[-1] + dump_skip (skip, t-last_t)
++            d = t - last_t
++            if bar_max and t > time.bar_clocks () * bar_max:
++                d = time.bar_clocks () * bar_max - last_t
++            lines[-1] = lines[-1] + dump_skip (skip, d)
+         elif t - last_t < 0:
+             errorport.write ('BUG: time skew')
+ 
+         (s, last_bar_t, bar_count) = dump_bar_line (last_bar_t,
+                               t, bar_count)
+-        lines[-1] = lines[-1] + s
+ 
++        if bar_max and bar_count > bar_max:
++            break
++
++        lines[-1] = lines[-1] + s
+         lines[-1] = lines[-1] + dump_chord (ch[1])
+ 
+         clocks = 0
+@@ -707,7 +713,7 @@ def dump_channel (thread, skip):
+         last_t = t + clocks
+ 
+         (s, last_bar_t, bar_count) = dump_bar_line (last_bar_t,
+-                              last_t, bar_count)
++                                                    last_t, bar_count)
+         lines[-1] = lines[-1] + s
+ 
+     return '\n  '.join (lines) + '\n'
+@@ -886,8 +892,10 @@ def get_option_parser ():
+           metavar=_ ('ALT[:MINOR]'),
+           default='0'),
+     p.add_option ('-o', '--output', help=_ ('write output to FILE'),
+-           metavar=_('FILE'),
++           metavar=_ ('FILE'),
+            action='store')
++    p.add_option ('-p', '--preview', help=_ ('preview of first 4 bars'),
++           action='store_true')
+     p.add_option ('-s', '--start-quant',help= _ ('quantise note starts on DUR'),
+            metavar=_ ('DUR'))
+     p.add_option ('-t', '--allow-tuplet',
+@@ -949,10 +957,13 @@ def do_options ():
+ 
+         options.key = Key (sharps, flats, minor)
+ 
+-
+     if options.start_quant:
+         options.start_quant = int (options.start_quant)
+ 
++    global bar_max
++    if options.preview:
++        bar_max = 4
++
+     options.allowed_tuplets = [map (int, a.replace ('/','*').split ('*'))
+                 for a in options.allowed_tuplets]
+ 
+-- 
+1.7.1
+
+From 7a2766a80beb907df0b291584c1a84b6b4fe4c4f Mon Sep 17 00:00:00 2001
+From: Jan Nieuwenhuizen <janneke@gnu.org>
+Date: Mon, 24 Jan 2011 14:30:37 +0100
+Subject: [PATCH 3/5] Midi2ly: bug fix for --allow-tuplets.
+
+---
+ scripts/midi2ly.py |    8 +++++++-
+ 1 files changed, 7 insertions(+), 1 deletions(-)
+
+diff --git a/scripts/midi2ly.py b/scripts/midi2ly.py
+index 1b3723e..afe5c5a 100644
+--- a/scripts/midi2ly.py
++++ b/scripts/midi2ly.py
+@@ -830,7 +830,10 @@ def convert_midi (in_file, out_file):
+ 
+     allowed_tuplet_clocks = []
+     for (dur, num, den) in global_options.allowed_tuplets:
+-        allowed_tuplet_clocks.append (clocks_per_1 / den)
++        allowed_tuplet_clocks.append (clocks_per_1 / dur * num / den)
++
++    if global_options.verbose:
++        print 'allowed tuplet clocks:', allowed_tuplet_clocks
+ 
+     tracks = []
+     for t in midi_dump[1]:
+@@ -967,6 +970,9 @@ def do_options ():
+     options.allowed_tuplets = [map (int, a.replace ('/','*').split ('*'))
+                 for a in options.allowed_tuplets]
+ 
++    if options.verbose:
++        sys.stderr.write ('Allowed tuplets: %s\n' % `options.allowed_tuplets`)
++
+     global global_options
+     global_options = options
+ 
+-- 
+1.7.1
+
+From a013e110e10a1531521d73455b89bd0b00fbf3d0 Mon Sep 17 00:00:00 2001
+From: Jan Nieuwenhuizen <janneke@gnu.org>
+Date: Mon, 24 Jan 2011 15:13:05 +0100
+Subject: [PATCH 4/5] midi.c: resurrect debug printing.
+
+---
+ python/midi.c |   11 ++++++-----
+ 1 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/python/midi.c b/python/midi.c
+index 4e6368a..2ec5224 100644
+--- a/python/midi.c
++++ b/python/midi.c
+@@ -60,7 +60,8 @@ compat_itoa (int i)
+ #if 0
+ int x = 0;
+ int *track = &x;
+-#define debug_print(f, args...) fprintf (stderr, "%s:%d: track: %p :" f, __FUNCTION__, __LINE__, *track, ##args)
++#define urg_debug_print(f, args...) fprintf (stderr, "%s:%d: track: %p: " f, __FUNCTION__, __LINE__, *track, ##args)
++#define debug_print(f, args...) fprintf (stderr, f, ##args)
+ #else
+ #define debug_print(f, args...)
+ #endif
+@@ -161,7 +162,7 @@ get_number (unsigned char ** str, unsigned char * end_str, int length)
+     sum = (sum << 8) + (unsigned char) (*str)[i];
+ 
+   *str += length;
+-  debug_print ("%d:\n", sum);
++  debug_print ("%ld:\n", sum);
+   return sum;
+ }
+ 
+@@ -178,7 +179,7 @@ get_variable_length_number (unsigned char **str, unsigned char * end_str)
+       if (!(x & 0x80))
+ 	break;
+     }
+-  debug_print ("%d:\n", sum);
++  debug_print ("%ld:\n", sum);
+   return sum;
+ }
+ 
+@@ -312,8 +313,8 @@ midi_parse_track (unsigned char **track, unsigned char *track_end)
+ 
+   track_len = get_number (track, *track + 4, 4);
+ 
+-  debug_print ("track_len: %u\n", track_len);
+-  debug_print ("track_size: %u\n", track_size);
++  debug_print ("track_len: %lu\n", track_len);
++  debug_print ("track_size: %lu\n", track_size);
+   debug_print ("track begin: %p\n", track);
+   debug_print ("track end: %p\n", track + track_len);
+   
+-- 
+1.7.1
+
+From 0996f6663b2635491b5efa385e0e3a581fb96292 Mon Sep 17 00:00:00 2001
+From: Jan Nieuwenhuizen <janneke@gnu.org>
+Date: Mon, 24 Jan 2011 15:17:10 +0100
+Subject: [PATCH 5/5] Midi2ly: in --preview mode, only parse first eight 4/4 bars (12288 clocks).
+
+---
+ python/midi.c      |   26 +++++++++++++++-----------
+ scripts/midi2ly.py |    3 ++-
+ 2 files changed, 17 insertions(+), 12 deletions(-)
+
+diff --git a/python/midi.c b/python/midi.c
+index 2ec5224..187268b 100644
+--- a/python/midi.c
++++ b/python/midi.c
+@@ -292,7 +292,7 @@ read_event (unsigned char **track, unsigned char *end, PyObject *time,
+ }
+ 
+ static PyObject *
+-midi_parse_track (unsigned char **track, unsigned char *track_end)
++midi_parse_track (unsigned char **track, unsigned char *track_end, int clocks_max)
+ {
+   unsigned int time = 0;
+   unsigned long track_len, track_size;
+@@ -338,7 +338,8 @@ midi_parse_track (unsigned char **track, unsigned char *track_end)
+ 	time += dt;
+ 	if (dt)
+ 	  pytime = PyInt_FromLong (time);
+-
++	if (clocks_max && time > clocks_max)
++	  break;
+ 	pyev = read_event (track, track_end, pytime,
+ 			   &running_status);
+ 	if (pyev)
+@@ -356,21 +357,23 @@ pymidi_parse_track (PyObject *self, PyObject *args)
+ {
+   unsigned char *track, *track_end;
+   unsigned long track_size;
++  int clocks_max;
+ 
+   debug_print ("%s", "\n");
+-  if (!PyArg_ParseTuple (args, "s#", &track, &track_size))
++  if (!PyArg_ParseTuple (args, "s#|i", &track, &track_size, &clocks_max))
+     return 0;
++  debug_print ("clocks_max: %d\n", clocks_max);
+ 
+   if (track_size < 0)
+     return midi_error (__FUNCTION__,   ": negative track size: ", compat_itoa (track_size));
+ 
+   track_end = track + track_size;
+   
+-  return midi_parse_track (&track, track_end);
++  return midi_parse_track (&track, track_end, clocks_max);
+ }
+ 
+ static PyObject *
+-midi_parse (unsigned char **midi,unsigned  char *midi_end)
++midi_parse (unsigned char **midi,unsigned  char *midi_end, int clocks_max)
+ {
+   PyObject *pymidi = 0;
+   unsigned long header_len;
+@@ -404,7 +407,7 @@ midi_parse (unsigned char **midi,unsigned  char *midi_end)
+ 
+   /* Tracks */
+   for (i = 0; i < tracks; i++)
+-    PyList_Append (pymidi, midi_parse_track (midi, midi_end));
++    PyList_Append (pymidi, midi_parse_track (midi, midi_end, clocks_max));
+ 
+   pymidi = Py_BuildValue ("(OO)", Py_BuildValue ("(ii)", format, division),
+ 			  pymidi);
+@@ -416,10 +419,12 @@ pymidi_parse (PyObject *self, PyObject *args)
+ {
+   unsigned char *midi, *midi_end;
+   unsigned long midi_size;
++  int clocks_max;
+   
+   debug_print ("%s", "\n");
+-  if (!PyArg_ParseTuple (args, "s#", &midi, &midi_size))
++  if (!PyArg_ParseTuple (args, "s#|i", &midi, &midi_size, &clocks_max))
+     return 0;
++  debug_print ("clocks_max: %d\n", clocks_max);
+ 
+   if (memcmp (midi, "MThd", 4))
+     {
+@@ -431,14 +436,13 @@ pymidi_parse (PyObject *self, PyObject *args)
+ 
+   midi_end = midi + midi_size;
+ 
+-  return midi_parse (&midi, midi_end);
++  return midi_parse (&midi, midi_end, clocks_max);
+ }
+ 
+-
+ static PyMethodDef MidiMethods[] = 
+ {
+-  {"parse",  pymidi_parse, 1},
+-  {"parse_track",  pymidi_parse_track, 1},
++  {"parse",  pymidi_parse, METH_VARARGS},
++  {"parse_track",  pymidi_parse_track, METH_VARARGS},
+   {0, 0}        /* Sentinel */
+ };
+ 
+diff --git a/scripts/midi2ly.py b/scripts/midi2ly.py
+index afe5c5a..9ce050b 100644
+--- a/scripts/midi2ly.py
++++ b/scripts/midi2ly.py
+@@ -817,7 +817,8 @@ def convert_midi (in_file, out_file):
+     global allowed_tuplet_clocks
+ 
+     str = open (in_file, 'rb').read ()
+-    midi_dump = midi.parse (str)
++    clocks_max = bar_max * clocks_per_1 * 2
++    midi_dump = midi.parse (str, clocks_max)
+ 
+     clocks_per_1 = midi_dump[0][1]
+     clocks_per_4 = clocks_per_1 / 4
+-- 
+1.7.1
+