--- abcmidi-20070318.orig/abcmatch.c
+++ abcmidi-20070318/abcmatch.c
@@ -132,7 +132,7 @@
 float fract;
 int i;
 int skip_rests,multiplier,inchord,ingrace;
-int maxpitch;
+int maxpitch = -9999;
 *nnotes = 0;
 *nbars  = 0;
 inchord = 0;
@@ -392,6 +392,7 @@
 int changes;
 int last_sample;
 if (mmsamples != isamples) return -1;
+i = 0;
 dif = 0;
 changes = 0;
 last_sample = ipitch_samples[i];
@@ -683,10 +684,10 @@
 {
   char *filename;
   int i,j;
-  int ikey,mkey;
+  int ikey,mkey = 0;
   int moffset;
   int transpose;
-  int mseqno;
+  int mseqno = 0;
   /* sequence number of template (match.abc) 
    * mseqno can differ from xrefnum when running count_matched_tune_bars
    * because there is no guarantee the xref numbers are in
@@ -717,6 +718,7 @@
       &mtimesig_num, &mtimesig_denom,mbarlineptr,mnotelength,mmidipitch);
 
   /* trim off any initial bar lines */
+  j = 0;
   for (i=0;i<mnbars;i++)
     {
     j = i;
--- abcmidi-20070318.orig/midifile.c
+++ abcmidi-20070318/midifile.c
@@ -63,7 +63,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#ifdef ANSILIBS
+#if defined(ANSILIBS) || defined(__STDC__)
 #include <string.h>
 #include <stdlib.h>
 #else
@@ -73,6 +73,22 @@
 /* int exit(), free(); */ /* Line commmented out JRA 19/12/95 */
 
 /* public stuff */
+static int readtrack();
+static void readheader();
+static void badbyte();
+static void metaevent();
+static void sysex();
+static void chanmessage();
+static void msginit();
+static void msgadd();
+static void biggermsg();
+static void mf_write_track_chunk();
+static void mf_write_header_chunk();
+static void WriteVarLen();
+static void write32bit();
+static void write16bit();
+static int msgleng();
+static int eputc();
 
 /* Functions to be called while processing the MIDI file. */
 int (*Mf_getc)() = NULLFUNC;
@@ -172,7 +188,7 @@
 {
   int n = 0;
   char *p = s;
-  int c;
+  int c = EOF;
 
   while ( n++<4 && (c=(*Mf_getc)()) != EOF ) {
     if ( c != *p++ ) {
@@ -687,7 +703,7 @@
 {
   long trkhdr,trklength;
   long offset, place_marker;
-  long endspace;
+  long endspace = 0L;
 
 /* There is an alternate version of this code selected by NOFTELL
    which doesn't require use of file seek */
--- abcmidi-20070318.orig/store.c
+++ abcmidi-20070318/store.c
@@ -65,7 +65,7 @@
 #define strchr index
 #endif
 
-#ifdef ANSILIBS
+#if defined(ANSILIBS) || defined(__STDC__)
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -73,7 +73,7 @@
 extern char* strchr();
 extern void reduce();
 #endif
-/*int snprintf(char *str, size_t size, const char *format, ...);*/
+int snprintf(char *str, size_t size, const char *format, ...);
 
 
 #define MAXLINE 500
@@ -1767,7 +1767,7 @@
   int i, j;
   int stackptr;
   char* stack[10];
-  char lastch;
+  char lastch = 0;
 
   stackptr = 0;
   in = spec;
@@ -2103,7 +2103,8 @@
   };
 }
 
-
+/* This function is never actually used */
+#if 0
 static void slurtotie()
 /* converts a pair of identical slurred notes to tied notes */
 {
@@ -2158,6 +2159,7 @@
     };
   };
 }
+#endif
 
 void event_sluron(t)
 /* called when ( is encountered in the abc */
@@ -2295,6 +2297,8 @@
   };
 }
 
+/* This function is never actually used. */
+#if 0
 static void applybroken(place, type, n)
 int place, type, n;
 /* adjust lengths of broken notes */
@@ -2424,6 +2428,7 @@
     };
   };
 }
+#endif
 
 static void brokenadjust()
 /* adjust lengths of broken notes */
@@ -2433,6 +2438,8 @@
   int failed;
 
   switch(v->brokenmult) {
+    default:
+      event_error("unknown type of broken rhythm");
     case 1:
       num1 = ratio_b;
       num2 = ratio_a;
@@ -3540,7 +3547,7 @@
 {
   int j;
   int inchord;
-  int chord_num, chord_denom;
+  int chord_num = 1, chord_denom = 1;
   int chord_start,chord_end;
   int voiceno;
 
@@ -3586,14 +3593,14 @@
       j = j + 1;
       break;
     case TIE:
-/*
+#if 0
       if (chord_end+1 == j) { /* did a TIE connect with a chord */
 	      /* removefeature(j);
-	       patchup and backtrack/
+	       patchup and backtrack */
 	      j = patchup_chordtie(chord_start,chord_end);
 	      inchord=1;
               }
-*/
+#endif 
       dotie(j, inchord,voiceno);
       j = j + 1;
       break;
@@ -3632,7 +3639,6 @@
  */
 {
   int start, end, p;
-  int next_num, next_denom;
   int fact_num, fact_denom;
   int grace_num, grace_denom;
   int j;
@@ -3690,6 +3696,7 @@
   if (hostnotestart == -1) {
     event_error("No note found to follow grace notes");
   } else {
+    int next_num = 1, next_denom = 1;
     /* count up grace units */
     grace_num = 0;
     grace_denom = 1;
@@ -3934,7 +3941,8 @@
  }
 }
 
-
+/* This function is never actually used */
+#if 0
 static void delendrep(j)
 int j;
 /* remove bogus repeat */
@@ -3953,6 +3961,7 @@
     break;
   };
 }
+#endif
 
 static void placeendrep(j)
 /* patch up missing repeat */
@@ -4010,7 +4019,7 @@
 /* This can be converted to |: if necessary. */
 {
   int j;
-  int rep_point; /* where to assume a repeat starts */
+  int rep_point = 0; /* where to assume a repeat starts */
   int expect_repeat;   /* = 1 after |: or ::  otherwise 0*/
   int use_next; /* if 1 set next bar line as ref_point */
   int nplays; /* counts PLAY_ON_REP associated with a BAR_REP*/
--- abcmidi-20070318.orig/midifile.h
+++ abcmidi-20070318/midifile.h
@@ -34,26 +34,10 @@
 long mf_sec2ticks();
 void mfwrite();
 void mfread();
-static int readtrack();
 int mf_write_meta_event();
 int mf_write_midi_event();
 void mf_write_tempo();
-static void readheader();
 void mferror();
-static void badbyte();
-static void metaevent();
-static void sysex();
-static void chanmessage();
-static void msginit();
-static void msgadd();
-static void biggermsg();
-static void mf_write_track_chunk();
-static void mf_write_header_chunk();
-static void WriteVarLen();
-static void write32bit();
-static void write16bit();
-static int msgleng();
-static int eputc();
 
 /* MIDI status commands most significant bit is 1 */
 #define note_off         	0x80
--- abcmidi-20070318.orig/midi2abc.c
+++ abcmidi-20070318/midi2abc.c
@@ -1,3507 +1,3506 @@
-/*
- * midi2abc - program to convert MIDI files to abc notation.
- * Copyright (C) 1998 James Allwright
- * e-mail: J.R.Allwright@westminster.ac.uk
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/* new midi2abc - converts MIDI file to abc format files
- * 
- *
- * re-written to use dynamic data structures 
- *              James Allwright
- *               5th June 1998
- *
- * added output file option -o
- * added summary option -sum
- * added option -u to enter xunit directly
- * fixed computation of xunit using -b option
- * added -obpl (one bar per line) option
- * add check for carriage return embedded inside midi text line
- *                Seymour Shlien  04/March/00
- * made to conform as much as possible to the official version.
- * check for drum track added
- * when midi program channel is command encountered, we ensure that 
- * we are using the correct channel number for the Voice by sending
- * a %%MIDI channel message.
- *
- * Many more changes (see doc/CHANGES) 
- *
- *                Seymour Shlien  2005
- * 
- * based on public domain 'midifilelib' package.
- */
-
-#define VERSION "2.90 March 15 2007"
-#define SPLITCODE
-
-/* Microsoft Visual C++ Version 6.0 or higher */
-#ifdef _MSC_VER
-#define ANSILIBS
-#endif
-
-#include <stdio.h>
-#ifdef PCCFIX
-#define stdout 1
-#endif
-
-/* define USE_INDEX if your C libraries have index() instead of strchr() */
-#ifdef USE_INDEX
-#define strchr index
-#endif
-
-#ifdef ANSILIBS
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#else
-extern char* malloc();
-extern char* strchr();
-#endif
-#include "midifile.h"
-#define BUFFSIZE 200
-/* declare MIDDLE C */
-#define MIDDLE 72
-void initfuncs();
-void setupkey(int);
-int testtrack(int trackno, int barbeats, int anacrusis);
-int open_note(int chan, int pitch, int vol);
-int close_note(int chan, int pitch, int *initvol);
-
-
-/* Global variables and structures */
-
-extern long Mf_toberead;
-
-static FILE *F;
-static FILE *outhandle; /* for producing the abc file */
-
-int tracknum=0;  /* track number */
-int division;    /* pulses per quarter note defined in MIDI header    */
-long tempo = 500000; /* the default tempo is 120 quarter notes/minute */
-int unitlen;     /* abc unit length usually defined in L: field       */
-int header_unitlen; /* first unitlen set                              */
-int unitlen_set =0; /* once unitlen is set don't allow it to change   */
-int parts_per_unitlen = 2; /* specifies minimum quantization size */
-long laston = 0; /* length of MIDI track in pulses or ticks           */
-char textbuff[BUFFSIZE]; /*buffer for handling text output to abc file*/
-int trans[256], back[256]; /*translation tables for MIDI pitch to abc note*/
-char atog[256]; /* translation tables for MIDI pitch to abc note */
-int symbol[256]; /*translation tables for MIDI pitch to abc note */
-int key[12];
-int sharps;
-int trackno, maintrack;
-int format; /* MIDI file type                                   */
-
-int karaoke, inkaraoke;
-int midline;
-int tempocount=0;  /* number of tempo indications in MIDI file */
-int gotkeysig=0; /*set to 1 if keysignature found in MIDI file */
-
-/* global parameters that may be set by command line options    */
-int xunit;    /* pulses per abc unit length                     */
-int tsig_set; /* flag - time signature already set by user      */
-int ksig_set; /* flag - key signature already set by user       */
-int xunit_set;/* flat - xunit already set by user               */
-int extracta; /* flag - get anacrusis from strong beat          */
-int guessu;   /* flag - estimate xunit from note durations      */
-int guessa;   /* flag - get anacrusis by minimizing tied notes  */
-int guessk;   /* flag - guess key signature                     */
-int summary;  /* flag - output summary info of MIDI file        */
-int keep_short; /*flag - preserve short notes                   */
-int swallow_rests; /* flag - absorb short rests                 */
-int midiprint; /* flag - run midigram instead of midi2abc       */
-#ifdef SPLITCODE
-int usesplits; /* flag - split measure into parts if needed     */
-#endif
-int restsize; /* smallest rest to absorb                        */
-int no_triplets; /* flag - suppress triplets or broken rhythm   */
-int obpl = 0; /* flag to specify one bar per abc text line      */
-int nogr = 0; /* flag to put a space between every note         */
-int bars_per_line=4;  /* number of bars per output line         */
-int bars_per_staff=4; /* number of bars per music staff         */
-int asig, bsig;  /* time signature asig/bsig                    */
-int header_asig =0; /* first time signature encountered         */
-int header_bsig =0; /* first time signature encountered         */
-int header_bb;      /* first ticks/quarter note encountered     */
-int active_asig,active_bsig;  /* last time signature declared   */
-int last_asig, last_ksig; /* last time signature printed        */
-int barsize; /* barsize in parts_per_unitlen units                   */
-int Qval;        /* tempo - quarter notes per minute            */
-int verbosity=0; /* control amount of detail messages in abcfile*/
-
-/* global arguments dependent on command line options or computed */
-
-int anacrusis=0; 
-int bars;
-int keysig;
-int header_keysig=  -50;  /* header key signature                     */
-int active_keysig = -50;  /* last key signature declared        */
-int xchannel;  /* channel number to be extracted. -1 means all  */
-
-
-/* structure for storing music notes */
-struct anote {
-  int pitch;  /* MIDI pitch    */
-  int chan;   /* MIDI channel  */
-  int vel;    /* MIDI velocity */
-  long time;  /* MIDI onset time in pulses */
-  long dtnext; /* time increment to next note in pulses */
-  long tplay;  /* note duration in pulses */
-  int xnum;    /* number of xunits to next note */
-  int playnum; /* note duration in number of xunits */
-  int posnum; /* note position in xunits */
-  int splitnum; /* voice split number */
-  /* int denom; */
-};
-
-
-/* linked list of notes */
-struct listx {
-  struct listx* next;
-  struct anote* note;
-};
-
-/* linked list of text items (strings) */
-struct tlistx {
-  struct tlistx* next;
-  char* text;
-  long when; 	/* time in pulses to output */
-  int type;     /* 0 - comments, other - field commands */
-};
-
-
-/* a MIDI track */
-struct atrack {
-  struct listx* head;    /* first note */
-  struct listx* tail;    /* last note */
-  struct tlistx* texthead; /* first text string */
-  struct tlistx* texttail; /* last text string */
-  int notes;             /* number of notes in track */
-  long tracklen;
-  long startwait;
-  int startunits;
-  int drumtrack;
-};
-
-/* can cope with up to 64 track MIDI files */
-struct atrack track[64];
-int trackcount = 0;
-int maxbarcount = 0;
-/* maxbarcount  is used to return the numbers of bars created.*/
-/* obpl is a flag for one bar per line. */
-
-/* double linked list of notes */
-/* used for temporary list of chords while abc is being generated */
-struct dlistx {
-  struct dlistx* next;
-  struct dlistx* last;
-  struct anote* note;
-};
-
-int notechan[2048],notechanvol[2048]; /*for linking on and off midi
-					channel commands            */
-int last_tick; /* for getting last pulse number in MIDI file */
-
-
-
-void remove_carriage_returns();
-int validnote();
-void printpitch(struct anote*);
-void printfract(int, int);
-
-
-
-
-
-/*              Stage 1. Parsing MIDI file                   */
-
-/* Functions called during the reading pass of the MIDI file */
-
-/* The following C routines are required by midifilelib.  */
-/* They specify the action to be taken when various items */
-/* are encountered in the MIDI.  The mfread function scans*/
-/* the MIDI file and calls these functions when needed.   */
-
-
-int filegetc()
-{
-    return(getc(F));
-}
-
-
-void fatal_error(s)
-char* s;
-/* fatal error encounterd - abort program */
-{
-  fprintf(stderr, "%s\n", s);
-  exit(1);
-}
-
-
-void event_error(s)
-char *s;
-/* problem encountered but OK to continue */
-{
-  char msg[256];
-
-  sprintf(msg, "Error: Time=%ld Track=%d %s\n", Mf_currtime, trackno, s);
-  printf(msg);
-}
-
-
-int* checkmalloc(bytes)
-/* malloc with error checking */
-int bytes;
-{
-  int *p;
-
-  p = (int*) malloc(bytes);
-  if (p == NULL) {
-    fatal_error("Out of memory error - cannot malloc!");
-  };
-  return (p);
-}
-
-
-
-char* addstring(s)
-/* create space for string and store it in memory */
-char* s;
-{
-  char* p;
-
-  p = (char*) checkmalloc(strlen(s)+1);
-  strcpy(p, s);
-  return(p);
-}
-
-void addtext(s, type)
-/* add structure for text */
-/* used when parsing MIDI file */
-char* s;
-int type;
-{
-  struct tlistx* newx;
-
-  newx = (struct tlistx*) checkmalloc(sizeof(struct tlistx));
-  newx->next = NULL;
-  newx->text = addstring(s);
-  newx->type = type;
-  newx->when = Mf_currtime;
-  if (track[trackno].texthead == NULL) {
-    track[trackno].texthead = newx;
-    track[trackno].texttail = newx;
-  }
-  else {
-    track[trackno].texttail->next = newx;
-    track[trackno].texttail = newx;
-  };
-}
-  
-
-
-/* The MIDI file has  separate commands for starting                 */
-/* and stopping a note. In order to determine the duration of        */
-/* the note it is necessary to find the note_on command associated   */
-/* with the note off command. We rely on the note's pitch and channel*/
-/* number to find the right note. While we are parsing the MIDI file */
-/* we maintain a list of all the notes that are currently on         */
-/* head and tail of list of notes still playing.                     */
-/* The following doubly linked list is used for this purpose         */
-
-struct dlistx* playinghead;
-struct dlistx* playingtail; 
-
-
-void noteplaying(p)
-/* This function adds a new note to the playinghead list. */
-struct anote* p;
-{
-  struct dlistx* newx;
-
-  newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx));
-  newx->note = p;
-  newx->next = NULL;
-  newx->last = playingtail;
-  if (playinghead == NULL) {
-    playinghead = newx;
-  };
-  if (playingtail == NULL) {
-    playingtail = newx;
-  } 
-  else {
-    playingtail->next = newx;
-    playingtail = newx;
-  };
-}
-
-
-void addnote(p, ch, v)
-/* add structure for note */
-/* used when parsing MIDI file */
-int p, v;
-{
-  struct listx* newx;
-  struct anote* newnote;
-
-  track[trackno].notes = track[trackno].notes + 1;
-  newx = (struct listx*) checkmalloc(sizeof(struct listx));
-  newnote = (struct anote*) checkmalloc(sizeof(struct anote));
-  newx->next = NULL;
-  newx->note = newnote;
-  if (track[trackno].head == NULL) {
-    track[trackno].head = newx;
-    track[trackno].tail = newx;
-  } 
-  else {
-    track[trackno].tail->next = newx;
-    track[trackno].tail = newx;
-  };
-  if (ch == 9) {
-    track[trackno].drumtrack = 1;
-  };
-  newnote->pitch = p;
-  newnote->chan = ch;
-  newnote->vel = v;
-  newnote->time = Mf_currtime;
-  laston = Mf_currtime;
-  newnote->tplay = Mf_currtime;
-  noteplaying(newnote);
-}
-
-
-
-void notestop(p, ch)
-/* MIDI note stops */
-/* used when parsing MIDI file */
-int p, ch;
-{
-  struct dlistx* i;
-  int found;
-  char msg[80];
-
-  i = playinghead;
-  found = 0;
-  while ((found == 0) && (i != NULL)) {
-    if ((i->note->pitch == p)&&(i->note->chan==ch)) {
-      found = 1;
-    } 
-    else {
-      i = i->next;
-    };
-  };
-  if (found == 0) {
-    sprintf(msg, "Note terminated when not on - pitch %d", p);
-    event_error(msg);
-    return;
-  };
-  /* fill in tplay field */
-  i->note->tplay = Mf_currtime - (i->note->tplay);
-  /* remove note from list */
-  if (i->last == NULL) {
-    playinghead = i->next;
-  } 
-  else {
-    (i->last)->next = i->next;
-  };
-  if (i->next == NULL) {
-    playingtail = i->last;
-  } 
-  else {
-    (i->next)->last = i->last;
-  };
-  free(i);
-}
-
-
-
-
-FILE *
-efopen(name,mode)
-char *name;
-char *mode;
-{
-    FILE *f;
-
-    if ( (f=fopen(name,mode)) == NULL ) {
-      char msg[256];
-      sprintf(msg,"Error - Cannot open file %s",name);
-      fatal_error(msg);
-    }
-    return(f);
-}
-
-
-void error(s)
-char *s;
-{
-    fprintf(stderr,"Error: %s\n",s);
-}
-
-
-
-void txt_header(xformat,ntrks,ldivision)
-int xformat, ntrks, ldivision;
-{
-    division = ldivision; 
-    format = xformat;
-    if (format != 0) {
-    /*  fprintf(outhandle,"%% format %d file %d tracks\n", format, ntrks);*/
-      if(summary>0) printf("This midi file has %d tracks\n\n",ntrks);
-    } 
-    else {
-/*     fprintf(outhandle,"%% type 0 midi file\n"); */
-     if(summary>0) {
-	     printf("This is a type 0 midi file.\n");
-             printf("All the channels are in one track.\n");
-             printf("You may need to process the channels separately\n\n");
-            }
-     }
-     
-}
-
-
-void txt_trackstart()
-{
-  laston = 0L;
-  track[trackno].notes = 0;
-  track[trackno].head = NULL;
-  track[trackno].tail = NULL;
-  track[trackno].texthead = NULL;
-  track[trackno].texttail = NULL;
-  track[trackno].tracklen = Mf_currtime;
-  track[trackno].drumtrack = 0;
-}
-
-void txt_trackend()
-{
-  /* check for unfinished notes */
-  if (playinghead != NULL) {
-    printf("Error in MIDI file - notes still on at end of track!\n");
-  };
-  track[trackno].tracklen = Mf_currtime - track[trackno].tracklen;
-  trackno = trackno + 1;
-  trackcount = trackcount + 1;
-}
-
-void txt_noteon(chan,pitch,vol)
-int chan, pitch, vol;
-{
-  if ((xchannel == -1) || (chan == xchannel)) {
-    if (vol != 0) {
-      addnote(pitch, chan, vol);
-    } 
-    else {
-      notestop(pitch, chan);
-    };
-  };
-}
-
-void txt_noteoff(chan,pitch,vol)
-int chan, pitch, vol;
-{
-  if ((xchannel == -1) || (chan == xchannel)) {
-    notestop(pitch, chan);
-  };
-}
-
-void txt_pressure(chan,pitch,press)
-int chan, pitch, press;
-{
-}
-
-void txt_parameter(chan,control,value)
-int chan, control, value;
-{
-}
-
-void txt_pitchbend(chan,msb,lsb)
-int chan, msb, lsb;
-{
-}
-
-void txt_program(chan,program)
-int chan, program;
-{
-/*
-  sprintf(textbuff, "%%%%MIDI program %d %d",
-         chan+1, program);
-*/
-  sprintf(textbuff, "%%%%MIDI program %d", program);
-  addtext(textbuff,0);
-/* abc2midi does not use the same channel number as specified in 
-  the original midi file, so we should not specify that channel
-  number in the %%MIDI program. If we leave it out the program
-  will refer to the current channel assigned to this voice.
-*/
-}
-
-void txt_chanpressure(chan,press)
-int chan, press;
-{
-}
-
-void txt_sysex(leng,mess)
-int leng;
-char *mess;
-{
-}
-
-void txt_metamisc(type,leng,mess)
-int type, leng;
-char *mess;
-{
-}
-
-void txt_metaspecial(type,leng,mess)
-int type, leng;
-char *mess;
-{
-}
-
-void txt_metatext(type,leng,mess)
-int type, leng;
-char *mess;
-{ 
-    char *ttype[] = {
-    NULL,
-    "Text Event",        /* type=0x01 */
-    "Copyright Notice",    /* type=0x02 */
-    "Sequence/Track Name",
-    "Instrument Name",    /* ...     */
-    "Lyric",
-    "Marker",
-    "Cue Point",        /* type=0x07 */
-    "Unrecognized"
-  };
-  int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
-  unsigned char c;
-  int n;
-  char *p = mess;
-  char *buff;
-  char buffer2[BUFFSIZE];
-
-  if ((type < 1)||(type > unrecognized))
-      type = unrecognized;
-  buff = textbuff;
-  for (n=0; n<leng; n++) {
-    c = *p++;
-    if (buff - textbuff < BUFFSIZE - 6) {
-      sprintf(buff, 
-           (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c);
-      buff = buff + strlen(buff);
-    };
-  }
-  if (strncmp(textbuff, "@KMIDI KARAOKE FILE", 14) == 0) {
-    karaoke = 1;
-  } 
-  else {
-    if ((karaoke == 1) && (*textbuff != '@')) {
-      addtext(textbuff,0);
-    } 
-    else {
-      if (leng < BUFFSIZE - 3) {
-        sprintf(buffer2, " %s", textbuff); 
-        addtext(buffer2,0);
-      };
-    };
-  };
-}
-
-void txt_metaseq(num)
-int num;
-{  
-  sprintf(textbuff, "%%Meta event, sequence number = %d",num);
-  addtext(textbuff,0);
-}
-
-void txt_metaeot()
-/* Meta event, end of track */
-{
-}
-
-void txt_keysig(sf,mi)
-char sf, mi;
-{
-  int accidentals;
-  gotkeysig =1;
-  sprintf(textbuff, 
-         "%% MIDI Key signature, sharp/flats=%d  minor=%d",
-          (int) sf, (int) mi);
-  if(verbosity) addtext(textbuff,0);
-  sprintf(textbuff,"%d %d\n",sf,mi);
-  if (!ksig_set) {
-	  addtext(textbuff,1);
-	  keysig=sf;
-  }
-  if (header_keysig == -50) header_keysig = keysig;
-  if (summary <= 0) return;
-  /* There may be several key signature changes in the midi
-     file so that key signature in the mid file does not conform
-     with the abc file. Show all key signature changes. 
-  */   
-  accidentals = (int) sf;
-  if (accidentals <0 )
-    {
-    accidentals = -accidentals;
-    printf("Key signature: %d flats", accidentals);
-    }
-  else
-     printf("Key signature : %d sharps", accidentals);
-  if (ksig_set) printf(" suppressed\n");
-  else printf("\n");
-}
-
-void txt_tempo(ltempo)
-long ltempo;
-{
-    if(tempocount>0) return; /* ignore other tempo indications */
-    tempo = ltempo;
-    tempocount++;
-}
-
-
-void setup_timesig(nn,  denom,  bb)
-int nn,denom,bb;
-{
-  asig = nn;
-  bsig = denom;
-/* we must keep unitlen and xunit fixed for the entire tune */
-  if (unitlen_set == 0) {
-    unitlen_set = 1; 
-    if ((asig*4)/bsig >= 3) {
-      unitlen =8;
-      } 
-    else {
-      unitlen = 16;
-      };
-   }
-/* set xunit for this unitlen */
-  if(!xunit_set) xunit = (division*bb*4)/(8*unitlen);
-  barsize = parts_per_unitlen*asig*unitlen/bsig;
-/*  printf("setup_timesig: unitlen=%d xunit=%d barsize=%d\n",unitlen,xunit,barsize); */
-  if (header_asig ==0) {header_asig = asig;
-	                header_bsig = bsig;
-			header_unitlen = unitlen;
-			header_bb = bb;
-                       }
-}
-
-
-void txt_timesig(nn,dd,cc,bb)
-int nn, dd, cc, bb;
-{
-  int denom = 1;
-  while ( dd-- > 0 )
-    denom *= 2;
-  sprintf(textbuff, 
-          "%% Time signature=%d/%d  MIDI-clocks/click=%d  32nd-notes/24-MIDI-clocks=%d", 
-    nn,denom,cc,bb);
-  if (verbosity) addtext(textbuff,0);
-  sprintf(textbuff,"%d %d %d\n",nn,denom,bb);
-  if (!tsig_set) {
-	  addtext(textbuff,2);
-          setup_timesig(nn, denom,bb);
-   }
-  if (summary>0) {
-    if(tsig_set) printf("Time signature = %d/%d suppressed\n",nn,denom);
-    else printf("Time signature = %d/%d\n",nn,denom);
-    }
-}
-
-
-void txt_smpte(hr,mn,se,fr,ff)
-int hr, mn, se, fr, ff;
-{
-}
-
-void txt_arbitrary(leng,mess)
-char *mess;
-int leng;
-{
-}
-
-
-
-/* Dummy functions for handling MIDI messages.
- *    */
- void no_op0() {}
- void no_op1(int dummy1) {}
- void no_op2(int dummy1, int dummy2) {}
- void no_op3(int dummy1, int dummy2, int dummy3) { }
- void no_op4(int dummy1, int dummy2, int dummy3, int dummy4) { }
- void no_op5(int dummy1, int dummy2, int dummy3, int dummy4, int dummy5) { }
-
-
-
-void print_txt_noteon(chan, pitch, vol)
-{
-int start_time;
-int initvol;
-if (vol > 0)
-open_note(chan, pitch, vol);
-else {
-  start_time = close_note(chan, pitch,&initvol);
-  if (start_time >= 0)
-     /* printf("%8.4f %8.4f %d %d %d %d\n",
-       (double) start_time/(double) division,
-       (double) Mf_currtime/(double) division,
-       trackno+1, chan +1, pitch,initvol);
-     */
-       printf("%d %ld %d %d %d %d\n",
-       start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol);
-
-      if(Mf_currtime > last_tick) last_tick = Mf_currtime;
-   }
-}
-
-
-
-void print_txt_noteoff(chan, pitch, vol)
-{
-int start_time,initvol;
-
-start_time = close_note(chan, pitch, &initvol);
-if (start_time >= 0)
-/*
-    printf("%8.4f %8.4f %d %d %d %d\n",
-     (double) start_time/(double) division,
-     (double) Mf_currtime/(double) division,
-     trackno+1, chan+1, pitch,initvol);
-*/
-     printf("%d %ld %d %d %d %d\n",
-       start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol);
-    if(Mf_currtime > last_tick) last_tick = Mf_currtime;
-}
-
-
-
-/* In order to associate a channel note off message with its
- * corresponding note on message, we maintain the information
- * the notechan array. When a midi pitch (0-127) is switched
- * on for a particular channel, we record the time that it
- * was turned on in the notechan array. As there are 16 channels
- * and 128 pitches, we initialize an array 128*16 = 2048 elements
- * long.
-**/
-void init_notechan()
-{
-/* signal that there are no active notes */
- int i;
- for (i = 0; i < 2048; i++) notechan[i] = -1;
-}
-
-
-/* The next two functions update notechan when a channel note on
-   or note off is encountered. The second function close_note,
-   returns the time when the note was turned on.
-*/
-int open_note(int chan, int pitch, int vol)
-{
-    notechan[128 * chan + pitch] = Mf_currtime;
-    notechanvol[128 * chan + pitch] = vol;
-    return 0;
-}
-
-
-int close_note(int chan, int pitch, int *initvol)
-{
-    int index, start_tick;
-    index = 128 * chan + pitch;
-    if (notechan[index] < 0)
-	return -1;
-    start_tick = notechan[index];
-    *initvol = notechanvol[index];
-    notechan[index] = -1;
-    return start_tick;
-}
-
-
-/* mftext mode */
-int prtime()
-{
-/*  if(Mf_currtime >= pulses) ignore=0; 
-  if (ignore) return 1; 
-  linecount++;
-  if(linecount > maxlines) {fclose(F); exit(0);}
-*/
-  int units;
-  units = 2;
-  if(units==1)
- /*seconds*/
-     printf("%6.2f   ",mf_ticks2sec(Mf_currtime,division,tempo));
-  else if (units==2)
- /*beats*/
-     printf("%6.2f   ",(float) Mf_currtime/(float) division);
-  else
- /*pulses*/
-    printf("%6ld  ",Mf_currtime);
-  return 0;
-}
-
-char * pitch2key(int note)
-{
-static char name[5];
-char* s = name;
-  switch(note % 12)
-  {
-  case 0: *s++ = 'c'; break;
-  case 1: *s++ = 'c'; *s++ = '#'; break;
-  case 2: *s++ = 'd'; break;
-  case 3: *s++ = 'd'; *s++ = '#'; break;
-  case 4: *s++ = 'e'; break;
-  case 5: *s++ = 'f'; break;
-  case 6: *s++ = 'f'; *s++ = '#'; break;
-  case 7: *s++ = 'g'; break;
-  case 8: *s++ = 'g'; *s++ = '#'; break;
-  case 9: *s++ = 'a'; break;
-  case 10: *s++ = 'a'; *s++ = '#'; break;
-  case 11: *s++ = 'b'; break;
-  }
-  sprintf(s, "%d", (note / 12)-1);  /* octave  (assuming Piano C4 is 60)*/
-  return  name;
-}
-
-void mftxt_header (int format, int ntrks, int ldivision)
-{
-  division = ldivision;
-  printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division);
-}
-
-void mftxt_trackstart()
-{
-  int numbytes;
-  tracknum++;
-  numbytes = Mf_toberead;
-  /*if(track != 0 && tracknum != track) {ignore_bytes(numbytes); return;} */
-  printf("Track %d contains %d bytes\n",tracknum,numbytes);
-}
-
-
-void mftxt_noteon(chan,pitch,vol)
-{
-  char *key;
-/*
-  if (onlychan >=0 && chan != onlychan) return;
-*/
-  if (prtime()) return;
-  key = pitch2key(pitch);
-  printf("Note on  %2d  %3s %3d\n",chan+1, key,vol);
-}
-
-void mftxt_noteoff(chan,pitch,vol)
-{
-  char *key;
-/*
-  if (onlychan >=0 && chan != onlychan) return;
-*/
-  if (prtime()) return;
-  key = pitch2key(pitch);
-  printf("Note off %2d  %3s %3d\n",chan+1,key,vol);
-}
-
-void mftxt_pressure(chan,pitch,press)
-{
-  char *key;
-  if (prtime()) return;
-  key = pitch2key(pitch);
-  printf("Pressure %2d   %3s %3d\n",chan+1,key,press);
-}
-
-
-void mftxt_pitchbend(chan,msb,lsb)
-{
-/*
-  if (onlychan >=0 && chan != onlychan) return;
-*/
-  if (prtime()) return;
-  printf("Pitchbnd %2d msb=%d lsb=%d\n",chan+1,msb,lsb);
-}
-
-
-
-void mftxt_program(chan,program)
-{
-static char *patches[] = {
- "Acoustic Grand","Bright Acoustic","Electric Grand","Honky-Tonk", 
- "Electric Piano 1","Electric Piano 2","Harpsichord","Clav", 
- "Celesta", "Glockenspiel",  "Music Box",  "Vibraphone", 
- "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", 
- "Drawbar Organ", "Percussive Organ", "Rock Organ", "Church Organ", 
- "Reed Organ", "Accordian", "Harmonica", "Tango Accordian",
- "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)",
- "Electric Guitar (jazz)", "Electric Guitar (clean)", 
- "Electric Guitar (muted)", "Overdriven Guitar",
- "Distortion Guitar", "Guitar Harmonics",
- "Acoustic Bass", "Electric Bass (finger)",
- "Electric Bass (pick)", "Fretless Bass",
- "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2",
- "Violin", "Viola", "Cello", "Contrabass",
- "Tremolo Strings", "Pizzicato Strings",
- "Orchestral Strings", "Timpani",
- "String Ensemble 1", "String Ensemble 2",
- "SynthStrings 1", "SynthStrings 2", 
- "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit",
- "Trumpet", "Trombone", "Tuba", "Muted Trumpet",
- "French Horn", "Brass Section", "SynthBrass 1", "SynthBrass 2",
- "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax",
- "Oboe", "English Horn", "Bassoon", "Clarinet",
- "Piccolo", "Flute", "Recorder", "Pan Flute",
- "Blown Bottle", "Skakuhachi", "Whistle", "Ocarina",
- "Lead 1 (square)", "Lead 2 (sawtooth)",
- "Lead 3 (calliope)", "Lead 4 (chiff)", 
- "Lead 5 (charang)", "Lead 6 (voice)",
- "Lead 7 (fifths)", "Lead 8 (bass+lead)",
- "Pad 1 (new age)", "Pad 2 (warm)",
- "Pad 3 (polysynth)", "Pad 4 (choir)",
- "Pad 5 (bowed)", "Pad 6 (metallic)",
- "Pad 7 (halo)", "Pad 8 (sweep)",
- "FX 1 (rain)", "(soundtrack)",
- "FX 3 (crystal)", "FX 4 (atmosphere)",
- "FX 5 (brightness)", "FX 6 (goblins)",
- "FX 7 (echoes)", "FX 8 (sci-fi)",
- "Sitar", "Banjo", "Shamisen", "Koto",
- "Kalimba", "Bagpipe", "Fiddle", "Shanai",
- "Tinkle Bell", "Agogo", "Steel Drums", "Woodblock",
- "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal",
- "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet",
- "Telephone ring", "Helicopter", "Applause", "Gunshot"};
-/*
-  if (onlychan >=0 && chan != onlychan) return;
-*/
-  if (prtime()) return;
-  printf("Program  %2d %d (%s)\n",chan+1, program,patches[program]);
-   }
-
-void mftxt_chanpressure(chan,press)
-{
-  prtime();
-  printf("Chanpres %2d pressure=%d\n",chan+1,press);
-}
-
-
-void mftxt_parameter(chan,control,value)
-{
-  static char *ctype[] = {
- "Bank Select",       "Modulation Wheel",     /*1*/
- "Breath controller", "unknown",              /*3*/
- "Foot Pedal",        "Portamento Time",      /*5*/
- "Data Entry",        "Volume",               /*7*/
- "Balance",           "unknown",              /*9*/
- "Pan position",      "Expression",           /*11*/
- "Effect Control 1",  "Effect Control 2",     /*13*/
- "unknown",           "unknown",              /*15*/
- "Slider 1",          "Slider 2",             /*17*/
- "Slider 3",          "Slider 4",             /*19*/
- "unknown",           "unknown",              /*21*/
- "unknown",           "unknown",              /*23*/
- "unknown",           "unknown",              /*25*/
- "unknown",           "unknown",              /*27*/
- "unknown",           "unknown",              /*29*/
- "unknown",           "unknown",              /*31*/
- "Bank Select (fine)",  "Modulation Wheel (fine)",    /*33*/
- "Breath controller (fine)",  "unknown",              /*35*/
- "Foot Pedal (fine)",   "Portamento Time (fine)",     /*37*/
- "Data Entry (fine)",   "Volume (fine)",              /*39*/
- "Balance (fine)",      "unknown",                    /*41*/
- "Pan position (fine)", "Expression (fine)",          /*43*/
- "Effect Control 1 (fine)",  "Effect Control 2 (fine)", /*45*/
- "unknown",           "unknown",             /*47*/
- "unknown",           "unknown",             /*49*/
- "unknown",           "unknown",             /*51*/
- "unknown",           "unknown",             /*53*/
- "unknown",           "unknown",             /*55*/
- "unknown",           "unknown",             /*57*/
- "unknown",           "unknown",             /*59*/
-"unknown",           "unknown",             /*61*/
- "unknown",           "unknown",             /*63*/
- "Hold Pedal",        "Portamento",          /*65*/
- "Susteno Pedal",     "Soft Pedal",          /*67*/
- "Legato Pedal",      "Hold 2 Pedal",        /*69*/
- "Sound Variation",   "Sound Timbre",        /*71*/
- "Sound Release Time",  "Sound Attack Time", /*73*/
- "Sound Brightness",  "Sound Control 6",     /*75*/
- "Sound Control 7",   "Sound Control 8",     /*77*/
- "Sound Control 9",   "Sound Control 10",    /*79*/
- "GP Button 1",       "GP Button 2",         /*81*/
- "GP Button 3",       "GP Button 4",         /*83*/
- "unknown",           "unknown",             /*85*/
- "unknown",           "unknown",             /*87*/
- "unknown",           "unknown",             /*89*/
- "unknown",           "Effects Level",       /*91*/
- "Tremolo Level",     "Chorus Level",        /*93*/
- "Celeste Level",     "Phaser Level",        /*95*/
- "Data button increment",  "Data button decrement", /*97*/
- "NRP (fine)",        "NRP (coarse)",        /*99*/
- "Registered parameter (fine)", "Registered parameter (coarse)", /*101*/
- "unknown",           "unknown",             /*103*/
- "unknown",           "unknown",             /*105*/
- "unknown",           "unknown",             /*107*/
- "unknown",           "unknown",             /*109*/
- "unknown",           "unknown",             /*111*/
- "unknown",           "unknown",             /*113*/
- "unknown",           "unknown",             /*115*/
- "unknown",           "unknown",             /*117*/
- "unknown",           "unknown",             /*119*/
- "All Sound Off",     "All Controllers Off", /*121*/
- "Local Keyboard (on/off)","All Notes Off",  /*123*/
- "Omni Mode Off",     "Omni Mode On",        /*125*/
- "Mono Operation",    "Poly Operation"};
-
-/*  if (onlychan >=0 && chan != onlychan) return; */
-  if (prtime()) return;
-
-  printf("CntlParm %2d %s = %d\n",chan+1, ctype[control],value);
-}
-
-
-void mftxt_metatext(type,leng,mess)
-char *mess;
-{
-  static char *ttype[] = {
-    NULL,
-    "Text Event",    /* type=0x01 */
-    "Copyright Notice",  /* type=0x02 */
-    "Seqnce/Track Name",
-    "Instrument Name",  /* ...       */
-    "Lyric",
-    "Marker",
-    "Cue Point",    /* type=0x07 */
-    "Unrecognized"
-  };
-  int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
-  int len;
-  register int n, c;
-  register char *p = mess;
-
-  if ( type < 1 || type > unrecognized )
-    type = unrecognized;
-  if (prtime()) return;
-  printf("Metatext (%s) ",ttype[type]);
-  len = leng;
-  if (len > 15) len = 15;
-  for ( n=0; n<len; n++ ) {
-    c = (*p++) & 0xff;
-    if(iscntrl(c)) {printf(" \\0x%02x",c); continue;} /* no <cr> <lf> */
-    printf( (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c);
-  }
-  if (leng>15) printf("...");
-  printf("\n");
-}
-
-void mftxt_keysig(sf,mi)
-{
-  static char *major[] = {"Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F",
-    "C", "G", "D", "A", "E", "B", "F#", "C#"};
-  static char *minor[] = {"Abmin", "Ebmin", "Bbmin", "Fmin", "Cmin",
-    "Gmin", "Dmin", "Amin", "Emin", "Bmin", "F#min", "C#min", "G#min"};
-  int index;
-  index = sf + 7;
-  if (prtime()) return;
-  if (mi)
-    printf("Metatext key signature %s (%d/%d)\n",minor[index],sf,mi);
-  else
-    printf("Metatext key signature %s (%d/%d)\n",major[index],sf,mi);
-}
-
-void mftxt_tempo(ltempo)
-long ltempo;
-{
-  tempo = ltempo;
-  if (prtime()) return;
-  printf("Metatext tempo = %6.2f bpm\n",60000000.0/tempo);
-}
-
-void mftxt_timesig(nn,dd,cc,bb)
-{
-  int denom = 1;
-  while ( dd-- > 0 )
-    denom *= 2;
-  if (prtime()) return;
-  printf("Metatext time signature=%d/%d\n",nn,denom);
-/*  printf("Time signature=%d/%d  MIDI-clocks/click=%d \
-  32nd-notes/24-MIDI-clocks=%d\n", nn,denom,cc,bb); */
-}
-
-void mftxt_smpte(hr,mn,se,fr,ff)
-{
-  if (prtime()) return;
-  printf("Metatext SMPTE, %d:%d:%d  %d=%d\n", hr,mn,se,fr,ff);
-}
-
-void mftxt_metaeot()
-{
-  if (prtime()) return;
-  printf("Meta event, end of track\n");
-}
-
-
-void initfunc_for_midinotes()
-{
-    Mf_error = error;
-    Mf_header = txt_header;
-    Mf_trackstart = txt_trackstart;
-    Mf_trackend = txt_trackend;
-    Mf_noteon = print_txt_noteon;
-    Mf_noteoff = print_txt_noteoff;
-    Mf_pressure = no_op3;
-    Mf_parameter = no_op3;
-    Mf_pitchbend = no_op3;
-    Mf_program = no_op2;
-    Mf_chanpressure = no_op3;
-    Mf_sysex = no_op2;
-    Mf_metamisc = no_op3;
-    Mf_seqnum = no_op1;
-    Mf_eot = no_op0;
-    Mf_timesig = no_op4;
-    Mf_smpte = no_op5;
-    Mf_tempo = no_op1;
-    Mf_keysig = no_op2;
-    Mf_seqspecific = no_op3;
-    Mf_text = no_op3;
-    Mf_arbitrary = no_op2;
-}
-
-
-void initfunc_for_mftext()
-{
-    Mf_error = error;
-    Mf_header = mftxt_header;
-    Mf_trackstart = mftxt_trackstart;
-    Mf_trackend = txt_trackend;
-    Mf_noteon = mftxt_noteon;
-    Mf_noteoff = mftxt_noteoff;
-    Mf_pressure =mftxt_pressure;
-    Mf_parameter = mftxt_parameter;
-    Mf_pitchbend = mftxt_pitchbend;
-    Mf_program = mftxt_program;
-    Mf_chanpressure = mftxt_chanpressure;
-    Mf_sysex = no_op2;
-    Mf_metamisc = no_op3;
-    Mf_seqnum = no_op1;
-    Mf_eot = mftxt_metaeot;
-    Mf_timesig = mftxt_timesig;
-    Mf_smpte = mftxt_smpte;
-    Mf_tempo = mftxt_tempo;
-    Mf_keysig = mftxt_keysig;
-    Mf_seqspecific = no_op3;
-    Mf_text = mftxt_metatext;
-    Mf_arbitrary = no_op2;
-}
-
-
-
-
-void initfuncs()
-{
-    Mf_error = error;
-    Mf_header =  txt_header;
-    Mf_trackstart =  txt_trackstart;
-    Mf_trackend =  txt_trackend;
-    Mf_noteon =  txt_noteon;
-    Mf_noteoff =  txt_noteoff;
-    Mf_pressure =  txt_pressure;
-    Mf_parameter =  txt_parameter;
-    Mf_pitchbend =  txt_pitchbend;
-    Mf_program =  txt_program;
-    Mf_chanpressure =  txt_chanpressure;
-    Mf_sysex =  txt_sysex;
-    Mf_metamisc =  txt_metamisc;
-    Mf_seqnum =  txt_metaseq;
-    Mf_eot =  txt_metaeot;
-    Mf_timesig =  txt_timesig;
-    Mf_smpte =  txt_smpte;
-    Mf_tempo =  txt_tempo;
-    Mf_keysig =  txt_keysig;
-    Mf_seqspecific =  txt_metaspecial;
-    Mf_text =  txt_metatext;
-    Mf_arbitrary =  txt_arbitrary;
-}
-
-
-/*  Stage 2 Quantize MIDI tracks. Get key signature, time signature...   */ 
-
-
-void postprocess(trackno)
-/* This routine calculates the time interval before the next note */
-/* called after the MIDI file has been read in */
-int trackno;
-{
-  struct listx* i;
-
-  i = track[trackno].head;
-  if (i != NULL) {
-    track[trackno].startwait = i->note->time;
-  } 
-  else {
-    track[trackno].startwait = 0;
-  };
-  while (i != NULL) {
-    if (i->next != NULL) {
-      i->note->dtnext = i->next->note->time - i->note->time;
-    } 
-    else {
-      i->note->dtnext = i->note->tplay;
-    };
-    i = i->next;
-  };
-}
-
-void scannotes(trackno)
-int trackno;
-/* diagnostic routine to output notes in a track */
-{
-  struct listx* i;
-
-  i = track[trackno].head;
-  while (i != NULL) {
-    printf("Pitch %d chan %d vel %d time %ld  %ld xnum %d playnum %d\n",
-            i->note->pitch, i->note->chan, 
-            i->note->vel, i->note->dtnext, i->note->tplay,
-            i->note->xnum, i->note->playnum);
-    i = i->next;
-  };
-}
-
-
-int xnum_to_next_nonchordal_note(fromitem,spare,quantum)
-struct listx* fromitem;
-int spare,quantum;
-{
-struct anote* jnote;
-struct listx* nextitem;
-int i,xxnum;
-jnote = fromitem->note;
-if (jnote->xnum > 0) return jnote->xnum;
-i = 0;
-nextitem = fromitem->next;
-while (nextitem != NULL && i < 5) {
-  jnote = nextitem->note;
-  xxnum = (2*(jnote->dtnext + spare + (quantum/4)))/quantum;
-  if (xxnum > 0) return xxnum;
-  i++;
-  nextitem = nextitem->next;
-  }
-return 0;
-}
-
-int quantize(trackno, xunit)
-/* Work out how long each note is in musical time units.
- * The results are placed in note.playnum              */
-int trackno, xunit;
-{
-  struct listx* j;
-  struct anote* this;
-  int spare;
-  int toterror;
-  int quantum;
-  int posnum,xxnum;
-
-  /* fix to avoid division by zero errors in strange MIDI */
-  if (xunit == 0) {
-    return(10000);
-  };
-  quantum = (int) (2.*xunit/parts_per_unitlen); /* xunit assume 2 parts_per_unit */
-  track[trackno].startunits = (2*(track[trackno].startwait + (quantum/4)))/quantum;
-  spare = 0;
-  toterror = 0;
-  j = track[trackno].head;
-  posnum = 0;
-  while (j != NULL) {
-    this = j->note;
-    /* this->xnum is the quantized inter onset time */
-    /* this->playnum is the quantized note length   */
-    this->xnum = (2*(this->dtnext + spare + (quantum/4)))/quantum;
-    this->playnum = (2*(this->tplay + (quantum/4)))/quantum;
-    if ((this->playnum == 0) && (keep_short)) {
-      this->playnum = 1;
-    };
-    /* In the event of short rests, the inter onset time
-     * will be larger than the note length. However, for
-     * chords the inter onset time can be zero.          */
-    xxnum =  xnum_to_next_nonchordal_note(j,spare,quantum);
-    if ((swallow_rests>=0) && (xxnum - this->playnum <= restsize)
-		        && xxnum > 0) {
-      this->playnum = xxnum;
-    };
-   /* this->denom = parts_per_unitlen;  this variable is never used ! */
-    spare = spare + this->dtnext - (this->xnum*xunit/parts_per_unitlen);
-    if (spare > 0) {
-      toterror = toterror + spare;
-    } 
-    else {
-      toterror = toterror - spare;
-    };
-    /* gradually forget old errors so that if xunit is slightly off,
-       errors don't accumulate over several bars */
-    spare = (spare * 96)/100;
-    this->posnum = posnum;
-    posnum += this->xnum;
-    j = j->next;
-  };
-  return(toterror);
-}
-
-
-void guesslengths(trackno)
-/* work out most appropriate value for a unit of musical time */
-int trackno;
-{
-  int i;
-  int trial[100];
-  float avlen, factor, tryx;
-  long min;
-
-  min = track[trackno].tracklen;
-  if (track[trackno].notes == 0) {
-    return;
-  };
-  avlen = ((float)(min))/((float)(track[trackno].notes));
-  tryx = avlen * (float) 0.75;
-  factor = tryx/100;
-  for (i=0; i<100; i++) {
-    trial[i] = quantize(trackno, (int) tryx);
-    if ((long) trial[i] < min) {
-      min = (long) trial[i];
-      xunit = (int) tryx;
-    };
-    tryx = tryx + factor;
-  };
-xunit_set = 1;
-}
-
-
-int findana(maintrack, barsize)
-/* work out anacrusis from MIDI */
-/* look for a strong beat marking the start of a bar */
-int maintrack;
-int barsize;
-{
-  int min, mincount;
-  int place;
-  struct listx* p;
-
-  min = 0;
-  mincount = 0;
-  place = 0;
-  p = track[maintrack].head;
-  while ((p != NULL) && (place < barsize)) {
-    if ((p->note->vel > min) && (place > 0)) {
-      min = p->note->vel;
-      mincount = place;
-    };
-    place = place + (p->note->xnum);
-    p = p->next;
-  };
-  return(mincount);
-}
-
-
-
-int guessana(barbeats)
-int barbeats;
-/* try to guess length of anacrusis */
-{
-  int score[64];
-  int min, minplace;
-  int i,j;
-
-  if (barbeats > 64) {
-    fatal_error("Bar size exceeds static limit of 64 units!");
-  };
-  for (j=0; j<barbeats; j++) {
-    score[j] = 0;
-    for (i=0; i<trackcount; i++) {
-      score[j] = score[j] + testtrack(i, barbeats, j);
-      /* restore values to num */
-      quantize(i, xunit);
-    };
-  };
-  min = score[0];
-  minplace = 0;
-  for (i=0; i<barbeats; i++) {
-    if (score[i] < min) {
-      min = score[i];
-      minplace = i;
-    };
-  };
-  return(minplace);
-}
-
-
-int findkey(maintrack)
-int maintrack;
-/* work out what key MIDI file is in */
-/* algorithm is simply to minimize the number of accidentals needed. */
-{
-  int j;
-  int max, min, n[12], key_score[12];
-  int minkey, minblacks;
-  static int keysharps[12] = {
-	  0, -5, 2, -3, 4, -1, 6, 1, -4, 3, -2, 5};
-  struct listx* p;
-  int thispitch;
-  int lastpitch;
-  int totalnotes;
-
-  /* analyse pitches */
-  /* find key */
-  for (j=0; j<12; j++) {
-    n[j] = 0;
-  };
-  min = track[maintrack].tail->note->pitch;
-  max = min;
-  totalnotes = 0;
-  for (j=0; j<trackcount; j++) {
-    totalnotes = totalnotes + track[j].notes;
-    p = track[j].head;
-    while (p != NULL) {
-      thispitch = p->note->pitch;
-      if (thispitch > max) {
-        max = thispitch;
-      } 
-      else {
-        if (thispitch < min) {
-          min = thispitch;
-        };
-      };
-      n[thispitch % 12] = n[thispitch % 12] + 1;
-      p = p->next;
-    };
-  };
-  /* count black notes for each key */
-  /* assume pitch = 0 is C */
-  minkey = 0;
-  minblacks = totalnotes;
-  for (j=0; j<12; j++) {
-    key_score[j] = n[(j+1)%12] + n[(j+3)%12] + n[(j+6)%12] +
-                   n[(j+8)%12] + n[(j+10)%12];
-    /* printf("Score for key %d is %d\n", j, key_score[j]); */
-    if (key_score[j] < minblacks) {
-      minkey = j;
-      minblacks = key_score[j];
-    };
-  };
-  /* do conversion to abc pitches */
-  /* Code changed to use absolute rather than */
-  /* relative choice of pitch for 'c' */
-  /* MIDDLE = (min + (max - min)/2 + 6)/12 * 12; */
-  /* Do last note analysis */
-  lastpitch = track[maintrack].tail->note->pitch;
-  if (minkey != (lastpitch%12)) {
-    fprintf(outhandle,"%% Last note suggests ");
-    switch((lastpitch+12-minkey)%12) {
-    case(2):
-      fprintf(outhandle,"Dorian ");
-      break;
-    case(4):
-      fprintf(outhandle,"Phrygian ");
-      break;
-    case(5):
-      fprintf(outhandle,"Lydian ");
-      break;
-    case(7):
-      fprintf(outhandle,"Mixolydian ");
-      break;
-    case(9):
-      fprintf(outhandle,"minor ");
-      break;
-    case(11):
-      fprintf(outhandle,"Locrian ");
-      break;
-    default:
-      fprintf(outhandle,"unknown ");
-      break;
-    };
-    fprintf(outhandle,"mode tune\n");
-  };
-  /* switch to minor mode if it gives same number of accidentals */
-  if ((minkey != ((lastpitch+3)%12)) && 
-      (key_score[minkey] == key_score[(lastpitch+3)%12])) {
-         minkey = (lastpitch+3)%12;
-  };
-  /* switch to major mode if it gives same number of accidentals */
-  if ((minkey != (lastpitch%12)) && 
-      (key_score[minkey] == key_score[lastpitch%12])) {
-         minkey = lastpitch%12;
-  };
-  sharps = keysharps[minkey];
-  return(sharps);
-}
-
-
-
-
-/* Stage 3  output MIDI tracks in abc format                        */
-
-
-/* head and tail of list of notes in current chord playing */
-/* used while abc is being generated */
-struct dlistx* chordhead;
-struct dlistx* chordtail;
-
-
-void printchordlist()
-/* diagnostic routine */
-{
-  struct dlistx* i;
-
-  i = chordhead;
-  printf("----CHORD LIST------\n");
-  while(i != NULL) {
-    printf("pitch %d len %d\n", i->note->pitch, i->note->playnum);
-    if (i->next == i) {
-      fatal_error("Loopback problem!");
-    };
-    i = i->next;
-  };
-}
-
-void checkchordlist()
-/* diagnostic routine */
-/* validates data structure */
-{
-  struct dlistx* i;
-  int n;
-
-  if ((chordhead == NULL) && (chordtail == NULL)) {
-    return;
-  };
-  if ((chordhead == NULL) && (chordtail != NULL)) {
-    fatal_error("chordhead == NULL and chordtail != NULL");
-  };
-  if ((chordhead != NULL) && (chordtail == NULL)) {
-    fatal_error("chordhead != NULL and chordtail == NULL");
-  };
-  if (chordhead->last != NULL) {
-    fatal_error("chordhead->last != NULL");
-  };
-  if (chordtail->next != NULL) {
-    fatal_error("chordtail->next != NULL");
-  };
-  i = chordhead;
-  n = 0;
-  while((i != NULL) && (i->next != NULL)) {
-    if (i->next->last != i) {
-      char msg[80];
-
-      sprintf(msg, "chordlist item %d : i->next->last!", n);
-      fatal_error(msg);
-    };
-    i = i->next;
-    n = n + 1;
-  };
-  /* checkchordlist(); */
-}
-
-void addtochord(p)
-/* used when printing out abc */
-struct anote* p;
-{
-  struct dlistx* newx;
-  struct dlistx* place;
-
-  newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx));
-  newx->note = p;
-  newx->next = NULL;
-  newx->last = NULL;
-
-  if (chordhead == NULL) {
-    chordhead = newx;
-    chordtail = newx;
-    checkchordlist();
-    return;
-  };
-  place = chordhead;
-  while ((place != NULL) && (place->note->pitch > p->pitch)) {
-    place = place->next;
-  };
-  if (place == chordhead) {
-    newx->next = chordhead;
-    chordhead->last = newx;
-    chordhead = newx;
-    checkchordlist();
-    return;
-  };
-  if (place == NULL) {
-    newx->last = chordtail;
-    chordtail->next = newx;
-    chordtail = newx;
-    checkchordlist();
-    return;
-  };
-  newx->next = place;
-  newx->last = place->last;
-  place->last = newx;
-  newx->last->next = newx;
-  checkchordlist();
-}
-
-struct dlistx* removefromchord(i)
-/* used when printing out abc */
-struct dlistx* i;
-{
-  struct dlistx* newi;
-
-  /* remove note from list */
-  if (i->last == NULL) {
-    chordhead = i->next;
-  } 
-  else {
-    (i->last)->next = i->next;
-  };
-  if (i->next == NULL) {
-    chordtail = i->last;
-  } 
-  else {
-    (i->next)->last = i->last;
-  };
-  newi = i->next;
-  free(i);
-  checkchordlist();
-  return(newi);
-}
-
-int findshortest(gap)
-/* find the first note in the chord to terminate */
-int gap;
-{
-  int min, v;
-  struct dlistx* p;
-
-  p = chordhead;
-  min = gap;
-  while (p != NULL) {
-    v = p->note->playnum;
-    if (v < min) {
-      min = v;
-    };
-    p = p->next;
-  };
-  return(min);
-}
-
-void advancechord(len)
-/* adjust note lengths for all notes in the chord */
-int len;
-{
-  struct dlistx* p;
-
-  p = chordhead;
-  while (p != NULL) {
-    if (p->note->playnum <= len) {
-      if (p->note->playnum < len) {
-        fatal_error("Error - note too short!");
-      };
-      /* remove note */
-      checkchordlist();
-      p = removefromchord(p);
-    } 
-    else {
-      /* shorten note */
-      p->note->playnum = p->note->playnum - len;
-      p = p->next;
-    };
-  };
-}
-
-void freshline()
-/* if the current line of abc or text is non-empty, start a new line */
-{
-  if (midline == 1) {
-    fprintf(outhandle,"\n");
-    midline = 0;
-  };
-}
-
-
-void printnote (struct listx *i)
-{
-      printf("%ld ",i->note->time);
-      printpitch(i->note);
-      printfract(i->note->playnum, parts_per_unitlen);
-      printf(" %d %d %d %d\n",i->note->xnum, i->note->playnum,
-       i->note->posnum,i->note->splitnum); 
-}
-
-void listnotes(int trackno, int start, int end)
-/* A diagnostic like scannotes. I usually call it when
-   I am in the debugger (for example in printtrack).
-*/
-{
-struct listx* i;
-int k;
-i = track[trackno].head;
-k = 0;
-printf("ticks pitch xnum,playnum,posnum,splitnum\n");
-while (i != NULL && k < end)
-  {
-  if (k >= start) 
-    printnote(i);
-  k++;
-  i = i->next;
-  }
-}
-
-
-
-int testtrack(trackno, barbeats, anacrusis)
-/* print out one track as abc */
-int trackno, barbeats, anacrusis;
-{
-  struct listx* i;
-  int step, gap;
-  int barnotes;
-  int barcount;
-  int breakcount;
-
-  breakcount = 0;
-  chordhead = NULL;
-  chordtail = NULL;
-  i = track[trackno].head;
-  gap = 0;
-  if (anacrusis > 0) {
-    barnotes = anacrusis;
-  } 
-  else {
-    barnotes = barbeats;
-  };
-  barcount = 0;
-  while((i != NULL)||(gap != 0)) {
-    if (gap == 0) {
-      /* add notes to chord */
-      addtochord(i->note);
-      gap = i->note->xnum;
-      i = i->next;
-      advancechord(0); /* get rid of any zero length notes */
-    } 
-    else {
-      step = findshortest(gap);
-      if (step > barnotes) {
-        step = barnotes;
-      };
-      if (step == 0) {
-        fatal_error("Advancing by 0 in testtrack!");
-      };
-      advancechord(step);
-      gap = gap - step;
-      barnotes = barnotes - step;
-      if (barnotes == 0) {
-        if (chordhead != NULL) {
-          breakcount = breakcount + 1;
-        };
-        barnotes = barbeats;
-        barcount = barcount + 1;
-        if (barcount>0  && barcount%4 ==0) {
-        /* can't zero barcount because I use it for computing maxbarcount */
-          freshline();
-          barcount = 0;
-        };
-      };
-    };
-  };
-  return(breakcount);
-}
-
-void printpitch(j)
-/* convert numerical value to abc pitch */
-struct anote* j;
-{
-  int p, po,i;
-
-  p = j->pitch;
-  if (p == -1) {
-    fprintf(outhandle,"z");
-  } 
-  else {
-    po = p % 12;
-    if ((back[trans[p]] != p) || (key[po] == 1)) {
-      fprintf(outhandle,"%c%c", symbol[po], atog[p]);
-      for (i=p%12; i<256; i += 12) /* apply accidental to all octaves */
-         back[trans[i]] = i;
-    } 
-    else {
-      fprintf(outhandle,"%c", atog[p]);
-    };
-    while (p >= MIDDLE + 12) {
-      fprintf(outhandle,"'");
-      p = p - 12;
-    };
-    while (p < MIDDLE - 12) {
-      fprintf(outhandle,",");
-      p = p + 12;
-    };
-  };
-}
-
-static void reduce(a, b)
-int *a, *b;
-{
-  int t, n, m;
-
-    /* find HCF using Euclid's algorithm */
-    if (*a > *b) {
-        n = *a;
-        m = *b;
-      }
-    else {
-        n = *b;
-        m = *a;
-       };
-while (m != 0) {
-      t = n % m;
-      n = m;
-      m = t;
-    };
-*a = *a/n;
-*b = *b/n;
-}
-
-
-
-void printfract(a, b)
-/* print fraction */
-/* used when printing abc */
-int a, b;
-{
-  int c, d;
-
-  c = a;
-  d = b;
-  reduce(&c,&d);
-  /* print out length */
-  if (c != 1) {
-    fprintf(outhandle,"%d", c);
-  };
-  if (d != 1) {
-    fprintf(outhandle,"/%d", d);
-  };
-}
-
-void printchord(len)
-/* Print out the current chord. Any notes that haven't            */
-/* finished at the end of the chord are tied into the next chord. */
-int len;
-{
-  struct dlistx* i;
-
-  i = chordhead;
-  if (i == NULL) {
-    /* no notes in chord */
-#ifdef SPLITCODE
-    fprintf(outhandle,"x");
-#else
-    fprintf(outhandle,"z");
-#endif
-    printfract(len, parts_per_unitlen);
-    midline = 1;
-  } 
-  else {
-    if (i->next == NULL) {
-      /* only one note in chord */
-      printpitch(i->note);
-      printfract(len, parts_per_unitlen);
-      midline = 1;
-      if (len < i->note->playnum) {
-        fprintf(outhandle,"-");
-      };
-    } 
-    else {
-      fprintf(outhandle,"[");
-      while (i != NULL) {
-        printpitch(i->note);
-        printfract(len, parts_per_unitlen);
-        if (len < i->note->playnum) {
-          fprintf(outhandle,"-");
-        };
-      if (nogr && i->next != NULL) fprintf(outhandle," ");
-        i = i->next;
-      };
-      fprintf(outhandle,"]");
-      midline = 1;
-    };
-  };
-}
-
-char dospecial(i, barnotes, featurecount)
-/* identify and print out triplets and broken rhythm */
-struct listx* i;
-int* barnotes;
-int* featurecount;
-{
-  int v1, v2, v3, vt;
-  int xa, xb;
-  int pnum;
-  long total, t1, t2, t3;
-
-  
-  if ((chordhead != NULL) || (i == NULL) || (i->next == NULL)
-  /* || (asig%3 == 0) || (asig%2 != 0) 2004/may/09 SS*/) {
-    return(' ');
-  };
-  t1 = i->note->dtnext;
-  v1 = i->note->xnum;
-  pnum = i->note->playnum;
-  if ((v1 < pnum) || (v1 > 1 + pnum) || (pnum == 0)) {
-    return(' ');
-  };
-  t2 = i->next->note->dtnext;
-  v2 = i->next->note->xnum;
-  pnum = i->next->note->playnum;
-  if (/*(v2 < pnum) ||*/ (v2 > 1 + pnum) || (pnum == 0) || (v1+v2 > *barnotes)) {
-    return(' ');
-  };
-  /* look for broken rhythm */
-  total = t1 + t2;
-  if (total == 0L) {
-    /* shouldn't happen, but avoids possible divide by zero */
-    return(' ');
-  };
-  if (((v1+v2)%2 == 0) && ((v1+v2)%3 != 0)) {
-    vt = (v1+v2)/2;
-      if (vt == validnote(vt)) {
-      /* do not try to break a note which cannot be legally expressed */
-      switch ((int) ((t1*6+(total/2))/total)) {
-        case 2:
-          *featurecount = 2;
-          i->note->xnum  = vt;
-          i->note->playnum = vt;
-          i->next->note->xnum  = vt;
-          i->next->note->playnum = vt;
-          return('<');
-          break;
-        case 4:
-          *featurecount = 2;
-          i->note->xnum  = vt;
-          i->note->playnum = vt;
-          i->next->note->xnum  = vt;
-          i->next->note->playnum = vt;
-          return('>');
-          break;
-        default:
-          break;
-      };
-    };
-  };
-  /* look for triplet */
-  if (i->next->next != NULL) {
-    t3 = i->next->next->note->dtnext;
-    v3 = i->next->next->note->xnum;
-    pnum = i->next->next->note->playnum;
-    if ((v3 < pnum) || (v3 > 1 + pnum) || (pnum == 0) || 
-        (v1+v2+v3 > *barnotes)) {
-      return(' ');
-    };
-    if ((v1+v2+v3)%2 != 0) {
-      return(' ');
-    };
-    vt = (v1+v2+v3)/2;
-    if ((vt%2 == 1) && (vt > 1)) {
-      /* don't want strange fractions in triplet */
-      return(' ');
-    };
-    total = t1+t2+t3;
-    xa = (int) ((t1*6+(total/2))/total); 
-    xb = (int) (((t1+t2)*6+(total/2))/total);
-    if ((xa == 2) && (xb == 4) && (vt%3 != 0) ) {
-      *featurecount = 3;
-      *barnotes = *barnotes + vt;
-      i->note->xnum = vt;
-      i->note->playnum = vt;
-      i->next->note->xnum = vt;
-      i->next->note->playnum = vt;
-      i->next->next->note->xnum = vt;
-      i->next->next->note->playnum = vt;
-    };
-  };
-  return(' ');
-}
-
-int validnote(n)
-int n;
-/* work out a step which can be expressed as a musical time */
-{
-  int v;
-
-  if (n <= 4) {
-    v = n;
-  } 
-  else {
-    v = 4;
-    while (v*2 <= n) {
-      v = v*2;
-    };
-    if (v + v/2 <= n) {
-      v = v + v/2;
-    };
-  };
-  return(v);
-}
-
-void handletext(t, textplace, trackno)
-/* print out text occuring in the body of the track */
-/* The text is printed out at the appropriate place within the track */
-/* In addition the function handles key signature and time */
-/* signature changes that can occur in the middle of the tune. */
-long t;
-struct tlistx** textplace;
-int trackno;
-{
-  char* str;
-  char ch;
-  int type,sf,mi,nn,denom,bb;
-
-  while (((*textplace) != NULL) && ((*textplace)->when <= t)) {
-    str = (*textplace)->text;
-    ch = *str;
-    type = (*textplace)->type;
-    remove_carriage_returns(str);
-    if (((int)ch == '\\') || ((int)ch == '/')) {
-      inkaraoke = 1;
-    };
-    if ((inkaraoke == 1) && (karaoke == 1)) {
-      switch(ch) {
-        case ' ':
-          fprintf(outhandle,"%s", str);
-          midline = 1;
-          break;
-        case '\\':
-          freshline();
-          fprintf(outhandle,"w:%s", str + 1);
-          midline = 1;
-          break;
-        case '/':
-          freshline();
-          fprintf(outhandle,"w:%s", str + 1);
-          midline = 1;
-          break;
-        default :
-          if (midline == 0) {
-            fprintf(outhandle,"%%%s", str);
-          } 
-	  else {
-            fprintf(outhandle,"-%s", str);
-          };
-          break;
-      };
-    } 
-    else {
-      freshline();
-      ch=*(str+1);
-      switch (type) {
-      case 0:
-      if (ch != '%') 
-      fprintf(outhandle,"%%%s\n", str);
-      else 
-      fprintf(outhandle,"%s\n", str);
-      break;
-      case 1: /* key signature change */
-      sscanf(str,"%d %d",&sf,&mi);
-      if((trackno != 0 || trackcount==1) &&
-	 (active_keysig != sf)) {
-	      setupkey(sf);
-	      active_keysig=sf;
-              }
-      break;
-      case 2: /* time signature change */
-      sscanf(str,"%d %d %d",&nn,&denom,&bb);
-      if ((trackno != 0 || trackcount ==1) &&
-	  (active_asig != nn || active_bsig != denom))
-        {
-  	setup_timesig(nn,denom,bb);
-	fprintf(outhandle,"M: %d/%d\n",nn,denom);
-        fprintf(outhandle,"L: 1/%d\n",unitlen);
-	active_asig=nn;
-	active_bsig=denom;
-	}
-      break;
-     default:
-      break;
-      }
-  }
-  *textplace = (*textplace)->next;
- }
-}
-
-
-#ifdef SPLITCODE
-
-/* This function identifies irregular chords, (notes which
-   do not exactly overlap in time). The notes in the
-   chords are split into separate lines (split numbers).
-   The xnum (delay) to next note is updated.
-*/
-
-int splitstart[10],splitend[10]; /* used in forming chords from notes*/
-int lastposnum[10]; /* posnum of previous note in linked list */
-int endposnum; /* posnum at last note in linked list */
-struct anote* prevnote[10]; /*previous note in linked list */
-struct listx*  last_i[10];  /*note after finishing processing bar*/
-int existingsplits[10]; /* existing splits in active bar */
-struct dlistx* splitchordhead[10]; /* chordhead list for splitnum */
-struct dlistx* splitchordtail[10]; /* chordtail list for splitnum */
-int splitgap[10]; /* gap to next note at end of split measure */
-
-void label_split(struct anote *note, int activesplit)
-{
-/* The function assigns a split number (activesplit), to
-   a specific note, (*note). We also update splitstart
-   and splitend which specifies the region in time where
-   the another note must occur if it forms a proper chord.
-   After assigning a split number to the note we need to
-   update note->xnum as this indicates the gap to the
-   next note in the same split number. The function uses
-   a greedy algorithm. It assigns a note to the first
-   splitnumber code which satisfies the above constraint.
-   If it cannot find a splitnumber, a new one (voice or track)
-   is created. It would be nice if the voices kept the
-   high and low notes (in pitch) separate.
-*/
-     note->splitnum = activesplit;
-     splitstart[activesplit] = note->posnum;
-     splitend[activesplit] = splitstart[activesplit] + note->playnum;
-     if (prevnote[activesplit]) 
-         prevnote[activesplit]->xnum = note->posnum - lastposnum[activesplit];
-     lastposnum[activesplit] = note->posnum;
-     prevnote[activesplit] = note;
-     /* in case this is the last activesplit note make sure it
-        xnum points to end of track. Otherwise it will be changed
-        when the next activesplit note is labeled.
-     */
-     note->xnum = endposnum - note->posnum;
-     existingsplits[activesplit]++;
-}
-
-
-void label_split_voices (int trackno)
-{
-/* This function sorts all the notes in the track into
-   separate split part. A note is placed into a separate
-   part if it forms a chord in the current part but
-   does not have the same onset time and same end time.
-   If this occurs, we search for another part where
-   this does not happen. If we can't find such a part
-   a new part (split) is created.
-   The heuristic used needs to be improved, so
-   that split number 0 always contains notes and so
-   that notes in the same pitch range or duration are
-   given the same split number.
-*/ 
-int activesplit,nsplits;
-int done;
-struct listx* i;
-int k;
-int firstposnum;
-/* initializations */
-activesplit = 0;
-nsplits = 0;
-for (k=0;k<10;k++) {
-       splitstart[k]=splitend[k]=lastposnum[k]=0;
-       prevnote[k] = NULL;
-       existingsplits[k] = 0;
-       splitgap[k]=0;
-       }
-i = track[trackno].head;
-if (track[trackno].tail == 0x0) return;
-endposnum =track[trackno].tail->note->posnum +
-           track[trackno].tail->note->playnum;
-
-if (i != NULL) label_split(i->note, activesplit);
-/* now label all the notes in the track */
-while (i != NULL)
-  {
-  done =0;
-  if (nsplits == 0) { /*no splits exist, create split number 0 */
-     activesplit = 0;
-     nsplits++;
-     i->note->splitnum = activesplit;
-     splitstart[activesplit] = i->note->posnum;
-     splitend[activesplit] = splitstart[activesplit] + i->note->playnum;
-     firstposnum = splitstart[activesplit];
-     } else {  /* do a compatibility check with the last split number */
-  if (  (   i->note->posnum == splitstart[activesplit] 
-         && i->note->playnum == (splitend[activesplit] - splitstart[activesplit]))
-      || i->note->posnum >= splitend[activesplit])
-     {
-     if (existingsplits[activesplit] == 0) {
-         last_i[activesplit] = i;
-         splitgap[activesplit] = i->note->posnum - firstposnum;
-         }
-     label_split(i->note, activesplit);
-     done = 1;
-     }
-/* need to search for any other compatible split numbers  */
-  if (done == 0) for (activesplit=0;activesplit<nsplits;activesplit++) {
-      if (  (   i->note->posnum == splitstart[activesplit] 
-             && i->note->playnum == splitend[activesplit] - splitstart[activesplit])
-          || i->note->posnum >= splitend[activesplit])
-       {
-        if (existingsplits[activesplit] == 0) {
-           last_i[activesplit] = i;
-           splitgap[activesplit] = i->note->posnum - firstposnum;
-           }
-        label_split(i->note,activesplit);
-        done = 1;
-        break;
-        }
-      }
-     
-/* No compatible split number found. Create new split */
-   if (done == 0) {
-     if(nsplits < 10) {nsplits++; activesplit = nsplits-1;}  
-     if (existingsplits[activesplit] == 0) {
-         last_i[activesplit] = i;
-         splitgap[activesplit] = i->note->posnum - firstposnum;
-         }
-     label_split(i->note,activesplit);
-     }
-   } 
-/*  printf("note %d links to %d  %d (%d %d)\n",i->note->pitch,activesplit,
-i->note->posnum,splitstart[activesplit],splitend[activesplit]);
-*/
-  i = i->next;
-  } /* end while loop */
-}
-
-
-int nextsplitnum(int splitnum)
-  {
-  while (splitnum < 9) {
-      splitnum++;
-      if (existingsplits[splitnum]) return splitnum;
-      } 
-     return -1;
-}
-
-
-int count_splits()
-{
-int i,n;
-n = 0;
-for (i=0;i<10;i++)
-  if (existingsplits[i]) n++;
-return n;
-}
-
-
-
-
-
-void printtrack_with_splits(trackno, anacrusis)
-int trackno,  anacrusis;
-/* This function is an adaption of printtrack so that
-   notes with separate split numbers are in separated
-   regions in the measure. (Separated with &'s).
-   To do this we must make multiple passes through
-   each bar and maintain separate chordlists (in
-   event that some chords overlap over more than
-   one measure).
-*/
-{
-  struct listx* i;
-  struct tlistx* textplace;
-  struct tlistx* textplace0; /* track 0 text storage */
-  int step, gap;
-  int barnotes;
-  int barcount;
-  int bars_on_line;
-  long now;
-  char broken;
-  int featurecount;
-  int last_barsize,barnotes_correction;
-  int splitnum = 0;
-  int j;
-  int nlines;
-  int done;
-
-  nlines= 0;
-  label_split_voices (trackno);
-
-  midline = 0;
-  featurecount = 0;
-  inkaraoke = 0;
-  now = 0L;
-  broken = ' ';
-  for (j=0;j<10;j++) {
-      splitchordhead[j] = NULL;
-      splitchordtail[j] = NULL;
-      }
-  i = track[trackno].head;
-  textplace = track[trackno].texthead;
-  textplace0 = track[0].texthead;
-  /*gap = track[trackno].startunits;*/ gap = 0;
-  if (anacrusis > 0) {
-    barnotes = anacrusis;
-    barcount = -1;
-  } 
-  else {
-    barnotes = barsize;
-    barcount = 0;
-  };
-  bars_on_line = 0;
-  last_barsize = barsize;
-  active_asig = header_asig;
-  active_bsig = header_bsig;
-  setup_timesig(header_asig,header_bsig,header_bb);
-  active_keysig = header_keysig;
-  handletext(now, &textplace, trackno);
-  splitnum = 0;
-  chordhead = splitchordhead[splitnum]; 
-  chordtail = splitchordtail[splitnum]; 
-  gap = splitgap[splitnum];
-
-  while((i != NULL)||(gap != 0)) {
-    if (gap == 0) {
-      /* do triplet here */
-      if (featurecount == 0) {
-	if (!no_triplets) {
-	  broken = dospecial(i, &barnotes, &featurecount);
-	};
-      };
-
-/* ignore any notes that are not in the current splitnum */
-      if (i->note->splitnum == splitnum) {
-               /*printf("\nadding ");
-                 printnote(i); */
-	addtochord(i->note);
-	gap = i->note->xnum;
-	now = i->note->time;
-	}
-
-      i = i->next;
-      advancechord(0); /* get rid of any zero length notes */
-      if (trackcount > 1 && trackno !=0)
-	      handletext(now, &textplace0, trackno);
-      handletext(now, &textplace,trackno);
-      barnotes_correction = barsize - last_barsize;
-      barnotes += barnotes_correction;
-      last_barsize = barsize;
-    } 
-    else {
-      step = findshortest(gap);
-      if (step > barnotes) {
-	step = barnotes;
-      };
-      step = validnote(step);
-      if (step == 0) {
-	fatal_error("Advancing by 0 in printtrack!");
-      };
-      if (featurecount == 3)
-        {
-        fprintf(outhandle," (3");
-        };
-      printchord(step); if ( featurecount > 0) { featurecount = featurecount - 1; };
-      if ((featurecount == 1) && (broken != ' ')) {
-        fprintf(outhandle,"%c", broken);
-      };
-      advancechord(step);
-      gap = gap - step;
-      barnotes = barnotes - step;
-
-/* at the end of the bar we must decide whether to place
-   a | or &. If we place a & then we have to return to
-   the beginning of the bar and process the next split number.
-*/  
-      if (barnotes == 0) { /* end of bar  ? */
-        nlines++;
-        if (nlines > 5000) {
-            printf("\nProbably infinite loop: aborting\n");
-            fprintf(outhandle,"\n\nProbably infinite loop: aborting\n");
-            return;
-            }
-/* save state for the last splitnum before going to the next */
-        last_i[splitnum] = i;
-        splitchordhead[splitnum] = chordhead;
-        splitchordtail[splitnum] = chordtail;
-        splitgap[splitnum] = gap;
-
-/*     look for the next splitnum which contains notes in
-       the current measure. If not, end the measure.
-*/
-        done = 0;
-        while (done != 1) {
-           splitnum = nextsplitnum(splitnum);
-
-           if (splitnum == -1) {
-              fprintf(outhandle," | ");
-              splitnum = nextsplitnum(splitnum);
-              done = 1;
-              break;
-              }
-
-           if (splitgap[splitnum] >= barsize)
-               {
-               splitgap[splitnum] -= barsize;
-               continue; /* look for other splits */
-               }
- 
-           fprintf(outhandle, " & ");
-           i = last_i[splitnum]; 
-           done = 1;
-           }
-/* restore state for the next splitnum */
-       chordhead = splitchordhead[splitnum];
-       chordtail = splitchordtail[splitnum];
-       checkchordlist();
-       gap = splitgap[splitnum];
-       i = last_i[splitnum];
-
-       /*
-        printf("returning to %ld ",i->note->time);
-        printpitch(i->note);
-        printf("\n");
-       */
-     
-        barnotes = barsize;
-        barcount = barcount + 1;
-	bars_on_line++;
-        if (barcount >0 && barcount%bars_per_staff == 0)  {
-		freshline();
-		bars_on_line=0;
-	}
-     /* can't zero barcount because I use it for computing maxbarcount */
-        else if(bars_on_line >= bars_per_line && i != NULL) {
-		fprintf(outhandle," \\");
-	       	freshline();
-	        bars_on_line=0;}
-      }
-      else if (featurecount == 0) {
-          /* note grouping algorithm */
-          if ((barsize/parts_per_unitlen) % 3 == 0) {
-            if ( (barnotes/parts_per_unitlen) % 3 == 0
-               &&(barnotes%parts_per_unitlen) == 0) {
-              fprintf(outhandle," ");
-            };
-          } 
-	  else {
-            if (((barsize/parts_per_unitlen) % 2 == 0)
-                && (barnotes % parts_per_unitlen) == 0
-                && ((barnotes/parts_per_unitlen) % 2 == 0)) {
-              fprintf(outhandle," ");
-            };
-          };
-      }
-      if (nogr) fprintf(outhandle," ");
-    };
-   if (i == NULL) /* end of track before end of measure ? */
-    {
-     last_i[splitnum] = i;
-     splitchordhead[splitnum] = chordhead;
-     splitchordtail[splitnum] = chordtail;
-     splitgap[splitnum] = gap;
-     splitnum = nextsplitnum(splitnum);
-     if (splitnum == -1) break;
-     chordhead = splitchordhead[splitnum];
-     chordtail = splitchordtail[splitnum];
-     gap = splitgap[splitnum];
-     i = last_i[splitnum];
-     if (barnotes != barsize) fprintf(outhandle, " & ");
-     barnotes = barsize;
-    }
- 
-  };
-  /* print out all extra text */
-  while (textplace != NULL) {
-    handletext(textplace->when, &textplace, trackno);
-  };
-  freshline();
-  if (barcount > maxbarcount) maxbarcount = barcount;
-}
-
-
-
-void printtrack_split_voice(trackno, anacrusis)
-/* print out one track as abc */
-int trackno,  anacrusis;
-{
-  struct listx* i;
-  struct tlistx* textplace;
-  struct tlistx* textplace0; /* track 0 text storage */
-  int step, gap;
-  int barnotes;
-  int barcount;
-  int bars_on_line;
-  long now;
-  char broken;
-  int featurecount;
-  int last_barsize,barnotes_correction;
-  int nlines;
-  int splitnum;
-  int lastnote_in_split;
-
-  nlines= 0;
-  lastnote_in_split = 0;
-  label_split_voices (trackno);
-  midline = 0;
-  featurecount = 0;
-  inkaraoke = 0;
-  now = 0L;
-  broken = ' ';
-  chordhead = NULL;
-  chordtail = NULL;
-  i = track[trackno].head;
-  textplace = track[trackno].texthead;
-  textplace0 = track[0].texthead;
-  gap = track[trackno].startunits;
-  if (anacrusis > 0) {
-    barnotes = anacrusis;
-    barcount = -1;
-  } 
-  else {
-    barnotes = barsize;
-    barcount = 0;
-  };
-  bars_on_line = 0;
-  last_barsize = barsize;
-  active_asig = header_asig;
-  active_bsig = header_bsig;
-  setup_timesig(header_asig,header_bsig,header_bb);
-  active_keysig = header_keysig;
-  handletext(now, &textplace, trackno);
-  splitnum = 0;
-  gap = splitgap[splitnum];
-  if (count_splits() > 1) fprintf(outhandle,"V: split%d%c\n",trackno+1,'A'+splitnum);
-
-  while((i != NULL)||(gap != 0)) {
-    if (gap == 0) {
-      if (i->note->posnum + i->note->xnum == endposnum) lastnote_in_split = 1;
-      /* do triplet here */
-      if (featurecount == 0) {
-        if (!no_triplets) {
-          broken = dospecial(i, &barnotes, &featurecount);
-        };
-      };
-/* ignore any notes that are not in the current splitnum */
-      if (i->note->splitnum == splitnum) {
-               /*printf("\nadding ");
-                 printnote(i); */
-	addtochord(i->note);
-	gap = i->note->xnum;
-	now = i->note->time;
-	}
-      i = i->next;
-      advancechord(0); /* get rid of any zero length notes */
-      if (trackcount > 1 && trackno !=0)
-	      handletext(now, &textplace0, trackno);
-      handletext(now, &textplace,trackno);
-      barnotes_correction = barsize - last_barsize;
-      barnotes += barnotes_correction;
-      last_barsize = barsize;
-    } 
-    else {
-      step = findshortest(gap);
-      if (step > barnotes) {
-        step = barnotes;
-      };
-      step = validnote(step);
-      if (step == 0) {
-        fatal_error("Advancing by 0 in printtrack!");
-      };
-      if (featurecount == 3)
-        {
-        fprintf(outhandle," (3");
-        };
-      printchord(step);
-      if ( featurecount > 0) {
-        featurecount = featurecount - 1;
-      };
-      if ((featurecount == 1) && (broken != ' ')) {
-        fprintf(outhandle,"%c", broken);
-      };
-      advancechord(step);
-      gap = gap - step;
-      barnotes = barnotes - step;
-      if (barnotes == 0) {
-        nlines++;
-        if (nlines > 5000) {
-            printf("\nProbably infinite loop: aborting\n");
-            fprintf(outhandle,"\n\nProbably infinite loop: aborting\n");
-            return;
-            }
-        fprintf(outhandle,"|");
-        barnotes = barsize;
-        barcount = barcount + 1;
-	bars_on_line++;
-        if (barcount >0 && barcount%bars_per_staff == 0)  {
-		freshline();
-		bars_on_line=0;
-	}
-     /* can't zero barcount because I use it for computing maxbarcount */
-        else if(bars_on_line >= bars_per_line && i != NULL) {
-		if (!lastnote_in_split) fprintf(outhandle," \\");
-	       	freshline();
-	        bars_on_line=0;}
-      }
-      else if (featurecount == 0) {
-          /* note grouping algorithm */
-          if ((barsize/parts_per_unitlen) % 3 == 0) {
-            if ( (barnotes/parts_per_unitlen) % 3 == 0
-               &&(barnotes%parts_per_unitlen) == 0) {
-              fprintf(outhandle," ");
-            };
-          } 
-	  else {
-            if (((barsize/parts_per_unitlen) % 2 == 0)
-                && (barnotes % parts_per_unitlen) == 0
-                && ((barnotes/parts_per_unitlen) % 2 == 0)) {
-              fprintf(outhandle," ");
-            };
-          };
-      }
-      if (nogr) fprintf(outhandle," ");
-    };
-  if (i == NULL && gap == 0) 
-    {
-    i = track[trackno].head;
-    splitnum = nextsplitnum(splitnum);
-    lastnote_in_split = 0;
-    if (splitnum == -1) break;
-    gap = splitgap[splitnum];
-    if(barnotes != barsize) freshline();
-    fprintf(outhandle,"V:split%d%c\n",trackno+1,'A'+splitnum);
-    if (anacrusis > 0) {
-      barnotes = anacrusis;
-      barcount = -1;
-      } 
-    else {
-      barnotes = barsize;
-      barcount = 0;
-      };
-    }
-  };
-  /* print out all extra text */
-  while (textplace != NULL) {
-    handletext(textplace->when, &textplace, trackno);
-  };
-  freshline();
-  if (barcount > maxbarcount) maxbarcount = barcount;
-}
-
-#endif
-
-void printtrack(trackno, anacrusis)
-/* print out one track as abc */
-int trackno,  anacrusis;
-{
-  struct listx* i;
-  struct tlistx* textplace;
-  struct tlistx* textplace0; /* track 0 text storage */
-  int step, gap;
-  int barnotes;
-  int barcount;
-  int bars_on_line;
-  long now;
-  char broken;
-  int featurecount;
-  int last_barsize,barnotes_correction;
-
-  midline = 0;
-  featurecount = 0;
-  inkaraoke = 0;
-  now = 0L;
-  broken = ' ';
-  chordhead = NULL;
-  chordtail = NULL;
-  i = track[trackno].head;
-  textplace = track[trackno].texthead;
-  textplace0 = track[0].texthead;
-  gap = track[trackno].startunits;
-  if (anacrusis > 0) {
-    barnotes = anacrusis;
-    barcount = -1;
-  } 
-  else {
-    barnotes = barsize;
-    barcount = 0;
-  };
-  bars_on_line = 0;
-  last_barsize = barsize;
-  active_asig = header_asig;
-  active_bsig = header_bsig;
-  setup_timesig(header_asig,header_bsig,header_bb);
-  active_keysig = header_keysig;
-  handletext(now, &textplace, trackno);
-
-  while((i != NULL)||(gap != 0)) {
-    if (gap == 0) {
-      /* do triplet here */
-      if (featurecount == 0) {
-        if (!no_triplets) {
-          broken = dospecial(i, &barnotes, &featurecount);
-        };
-      };
-      /* add notes to chord */
-      addtochord(i->note);
-      gap = i->note->xnum;
-      now = i->note->time;
-      i = i->next;
-      advancechord(0); /* get rid of any zero length notes */
-      if (trackcount > 1 && trackno !=0)
-	      handletext(now, &textplace0, trackno);
-      handletext(now, &textplace,trackno);
-      barnotes_correction = barsize - last_barsize;
-      barnotes += barnotes_correction;
-      last_barsize = barsize;
-    } 
-    else {
-      step = findshortest(gap);
-      if (step > barnotes) {
-        step = barnotes;
-      };
-      step = validnote(step);
-      if (step == 0) {
-        fatal_error("Advancing by 0 in printtrack!");
-      };
-      if (featurecount == 3)
-        {
-        fprintf(outhandle," (3");
-        };
-      printchord(step);
-      if ( featurecount > 0) {
-        featurecount = featurecount - 1;
-      };
-      if ((featurecount == 1) && (broken != ' ')) {
-        fprintf(outhandle,"%c", broken);
-      };
-      advancechord(step);
-      gap = gap - step;
-      barnotes = barnotes - step;
-      if (barnotes == 0) {
-        fprintf(outhandle,"|");
-        barnotes = barsize;
-        barcount = barcount + 1;
-	bars_on_line++;
-        if (barcount >0 && barcount%bars_per_staff == 0)  {
-		freshline();
-		bars_on_line=0;
-	}
-     /* can't zero barcount because I use it for computing maxbarcount */
-        else if(bars_on_line >= bars_per_line && i != NULL) {
-		fprintf(outhandle," \\");
-	       	freshline();
-	        bars_on_line=0;}
-      }
-      else if (featurecount == 0) {
-          /* note grouping algorithm */
-          if ((barsize/parts_per_unitlen) % 3 == 0) {
-            if ( (barnotes/parts_per_unitlen) % 3 == 0
-               &&(barnotes%parts_per_unitlen) == 0) {
-              fprintf(outhandle," ");
-            };
-          } 
-	  else {
-            if (((barsize/parts_per_unitlen) % 2 == 0)
-                && (barnotes % parts_per_unitlen) == 0
-                && ((barnotes/parts_per_unitlen) % 2 == 0)) {
-              fprintf(outhandle," ");
-            };
-          };
-      }
-      if (nogr) fprintf(outhandle," ");
-    };
-  };
-  /* print out all extra text */
-  while (textplace != NULL) {
-    handletext(textplace->when, &textplace, trackno);
-  };
-  freshline();
-  if (barcount > maxbarcount) maxbarcount = barcount;
-}
-
-
-
-
-void remove_carriage_returns(char *str)
-{
-/* a carriage return might be embedded in a midi text meta-event.
-   do not output this in the abc file or this would make a nonsyntactic
-   abc file.
-*/
-char * loc;
-while (loc  = (char *) strchr(str,'\r')) *loc = ' ';
-while (loc  = (char *) strchr(str,'\n')) *loc = ' ';
-}
-
-
-
-void printQ()
-/* print out tempo for abc */
-{
-  float Tnote, freq;
-  Tnote = mf_ticks2sec((long)((xunit*unitlen)/4), division, tempo);
-  freq = (float) 60.0/Tnote;
-  fprintf(outhandle,"Q:1/4=%d\n", (int) (freq+0.5));
-  if (summary>0) printf("Tempo: %d quarter notes per minute\n",
-    (int) (freq + 0.5));
-}
-
-
-
-
-void setupkey(sharps)
-int sharps;
-/* set up variables related to key signature */
-{
-  char sharp[13], flat[13], shsymbol[13], flsymbol[13];
-  int j, t, issharp;
-  int minkey;
-
-  for (j=0; j<12; j++) 
-    key[j] = 0;
-  minkey = (sharps+12)%12;
-  if (minkey%2 != 0) {
-    minkey = (minkey+6)%12;
-  };
-  strcpy(sharp,    "ccddeffggaab");
-  strcpy(shsymbol, "=^=^==^=^=^=");
-  if (sharps == 6) {
-    sharp[6] = 'e';
-    shsymbol[6] = '^';
-  };
-  strcpy(flat, "cddeefggaabb");
-  strcpy(flsymbol, "=_=_==_=_=_=");
-  /* Print out key */
-
-  if (sharps >= 0) {
-    if (sharps == 6) {
-      fprintf(outhandle,"K:F#");
-    } 
-    else {
-      fprintf(outhandle,"K:%c", sharp[minkey] + 'A' - 'a');
-    };
-    issharp = 1;
-  } 
-  else {
-    if (sharps == -1) {
-      fprintf(outhandle,"K:%c", flat[minkey] + 'A' - 'a');
-    } 
-    else {
-      fprintf(outhandle,"K:%cb", flat[minkey] + 'A' - 'a');
-    };
-    issharp = 0;
-  };
-  if (sharps >= 0) {
-    fprintf(outhandle," %% %d sharps\n", sharps);
-  }
-  else {
-    fprintf(outhandle," %% %d flats\n", -sharps);
-  };
-  key[(minkey+1)%12] = 1;
-  key[(minkey+3)%12] = 1;
-  key[(minkey+6)%12] = 1;
-  key[(minkey+8)%12] = 1;
-  key[(minkey+10)%12] = 1;
-  for (j=0; j<256; j++) {
-    t = j%12;
-    if (issharp) {
-      atog[j] = sharp[t];
-      symbol[j] = shsymbol[t];
-    } 
-    else {
-      atog[j] = flat[t];
-      symbol[j] = flsymbol[t];
-    };
-    trans[j] = 7*(j/12)+((int) atog[j] - 'a');
-    if (j < MIDDLE) {
-      atog[j] = (char) (int) atog[j] + 'A' - 'a';
-    };
-    if (key[t] == 0) {
-      back[trans[j]] = j;
-    };
-  };
-}
-
-
-
-
-/*  Functions for supporting the command line user interface to midi2abc.     */
-
-
-int readnum(num) 
-/* read a number from a string */
-/* used for processing command line */
-char *num;
-{
-  int t;
-  char *p;
-  int neg;
-  
-  t = 0;
-  neg = 1;
-  p = num;
-  if (*p == '-') {
-    p = p + 1;
-    neg = -1;
-  };
-  while (((int)*p >= '0') && ((int)*p <= '9')) {
-    t = t * 10 + (int) *p - '0';
-    p = p + 1;
-  };
-  return neg*t;
-}
-
-
-int readnump(p) 
-/* read a number from a string (subtly different) */
-/* used for processing command line */
-char **p;
-{
-  int t;
-  
-  t = 0;
-  while (((int)**p >= '0') && ((int)**p <= '9')) {
-    t = t * 10 + (int) **p - '0';
-    *p = *p + 1;
-  };
-  return t;
-}
-
-
-void readsig(a, b, sig)
-/* read time signature */
-/* used for processing command line */
-int *a, *b;
-char *sig;
-{
-  char *p;
-  int t;
-
-  p = sig;
-  if ((int)*p == 'C') {
-    *a = 4;
-    *b = 4;
-    return;
-  };
-  *a = readnump(&p);
-  if ((int)*p != '/') {
-    char msg[80];
-
-    sprintf(msg, "Expecting / in time signature found %c!", *p);
-    fatal_error(msg);
-  };
-  p = p + 1;
-  *b = readnump(&p);
-  if ((*a == 0) || (*b == 0)) {
-    char msg[80];
-
-    sprintf(msg, "%d/%d is not a valid time signature!", *a, *b);
-    fatal_error(msg);
-  };
-  t = *b;
-  while (t > 1) {
-    if (t%2 != 0) {
-      fatal_error("Bad key signature, divisor must be a power of 2!");
-    }
-    else {
-      t = t/2;
-    };
-  };
-}
-
-int is_power_of_two(int numb)
-/* checks whether numb is a power of 2 less than 256 */
-{
-int i,k;
-k = 1;
-for (i= 0;i<8;i++) {
-  if(numb == k) return(1);
-  k *= 2;
-  }
-return(0);
-}
-
-int getarg(option, argc, argv)
-/* extract arguments from command line */
-char *option;
-char *argv[];
-int argc;
-{
-  int j, place;
-
-  place = -1;
-  for (j=0; j<argc; j++) {
-    if (strcmp(option, argv[j]) == 0) {
-      place = j + 1;
-    };
-  };
-  return (place);
-}
-
-int huntfilename(argc, argv)
-/* look for filename argument if -f option is missing */
-/* assumes filename does not begin with '-'           */
-char *argv[];
-int argc;
-{
-  int j, place;
-
-  place = -1;
-  j = 1;
-  while ((place == -1) && (j < argc)) {
-    if (strncmp("-", argv[j], 1) != 0) {
-      place = j;
-    } 
-    else {
-     if (strchr("ambQkcou", *(argv[j]+1)) == NULL) {
-       j = j + 1;
-     }
-     else {
-       j = j + 2;
-     };
-    };
-  };
-  return(place);
-}
-
-int process_command_line_arguments(argc,argv)
-char *argv[];
-int argc;
-{
-  int val;
-  int arg;
-  arg = getarg("-ver",argc,argv);
-  if (arg != -1) {printf("%s\n",VERSION); exit(0);}
-  midiprint = 0;
-  arg = getarg("-midigram",argc,argv);
-  if (arg != -1) 
-   {
-   midiprint = 1;
-   }
-
-#ifdef SPLITCODE
-  usesplits = 0;
-  arg = getarg("-splitbars",argc,argv);
-  if (arg != -1) 
-   usesplits = 1;
-  arg = getarg("-splitvoices",argc,argv);
-  if (arg != -1) 
-   usesplits = 2;
-#endif 
-
-  arg = getarg("-mftext",argc,argv);
-  if (arg != -1) 
-   {
-   midiprint = 2;
-   }
-
-  arg = getarg("-a", argc, argv);
-  if ((arg != -1) && (arg < argc)) {
-    anacrusis = readnum(argv[arg]);
-  } 
-  else {
-    anacrusis = 0;
-  };
-  arg = getarg("-m", argc, argv);
-  if ((arg != -1) && (arg < argc)) {
-    readsig(&asig, &bsig, argv[arg]);
-    tsig_set = 1;
-  }
-  else {
-    asig = 4;
-    bsig = 4;
-    tsig_set = 0;
-  };
-  arg = getarg("-Q", argc, argv);
-  if (arg != -1) {
-    Qval = readnum(argv[arg]);
-  }
-  else {
-    Qval = 0;
-  };
-  arg = getarg("-u", argc,argv);
-  if (arg != -1) {
-    xunit = readnum(argv[arg]);
-    xunit_set = 1;
-  }
-  else {
-	xunit = 0;
-	xunit_set = 0;
-       };
-  arg = getarg("-ppu",argc,argv);
-  if (arg != -1) {
-     val = readnum(argv[arg]);
-     if (is_power_of_two(val)) parts_per_unitlen = val;
-     else {
-	   printf("*error* -ppu parameter must be a power of 2\n");
-           parts_per_unitlen = 2;
-          }
-  }
-  else
-     parts_per_unitlen = 2;
-  arg = getarg("-aul",argc,argv);
-  if (arg != -1) {
-     val = readnum(argv[arg]);
-     if (is_power_of_two(val)) {
-	    unitlen = val;
-	    unitlen_set = 1;}
-        else 
-           printf("*error* -aul parameter must be a power of 2\n");
-      }
-  arg = getarg("-bps",argc,argv);
-  if (arg != -1)
-   bars_per_staff = readnum(argv[arg]);
-  else {
-       bars_per_staff=4;
-   };
-  arg = getarg("-bpl",argc,argv);
-  if (arg != -1)
-   bars_per_line = readnum(argv[arg]);
-  else {
-       bars_per_line=1;
-   };
-
-
-  extracta = (getarg("-xa", argc, argv) != -1);
-  guessa = (getarg("-ga", argc, argv) != -1);
-  guessu = (getarg("-gu", argc, argv) != -1);
-  guessk = (getarg("-gk", argc, argv) != -1);
-  keep_short = (getarg("-s", argc, argv) != -1);
-  summary = getarg("-sum",argc,argv); 
-  swallow_rests = getarg("-sr",argc,argv);
-  if (swallow_rests != -1) {
-	 restsize = readnum(argv[swallow_rests]);
-         if(restsize <1) restsize=1;
-        }
-  obpl = getarg("-obpl",argc,argv);
-  if (obpl>= 0) bars_per_line=1;
-  if (!unitlen_set) {
-    if ((asig*4)/bsig >= 3) {
-      unitlen =8;
-     }
-    else {
-      unitlen = 16;
-     };
-   }
-  arg = getarg("-b", argc, argv);
-  if ((arg != -1) && (arg < argc)) {
-    bars = readnum(argv[arg]);
-  }
-  else {
-    bars = 0;
-  };
-  arg = getarg("-c", argc, argv);
-  if ((arg != -1) && (arg < argc)) {
-    xchannel = readnum(argv[arg]) - 1;
-  }
-  else {
-    xchannel = -1;
-  };
-  arg = getarg("-k", argc, argv);
-  if ((arg != -1) && (arg < argc)) {
-    keysig = readnum(argv[arg]);
-    if (keysig<-6) keysig = 12 - ((-keysig)%12);
-    if (keysig>6)  keysig = keysig%12;
-    if (keysig>6)  keysig = keysig - 12;
-    ksig_set = 1;
-  } 
-  else {
-    keysig = -50;
-    ksig_set = 0;
-  };
-
-  if(guessk) ksig_set=1;
-
-  arg = getarg("-o",argc,argv);
-  if ((arg != -1) && (arg < argc))  {
-    outhandle = efopen(argv[arg],"w");  /* open output abc file */
-  } 
-  else {
-    outhandle = stdout;
-  };
-  arg = getarg("-nt", argc, argv);
-  if (arg == -1) {
-    no_triplets = 0;
-  } 
-  else {
-    no_triplets = 1;
-  };
-  arg = getarg("-nogr",argc,argv);
-  if (arg != -1)
-     nogr=1;
-  else nogr = 0;
-
-  arg = getarg("-f", argc, argv);
-  if (arg == -1) {
-    arg = huntfilename(argc, argv);
-  };
-  if ((arg != -1) && (arg < argc)) {
-    F = efopen(argv[arg],"rb");
-/*    fprintf(outhandle,"%% input file %s\n", argv[arg]); */
-  }
-  else {
-    printf("midi2abc version %s\n  usage :\n",VERSION);
-    printf("midi2abc filename <options>\n");
-    printf("         -a <beats in anacrusis>\n");
-    printf("         -xa  Extract anacrusis from file ");
-    printf("(find first strong note)\n");
-    printf("         -ga  Guess anacrusis (minimize ties across bars)\n");
-    printf("         -gk  Guess key signature \n");
-    printf("         -gu  Guess xunit from note duration statistics\n");
-    printf("         -m <time signature>\n");
-    printf("         -b <bars wanted in output>\n");
-    printf("         -Q <tempo in quarter-notes per minute>\n");
-    printf("         -k <key signature> -6 to 6 sharps\n");
-    printf("         -c <channel>\n");
-    printf("         -u <number of midi pulses in abc time unit>\n");
-    printf("         -ppu <number of parts in abc time unit>\n");
-    printf("         -aul <denominator of L: unit length>\n");
-    printf("         [-f] <input file>\n");
-    printf("         -o <output file>\n");
-    printf("         -s Do not discard very short notes\n");
-    printf("         -sr <number> Absorb short rests following note\n");
-    printf("           where <number> specifies its size\n");
-    printf("         -sum summary\n");
-    printf("         -nt Do not look for triplets or broken rhythm\n");
-    printf("         -bpl <number> of bars printed on one line\n");
-    printf("         -bps <number> of bars to be printed on staff\n");
-    printf("         -obpl One bar per line\n");
-    printf("         -nogr No note grouping. Space between all notes\n");
-#ifdef SPLITCODE
-    printf("         -splitbars  splits bars to avoid nonhomophonic chords\n");
-    printf("         -splitvoices  splits voices to avoid nonhomophonic chords\n");
-#endif
-    printf("         -midigram   Prints midigram instead of abc file\n");
-    printf("         -mftext mftext output\n"); 
-    printf("         -ver version number\n");
-    printf(" None or only one of the options -gu, -b, -Q -u should\n");
-    printf(" be specified. If none are present, midi2abc will uses the\n");
-    printf(" the PPQN information in the MIDI file header to determine\n");
-    printf(" the suitable note length. This is the recommended method.\n");
-    printf(" The input filename is assumed to be any string not\n");
-    printf(" beginning with a - (hyphen). It may be placed anywhere.\n");
-
-    exit(0);
-  };
-  return arg;
-}
-
-
-
-void midi2abc (arg, argv)
-char *argv[];
-int arg;
-{
-int voiceno;
-int accidentals; /* used for printing summary */
-int j;
-int argc;
-
-/* initialization */
-  trackno = 0;
-  track[trackno].texthead = NULL;
-  track[trackno].texttail = NULL;
-  initfuncs();
-  playinghead = NULL;
-  playingtail = NULL;
-  karaoke = 0;
-  Mf_getc = filegetc;
-
-/* parse MIDI file */
-  mfread();
-
-  fclose(F);
-
-/* count MIDI tracks with notes */
-  maintrack = 0;
-  while ((track[maintrack].notes == 0) && (maintrack < trackcount)) {
-    maintrack = maintrack + 1;
-  };
-  if (track[maintrack].notes == 0) {
-    fatal_error("MIDI file has no notes!");
-  };
-
-/* compute dtnext for each note */
-  for (j=0; j<trackcount; j++) {
-    postprocess(j);
-  };
-
-  if (tsig_set == 1){  /* for -m parameter set up time signature*/
-       header_asig = asig; 
-       header_unitlen = unitlen;
-       header_bsig = bsig;
-  };
-
-/* print abc header block */
-  argc = huntfilename(arg, argv);
-  fprintf(outhandle,"X: 1\n"); 
-  fprintf(outhandle,"T: from %s\n",argv[argc]); 
-  if (header_bsig == 0) {
-     fprintf(outhandle,"%%***Missing time signature meta command in MIDI file\n");
-     setup_timesig(4,  4,  8);
-     }
-  fprintf(outhandle,"M: %d/%d\n", header_asig, header_bsig);
-  fprintf(outhandle,"L: 1/%d\n", header_unitlen); 
-
-  barsize = parts_per_unitlen*header_asig*header_unitlen/header_bsig;
-
-/* compute xunit size for -Q -b options */
-  if (Qval != 0) {
-    xunit = mf_sec2ticks((60.0*4.0)/((float)(Qval*unitlen)), division, tempo);
-  };
-  if (bars > 0) {
-    xunit = (int) ((float) track[maintrack].tracklen*2/(float) (bars*barsize));
-    /* we multiply by 2 because barsize is in half unitlen. */
-  };
-
-/* estimate xunit if not set or if -gu runtime option */
-  if (xunit == 0 || guessu) {
-    guesslengths(maintrack);
-  };
-
-/* output Q: (tempo) to abc file */
-  printQ();
-
-/* Quantize note lengths of all tracks */
-  for (j=0; j<trackcount; j++) {
-    quantize(j, xunit);
-  };
-
-/* Estimate anacrusis if requested. Otherwise it is set by       */
-/* user or set to 0.                                             */
-  if (extracta) {
-    anacrusis = findana(maintrack, barsize);
-    fprintf(outhandle,"%%beats in anacrusis = %d\n", anacrusis);
-  };
-  if (guessa) {
-    anacrusis = guessana(barsize);
-    fprintf(outhandle,"%%beats in anacrusis = %d\n", anacrusis);
-  };
-
-/* If key signature is not known find the best one.              */
-  if ((keysig == -50 && gotkeysig ==0) || guessk) {
-       keysig = findkey(maintrack);
-       if (summary>0) printf("Best key signature = %d flats/sharps\n",keysig);
-       }
-       header_keysig = keysig;
-       setupkey(header_keysig);
-
-/* scannotes(maintrack); For debugging */
-
-/* Convert each track to abc format and print */
-  if (trackcount > 1) {
-    voiceno = 1;
-    for (j=0; j<trackcount; j++) {
-      freshline();
-      if (track[j].notes > 0) {
-        fprintf(outhandle,"V:%d\n", voiceno);
-	if (track[j].drumtrack) fprintf(outhandle,"%%%%MIDI channel 10\n");
-        voiceno = voiceno + 1;
-      };
-#ifdef SPLITCODE
-      if (usesplits==1) printtrack_with_splits(j, anacrusis); 
-      else if (usesplits==2) printtrack_split_voice(j, anacrusis);
-      else printtrack(j,anacrusis);
-#else
-      printtrack(j,anacrusis); 
-#endif
-    };
-  }
-  else {
-#ifdef SPLITCODE
-     if (usesplits==1) printtrack_with_splits(maintrack, anacrusis);
-     else if (usesplits==2) printtrack_split_voice(maintrack, anacrusis);
-     else printtrack(maintrack,anacrusis);
-#else
-     printtrack(maintrack, anacrusis);  
-#endif
-  };
-
-  /* scannotes(maintrack); for debugging */
-
-/* output report if requested */
-  if(summary>0) {
-   accidentals = keysig;
-   if (accidentals <0 )
-     {
-     accidentals = -accidentals;
-     printf("Using key signature: %d flats\n", accidentals);
-     }
-   else
-     printf("Using key signature : %d sharps\n", accidentals);
-   printf("Using an anacrusis of %d beats\n",anacrusis);
-   printf("Using unit length : 1/%d\n",unitlen);
-   printf("Using %d pulses per unit length (xunit).\n",xunit);
-   printf("Producing %d bars of output.\n",maxbarcount);
-   }
-
-
-/* free up data structures */
-  for (j=0; j< trackcount; j++) {
-    struct listx* this;
-    struct listx* x;
-    struct tlistx* tthis;
-    struct tlistx* tx;
-
-    this = track[j].head;
-    while (this != NULL) {
-      free(this->note);
-      x = this->next ;
-      free(this);
-      this = x;
-    };
-    tthis = track[j].texthead;
-    while (tthis != NULL) {
-      free(tthis->text);
-      tx = tthis->next;
-      free(tthis);
-      tthis = tx;
-    };
-  };
-  fclose(outhandle);
-}
-
-void midigram(argc,argv)
-char *argv[];
-int argc;
-{
-initfunc_for_midinotes();
-init_notechan();
-last_tick=0;
-/*F = efopen(argv[argc -1],"rb");*/
-Mf_getc = filegetc;
-mfread();
-printf("%d\n",last_tick);
-}
-
-void mftext(argc,argv)
-char *argv[];
-int argc;
-{
-initfunc_for_mftext();
-init_notechan();
-last_tick=0;
-/*F = efopen(argv[argc -1],"rb");*/
-Mf_getc = filegetc;
-mfread();
-/*printf("%d\n",last_tick);*/
-}
-
-
-int main(argc,argv)
-char *argv[];
-int argc;
-{
-  FILE *efopen();
-  int arg;
-
-  arg = process_command_line_arguments(argc,argv);
-  if(midiprint ==1) midigram(argc,argv);
-  else if(midiprint ==2) mftext(argc,argv);
-  else midi2abc(argc,argv); 
-  return 0;
-}
+/*
+ * midi2abc - program to convert MIDI files to abc notation.
+ * Copyright (C) 1998 James Allwright
+ * e-mail: J.R.Allwright@westminster.ac.uk
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/* new midi2abc - converts MIDI file to abc format files
+ * 
+ *
+ * re-written to use dynamic data structures 
+ *              James Allwright
+ *               5th June 1998
+ *
+ * added output file option -o
+ * added summary option -sum
+ * added option -u to enter xunit directly
+ * fixed computation of xunit using -b option
+ * added -obpl (one bar per line) option
+ * add check for carriage return embedded inside midi text line
+ *                Seymour Shlien  04/March/00
+ * made to conform as much as possible to the official version.
+ * check for drum track added
+ * when midi program channel is command encountered, we ensure that 
+ * we are using the correct channel number for the Voice by sending
+ * a %%MIDI channel message.
+ *
+ * Many more changes (see doc/CHANGES) 
+ *
+ *                Seymour Shlien  2005
+ * 
+ * based on public domain 'midifilelib' package.
+ */
+
+#define VERSION "2.90 March 15 2007"
+#define SPLITCODE
+
+/* Microsoft Visual C++ Version 6.0 or higher */
+#ifdef _MSC_VER
+#define ANSILIBS
+#endif
+
+#include <stdio.h>
+#ifdef PCCFIX
+#define stdout 1
+#endif
+
+/* define USE_INDEX if your C libraries have index() instead of strchr() */
+#ifdef USE_INDEX
+#define strchr index
+#endif
+
+#if defined(ANSILIBS) || defined(__STDC__)
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#else
+extern char* malloc();
+extern char* strchr();
+#endif
+#include "midifile.h"
+#define BUFFSIZE 200
+/* declare MIDDLE C */
+#define MIDDLE 72
+void initfuncs();
+void setupkey(int);
+int testtrack(int trackno, int barbeats, int anacrusis);
+int open_note(int chan, int pitch, int vol);
+int close_note(int chan, int pitch, int *initvol);
+
+
+/* Global variables and structures */
+
+extern long Mf_toberead;
+
+static FILE *F;
+static FILE *outhandle; /* for producing the abc file */
+
+int tracknum=0;  /* track number */
+int division;    /* pulses per quarter note defined in MIDI header    */
+long tempo = 500000; /* the default tempo is 120 quarter notes/minute */
+int unitlen;     /* abc unit length usually defined in L: field       */
+int header_unitlen; /* first unitlen set                              */
+int unitlen_set =0; /* once unitlen is set don't allow it to change   */
+int parts_per_unitlen = 2; /* specifies minimum quantization size */
+long laston = 0; /* length of MIDI track in pulses or ticks           */
+char textbuff[BUFFSIZE]; /*buffer for handling text output to abc file*/
+int trans[256], back[256]; /*translation tables for MIDI pitch to abc note*/
+char atog[256]; /* translation tables for MIDI pitch to abc note */
+int symbol[256]; /*translation tables for MIDI pitch to abc note */
+int key[12];
+int sharps;
+int trackno, maintrack;
+int format; /* MIDI file type                                   */
+
+int karaoke, inkaraoke;
+int midline;
+int tempocount=0;  /* number of tempo indications in MIDI file */
+int gotkeysig=0; /*set to 1 if keysignature found in MIDI file */
+
+/* global parameters that may be set by command line options    */
+int xunit;    /* pulses per abc unit length                     */
+int tsig_set; /* flag - time signature already set by user      */
+int ksig_set; /* flag - key signature already set by user       */
+int xunit_set;/* flat - xunit already set by user               */
+int extracta; /* flag - get anacrusis from strong beat          */
+int guessu;   /* flag - estimate xunit from note durations      */
+int guessa;   /* flag - get anacrusis by minimizing tied notes  */
+int guessk;   /* flag - guess key signature                     */
+int summary;  /* flag - output summary info of MIDI file        */
+int keep_short; /*flag - preserve short notes                   */
+int swallow_rests; /* flag - absorb short rests                 */
+int midiprint; /* flag - run midigram instead of midi2abc       */
+#ifdef SPLITCODE
+int usesplits; /* flag - split measure into parts if needed     */
+#endif
+int restsize; /* smallest rest to absorb                        */
+int no_triplets; /* flag - suppress triplets or broken rhythm   */
+int obpl = 0; /* flag to specify one bar per abc text line      */
+int nogr = 0; /* flag to put a space between every note         */
+int bars_per_line=4;  /* number of bars per output line         */
+int bars_per_staff=4; /* number of bars per music staff         */
+int asig, bsig;  /* time signature asig/bsig                    */
+int header_asig =0; /* first time signature encountered         */
+int header_bsig =0; /* first time signature encountered         */
+int header_bb;      /* first ticks/quarter note encountered     */
+int active_asig,active_bsig;  /* last time signature declared   */
+int last_asig, last_ksig; /* last time signature printed        */
+int barsize; /* barsize in parts_per_unitlen units                   */
+int Qval;        /* tempo - quarter notes per minute            */
+int verbosity=0; /* control amount of detail messages in abcfile*/
+
+/* global arguments dependent on command line options or computed */
+
+int anacrusis=0; 
+int bars;
+int keysig;
+int header_keysig=  -50;  /* header key signature                     */
+int active_keysig = -50;  /* last key signature declared        */
+int xchannel;  /* channel number to be extracted. -1 means all  */
+
+
+/* structure for storing music notes */
+struct anote {
+  int pitch;  /* MIDI pitch    */
+  int chan;   /* MIDI channel  */
+  int vel;    /* MIDI velocity */
+  long time;  /* MIDI onset time in pulses */
+  long dtnext; /* time increment to next note in pulses */
+  long tplay;  /* note duration in pulses */
+  int xnum;    /* number of xunits to next note */
+  int playnum; /* note duration in number of xunits */
+  int posnum; /* note position in xunits */
+  int splitnum; /* voice split number */
+  /* int denom; */
+};
+
+
+/* linked list of notes */
+struct listx {
+  struct listx* next;
+  struct anote* note;
+};
+
+/* linked list of text items (strings) */
+struct tlistx {
+  struct tlistx* next;
+  char* text;
+  long when; 	/* time in pulses to output */
+  int type;     /* 0 - comments, other - field commands */
+};
+
+
+/* a MIDI track */
+struct atrack {
+  struct listx* head;    /* first note */
+  struct listx* tail;    /* last note */
+  struct tlistx* texthead; /* first text string */
+  struct tlistx* texttail; /* last text string */
+  int notes;             /* number of notes in track */
+  long tracklen;
+  long startwait;
+  int startunits;
+  int drumtrack;
+};
+
+/* can cope with up to 64 track MIDI files */
+struct atrack track[64];
+int trackcount = 0;
+int maxbarcount = 0;
+/* maxbarcount  is used to return the numbers of bars created.*/
+/* obpl is a flag for one bar per line. */
+
+/* double linked list of notes */
+/* used for temporary list of chords while abc is being generated */
+struct dlistx {
+  struct dlistx* next;
+  struct dlistx* last;
+  struct anote* note;
+};
+
+int notechan[2048],notechanvol[2048]; /*for linking on and off midi
+					channel commands            */
+int last_tick; /* for getting last pulse number in MIDI file */
+
+
+
+void remove_carriage_returns();
+int validnote();
+void printpitch(struct anote*);
+void printfract(int, int);
+
+
+
+
+
+/*              Stage 1. Parsing MIDI file                   */
+
+/* Functions called during the reading pass of the MIDI file */
+
+/* The following C routines are required by midifilelib.  */
+/* They specify the action to be taken when various items */
+/* are encountered in the MIDI.  The mfread function scans*/
+/* the MIDI file and calls these functions when needed.   */
+
+
+int filegetc()
+{
+    return(getc(F));
+}
+
+
+void fatal_error(s)
+char* s;
+/* fatal error encounterd - abort program */
+{
+  fprintf(stderr, "%s\n", s);
+  exit(1);
+}
+
+
+void event_error(s)
+char *s;
+/* problem encountered but OK to continue */
+{
+  printf("Error: Time=%ld Track=%d %s\n", Mf_currtime, trackno, s);
+}
+
+
+int* checkmalloc(bytes)
+/* malloc with error checking */
+int bytes;
+{
+  int *p;
+
+  p = (int*) malloc(bytes);
+  if (p == NULL) {
+    fatal_error("Out of memory error - cannot malloc!");
+  };
+  return (p);
+}
+
+
+
+char* addstring(s)
+/* create space for string and store it in memory */
+char* s;
+{
+  char* p;
+
+  p = (char*) checkmalloc(strlen(s)+1);
+  strcpy(p, s);
+  return(p);
+}
+
+void addtext(s, type)
+/* add structure for text */
+/* used when parsing MIDI file */
+char* s;
+int type;
+{
+  struct tlistx* newx;
+
+  newx = (struct tlistx*) checkmalloc(sizeof(struct tlistx));
+  newx->next = NULL;
+  newx->text = addstring(s);
+  newx->type = type;
+  newx->when = Mf_currtime;
+  if (track[trackno].texthead == NULL) {
+    track[trackno].texthead = newx;
+    track[trackno].texttail = newx;
+  }
+  else {
+    track[trackno].texttail->next = newx;
+    track[trackno].texttail = newx;
+  };
+}
+  
+
+
+/* The MIDI file has  separate commands for starting                 */
+/* and stopping a note. In order to determine the duration of        */
+/* the note it is necessary to find the note_on command associated   */
+/* with the note off command. We rely on the note's pitch and channel*/
+/* number to find the right note. While we are parsing the MIDI file */
+/* we maintain a list of all the notes that are currently on         */
+/* head and tail of list of notes still playing.                     */
+/* The following doubly linked list is used for this purpose         */
+
+struct dlistx* playinghead;
+struct dlistx* playingtail; 
+
+
+void noteplaying(p)
+/* This function adds a new note to the playinghead list. */
+struct anote* p;
+{
+  struct dlistx* newx;
+
+  newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx));
+  newx->note = p;
+  newx->next = NULL;
+  newx->last = playingtail;
+  if (playinghead == NULL) {
+    playinghead = newx;
+  };
+  if (playingtail == NULL) {
+    playingtail = newx;
+  } 
+  else {
+    playingtail->next = newx;
+    playingtail = newx;
+  };
+}
+
+
+void addnote(p, ch, v)
+/* add structure for note */
+/* used when parsing MIDI file */
+int p, v;
+{
+  struct listx* newx;
+  struct anote* newnote;
+
+  track[trackno].notes = track[trackno].notes + 1;
+  newx = (struct listx*) checkmalloc(sizeof(struct listx));
+  newnote = (struct anote*) checkmalloc(sizeof(struct anote));
+  newx->next = NULL;
+  newx->note = newnote;
+  if (track[trackno].head == NULL) {
+    track[trackno].head = newx;
+    track[trackno].tail = newx;
+  } 
+  else {
+    track[trackno].tail->next = newx;
+    track[trackno].tail = newx;
+  };
+  if (ch == 9) {
+    track[trackno].drumtrack = 1;
+  };
+  newnote->pitch = p;
+  newnote->chan = ch;
+  newnote->vel = v;
+  newnote->time = Mf_currtime;
+  laston = Mf_currtime;
+  newnote->tplay = Mf_currtime;
+  noteplaying(newnote);
+}
+
+
+
+void notestop(p, ch)
+/* MIDI note stops */
+/* used when parsing MIDI file */
+int p, ch;
+{
+  struct dlistx* i;
+  int found;
+  char msg[80];
+
+  i = playinghead;
+  found = 0;
+  while ((found == 0) && (i != NULL)) {
+    if ((i->note->pitch == p)&&(i->note->chan==ch)) {
+      found = 1;
+    } 
+    else {
+      i = i->next;
+    };
+  };
+  if (found == 0) {
+    sprintf(msg, "Note terminated when not on - pitch %d", p);
+    event_error(msg);
+    return;
+  };
+  /* fill in tplay field */
+  i->note->tplay = Mf_currtime - (i->note->tplay);
+  /* remove note from list */
+  if (i->last == NULL) {
+    playinghead = i->next;
+  } 
+  else {
+    (i->last)->next = i->next;
+  };
+  if (i->next == NULL) {
+    playingtail = i->last;
+  } 
+  else {
+    (i->next)->last = i->last;
+  };
+  free(i);
+}
+
+
+
+
+FILE *
+efopen(name,mode)
+char *name;
+char *mode;
+{
+    FILE *f;
+
+    if ( (f=fopen(name,mode)) == NULL ) {
+      char msg[256];
+      sprintf(msg,"Error - Cannot open file %s",name);
+      fatal_error(msg);
+    }
+    return(f);
+}
+
+
+void error(s)
+char *s;
+{
+    fprintf(stderr,"Error: %s\n",s);
+}
+
+
+
+void txt_header(xformat,ntrks,ldivision)
+int xformat, ntrks, ldivision;
+{
+    division = ldivision; 
+    format = xformat;
+    if (format != 0) {
+    /*  fprintf(outhandle,"%% format %d file %d tracks\n", format, ntrks);*/
+      if(summary>0) printf("This midi file has %d tracks\n\n",ntrks);
+    } 
+    else {
+/*     fprintf(outhandle,"%% type 0 midi file\n"); */
+     if(summary>0) {
+	     printf("This is a type 0 midi file.\n");
+             printf("All the channels are in one track.\n");
+             printf("You may need to process the channels separately\n\n");
+            }
+     }
+     
+}
+
+
+void txt_trackstart()
+{
+  laston = 0L;
+  track[trackno].notes = 0;
+  track[trackno].head = NULL;
+  track[trackno].tail = NULL;
+  track[trackno].texthead = NULL;
+  track[trackno].texttail = NULL;
+  track[trackno].tracklen = Mf_currtime;
+  track[trackno].drumtrack = 0;
+}
+
+void txt_trackend()
+{
+  /* check for unfinished notes */
+  if (playinghead != NULL) {
+    printf("Error in MIDI file - notes still on at end of track!\n");
+  };
+  track[trackno].tracklen = Mf_currtime - track[trackno].tracklen;
+  trackno = trackno + 1;
+  trackcount = trackcount + 1;
+}
+
+void txt_noteon(chan,pitch,vol)
+int chan, pitch, vol;
+{
+  if ((xchannel == -1) || (chan == xchannel)) {
+    if (vol != 0) {
+      addnote(pitch, chan, vol);
+    } 
+    else {
+      notestop(pitch, chan);
+    };
+  };
+}
+
+void txt_noteoff(chan,pitch,vol)
+int chan, pitch, vol;
+{
+  if ((xchannel == -1) || (chan == xchannel)) {
+    notestop(pitch, chan);
+  };
+}
+
+void txt_pressure(chan,pitch,press)
+int chan, pitch, press;
+{
+}
+
+void txt_parameter(chan,control,value)
+int chan, control, value;
+{
+}
+
+void txt_pitchbend(chan,msb,lsb)
+int chan, msb, lsb;
+{
+}
+
+void txt_program(chan,program)
+int chan, program;
+{
+/*
+  sprintf(textbuff, "%%%%MIDI program %d %d",
+         chan+1, program);
+*/
+  sprintf(textbuff, "%%%%MIDI program %d", program);
+  addtext(textbuff,0);
+/* abc2midi does not use the same channel number as specified in 
+  the original midi file, so we should not specify that channel
+  number in the %%MIDI program. If we leave it out the program
+  will refer to the current channel assigned to this voice.
+*/
+}
+
+void txt_chanpressure(chan,press)
+int chan, press;
+{
+}
+
+void txt_sysex(leng,mess)
+int leng;
+char *mess;
+{
+}
+
+void txt_metamisc(type,leng,mess)
+int type, leng;
+char *mess;
+{
+}
+
+void txt_metaspecial(type,leng,mess)
+int type, leng;
+char *mess;
+{
+}
+
+void txt_metatext(type,leng,mess)
+int type, leng;
+char *mess;
+{ 
+    char *ttype[] = {
+    NULL,
+    "Text Event",        /* type=0x01 */
+    "Copyright Notice",    /* type=0x02 */
+    "Sequence/Track Name",
+    "Instrument Name",    /* ...     */
+    "Lyric",
+    "Marker",
+    "Cue Point",        /* type=0x07 */
+    "Unrecognized"
+  };
+  int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
+  unsigned char c;
+  int n;
+  char *p = mess;
+  char *buff;
+  char buffer2[BUFFSIZE];
+
+  if ((type < 1)||(type > unrecognized))
+      type = unrecognized;
+  buff = textbuff;
+  for (n=0; n<leng; n++) {
+    c = *p++;
+    if (buff - textbuff < BUFFSIZE - 6) {
+      sprintf(buff, 
+           (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c);
+      buff = buff + strlen(buff);
+    };
+  }
+  if (strncmp(textbuff, "@KMIDI KARAOKE FILE", 14) == 0) {
+    karaoke = 1;
+  } 
+  else {
+    if ((karaoke == 1) && (*textbuff != '@')) {
+      addtext(textbuff,0);
+    } 
+    else {
+      if (leng < BUFFSIZE - 3) {
+        sprintf(buffer2, " %s", textbuff); 
+        addtext(buffer2,0);
+      };
+    };
+  };
+}
+
+void txt_metaseq(num)
+int num;
+{  
+  sprintf(textbuff, "%%Meta event, sequence number = %d",num);
+  addtext(textbuff,0);
+}
+
+void txt_metaeot()
+/* Meta event, end of track */
+{
+}
+
+void txt_keysig(sf,mi)
+char sf, mi;
+{
+  int accidentals;
+  gotkeysig =1;
+  sprintf(textbuff, 
+         "%% MIDI Key signature, sharp/flats=%d  minor=%d",
+          (int) sf, (int) mi);
+  if(verbosity) addtext(textbuff,0);
+  sprintf(textbuff,"%d %d\n",sf,mi);
+  if (!ksig_set) {
+	  addtext(textbuff,1);
+	  keysig=sf;
+  }
+  if (header_keysig == -50) header_keysig = keysig;
+  if (summary <= 0) return;
+  /* There may be several key signature changes in the midi
+     file so that key signature in the mid file does not conform
+     with the abc file. Show all key signature changes. 
+  */   
+  accidentals = (int) sf;
+  if (accidentals <0 )
+    {
+    accidentals = -accidentals;
+    printf("Key signature: %d flats", accidentals);
+    }
+  else
+     printf("Key signature : %d sharps", accidentals);
+  if (ksig_set) printf(" suppressed\n");
+  else printf("\n");
+}
+
+void txt_tempo(ltempo)
+long ltempo;
+{
+    if(tempocount>0) return; /* ignore other tempo indications */
+    tempo = ltempo;
+    tempocount++;
+}
+
+
+void setup_timesig(nn,  denom,  bb)
+int nn,denom,bb;
+{
+  asig = nn;
+  bsig = denom;
+/* we must keep unitlen and xunit fixed for the entire tune */
+  if (unitlen_set == 0) {
+    unitlen_set = 1; 
+    if ((asig*4)/bsig >= 3) {
+      unitlen =8;
+      } 
+    else {
+      unitlen = 16;
+      };
+   }
+/* set xunit for this unitlen */
+  if(!xunit_set) xunit = (division*bb*4)/(8*unitlen);
+  barsize = parts_per_unitlen*asig*unitlen/bsig;
+/*  printf("setup_timesig: unitlen=%d xunit=%d barsize=%d\n",unitlen,xunit,barsize); */
+  if (header_asig ==0) {header_asig = asig;
+	                header_bsig = bsig;
+			header_unitlen = unitlen;
+			header_bb = bb;
+                       }
+}
+
+
+void txt_timesig(nn,dd,cc,bb)
+int nn, dd, cc, bb;
+{
+  int denom = 1;
+  while ( dd-- > 0 )
+    denom *= 2;
+  sprintf(textbuff, 
+          "%% Time signature=%d/%d  MIDI-clocks/click=%d  32nd-notes/24-MIDI-clocks=%d", 
+    nn,denom,cc,bb);
+  if (verbosity) addtext(textbuff,0);
+  sprintf(textbuff,"%d %d %d\n",nn,denom,bb);
+  if (!tsig_set) {
+	  addtext(textbuff,2);
+          setup_timesig(nn, denom,bb);
+   }
+  if (summary>0) {
+    if(tsig_set) printf("Time signature = %d/%d suppressed\n",nn,denom);
+    else printf("Time signature = %d/%d\n",nn,denom);
+    }
+}
+
+
+void txt_smpte(hr,mn,se,fr,ff)
+int hr, mn, se, fr, ff;
+{
+}
+
+void txt_arbitrary(leng,mess)
+char *mess;
+int leng;
+{
+}
+
+
+
+/* Dummy functions for handling MIDI messages.
+ *    */
+ void no_op0() {}
+ void no_op1(int dummy1) {}
+ void no_op2(int dummy1, int dummy2) {}
+ void no_op3(int dummy1, int dummy2, int dummy3) { }
+ void no_op4(int dummy1, int dummy2, int dummy3, int dummy4) { }
+ void no_op5(int dummy1, int dummy2, int dummy3, int dummy4, int dummy5) { }
+
+
+
+void print_txt_noteon(chan, pitch, vol)
+{
+int start_time;
+int initvol;
+if (vol > 0)
+open_note(chan, pitch, vol);
+else {
+  start_time = close_note(chan, pitch,&initvol);
+  if (start_time >= 0)
+     /* printf("%8.4f %8.4f %d %d %d %d\n",
+       (double) start_time/(double) division,
+       (double) Mf_currtime/(double) division,
+       trackno+1, chan +1, pitch,initvol);
+     */
+       printf("%d %ld %d %d %d %d\n",
+       start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol);
+
+      if(Mf_currtime > last_tick) last_tick = Mf_currtime;
+   }
+}
+
+
+
+void print_txt_noteoff(chan, pitch, vol)
+{
+int start_time,initvol;
+
+start_time = close_note(chan, pitch, &initvol);
+if (start_time >= 0)
+/*
+    printf("%8.4f %8.4f %d %d %d %d\n",
+     (double) start_time/(double) division,
+     (double) Mf_currtime/(double) division,
+     trackno+1, chan+1, pitch,initvol);
+*/
+     printf("%d %ld %d %d %d %d\n",
+       start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol);
+    if(Mf_currtime > last_tick) last_tick = Mf_currtime;
+}
+
+
+
+/* In order to associate a channel note off message with its
+ * corresponding note on message, we maintain the information
+ * the notechan array. When a midi pitch (0-127) is switched
+ * on for a particular channel, we record the time that it
+ * was turned on in the notechan array. As there are 16 channels
+ * and 128 pitches, we initialize an array 128*16 = 2048 elements
+ * long.
+**/
+void init_notechan()
+{
+/* signal that there are no active notes */
+ int i;
+ for (i = 0; i < 2048; i++) notechan[i] = -1;
+}
+
+
+/* The next two functions update notechan when a channel note on
+   or note off is encountered. The second function close_note,
+   returns the time when the note was turned on.
+*/
+int open_note(int chan, int pitch, int vol)
+{
+    notechan[128 * chan + pitch] = Mf_currtime;
+    notechanvol[128 * chan + pitch] = vol;
+    return 0;
+}
+
+
+int close_note(int chan, int pitch, int *initvol)
+{
+    int index, start_tick;
+    index = 128 * chan + pitch;
+    if (notechan[index] < 0)
+	return -1;
+    start_tick = notechan[index];
+    *initvol = notechanvol[index];
+    notechan[index] = -1;
+    return start_tick;
+}
+
+
+/* mftext mode */
+int prtime()
+{
+/*  if(Mf_currtime >= pulses) ignore=0; 
+  if (ignore) return 1; 
+  linecount++;
+  if(linecount > maxlines) {fclose(F); exit(0);}
+*/
+  int units;
+  units = 2;
+  if(units==1)
+ /*seconds*/
+     printf("%6.2f   ",mf_ticks2sec(Mf_currtime,division,tempo));
+  else if (units==2)
+ /*beats*/
+     printf("%6.2f   ",(float) Mf_currtime/(float) division);
+  else
+ /*pulses*/
+    printf("%6ld  ",Mf_currtime);
+  return 0;
+}
+
+char * pitch2key(int note)
+{
+static char name[5];
+char* s = name;
+  switch(note % 12)
+  {
+  case 0: *s++ = 'c'; break;
+  case 1: *s++ = 'c'; *s++ = '#'; break;
+  case 2: *s++ = 'd'; break;
+  case 3: *s++ = 'd'; *s++ = '#'; break;
+  case 4: *s++ = 'e'; break;
+  case 5: *s++ = 'f'; break;
+  case 6: *s++ = 'f'; *s++ = '#'; break;
+  case 7: *s++ = 'g'; break;
+  case 8: *s++ = 'g'; *s++ = '#'; break;
+  case 9: *s++ = 'a'; break;
+  case 10: *s++ = 'a'; *s++ = '#'; break;
+  case 11: *s++ = 'b'; break;
+  }
+  sprintf(s, "%d", (note / 12)-1);  /* octave  (assuming Piano C4 is 60)*/
+  return  name;
+}
+
+void mftxt_header (int format, int ntrks, int ldivision)
+{
+  division = ldivision;
+  printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division);
+}
+
+void mftxt_trackstart()
+{
+  int numbytes;
+  tracknum++;
+  numbytes = Mf_toberead;
+  /*if(track != 0 && tracknum != track) {ignore_bytes(numbytes); return;} */
+  printf("Track %d contains %d bytes\n",tracknum,numbytes);
+}
+
+
+void mftxt_noteon(chan,pitch,vol)
+{
+  char *key;
+/*
+  if (onlychan >=0 && chan != onlychan) return;
+*/
+  if (prtime()) return;
+  key = pitch2key(pitch);
+  printf("Note on  %2d  %3s %3d\n",chan+1, key,vol);
+}
+
+void mftxt_noteoff(chan,pitch,vol)
+{
+  char *key;
+/*
+  if (onlychan >=0 && chan != onlychan) return;
+*/
+  if (prtime()) return;
+  key = pitch2key(pitch);
+  printf("Note off %2d  %3s %3d\n",chan+1,key,vol);
+}
+
+void mftxt_pressure(chan,pitch,press)
+{
+  char *key;
+  if (prtime()) return;
+  key = pitch2key(pitch);
+  printf("Pressure %2d   %3s %3d\n",chan+1,key,press);
+}
+
+
+void mftxt_pitchbend(chan,msb,lsb)
+{
+/*
+  if (onlychan >=0 && chan != onlychan) return;
+*/
+  if (prtime()) return;
+  printf("Pitchbnd %2d msb=%d lsb=%d\n",chan+1,msb,lsb);
+}
+
+
+
+void mftxt_program(chan,program)
+{
+static char *patches[] = {
+ "Acoustic Grand","Bright Acoustic","Electric Grand","Honky-Tonk", 
+ "Electric Piano 1","Electric Piano 2","Harpsichord","Clav", 
+ "Celesta", "Glockenspiel",  "Music Box",  "Vibraphone", 
+ "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", 
+ "Drawbar Organ", "Percussive Organ", "Rock Organ", "Church Organ", 
+ "Reed Organ", "Accordian", "Harmonica", "Tango Accordian",
+ "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)",
+ "Electric Guitar (jazz)", "Electric Guitar (clean)", 
+ "Electric Guitar (muted)", "Overdriven Guitar",
+ "Distortion Guitar", "Guitar Harmonics",
+ "Acoustic Bass", "Electric Bass (finger)",
+ "Electric Bass (pick)", "Fretless Bass",
+ "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2",
+ "Violin", "Viola", "Cello", "Contrabass",
+ "Tremolo Strings", "Pizzicato Strings",
+ "Orchestral Strings", "Timpani",
+ "String Ensemble 1", "String Ensemble 2",
+ "SynthStrings 1", "SynthStrings 2", 
+ "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit",
+ "Trumpet", "Trombone", "Tuba", "Muted Trumpet",
+ "French Horn", "Brass Section", "SynthBrass 1", "SynthBrass 2",
+ "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax",
+ "Oboe", "English Horn", "Bassoon", "Clarinet",
+ "Piccolo", "Flute", "Recorder", "Pan Flute",
+ "Blown Bottle", "Skakuhachi", "Whistle", "Ocarina",
+ "Lead 1 (square)", "Lead 2 (sawtooth)",
+ "Lead 3 (calliope)", "Lead 4 (chiff)", 
+ "Lead 5 (charang)", "Lead 6 (voice)",
+ "Lead 7 (fifths)", "Lead 8 (bass+lead)",
+ "Pad 1 (new age)", "Pad 2 (warm)",
+ "Pad 3 (polysynth)", "Pad 4 (choir)",
+ "Pad 5 (bowed)", "Pad 6 (metallic)",
+ "Pad 7 (halo)", "Pad 8 (sweep)",
+ "FX 1 (rain)", "(soundtrack)",
+ "FX 3 (crystal)", "FX 4 (atmosphere)",
+ "FX 5 (brightness)", "FX 6 (goblins)",
+ "FX 7 (echoes)", "FX 8 (sci-fi)",
+ "Sitar", "Banjo", "Shamisen", "Koto",
+ "Kalimba", "Bagpipe", "Fiddle", "Shanai",
+ "Tinkle Bell", "Agogo", "Steel Drums", "Woodblock",
+ "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal",
+ "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet",
+ "Telephone ring", "Helicopter", "Applause", "Gunshot"};
+/*
+  if (onlychan >=0 && chan != onlychan) return;
+*/
+  if (prtime()) return;
+  printf("Program  %2d %d (%s)\n",chan+1, program,patches[program]);
+   }
+
+void mftxt_chanpressure(chan,press)
+{
+  prtime();
+  printf("Chanpres %2d pressure=%d\n",chan+1,press);
+}
+
+
+void mftxt_parameter(chan,control,value)
+{
+  static char *ctype[] = {
+ "Bank Select",       "Modulation Wheel",     /*1*/
+ "Breath controller", "unknown",              /*3*/
+ "Foot Pedal",        "Portamento Time",      /*5*/
+ "Data Entry",        "Volume",               /*7*/
+ "Balance",           "unknown",              /*9*/
+ "Pan position",      "Expression",           /*11*/
+ "Effect Control 1",  "Effect Control 2",     /*13*/
+ "unknown",           "unknown",              /*15*/
+ "Slider 1",          "Slider 2",             /*17*/
+ "Slider 3",          "Slider 4",             /*19*/
+ "unknown",           "unknown",              /*21*/
+ "unknown",           "unknown",              /*23*/
+ "unknown",           "unknown",              /*25*/
+ "unknown",           "unknown",              /*27*/
+ "unknown",           "unknown",              /*29*/
+ "unknown",           "unknown",              /*31*/
+ "Bank Select (fine)",  "Modulation Wheel (fine)",    /*33*/
+ "Breath controller (fine)",  "unknown",              /*35*/
+ "Foot Pedal (fine)",   "Portamento Time (fine)",     /*37*/
+ "Data Entry (fine)",   "Volume (fine)",              /*39*/
+ "Balance (fine)",      "unknown",                    /*41*/
+ "Pan position (fine)", "Expression (fine)",          /*43*/
+ "Effect Control 1 (fine)",  "Effect Control 2 (fine)", /*45*/
+ "unknown",           "unknown",             /*47*/
+ "unknown",           "unknown",             /*49*/
+ "unknown",           "unknown",             /*51*/
+ "unknown",           "unknown",             /*53*/
+ "unknown",           "unknown",             /*55*/
+ "unknown",           "unknown",             /*57*/
+ "unknown",           "unknown",             /*59*/
+"unknown",           "unknown",             /*61*/
+ "unknown",           "unknown",             /*63*/
+ "Hold Pedal",        "Portamento",          /*65*/
+ "Susteno Pedal",     "Soft Pedal",          /*67*/
+ "Legato Pedal",      "Hold 2 Pedal",        /*69*/
+ "Sound Variation",   "Sound Timbre",        /*71*/
+ "Sound Release Time",  "Sound Attack Time", /*73*/
+ "Sound Brightness",  "Sound Control 6",     /*75*/
+ "Sound Control 7",   "Sound Control 8",     /*77*/
+ "Sound Control 9",   "Sound Control 10",    /*79*/
+ "GP Button 1",       "GP Button 2",         /*81*/
+ "GP Button 3",       "GP Button 4",         /*83*/
+ "unknown",           "unknown",             /*85*/
+ "unknown",           "unknown",             /*87*/
+ "unknown",           "unknown",             /*89*/
+ "unknown",           "Effects Level",       /*91*/
+ "Tremolo Level",     "Chorus Level",        /*93*/
+ "Celeste Level",     "Phaser Level",        /*95*/
+ "Data button increment",  "Data button decrement", /*97*/
+ "NRP (fine)",        "NRP (coarse)",        /*99*/
+ "Registered parameter (fine)", "Registered parameter (coarse)", /*101*/
+ "unknown",           "unknown",             /*103*/
+ "unknown",           "unknown",             /*105*/
+ "unknown",           "unknown",             /*107*/
+ "unknown",           "unknown",             /*109*/
+ "unknown",           "unknown",             /*111*/
+ "unknown",           "unknown",             /*113*/
+ "unknown",           "unknown",             /*115*/
+ "unknown",           "unknown",             /*117*/
+ "unknown",           "unknown",             /*119*/
+ "All Sound Off",     "All Controllers Off", /*121*/
+ "Local Keyboard (on/off)","All Notes Off",  /*123*/
+ "Omni Mode Off",     "Omni Mode On",        /*125*/
+ "Mono Operation",    "Poly Operation"};
+
+/*  if (onlychan >=0 && chan != onlychan) return; */
+  if (prtime()) return;
+
+  printf("CntlParm %2d %s = %d\n",chan+1, ctype[control],value);
+}
+
+
+void mftxt_metatext(type,leng,mess)
+char *mess;
+{
+  static char *ttype[] = {
+    NULL,
+    "Text Event",    /* type=0x01 */
+    "Copyright Notice",  /* type=0x02 */
+    "Seqnce/Track Name",
+    "Instrument Name",  /* ...       */
+    "Lyric",
+    "Marker",
+    "Cue Point",    /* type=0x07 */
+    "Unrecognized"
+  };
+  int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
+  int len;
+  register int n, c;
+  register char *p = mess;
+
+  if ( type < 1 || type > unrecognized )
+    type = unrecognized;
+  if (prtime()) return;
+  printf("Metatext (%s) ",ttype[type]);
+  len = leng;
+  if (len > 15) len = 15;
+  for ( n=0; n<len; n++ ) {
+    c = (*p++) & 0xff;
+    if(iscntrl(c)) {printf(" \\0x%02x",c); continue;} /* no <cr> <lf> */
+    printf( (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c);
+  }
+  if (leng>15) printf("...");
+  printf("\n");
+}
+
+void mftxt_keysig(sf,mi)
+{
+  static char *major[] = {"Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F",
+    "C", "G", "D", "A", "E", "B", "F#", "C#"};
+  static char *minor[] = {"Abmin", "Ebmin", "Bbmin", "Fmin", "Cmin",
+    "Gmin", "Dmin", "Amin", "Emin", "Bmin", "F#min", "C#min", "G#min"};
+  int index;
+  index = sf + 7;
+  if (prtime()) return;
+  if (mi)
+    printf("Metatext key signature %s (%d/%d)\n",minor[index],sf,mi);
+  else
+    printf("Metatext key signature %s (%d/%d)\n",major[index],sf,mi);
+}
+
+void mftxt_tempo(ltempo)
+long ltempo;
+{
+  tempo = ltempo;
+  if (prtime()) return;
+  printf("Metatext tempo = %6.2f bpm\n",60000000.0/tempo);
+}
+
+void mftxt_timesig(nn,dd,cc,bb)
+{
+  int denom = 1;
+  while ( dd-- > 0 )
+    denom *= 2;
+  if (prtime()) return;
+  printf("Metatext time signature=%d/%d\n",nn,denom);
+/*  printf("Time signature=%d/%d  MIDI-clocks/click=%d \
+  32nd-notes/24-MIDI-clocks=%d\n", nn,denom,cc,bb); */
+}
+
+void mftxt_smpte(hr,mn,se,fr,ff)
+{
+  if (prtime()) return;
+  printf("Metatext SMPTE, %d:%d:%d  %d=%d\n", hr,mn,se,fr,ff);
+}
+
+void mftxt_metaeot()
+{
+  if (prtime()) return;
+  printf("Meta event, end of track\n");
+}
+
+
+void initfunc_for_midinotes()
+{
+    Mf_error = error;
+    Mf_header = txt_header;
+    Mf_trackstart = txt_trackstart;
+    Mf_trackend = txt_trackend;
+    Mf_noteon = print_txt_noteon;
+    Mf_noteoff = print_txt_noteoff;
+    Mf_pressure = no_op3;
+    Mf_parameter = no_op3;
+    Mf_pitchbend = no_op3;
+    Mf_program = no_op2;
+    Mf_chanpressure = no_op3;
+    Mf_sysex = no_op2;
+    Mf_metamisc = no_op3;
+    Mf_seqnum = no_op1;
+    Mf_eot = no_op0;
+    Mf_timesig = no_op4;
+    Mf_smpte = no_op5;
+    Mf_tempo = no_op1;
+    Mf_keysig = no_op2;
+    Mf_seqspecific = no_op3;
+    Mf_text = no_op3;
+    Mf_arbitrary = no_op2;
+}
+
+
+void initfunc_for_mftext()
+{
+    Mf_error = error;
+    Mf_header = mftxt_header;
+    Mf_trackstart = mftxt_trackstart;
+    Mf_trackend = txt_trackend;
+    Mf_noteon = mftxt_noteon;
+    Mf_noteoff = mftxt_noteoff;
+    Mf_pressure =mftxt_pressure;
+    Mf_parameter = mftxt_parameter;
+    Mf_pitchbend = mftxt_pitchbend;
+    Mf_program = mftxt_program;
+    Mf_chanpressure = mftxt_chanpressure;
+    Mf_sysex = no_op2;
+    Mf_metamisc = no_op3;
+    Mf_seqnum = no_op1;
+    Mf_eot = mftxt_metaeot;
+    Mf_timesig = mftxt_timesig;
+    Mf_smpte = mftxt_smpte;
+    Mf_tempo = mftxt_tempo;
+    Mf_keysig = mftxt_keysig;
+    Mf_seqspecific = no_op3;
+    Mf_text = mftxt_metatext;
+    Mf_arbitrary = no_op2;
+}
+
+
+
+
+void initfuncs()
+{
+    Mf_error = error;
+    Mf_header =  txt_header;
+    Mf_trackstart =  txt_trackstart;
+    Mf_trackend =  txt_trackend;
+    Mf_noteon =  txt_noteon;
+    Mf_noteoff =  txt_noteoff;
+    Mf_pressure =  txt_pressure;
+    Mf_parameter =  txt_parameter;
+    Mf_pitchbend =  txt_pitchbend;
+    Mf_program =  txt_program;
+    Mf_chanpressure =  txt_chanpressure;
+    Mf_sysex =  txt_sysex;
+    Mf_metamisc =  txt_metamisc;
+    Mf_seqnum =  txt_metaseq;
+    Mf_eot =  txt_metaeot;
+    Mf_timesig =  txt_timesig;
+    Mf_smpte =  txt_smpte;
+    Mf_tempo =  txt_tempo;
+    Mf_keysig =  txt_keysig;
+    Mf_seqspecific =  txt_metaspecial;
+    Mf_text =  txt_metatext;
+    Mf_arbitrary =  txt_arbitrary;
+}
+
+
+/*  Stage 2 Quantize MIDI tracks. Get key signature, time signature...   */ 
+
+
+void postprocess(trackno)
+/* This routine calculates the time interval before the next note */
+/* called after the MIDI file has been read in */
+int trackno;
+{
+  struct listx* i;
+
+  i = track[trackno].head;
+  if (i != NULL) {
+    track[trackno].startwait = i->note->time;
+  } 
+  else {
+    track[trackno].startwait = 0;
+  };
+  while (i != NULL) {
+    if (i->next != NULL) {
+      i->note->dtnext = i->next->note->time - i->note->time;
+    } 
+    else {
+      i->note->dtnext = i->note->tplay;
+    };
+    i = i->next;
+  };
+}
+
+void scannotes(trackno)
+int trackno;
+/* diagnostic routine to output notes in a track */
+{
+  struct listx* i;
+
+  i = track[trackno].head;
+  while (i != NULL) {
+    printf("Pitch %d chan %d vel %d time %ld  %ld xnum %d playnum %d\n",
+            i->note->pitch, i->note->chan, 
+            i->note->vel, i->note->dtnext, i->note->tplay,
+            i->note->xnum, i->note->playnum);
+    i = i->next;
+  };
+}
+
+
+int xnum_to_next_nonchordal_note(fromitem,spare,quantum)
+struct listx* fromitem;
+int spare,quantum;
+{
+struct anote* jnote;
+struct listx* nextitem;
+int i,xxnum;
+jnote = fromitem->note;
+if (jnote->xnum > 0) return jnote->xnum;
+i = 0;
+nextitem = fromitem->next;
+while (nextitem != NULL && i < 5) {
+  jnote = nextitem->note;
+  xxnum = (2*(jnote->dtnext + spare + (quantum/4)))/quantum;
+  if (xxnum > 0) return xxnum;
+  i++;
+  nextitem = nextitem->next;
+  }
+return 0;
+}
+
+int quantize(trackno, xunit)
+/* Work out how long each note is in musical time units.
+ * The results are placed in note.playnum              */
+int trackno, xunit;
+{
+  struct listx* j;
+  struct anote* this;
+  int spare;
+  int toterror;
+  int quantum;
+  int posnum,xxnum;
+
+  /* fix to avoid division by zero errors in strange MIDI */
+  if (xunit == 0) {
+    return(10000);
+  };
+  quantum = (int) (2.*xunit/parts_per_unitlen); /* xunit assume 2 parts_per_unit */
+  track[trackno].startunits = (2*(track[trackno].startwait + (quantum/4)))/quantum;
+  spare = 0;
+  toterror = 0;
+  j = track[trackno].head;
+  posnum = 0;
+  while (j != NULL) {
+    this = j->note;
+    /* this->xnum is the quantized inter onset time */
+    /* this->playnum is the quantized note length   */
+    this->xnum = (2*(this->dtnext + spare + (quantum/4)))/quantum;
+    this->playnum = (2*(this->tplay + (quantum/4)))/quantum;
+    if ((this->playnum == 0) && (keep_short)) {
+      this->playnum = 1;
+    };
+    /* In the event of short rests, the inter onset time
+     * will be larger than the note length. However, for
+     * chords the inter onset time can be zero.          */
+    xxnum =  xnum_to_next_nonchordal_note(j,spare,quantum);
+    if ((swallow_rests>=0) && (xxnum - this->playnum <= restsize)
+		        && xxnum > 0) {
+      this->playnum = xxnum;
+    };
+   /* this->denom = parts_per_unitlen;  this variable is never used ! */
+    spare = spare + this->dtnext - (this->xnum*xunit/parts_per_unitlen);
+    if (spare > 0) {
+      toterror = toterror + spare;
+    } 
+    else {
+      toterror = toterror - spare;
+    };
+    /* gradually forget old errors so that if xunit is slightly off,
+       errors don't accumulate over several bars */
+    spare = (spare * 96)/100;
+    this->posnum = posnum;
+    posnum += this->xnum;
+    j = j->next;
+  };
+  return(toterror);
+}
+
+
+void guesslengths(trackno)
+/* work out most appropriate value for a unit of musical time */
+int trackno;
+{
+  int i;
+  int trial[100];
+  float avlen, factor, tryx;
+  long min;
+
+  min = track[trackno].tracklen;
+  if (track[trackno].notes == 0) {
+    return;
+  };
+  avlen = ((float)(min))/((float)(track[trackno].notes));
+  tryx = avlen * (float) 0.75;
+  factor = tryx/100;
+  for (i=0; i<100; i++) {
+    trial[i] = quantize(trackno, (int) tryx);
+    if ((long) trial[i] < min) {
+      min = (long) trial[i];
+      xunit = (int) tryx;
+    };
+    tryx = tryx + factor;
+  };
+xunit_set = 1;
+}
+
+
+int findana(maintrack, barsize)
+/* work out anacrusis from MIDI */
+/* look for a strong beat marking the start of a bar */
+int maintrack;
+int barsize;
+{
+  int min, mincount;
+  int place;
+  struct listx* p;
+
+  min = 0;
+  mincount = 0;
+  place = 0;
+  p = track[maintrack].head;
+  while ((p != NULL) && (place < barsize)) {
+    if ((p->note->vel > min) && (place > 0)) {
+      min = p->note->vel;
+      mincount = place;
+    };
+    place = place + (p->note->xnum);
+    p = p->next;
+  };
+  return(mincount);
+}
+
+
+
+int guessana(barbeats)
+int barbeats;
+/* try to guess length of anacrusis */
+{
+  int score[64];
+  int min, minplace;
+  int i,j;
+
+  if (barbeats > 64) {
+    fatal_error("Bar size exceeds static limit of 64 units!");
+  };
+  for (j=0; j<barbeats; j++) {
+    score[j] = 0;
+    for (i=0; i<trackcount; i++) {
+      score[j] = score[j] + testtrack(i, barbeats, j);
+      /* restore values to num */
+      quantize(i, xunit);
+    };
+  };
+  min = score[0];
+  minplace = 0;
+  for (i=0; i<barbeats; i++) {
+    if (score[i] < min) {
+      min = score[i];
+      minplace = i;
+    };
+  };
+  return(minplace);
+}
+
+
+int findkey(maintrack)
+int maintrack;
+/* work out what key MIDI file is in */
+/* algorithm is simply to minimize the number of accidentals needed. */
+{
+  int j;
+  int max, min, n[12], key_score[12];
+  int minkey, minblacks;
+  static int keysharps[12] = {
+	  0, -5, 2, -3, 4, -1, 6, 1, -4, 3, -2, 5};
+  struct listx* p;
+  int thispitch;
+  int lastpitch;
+  int totalnotes;
+
+  /* analyse pitches */
+  /* find key */
+  for (j=0; j<12; j++) {
+    n[j] = 0;
+  };
+  min = track[maintrack].tail->note->pitch;
+  max = min;
+  totalnotes = 0;
+  for (j=0; j<trackcount; j++) {
+    totalnotes = totalnotes + track[j].notes;
+    p = track[j].head;
+    while (p != NULL) {
+      thispitch = p->note->pitch;
+      if (thispitch > max) {
+        max = thispitch;
+      } 
+      else {
+        if (thispitch < min) {
+          min = thispitch;
+        };
+      };
+      n[thispitch % 12] = n[thispitch % 12] + 1;
+      p = p->next;
+    };
+  };
+  /* count black notes for each key */
+  /* assume pitch = 0 is C */
+  minkey = 0;
+  minblacks = totalnotes;
+  for (j=0; j<12; j++) {
+    key_score[j] = n[(j+1)%12] + n[(j+3)%12] + n[(j+6)%12] +
+                   n[(j+8)%12] + n[(j+10)%12];
+    /* printf("Score for key %d is %d\n", j, key_score[j]); */
+    if (key_score[j] < minblacks) {
+      minkey = j;
+      minblacks = key_score[j];
+    };
+  };
+  /* do conversion to abc pitches */
+  /* Code changed to use absolute rather than */
+  /* relative choice of pitch for 'c' */
+  /* MIDDLE = (min + (max - min)/2 + 6)/12 * 12; */
+  /* Do last note analysis */
+  lastpitch = track[maintrack].tail->note->pitch;
+  if (minkey != (lastpitch%12)) {
+    fprintf(outhandle,"%% Last note suggests ");
+    switch((lastpitch+12-minkey)%12) {
+    case(2):
+      fprintf(outhandle,"Dorian ");
+      break;
+    case(4):
+      fprintf(outhandle,"Phrygian ");
+      break;
+    case(5):
+      fprintf(outhandle,"Lydian ");
+      break;
+    case(7):
+      fprintf(outhandle,"Mixolydian ");
+      break;
+    case(9):
+      fprintf(outhandle,"minor ");
+      break;
+    case(11):
+      fprintf(outhandle,"Locrian ");
+      break;
+    default:
+      fprintf(outhandle,"unknown ");
+      break;
+    };
+    fprintf(outhandle,"mode tune\n");
+  };
+  /* switch to minor mode if it gives same number of accidentals */
+  if ((minkey != ((lastpitch+3)%12)) && 
+      (key_score[minkey] == key_score[(lastpitch+3)%12])) {
+         minkey = (lastpitch+3)%12;
+  };
+  /* switch to major mode if it gives same number of accidentals */
+  if ((minkey != (lastpitch%12)) && 
+      (key_score[minkey] == key_score[lastpitch%12])) {
+         minkey = lastpitch%12;
+  };
+  sharps = keysharps[minkey];
+  return(sharps);
+}
+
+
+
+
+/* Stage 3  output MIDI tracks in abc format                        */
+
+
+/* head and tail of list of notes in current chord playing */
+/* used while abc is being generated */
+struct dlistx* chordhead;
+struct dlistx* chordtail;
+
+
+void printchordlist()
+/* diagnostic routine */
+{
+  struct dlistx* i;
+
+  i = chordhead;
+  printf("----CHORD LIST------\n");
+  while(i != NULL) {
+    printf("pitch %d len %d\n", i->note->pitch, i->note->playnum);
+    if (i->next == i) {
+      fatal_error("Loopback problem!");
+    };
+    i = i->next;
+  };
+}
+
+void checkchordlist()
+/* diagnostic routine */
+/* validates data structure */
+{
+  struct dlistx* i;
+  int n;
+
+  if ((chordhead == NULL) && (chordtail == NULL)) {
+    return;
+  };
+  if ((chordhead == NULL) && (chordtail != NULL)) {
+    fatal_error("chordhead == NULL and chordtail != NULL");
+  };
+  if ((chordhead != NULL) && (chordtail == NULL)) {
+    fatal_error("chordhead != NULL and chordtail == NULL");
+  };
+  if (chordhead->last != NULL) {
+    fatal_error("chordhead->last != NULL");
+  };
+  if (chordtail->next != NULL) {
+    fatal_error("chordtail->next != NULL");
+  };
+  i = chordhead;
+  n = 0;
+  while((i != NULL) && (i->next != NULL)) {
+    if (i->next->last != i) {
+      char msg[80];
+
+      sprintf(msg, "chordlist item %d : i->next->last!", n);
+      fatal_error(msg);
+    };
+    i = i->next;
+    n = n + 1;
+  };
+  /* checkchordlist(); */
+}
+
+void addtochord(p)
+/* used when printing out abc */
+struct anote* p;
+{
+  struct dlistx* newx;
+  struct dlistx* place;
+
+  newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx));
+  newx->note = p;
+  newx->next = NULL;
+  newx->last = NULL;
+
+  if (chordhead == NULL) {
+    chordhead = newx;
+    chordtail = newx;
+    checkchordlist();
+    return;
+  };
+  place = chordhead;
+  while ((place != NULL) && (place->note->pitch > p->pitch)) {
+    place = place->next;
+  };
+  if (place == chordhead) {
+    newx->next = chordhead;
+    chordhead->last = newx;
+    chordhead = newx;
+    checkchordlist();
+    return;
+  };
+  if (place == NULL) {
+    newx->last = chordtail;
+    chordtail->next = newx;
+    chordtail = newx;
+    checkchordlist();
+    return;
+  };
+  newx->next = place;
+  newx->last = place->last;
+  place->last = newx;
+  newx->last->next = newx;
+  checkchordlist();
+}
+
+struct dlistx* removefromchord(i)
+/* used when printing out abc */
+struct dlistx* i;
+{
+  struct dlistx* newi;
+
+  /* remove note from list */
+  if (i->last == NULL) {
+    chordhead = i->next;
+  } 
+  else {
+    (i->last)->next = i->next;
+  };
+  if (i->next == NULL) {
+    chordtail = i->last;
+  } 
+  else {
+    (i->next)->last = i->last;
+  };
+  newi = i->next;
+  free(i);
+  checkchordlist();
+  return(newi);
+}
+
+int findshortest(gap)
+/* find the first note in the chord to terminate */
+int gap;
+{
+  int min, v;
+  struct dlistx* p;
+
+  p = chordhead;
+  min = gap;
+  while (p != NULL) {
+    v = p->note->playnum;
+    if (v < min) {
+      min = v;
+    };
+    p = p->next;
+  };
+  return(min);
+}
+
+void advancechord(len)
+/* adjust note lengths for all notes in the chord */
+int len;
+{
+  struct dlistx* p;
+
+  p = chordhead;
+  while (p != NULL) {
+    if (p->note->playnum <= len) {
+      if (p->note->playnum < len) {
+        fatal_error("Error - note too short!");
+      };
+      /* remove note */
+      checkchordlist();
+      p = removefromchord(p);
+    } 
+    else {
+      /* shorten note */
+      p->note->playnum = p->note->playnum - len;
+      p = p->next;
+    };
+  };
+}
+
+void freshline()
+/* if the current line of abc or text is non-empty, start a new line */
+{
+  if (midline == 1) {
+    fprintf(outhandle,"\n");
+    midline = 0;
+  };
+}
+
+
+void printnote (struct listx *i)
+{
+      printf("%ld ",i->note->time);
+      printpitch(i->note);
+      printfract(i->note->playnum, parts_per_unitlen);
+      printf(" %d %d %d %d\n",i->note->xnum, i->note->playnum,
+       i->note->posnum,i->note->splitnum); 
+}
+
+void listnotes(int trackno, int start, int end)
+/* A diagnostic like scannotes. I usually call it when
+   I am in the debugger (for example in printtrack).
+*/
+{
+struct listx* i;
+int k;
+i = track[trackno].head;
+k = 0;
+printf("ticks pitch xnum,playnum,posnum,splitnum\n");
+while (i != NULL && k < end)
+  {
+  if (k >= start) 
+    printnote(i);
+  k++;
+  i = i->next;
+  }
+}
+
+
+
+int testtrack(trackno, barbeats, anacrusis)
+/* print out one track as abc */
+int trackno, barbeats, anacrusis;
+{
+  struct listx* i;
+  int step, gap;
+  int barnotes;
+  int barcount;
+  int breakcount;
+
+  breakcount = 0;
+  chordhead = NULL;
+  chordtail = NULL;
+  i = track[trackno].head;
+  gap = 0;
+  if (anacrusis > 0) {
+    barnotes = anacrusis;
+  } 
+  else {
+    barnotes = barbeats;
+  };
+  barcount = 0;
+  while((i != NULL)||(gap != 0)) {
+    if (gap == 0) {
+      /* add notes to chord */
+      addtochord(i->note);
+      gap = i->note->xnum;
+      i = i->next;
+      advancechord(0); /* get rid of any zero length notes */
+    } 
+    else {
+      step = findshortest(gap);
+      if (step > barnotes) {
+        step = barnotes;
+      };
+      if (step == 0) {
+        fatal_error("Advancing by 0 in testtrack!");
+      };
+      advancechord(step);
+      gap = gap - step;
+      barnotes = barnotes - step;
+      if (barnotes == 0) {
+        if (chordhead != NULL) {
+          breakcount = breakcount + 1;
+        };
+        barnotes = barbeats;
+        barcount = barcount + 1;
+        if (barcount>0  && barcount%4 ==0) {
+        /* can't zero barcount because I use it for computing maxbarcount */
+          freshline();
+          barcount = 0;
+        };
+      };
+    };
+  };
+  return(breakcount);
+}
+
+void printpitch(j)
+/* convert numerical value to abc pitch */
+struct anote* j;
+{
+  int p, po,i;
+
+  p = j->pitch;
+  if (p == -1) {
+    fprintf(outhandle,"z");
+  } 
+  else {
+    po = p % 12;
+    if ((back[trans[p]] != p) || (key[po] == 1)) {
+      fprintf(outhandle,"%c%c", symbol[po], atog[p]);
+      for (i=p%12; i<256; i += 12) /* apply accidental to all octaves */
+         back[trans[i]] = i;
+    } 
+    else {
+      fprintf(outhandle,"%c", atog[p]);
+    };
+    while (p >= MIDDLE + 12) {
+      fprintf(outhandle,"'");
+      p = p - 12;
+    };
+    while (p < MIDDLE - 12) {
+      fprintf(outhandle,",");
+      p = p + 12;
+    };
+  };
+}
+
+static void reduce(a, b)
+int *a, *b;
+{
+  int t, n, m;
+
+    /* find HCF using Euclid's algorithm */
+    if (*a > *b) {
+        n = *a;
+        m = *b;
+      }
+    else {
+        n = *b;
+        m = *a;
+       };
+while (m != 0) {
+      t = n % m;
+      n = m;
+      m = t;
+    };
+*a = *a/n;
+*b = *b/n;
+}
+
+
+
+void printfract(a, b)
+/* print fraction */
+/* used when printing abc */
+int a, b;
+{
+  int c, d;
+
+  c = a;
+  d = b;
+  reduce(&c,&d);
+  /* print out length */
+  if (c != 1) {
+    fprintf(outhandle,"%d", c);
+  };
+  if (d != 1) {
+    fprintf(outhandle,"/%d", d);
+  };
+}
+
+void printchord(len)
+/* Print out the current chord. Any notes that haven't            */
+/* finished at the end of the chord are tied into the next chord. */
+int len;
+{
+  struct dlistx* i;
+
+  i = chordhead;
+  if (i == NULL) {
+    /* no notes in chord */
+#ifdef SPLITCODE
+    fprintf(outhandle,"x");
+#else
+    fprintf(outhandle,"z");
+#endif
+    printfract(len, parts_per_unitlen);
+    midline = 1;
+  } 
+  else {
+    if (i->next == NULL) {
+      /* only one note in chord */
+      printpitch(i->note);
+      printfract(len, parts_per_unitlen);
+      midline = 1;
+      if (len < i->note->playnum) {
+        fprintf(outhandle,"-");
+      };
+    } 
+    else {
+      fprintf(outhandle,"[");
+      while (i != NULL) {
+        printpitch(i->note);
+        printfract(len, parts_per_unitlen);
+        if (len < i->note->playnum) {
+          fprintf(outhandle,"-");
+        };
+      if (nogr && i->next != NULL) fprintf(outhandle," ");
+        i = i->next;
+      };
+      fprintf(outhandle,"]");
+      midline = 1;
+    };
+  };
+}
+
+char dospecial(i, barnotes, featurecount)
+/* identify and print out triplets and broken rhythm */
+struct listx* i;
+int* barnotes;
+int* featurecount;
+{
+  int v1, v2, v3, vt;
+  int xa, xb;
+  int pnum;
+  long total, t1, t2, t3;
+
+  
+  if ((chordhead != NULL) || (i == NULL) || (i->next == NULL)
+  /* || (asig%3 == 0) || (asig%2 != 0) 2004/may/09 SS*/) {
+    return(' ');
+  };
+  t1 = i->note->dtnext;
+  v1 = i->note->xnum;
+  pnum = i->note->playnum;
+  if ((v1 < pnum) || (v1 > 1 + pnum) || (pnum == 0)) {
+    return(' ');
+  };
+  t2 = i->next->note->dtnext;
+  v2 = i->next->note->xnum;
+  pnum = i->next->note->playnum;
+  if (/*(v2 < pnum) ||*/ (v2 > 1 + pnum) || (pnum == 0) || (v1+v2 > *barnotes)) {
+    return(' ');
+  };
+  /* look for broken rhythm */
+  total = t1 + t2;
+  if (total == 0L) {
+    /* shouldn't happen, but avoids possible divide by zero */
+    return(' ');
+  };
+  if (((v1+v2)%2 == 0) && ((v1+v2)%3 != 0)) {
+    vt = (v1+v2)/2;
+      if (vt == validnote(vt)) {
+      /* do not try to break a note which cannot be legally expressed */
+      switch ((int) ((t1*6+(total/2))/total)) {
+        case 2:
+          *featurecount = 2;
+          i->note->xnum  = vt;
+          i->note->playnum = vt;
+          i->next->note->xnum  = vt;
+          i->next->note->playnum = vt;
+          return('<');
+          break;
+        case 4:
+          *featurecount = 2;
+          i->note->xnum  = vt;
+          i->note->playnum = vt;
+          i->next->note->xnum  = vt;
+          i->next->note->playnum = vt;
+          return('>');
+          break;
+        default:
+          break;
+      };
+    };
+  };
+  /* look for triplet */
+  if (i->next->next != NULL) {
+    t3 = i->next->next->note->dtnext;
+    v3 = i->next->next->note->xnum;
+    pnum = i->next->next->note->playnum;
+    if ((v3 < pnum) || (v3 > 1 + pnum) || (pnum == 0) || 
+        (v1+v2+v3 > *barnotes)) {
+      return(' ');
+    };
+    if ((v1+v2+v3)%2 != 0) {
+      return(' ');
+    };
+    vt = (v1+v2+v3)/2;
+    if ((vt%2 == 1) && (vt > 1)) {
+      /* don't want strange fractions in triplet */
+      return(' ');
+    };
+    total = t1+t2+t3;
+    xa = (int) ((t1*6+(total/2))/total); 
+    xb = (int) (((t1+t2)*6+(total/2))/total);
+    if ((xa == 2) && (xb == 4) && (vt%3 != 0) ) {
+      *featurecount = 3;
+      *barnotes = *barnotes + vt;
+      i->note->xnum = vt;
+      i->note->playnum = vt;
+      i->next->note->xnum = vt;
+      i->next->note->playnum = vt;
+      i->next->next->note->xnum = vt;
+      i->next->next->note->playnum = vt;
+    };
+  };
+  return(' ');
+}
+
+int validnote(n)
+int n;
+/* work out a step which can be expressed as a musical time */
+{
+  int v;
+
+  if (n <= 4) {
+    v = n;
+  } 
+  else {
+    v = 4;
+    while (v*2 <= n) {
+      v = v*2;
+    };
+    if (v + v/2 <= n) {
+      v = v + v/2;
+    };
+  };
+  return(v);
+}
+
+void handletext(t, textplace, trackno)
+/* print out text occuring in the body of the track */
+/* The text is printed out at the appropriate place within the track */
+/* In addition the function handles key signature and time */
+/* signature changes that can occur in the middle of the tune. */
+long t;
+struct tlistx** textplace;
+int trackno;
+{
+  char* str;
+  char ch;
+  int type,sf,mi,nn,denom,bb;
+
+  while (((*textplace) != NULL) && ((*textplace)->when <= t)) {
+    str = (*textplace)->text;
+    ch = *str;
+    type = (*textplace)->type;
+    remove_carriage_returns(str);
+    if (((int)ch == '\\') || ((int)ch == '/')) {
+      inkaraoke = 1;
+    };
+    if ((inkaraoke == 1) && (karaoke == 1)) {
+      switch(ch) {
+        case ' ':
+          fprintf(outhandle,"%s", str);
+          midline = 1;
+          break;
+        case '\\':
+          freshline();
+          fprintf(outhandle,"w:%s", str + 1);
+          midline = 1;
+          break;
+        case '/':
+          freshline();
+          fprintf(outhandle,"w:%s", str + 1);
+          midline = 1;
+          break;
+        default :
+          if (midline == 0) {
+            fprintf(outhandle,"%%%s", str);
+          } 
+	  else {
+            fprintf(outhandle,"-%s", str);
+          };
+          break;
+      };
+    } 
+    else {
+      freshline();
+      ch=*(str+1);
+      switch (type) {
+      case 0:
+      if (ch != '%') 
+      fprintf(outhandle,"%%%s\n", str);
+      else 
+      fprintf(outhandle,"%s\n", str);
+      break;
+      case 1: /* key signature change */
+      sscanf(str,"%d %d",&sf,&mi);
+      if((trackno != 0 || trackcount==1) &&
+	 (active_keysig != sf)) {
+	      setupkey(sf);
+	      active_keysig=sf;
+              }
+      break;
+      case 2: /* time signature change */
+      sscanf(str,"%d %d %d",&nn,&denom,&bb);
+      if ((trackno != 0 || trackcount ==1) &&
+	  (active_asig != nn || active_bsig != denom))
+        {
+  	setup_timesig(nn,denom,bb);
+	fprintf(outhandle,"M: %d/%d\n",nn,denom);
+        fprintf(outhandle,"L: 1/%d\n",unitlen);
+	active_asig=nn;
+	active_bsig=denom;
+	}
+      break;
+     default:
+      break;
+      }
+  }
+  *textplace = (*textplace)->next;
+ }
+}
+
+
+#ifdef SPLITCODE
+
+/* This function identifies irregular chords, (notes which
+   do not exactly overlap in time). The notes in the
+   chords are split into separate lines (split numbers).
+   The xnum (delay) to next note is updated.
+*/
+
+int splitstart[10],splitend[10]; /* used in forming chords from notes*/
+int lastposnum[10]; /* posnum of previous note in linked list */
+int endposnum; /* posnum at last note in linked list */
+struct anote* prevnote[10]; /*previous note in linked list */
+struct listx*  last_i[10];  /*note after finishing processing bar*/
+int existingsplits[10]; /* existing splits in active bar */
+struct dlistx* splitchordhead[10]; /* chordhead list for splitnum */
+struct dlistx* splitchordtail[10]; /* chordtail list for splitnum */
+int splitgap[10]; /* gap to next note at end of split measure */
+
+void label_split(struct anote *note, int activesplit)
+{
+/* The function assigns a split number (activesplit), to
+   a specific note, (*note). We also update splitstart
+   and splitend which specifies the region in time where
+   the another note must occur if it forms a proper chord.
+   After assigning a split number to the note we need to
+   update note->xnum as this indicates the gap to the
+   next note in the same split number. The function uses
+   a greedy algorithm. It assigns a note to the first
+   splitnumber code which satisfies the above constraint.
+   If it cannot find a splitnumber, a new one (voice or track)
+   is created. It would be nice if the voices kept the
+   high and low notes (in pitch) separate.
+*/
+     note->splitnum = activesplit;
+     splitstart[activesplit] = note->posnum;
+     splitend[activesplit] = splitstart[activesplit] + note->playnum;
+     if (prevnote[activesplit]) 
+         prevnote[activesplit]->xnum = note->posnum - lastposnum[activesplit];
+     lastposnum[activesplit] = note->posnum;
+     prevnote[activesplit] = note;
+     /* in case this is the last activesplit note make sure it
+        xnum points to end of track. Otherwise it will be changed
+        when the next activesplit note is labeled.
+     */
+     note->xnum = endposnum - note->posnum;
+     existingsplits[activesplit]++;
+}
+
+
+void label_split_voices (int trackno)
+{
+/* This function sorts all the notes in the track into
+   separate split part. A note is placed into a separate
+   part if it forms a chord in the current part but
+   does not have the same onset time and same end time.
+   If this occurs, we search for another part where
+   this does not happen. If we can't find such a part
+   a new part (split) is created.
+   The heuristic used needs to be improved, so
+   that split number 0 always contains notes and so
+   that notes in the same pitch range or duration are
+   given the same split number.
+*/ 
+int activesplit,nsplits;
+int done;
+struct listx* i;
+int k;
+int firstposnum = 0;
+/* initializations */
+activesplit = 0;
+nsplits = 0;
+for (k=0;k<10;k++) {
+       splitstart[k]=splitend[k]=lastposnum[k]=0;
+       prevnote[k] = NULL;
+       existingsplits[k] = 0;
+       splitgap[k]=0;
+       }
+i = track[trackno].head;
+if (track[trackno].tail == 0x0) return;
+endposnum =track[trackno].tail->note->posnum +
+           track[trackno].tail->note->playnum;
+
+if (i != NULL) label_split(i->note, activesplit);
+/* now label all the notes in the track */
+while (i != NULL)
+  {
+  done =0;
+  if (nsplits == 0) { /*no splits exist, create split number 0 */
+     activesplit = 0;
+     nsplits++;
+     i->note->splitnum = activesplit;
+     splitstart[activesplit] = i->note->posnum;
+     splitend[activesplit] = splitstart[activesplit] + i->note->playnum;
+     firstposnum = splitstart[activesplit];
+     } else {  /* do a compatibility check with the last split number */
+  if (  (   i->note->posnum == splitstart[activesplit] 
+         && i->note->playnum == (splitend[activesplit] - splitstart[activesplit]))
+      || i->note->posnum >= splitend[activesplit])
+     {
+     if (existingsplits[activesplit] == 0) {
+         last_i[activesplit] = i;
+         splitgap[activesplit] = i->note->posnum - firstposnum;
+         }
+     label_split(i->note, activesplit);
+     done = 1;
+     }
+/* need to search for any other compatible split numbers  */
+  if (done == 0) for (activesplit=0;activesplit<nsplits;activesplit++) {
+      if (  (   i->note->posnum == splitstart[activesplit] 
+             && i->note->playnum == splitend[activesplit] - splitstart[activesplit])
+          || i->note->posnum >= splitend[activesplit])
+       {
+        if (existingsplits[activesplit] == 0) {
+           last_i[activesplit] = i;
+           splitgap[activesplit] = i->note->posnum - firstposnum;
+           }
+        label_split(i->note,activesplit);
+        done = 1;
+        break;
+        }
+      }
+     
+/* No compatible split number found. Create new split */
+   if (done == 0) {
+     if(nsplits < 10) {nsplits++; activesplit = nsplits-1;}  
+     if (existingsplits[activesplit] == 0) {
+         last_i[activesplit] = i;
+         splitgap[activesplit] = i->note->posnum - firstposnum;
+         }
+     label_split(i->note,activesplit);
+     }
+   } 
+/*  printf("note %d links to %d  %d (%d %d)\n",i->note->pitch,activesplit,
+i->note->posnum,splitstart[activesplit],splitend[activesplit]);
+*/
+  i = i->next;
+  } /* end while loop */
+}
+
+
+int nextsplitnum(int splitnum)
+  {
+  while (splitnum < 9) {
+      splitnum++;
+      if (existingsplits[splitnum]) return splitnum;
+      } 
+     return -1;
+}
+
+
+int count_splits()
+{
+int i,n;
+n = 0;
+for (i=0;i<10;i++)
+  if (existingsplits[i]) n++;
+return n;
+}
+
+
+
+
+
+void printtrack_with_splits(trackno, anacrusis)
+int trackno,  anacrusis;
+/* This function is an adaption of printtrack so that
+   notes with separate split numbers are in separated
+   regions in the measure. (Separated with &'s).
+   To do this we must make multiple passes through
+   each bar and maintain separate chordlists (in
+   event that some chords overlap over more than
+   one measure).
+*/
+{
+  struct listx* i;
+  struct tlistx* textplace;
+  struct tlistx* textplace0; /* track 0 text storage */
+  int step, gap;
+  int barnotes;
+  int barcount;
+  int bars_on_line;
+  long now;
+  char broken;
+  int featurecount;
+  int last_barsize,barnotes_correction;
+  int splitnum = 0;
+  int j;
+  int nlines;
+  int done;
+
+  nlines= 0;
+  label_split_voices (trackno);
+
+  midline = 0;
+  featurecount = 0;
+  inkaraoke = 0;
+  now = 0L;
+  broken = ' ';
+  for (j=0;j<10;j++) {
+      splitchordhead[j] = NULL;
+      splitchordtail[j] = NULL;
+      }
+  i = track[trackno].head;
+  textplace = track[trackno].texthead;
+  textplace0 = track[0].texthead;
+  /*gap = track[trackno].startunits;*/ gap = 0;
+  if (anacrusis > 0) {
+    barnotes = anacrusis;
+    barcount = -1;
+  } 
+  else {
+    barnotes = barsize;
+    barcount = 0;
+  };
+  bars_on_line = 0;
+  last_barsize = barsize;
+  active_asig = header_asig;
+  active_bsig = header_bsig;
+  setup_timesig(header_asig,header_bsig,header_bb);
+  active_keysig = header_keysig;
+  handletext(now, &textplace, trackno);
+  splitnum = 0;
+  chordhead = splitchordhead[splitnum]; 
+  chordtail = splitchordtail[splitnum]; 
+  gap = splitgap[splitnum];
+
+  while((i != NULL)||(gap != 0)) {
+    if (gap == 0) {
+      /* do triplet here */
+      if (featurecount == 0) {
+	if (!no_triplets) {
+	  broken = dospecial(i, &barnotes, &featurecount);
+	};
+      };
+
+/* ignore any notes that are not in the current splitnum */
+      if (i->note->splitnum == splitnum) {
+               /*printf("\nadding ");
+                 printnote(i); */
+	addtochord(i->note);
+	gap = i->note->xnum;
+	now = i->note->time;
+	}
+
+      i = i->next;
+      advancechord(0); /* get rid of any zero length notes */
+      if (trackcount > 1 && trackno !=0)
+	      handletext(now, &textplace0, trackno);
+      handletext(now, &textplace,trackno);
+      barnotes_correction = barsize - last_barsize;
+      barnotes += barnotes_correction;
+      last_barsize = barsize;
+    } 
+    else {
+      step = findshortest(gap);
+      if (step > barnotes) {
+	step = barnotes;
+      };
+      step = validnote(step);
+      if (step == 0) {
+	fatal_error("Advancing by 0 in printtrack!");
+      };
+      if (featurecount == 3)
+        {
+        fprintf(outhandle," (3");
+        };
+      printchord(step); if ( featurecount > 0) { featurecount = featurecount - 1; };
+      if ((featurecount == 1) && (broken != ' ')) {
+        fprintf(outhandle,"%c", broken);
+      };
+      advancechord(step);
+      gap = gap - step;
+      barnotes = barnotes - step;
+
+/* at the end of the bar we must decide whether to place
+   a | or &. If we place a & then we have to return to
+   the beginning of the bar and process the next split number.
+*/  
+      if (barnotes == 0) { /* end of bar  ? */
+        nlines++;
+        if (nlines > 5000) {
+            printf("\nProbably infinite loop: aborting\n");
+            fprintf(outhandle,"\n\nProbably infinite loop: aborting\n");
+            return;
+            }
+/* save state for the last splitnum before going to the next */
+        last_i[splitnum] = i;
+        splitchordhead[splitnum] = chordhead;
+        splitchordtail[splitnum] = chordtail;
+        splitgap[splitnum] = gap;
+
+/*     look for the next splitnum which contains notes in
+       the current measure. If not, end the measure.
+*/
+        done = 0;
+        while (done != 1) {
+           splitnum = nextsplitnum(splitnum);
+
+           if (splitnum == -1) {
+              fprintf(outhandle," | ");
+              splitnum = nextsplitnum(splitnum);
+              done = 1;
+              break;
+              }
+
+           if (splitgap[splitnum] >= barsize)
+               {
+               splitgap[splitnum] -= barsize;
+               continue; /* look for other splits */
+               }
+ 
+           fprintf(outhandle, " & ");
+           i = last_i[splitnum]; 
+           done = 1;
+           }
+/* restore state for the next splitnum */
+       chordhead = splitchordhead[splitnum];
+       chordtail = splitchordtail[splitnum];
+       checkchordlist();
+       gap = splitgap[splitnum];
+       i = last_i[splitnum];
+
+       /*
+        printf("returning to %ld ",i->note->time);
+        printpitch(i->note);
+        printf("\n");
+       */
+     
+        barnotes = barsize;
+        barcount = barcount + 1;
+	bars_on_line++;
+        if (barcount >0 && barcount%bars_per_staff == 0)  {
+		freshline();
+		bars_on_line=0;
+	}
+     /* can't zero barcount because I use it for computing maxbarcount */
+        else if(bars_on_line >= bars_per_line && i != NULL) {
+		fprintf(outhandle," \\");
+	       	freshline();
+	        bars_on_line=0;}
+      }
+      else if (featurecount == 0) {
+          /* note grouping algorithm */
+          if ((barsize/parts_per_unitlen) % 3 == 0) {
+            if ( (barnotes/parts_per_unitlen) % 3 == 0
+               &&(barnotes%parts_per_unitlen) == 0) {
+              fprintf(outhandle," ");
+            };
+          } 
+	  else {
+            if (((barsize/parts_per_unitlen) % 2 == 0)
+                && (barnotes % parts_per_unitlen) == 0
+                && ((barnotes/parts_per_unitlen) % 2 == 0)) {
+              fprintf(outhandle," ");
+            };
+          };
+      }
+      if (nogr) fprintf(outhandle," ");
+    };
+   if (i == NULL) /* end of track before end of measure ? */
+    {
+     last_i[splitnum] = i;
+     splitchordhead[splitnum] = chordhead;
+     splitchordtail[splitnum] = chordtail;
+     splitgap[splitnum] = gap;
+     splitnum = nextsplitnum(splitnum);
+     if (splitnum == -1) break;
+     chordhead = splitchordhead[splitnum];
+     chordtail = splitchordtail[splitnum];
+     gap = splitgap[splitnum];
+     i = last_i[splitnum];
+     if (barnotes != barsize) fprintf(outhandle, " & ");
+     barnotes = barsize;
+    }
+ 
+  };
+  /* print out all extra text */
+  while (textplace != NULL) {
+    handletext(textplace->when, &textplace, trackno);
+  };
+  freshline();
+  if (barcount > maxbarcount) maxbarcount = barcount;
+}
+
+
+
+void printtrack_split_voice(trackno, anacrusis)
+/* print out one track as abc */
+int trackno,  anacrusis;
+{
+  struct listx* i;
+  struct tlistx* textplace;
+  struct tlistx* textplace0; /* track 0 text storage */
+  int step, gap;
+  int barnotes;
+  int barcount;
+  int bars_on_line;
+  long now;
+  char broken;
+  int featurecount;
+  int last_barsize,barnotes_correction;
+  int nlines;
+  int splitnum;
+  int lastnote_in_split;
+
+  nlines= 0;
+  lastnote_in_split = 0;
+  label_split_voices (trackno);
+  midline = 0;
+  featurecount = 0;
+  inkaraoke = 0;
+  now = 0L;
+  broken = ' ';
+  chordhead = NULL;
+  chordtail = NULL;
+  i = track[trackno].head;
+  textplace = track[trackno].texthead;
+  textplace0 = track[0].texthead;
+  gap = track[trackno].startunits;
+  if (anacrusis > 0) {
+    barnotes = anacrusis;
+    barcount = -1;
+  } 
+  else {
+    barnotes = barsize;
+    barcount = 0;
+  };
+  bars_on_line = 0;
+  last_barsize = barsize;
+  active_asig = header_asig;
+  active_bsig = header_bsig;
+  setup_timesig(header_asig,header_bsig,header_bb);
+  active_keysig = header_keysig;
+  handletext(now, &textplace, trackno);
+  splitnum = 0;
+  gap = splitgap[splitnum];
+  if (count_splits() > 1) fprintf(outhandle,"V: split%d%c\n",trackno+1,'A'+splitnum);
+
+  while((i != NULL)||(gap != 0)) {
+    if (gap == 0) {
+      if (i->note->posnum + i->note->xnum == endposnum) lastnote_in_split = 1;
+      /* do triplet here */
+      if (featurecount == 0) {
+        if (!no_triplets) {
+          broken = dospecial(i, &barnotes, &featurecount);
+        };
+      };
+/* ignore any notes that are not in the current splitnum */
+      if (i->note->splitnum == splitnum) {
+               /*printf("\nadding ");
+                 printnote(i); */
+	addtochord(i->note);
+	gap = i->note->xnum;
+	now = i->note->time;
+	}
+      i = i->next;
+      advancechord(0); /* get rid of any zero length notes */
+      if (trackcount > 1 && trackno !=0)
+	      handletext(now, &textplace0, trackno);
+      handletext(now, &textplace,trackno);
+      barnotes_correction = barsize - last_barsize;
+      barnotes += barnotes_correction;
+      last_barsize = barsize;
+    } 
+    else {
+      step = findshortest(gap);
+      if (step > barnotes) {
+        step = barnotes;
+      };
+      step = validnote(step);
+      if (step == 0) {
+        fatal_error("Advancing by 0 in printtrack!");
+      };
+      if (featurecount == 3)
+        {
+        fprintf(outhandle," (3");
+        };
+      printchord(step);
+      if ( featurecount > 0) {
+        featurecount = featurecount - 1;
+      };
+      if ((featurecount == 1) && (broken != ' ')) {
+        fprintf(outhandle,"%c", broken);
+      };
+      advancechord(step);
+      gap = gap - step;
+      barnotes = barnotes - step;
+      if (barnotes == 0) {
+        nlines++;
+        if (nlines > 5000) {
+            printf("\nProbably infinite loop: aborting\n");
+            fprintf(outhandle,"\n\nProbably infinite loop: aborting\n");
+            return;
+            }
+        fprintf(outhandle,"|");
+        barnotes = barsize;
+        barcount = barcount + 1;
+	bars_on_line++;
+        if (barcount >0 && barcount%bars_per_staff == 0)  {
+		freshline();
+		bars_on_line=0;
+	}
+     /* can't zero barcount because I use it for computing maxbarcount */
+        else if(bars_on_line >= bars_per_line && i != NULL) {
+		if (!lastnote_in_split) fprintf(outhandle," \\");
+	       	freshline();
+	        bars_on_line=0;}
+      }
+      else if (featurecount == 0) {
+          /* note grouping algorithm */
+          if ((barsize/parts_per_unitlen) % 3 == 0) {
+            if ( (barnotes/parts_per_unitlen) % 3 == 0
+               &&(barnotes%parts_per_unitlen) == 0) {
+              fprintf(outhandle," ");
+            };
+          } 
+	  else {
+            if (((barsize/parts_per_unitlen) % 2 == 0)
+                && (barnotes % parts_per_unitlen) == 0
+                && ((barnotes/parts_per_unitlen) % 2 == 0)) {
+              fprintf(outhandle," ");
+            };
+          };
+      }
+      if (nogr) fprintf(outhandle," ");
+    };
+  if (i == NULL && gap == 0) 
+    {
+    i = track[trackno].head;
+    splitnum = nextsplitnum(splitnum);
+    lastnote_in_split = 0;
+    if (splitnum == -1) break;
+    gap = splitgap[splitnum];
+    if(barnotes != barsize) freshline();
+    fprintf(outhandle,"V:split%d%c\n",trackno+1,'A'+splitnum);
+    if (anacrusis > 0) {
+      barnotes = anacrusis;
+      barcount = -1;
+      } 
+    else {
+      barnotes = barsize;
+      barcount = 0;
+      };
+    }
+  };
+  /* print out all extra text */
+  while (textplace != NULL) {
+    handletext(textplace->when, &textplace, trackno);
+  };
+  freshline();
+  if (barcount > maxbarcount) maxbarcount = barcount;
+}
+
+#endif
+
+void printtrack(trackno, anacrusis)
+/* print out one track as abc */
+int trackno,  anacrusis;
+{
+  struct listx* i;
+  struct tlistx* textplace;
+  struct tlistx* textplace0; /* track 0 text storage */
+  int step, gap;
+  int barnotes;
+  int barcount;
+  int bars_on_line;
+  long now;
+  char broken;
+  int featurecount;
+  int last_barsize,barnotes_correction;
+
+  midline = 0;
+  featurecount = 0;
+  inkaraoke = 0;
+  now = 0L;
+  broken = ' ';
+  chordhead = NULL;
+  chordtail = NULL;
+  i = track[trackno].head;
+  textplace = track[trackno].texthead;
+  textplace0 = track[0].texthead;
+  gap = track[trackno].startunits;
+  if (anacrusis > 0) {
+    barnotes = anacrusis;
+    barcount = -1;
+  } 
+  else {
+    barnotes = barsize;
+    barcount = 0;
+  };
+  bars_on_line = 0;
+  last_barsize = barsize;
+  active_asig = header_asig;
+  active_bsig = header_bsig;
+  setup_timesig(header_asig,header_bsig,header_bb);
+  active_keysig = header_keysig;
+  handletext(now, &textplace, trackno);
+
+  while((i != NULL)||(gap != 0)) {
+    if (gap == 0) {
+      /* do triplet here */
+      if (featurecount == 0) {
+        if (!no_triplets) {
+          broken = dospecial(i, &barnotes, &featurecount);
+        };
+      };
+      /* add notes to chord */
+      addtochord(i->note);
+      gap = i->note->xnum;
+      now = i->note->time;
+      i = i->next;
+      advancechord(0); /* get rid of any zero length notes */
+      if (trackcount > 1 && trackno !=0)
+	      handletext(now, &textplace0, trackno);
+      handletext(now, &textplace,trackno);
+      barnotes_correction = barsize - last_barsize;
+      barnotes += barnotes_correction;
+      last_barsize = barsize;
+    } 
+    else {
+      step = findshortest(gap);
+      if (step > barnotes) {
+        step = barnotes;
+      };
+      step = validnote(step);
+      if (step == 0) {
+        fatal_error("Advancing by 0 in printtrack!");
+      };
+      if (featurecount == 3)
+        {
+        fprintf(outhandle," (3");
+        };
+      printchord(step);
+      if ( featurecount > 0) {
+        featurecount = featurecount - 1;
+      };
+      if ((featurecount == 1) && (broken != ' ')) {
+        fprintf(outhandle,"%c", broken);
+      };
+      advancechord(step);
+      gap = gap - step;
+      barnotes = barnotes - step;
+      if (barnotes == 0) {
+        fprintf(outhandle,"|");
+        barnotes = barsize;
+        barcount = barcount + 1;
+	bars_on_line++;
+        if (barcount >0 && barcount%bars_per_staff == 0)  {
+		freshline();
+		bars_on_line=0;
+	}
+     /* can't zero barcount because I use it for computing maxbarcount */
+        else if(bars_on_line >= bars_per_line && i != NULL) {
+		fprintf(outhandle," \\");
+	       	freshline();
+	        bars_on_line=0;}
+      }
+      else if (featurecount == 0) {
+          /* note grouping algorithm */
+          if ((barsize/parts_per_unitlen) % 3 == 0) {
+            if ( (barnotes/parts_per_unitlen) % 3 == 0
+               &&(barnotes%parts_per_unitlen) == 0) {
+              fprintf(outhandle," ");
+            };
+          } 
+	  else {
+            if (((barsize/parts_per_unitlen) % 2 == 0)
+                && (barnotes % parts_per_unitlen) == 0
+                && ((barnotes/parts_per_unitlen) % 2 == 0)) {
+              fprintf(outhandle," ");
+            };
+          };
+      }
+      if (nogr) fprintf(outhandle," ");
+    };
+  };
+  /* print out all extra text */
+  while (textplace != NULL) {
+    handletext(textplace->when, &textplace, trackno);
+  };
+  freshline();
+  if (barcount > maxbarcount) maxbarcount = barcount;
+}
+
+
+
+
+void remove_carriage_returns(char *str)
+{
+/* a carriage return might be embedded in a midi text meta-event.
+   do not output this in the abc file or this would make a nonsyntactic
+   abc file.
+*/
+  char * loc;
+  while ((loc  = (char *) strchr(str,'\r')) != NULL)
+    *loc = ' ';
+  while ((loc  = (char *) strchr(str,'\n')) != NULL)
+    *loc = ' ';
+}
+
+
+
+void printQ()
+/* print out tempo for abc */
+{
+  float Tnote, freq;
+  Tnote = mf_ticks2sec((long)((xunit*unitlen)/4), division, tempo);
+  freq = (float) 60.0/Tnote;
+  fprintf(outhandle,"Q:1/4=%d\n", (int) (freq+0.5));
+  if (summary>0) printf("Tempo: %d quarter notes per minute\n",
+    (int) (freq + 0.5));
+}
+
+
+
+
+void setupkey(sharps)
+int sharps;
+/* set up variables related to key signature */
+{
+  char sharp[13], flat[13], shsymbol[13], flsymbol[13];
+  int j, t, issharp;
+  int minkey;
+
+  for (j=0; j<12; j++) 
+    key[j] = 0;
+  minkey = (sharps+12)%12;
+  if (minkey%2 != 0) {
+    minkey = (minkey+6)%12;
+  };
+  strcpy(sharp,    "ccddeffggaab");
+  strcpy(shsymbol, "=^=^==^=^=^=");
+  if (sharps == 6) {
+    sharp[6] = 'e';
+    shsymbol[6] = '^';
+  };
+  strcpy(flat, "cddeefggaabb");
+  strcpy(flsymbol, "=_=_==_=_=_=");
+  /* Print out key */
+
+  if (sharps >= 0) {
+    if (sharps == 6) {
+      fprintf(outhandle,"K:F#");
+    } 
+    else {
+      fprintf(outhandle,"K:%c", sharp[minkey] + 'A' - 'a');
+    };
+    issharp = 1;
+  } 
+  else {
+    if (sharps == -1) {
+      fprintf(outhandle,"K:%c", flat[minkey] + 'A' - 'a');
+    } 
+    else {
+      fprintf(outhandle,"K:%cb", flat[minkey] + 'A' - 'a');
+    };
+    issharp = 0;
+  };
+  if (sharps >= 0) {
+    fprintf(outhandle," %% %d sharps\n", sharps);
+  }
+  else {
+    fprintf(outhandle," %% %d flats\n", -sharps);
+  };
+  key[(minkey+1)%12] = 1;
+  key[(minkey+3)%12] = 1;
+  key[(minkey+6)%12] = 1;
+  key[(minkey+8)%12] = 1;
+  key[(minkey+10)%12] = 1;
+  for (j=0; j<256; j++) {
+    t = j%12;
+    if (issharp) {
+      atog[j] = sharp[t];
+      symbol[j] = shsymbol[t];
+    } 
+    else {
+      atog[j] = flat[t];
+      symbol[j] = flsymbol[t];
+    };
+    trans[j] = 7*(j/12)+((int) atog[j] - 'a');
+    if (j < MIDDLE) {
+      atog[j] = (char) (int) atog[j] + 'A' - 'a';
+    };
+    if (key[t] == 0) {
+      back[trans[j]] = j;
+    };
+  };
+}
+
+
+
+
+/*  Functions for supporting the command line user interface to midi2abc.     */
+
+
+int readnum(num) 
+/* read a number from a string */
+/* used for processing command line */
+char *num;
+{
+  int t;
+  char *p;
+  int neg;
+  
+  t = 0;
+  neg = 1;
+  p = num;
+  if (*p == '-') {
+    p = p + 1;
+    neg = -1;
+  };
+  while (((int)*p >= '0') && ((int)*p <= '9')) {
+    t = t * 10 + (int) *p - '0';
+    p = p + 1;
+  };
+  return neg*t;
+}
+
+
+int readnump(p) 
+/* read a number from a string (subtly different) */
+/* used for processing command line */
+char **p;
+{
+  int t;
+  
+  t = 0;
+  while (((int)**p >= '0') && ((int)**p <= '9')) {
+    t = t * 10 + (int) **p - '0';
+    *p = *p + 1;
+  };
+  return t;
+}
+
+
+void readsig(a, b, sig)
+/* read time signature */
+/* used for processing command line */
+int *a, *b;
+char *sig;
+{
+  char *p;
+  int t;
+
+  p = sig;
+  if ((int)*p == 'C') {
+    *a = 4;
+    *b = 4;
+    return;
+  };
+  *a = readnump(&p);
+  if ((int)*p != '/') {
+    char msg[80];
+
+    sprintf(msg, "Expecting / in time signature found %c!", *p);
+    fatal_error(msg);
+  };
+  p = p + 1;
+  *b = readnump(&p);
+  if ((*a == 0) || (*b == 0)) {
+    char msg[80];
+
+    sprintf(msg, "%d/%d is not a valid time signature!", *a, *b);
+    fatal_error(msg);
+  };
+  t = *b;
+  while (t > 1) {
+    if (t%2 != 0) {
+      fatal_error("Bad key signature, divisor must be a power of 2!");
+    }
+    else {
+      t = t/2;
+    };
+  };
+}
+
+int is_power_of_two(int numb)
+/* checks whether numb is a power of 2 less than 256 */
+{
+int i,k;
+k = 1;
+for (i= 0;i<8;i++) {
+  if(numb == k) return(1);
+  k *= 2;
+  }
+return(0);
+}
+
+int getarg(option, argc, argv)
+/* extract arguments from command line */
+char *option;
+char *argv[];
+int argc;
+{
+  int j, place;
+
+  place = -1;
+  for (j=0; j<argc; j++) {
+    if (strcmp(option, argv[j]) == 0) {
+      place = j + 1;
+    };
+  };
+  return (place);
+}
+
+int huntfilename(argc, argv)
+/* look for filename argument if -f option is missing */
+/* assumes filename does not begin with '-'           */
+char *argv[];
+int argc;
+{
+  int j, place;
+
+  place = -1;
+  j = 1;
+  while ((place == -1) && (j < argc)) {
+    if (strncmp("-", argv[j], 1) != 0) {
+      place = j;
+    } 
+    else {
+     if (strchr("ambQkcou", *(argv[j]+1)) == NULL) {
+       j = j + 1;
+     }
+     else {
+       j = j + 2;
+     };
+    };
+  };
+  return(place);
+}
+
+int process_command_line_arguments(argc,argv)
+char *argv[];
+int argc;
+{
+  int val;
+  int arg;
+  arg = getarg("-ver",argc,argv);
+  if (arg != -1) {printf("%s\n",VERSION); exit(0);}
+  midiprint = 0;
+  arg = getarg("-midigram",argc,argv);
+  if (arg != -1) 
+   {
+   midiprint = 1;
+   }
+
+#ifdef SPLITCODE
+  usesplits = 0;
+  arg = getarg("-splitbars",argc,argv);
+  if (arg != -1) 
+   usesplits = 1;
+  arg = getarg("-splitvoices",argc,argv);
+  if (arg != -1) 
+   usesplits = 2;
+#endif 
+
+  arg = getarg("-mftext",argc,argv);
+  if (arg != -1) 
+   {
+   midiprint = 2;
+   }
+
+  arg = getarg("-a", argc, argv);
+  if ((arg != -1) && (arg < argc)) {
+    anacrusis = readnum(argv[arg]);
+  } 
+  else {
+    anacrusis = 0;
+  };
+  arg = getarg("-m", argc, argv);
+  if ((arg != -1) && (arg < argc)) {
+    readsig(&asig, &bsig, argv[arg]);
+    tsig_set = 1;
+  }
+  else {
+    asig = 4;
+    bsig = 4;
+    tsig_set = 0;
+  };
+  arg = getarg("-Q", argc, argv);
+  if (arg != -1) {
+    Qval = readnum(argv[arg]);
+  }
+  else {
+    Qval = 0;
+  };
+  arg = getarg("-u", argc,argv);
+  if (arg != -1) {
+    xunit = readnum(argv[arg]);
+    xunit_set = 1;
+  }
+  else {
+	xunit = 0;
+	xunit_set = 0;
+       };
+  arg = getarg("-ppu",argc,argv);
+  if (arg != -1) {
+     val = readnum(argv[arg]);
+     if (is_power_of_two(val)) parts_per_unitlen = val;
+     else {
+	   printf("*error* -ppu parameter must be a power of 2\n");
+           parts_per_unitlen = 2;
+          }
+  }
+  else
+     parts_per_unitlen = 2;
+  arg = getarg("-aul",argc,argv);
+  if (arg != -1) {
+     val = readnum(argv[arg]);
+     if (is_power_of_two(val)) {
+	    unitlen = val;
+	    unitlen_set = 1;}
+        else 
+           printf("*error* -aul parameter must be a power of 2\n");
+      }
+  arg = getarg("-bps",argc,argv);
+  if (arg != -1)
+   bars_per_staff = readnum(argv[arg]);
+  else {
+       bars_per_staff=4;
+   };
+  arg = getarg("-bpl",argc,argv);
+  if (arg != -1)
+   bars_per_line = readnum(argv[arg]);
+  else {
+       bars_per_line=1;
+   };
+
+
+  extracta = (getarg("-xa", argc, argv) != -1);
+  guessa = (getarg("-ga", argc, argv) != -1);
+  guessu = (getarg("-gu", argc, argv) != -1);
+  guessk = (getarg("-gk", argc, argv) != -1);
+  keep_short = (getarg("-s", argc, argv) != -1);
+  summary = getarg("-sum",argc,argv); 
+  swallow_rests = getarg("-sr",argc,argv);
+  if (swallow_rests != -1) {
+	 restsize = readnum(argv[swallow_rests]);
+         if(restsize <1) restsize=1;
+        }
+  obpl = getarg("-obpl",argc,argv);
+  if (obpl>= 0) bars_per_line=1;
+  if (!unitlen_set) {
+    if ((asig*4)/bsig >= 3) {
+      unitlen =8;
+     }
+    else {
+      unitlen = 16;
+     };
+   }
+  arg = getarg("-b", argc, argv);
+  if ((arg != -1) && (arg < argc)) {
+    bars = readnum(argv[arg]);
+  }
+  else {
+    bars = 0;
+  };
+  arg = getarg("-c", argc, argv);
+  if ((arg != -1) && (arg < argc)) {
+    xchannel = readnum(argv[arg]) - 1;
+  }
+  else {
+    xchannel = -1;
+  };
+  arg = getarg("-k", argc, argv);
+  if ((arg != -1) && (arg < argc)) {
+    keysig = readnum(argv[arg]);
+    if (keysig<-6) keysig = 12 - ((-keysig)%12);
+    if (keysig>6)  keysig = keysig%12;
+    if (keysig>6)  keysig = keysig - 12;
+    ksig_set = 1;
+  } 
+  else {
+    keysig = -50;
+    ksig_set = 0;
+  };
+
+  if(guessk) ksig_set=1;
+
+  arg = getarg("-o",argc,argv);
+  if ((arg != -1) && (arg < argc))  {
+    outhandle = efopen(argv[arg],"w");  /* open output abc file */
+  } 
+  else {
+    outhandle = stdout;
+  };
+  arg = getarg("-nt", argc, argv);
+  if (arg == -1) {
+    no_triplets = 0;
+  } 
+  else {
+    no_triplets = 1;
+  };
+  arg = getarg("-nogr",argc,argv);
+  if (arg != -1)
+     nogr=1;
+  else nogr = 0;
+
+  arg = getarg("-f", argc, argv);
+  if (arg == -1) {
+    arg = huntfilename(argc, argv);
+  };
+  if ((arg != -1) && (arg < argc)) {
+    F = efopen(argv[arg],"rb");
+/*    fprintf(outhandle,"%% input file %s\n", argv[arg]); */
+  }
+  else {
+    printf("midi2abc version %s\n  usage :\n",VERSION);
+    printf("midi2abc filename <options>\n");
+    printf("         -a <beats in anacrusis>\n");
+    printf("         -xa  Extract anacrusis from file ");
+    printf("(find first strong note)\n");
+    printf("         -ga  Guess anacrusis (minimize ties across bars)\n");
+    printf("         -gk  Guess key signature \n");
+    printf("         -gu  Guess xunit from note duration statistics\n");
+    printf("         -m <time signature>\n");
+    printf("         -b <bars wanted in output>\n");
+    printf("         -Q <tempo in quarter-notes per minute>\n");
+    printf("         -k <key signature> -6 to 6 sharps\n");
+    printf("         -c <channel>\n");
+    printf("         -u <number of midi pulses in abc time unit>\n");
+    printf("         -ppu <number of parts in abc time unit>\n");
+    printf("         -aul <denominator of L: unit length>\n");
+    printf("         [-f] <input file>\n");
+    printf("         -o <output file>\n");
+    printf("         -s Do not discard very short notes\n");
+    printf("         -sr <number> Absorb short rests following note\n");
+    printf("           where <number> specifies its size\n");
+    printf("         -sum summary\n");
+    printf("         -nt Do not look for triplets or broken rhythm\n");
+    printf("         -bpl <number> of bars printed on one line\n");
+    printf("         -bps <number> of bars to be printed on staff\n");
+    printf("         -obpl One bar per line\n");
+    printf("         -nogr No note grouping. Space between all notes\n");
+#ifdef SPLITCODE
+    printf("         -splitbars  splits bars to avoid nonhomophonic chords\n");
+    printf("         -splitvoices  splits voices to avoid nonhomophonic chords\n");
+#endif
+    printf("         -midigram   Prints midigram instead of abc file\n");
+    printf("         -mftext mftext output\n"); 
+    printf("         -ver version number\n");
+    printf(" None or only one of the options -gu, -b, -Q -u should\n");
+    printf(" be specified. If none are present, midi2abc will uses the\n");
+    printf(" the PPQN information in the MIDI file header to determine\n");
+    printf(" the suitable note length. This is the recommended method.\n");
+    printf(" The input filename is assumed to be any string not\n");
+    printf(" beginning with a - (hyphen). It may be placed anywhere.\n");
+
+    exit(0);
+  };
+  return arg;
+}
+
+
+
+void midi2abc (arg, argv)
+char *argv[];
+int arg;
+{
+int voiceno;
+int accidentals; /* used for printing summary */
+int j;
+int argc;
+
+/* initialization */
+  trackno = 0;
+  track[trackno].texthead = NULL;
+  track[trackno].texttail = NULL;
+  initfuncs();
+  playinghead = NULL;
+  playingtail = NULL;
+  karaoke = 0;
+  Mf_getc = filegetc;
+
+/* parse MIDI file */
+  mfread();
+
+  fclose(F);
+
+/* count MIDI tracks with notes */
+  maintrack = 0;
+  while ((track[maintrack].notes == 0) && (maintrack < trackcount)) {
+    maintrack = maintrack + 1;
+  };
+  if (track[maintrack].notes == 0) {
+    fatal_error("MIDI file has no notes!");
+  };
+
+/* compute dtnext for each note */
+  for (j=0; j<trackcount; j++) {
+    postprocess(j);
+  };
+
+  if (tsig_set == 1){  /* for -m parameter set up time signature*/
+       header_asig = asig; 
+       header_unitlen = unitlen;
+       header_bsig = bsig;
+  };
+
+/* print abc header block */
+  argc = huntfilename(arg, argv);
+  fprintf(outhandle,"X: 1\n"); 
+  fprintf(outhandle,"T: from %s\n",argv[argc]); 
+  if (header_bsig == 0) {
+     fprintf(outhandle,"%%***Missing time signature meta command in MIDI file\n");
+     setup_timesig(4,  4,  8);
+     }
+  fprintf(outhandle,"M: %d/%d\n", header_asig, header_bsig);
+  fprintf(outhandle,"L: 1/%d\n", header_unitlen); 
+
+  barsize = parts_per_unitlen*header_asig*header_unitlen/header_bsig;
+
+/* compute xunit size for -Q -b options */
+  if (Qval != 0) {
+    xunit = mf_sec2ticks((60.0*4.0)/((float)(Qval*unitlen)), division, tempo);
+  };
+  if (bars > 0) {
+    xunit = (int) ((float) track[maintrack].tracklen*2/(float) (bars*barsize));
+    /* we multiply by 2 because barsize is in half unitlen. */
+  };
+
+/* estimate xunit if not set or if -gu runtime option */
+  if (xunit == 0 || guessu) {
+    guesslengths(maintrack);
+  };
+
+/* output Q: (tempo) to abc file */
+  printQ();
+
+/* Quantize note lengths of all tracks */
+  for (j=0; j<trackcount; j++) {
+    quantize(j, xunit);
+  };
+
+/* Estimate anacrusis if requested. Otherwise it is set by       */
+/* user or set to 0.                                             */
+  if (extracta) {
+    anacrusis = findana(maintrack, barsize);
+    fprintf(outhandle,"%%beats in anacrusis = %d\n", anacrusis);
+  };
+  if (guessa) {
+    anacrusis = guessana(barsize);
+    fprintf(outhandle,"%%beats in anacrusis = %d\n", anacrusis);
+  };
+
+/* If key signature is not known find the best one.              */
+  if ((keysig == -50 && gotkeysig ==0) || guessk) {
+       keysig = findkey(maintrack);
+       if (summary>0) printf("Best key signature = %d flats/sharps\n",keysig);
+       }
+       header_keysig = keysig;
+       setupkey(header_keysig);
+
+/* scannotes(maintrack); For debugging */
+
+/* Convert each track to abc format and print */
+  if (trackcount > 1) {
+    voiceno = 1;
+    for (j=0; j<trackcount; j++) {
+      freshline();
+      if (track[j].notes > 0) {
+        fprintf(outhandle,"V:%d\n", voiceno);
+	if (track[j].drumtrack) fprintf(outhandle,"%%%%MIDI channel 10\n");
+        voiceno = voiceno + 1;
+      };
+#ifdef SPLITCODE
+      if (usesplits==1) printtrack_with_splits(j, anacrusis); 
+      else if (usesplits==2) printtrack_split_voice(j, anacrusis);
+      else printtrack(j,anacrusis);
+#else
+      printtrack(j,anacrusis); 
+#endif
+    };
+  }
+  else {
+#ifdef SPLITCODE
+     if (usesplits==1) printtrack_with_splits(maintrack, anacrusis);
+     else if (usesplits==2) printtrack_split_voice(maintrack, anacrusis);
+     else printtrack(maintrack,anacrusis);
+#else
+     printtrack(maintrack, anacrusis);  
+#endif
+  };
+
+  /* scannotes(maintrack); for debugging */
+
+/* output report if requested */
+  if(summary>0) {
+   accidentals = keysig;
+   if (accidentals <0 )
+     {
+     accidentals = -accidentals;
+     printf("Using key signature: %d flats\n", accidentals);
+     }
+   else
+     printf("Using key signature : %d sharps\n", accidentals);
+   printf("Using an anacrusis of %d beats\n",anacrusis);
+   printf("Using unit length : 1/%d\n",unitlen);
+   printf("Using %d pulses per unit length (xunit).\n",xunit);
+   printf("Producing %d bars of output.\n",maxbarcount);
+   }
+
+
+/* free up data structures */
+  for (j=0; j< trackcount; j++) {
+    struct listx* this;
+    struct listx* x;
+    struct tlistx* tthis;
+    struct tlistx* tx;
+
+    this = track[j].head;
+    while (this != NULL) {
+      free(this->note);
+      x = this->next ;
+      free(this);
+      this = x;
+    };
+    tthis = track[j].texthead;
+    while (tthis != NULL) {
+      free(tthis->text);
+      tx = tthis->next;
+      free(tthis);
+      tthis = tx;
+    };
+  };
+  fclose(outhandle);
+}
+
+void midigram(argc,argv)
+char *argv[];
+int argc;
+{
+initfunc_for_midinotes();
+init_notechan();
+last_tick=0;
+/*F = efopen(argv[argc -1],"rb");*/
+Mf_getc = filegetc;
+mfread();
+printf("%d\n",last_tick);
+}
+
+void mftext(argc,argv)
+char *argv[];
+int argc;
+{
+initfunc_for_mftext();
+init_notechan();
+last_tick=0;
+/*F = efopen(argv[argc -1],"rb");*/
+Mf_getc = filegetc;
+mfread();
+/*printf("%d\n",last_tick);*/
+}
+
+
+int main(argc,argv)
+char *argv[];
+int argc;
+{
+  FILE *efopen();
+  int arg;
+
+  arg = process_command_line_arguments(argc,argv);
+  if(midiprint ==1) midigram(argc,argv);
+  else if(midiprint ==2) mftext(argc,argv);
+  else midi2abc(argc,argv); 
+  return 0;
+}
--- abcmidi-20070318.orig/parser2.c
+++ abcmidi-20070318/parser2.c
@@ -1,151 +1,151 @@
-/* parser2.c - further parsing */
-/* part of abc2midi and yaps */
-/* implements event_info, event_instruction, event_gchord and event_slur */
-/* also implements event_reserved */
-/* parser2 requires parseabc, but parseabc does not need parser2 */
-
-#include <stdio.h>
-#include "abc.h"
-#include "parseabc.h"
-#include "parser2.h"
-
-void event_info(s)
-char* s;
-/* An I: field has been encountered. This routine scans the following */
-/* text to extract items of the form key=value  */
-{
-  char* key;
-  char* endkey;
-  char* value;
-  char* endvalue;
-  char* lastendvalue;
-  char* newword;
-  char* lastnewword;
-  char* ptr;
-  int doval;
-
-  ptr = s;
-  doval = 0;
-  while (*ptr != '\0') {
-    if (doval == 0) {
-      /* look for key */
-      skipspace(&ptr);
-      key = ptr;
-      while ((*ptr != '\0') && (*ptr != ' ') && (*ptr != '=')) {
-        ptr = ptr + 1;
-      };
-      endkey = ptr;
-      skipspace(&ptr);
-      if (*ptr == '=') {
-        doval = 1;
-        ptr = ptr + 1;
-        skipspace(&ptr);
-        value = ptr;
-        newword = ptr;
-        endvalue = NULL;
-        lastendvalue = NULL;
-      } else {
-        key = ptr;
-      };
-    } else {
-      /* look for value */
-      skipspace(&ptr);
-      while ((*ptr != '\0') && (*ptr != ' ') && (*ptr != '=')) {
-        ptr = ptr + 1;
-      };
-      lastendvalue = endvalue;
-      endvalue = ptr;
-      skipspace(&ptr);
-      lastnewword = newword;
-      newword = ptr;
-      if (*ptr == '\0') {
-        *endkey = '\0';
-        *endvalue = '\0';
-        event_info_key(key, value);
-      } else {
-        if (*ptr == '=') {
-          *endkey = '\0';
-          if (lastendvalue == NULL) {
-            event_error("missing key or value in I: field");
-          } else {
-            *lastendvalue = '\0';
-            event_info_key(key, value);
-          };
-          key = lastnewword;
-          endkey = endvalue; 
-          doval = 1;
-          ptr = ptr + 1;
-          skipspace(&ptr);
-          value = ptr;
-          endvalue = NULL;
-          lastendvalue = NULL;
-        };
-      };
-    };
-  };
-}
-
-
-static void splitstring(s, sep, handler)
-/* breaks up string into fields with sep as the field separator */
-/* and calls handler() for each sub-string */
-char* s;
-char sep;
-void (*handler)();
-{
-  char* out;
-  char* p;
-  int fieldcoming;
-
-  p = s;
-  fieldcoming = 1;
-  while (fieldcoming) {
-    out = p;
-    while ((*p != '\0') && (*p != sep)) p = p + 1;
-    if (*p == sep) {
-      *p = '\0';
-      p = p + 1;
-    } else {
-      fieldcoming = 0;
-    };
-    (*handler)(out);
-  };
-}
-
-void event_gchord(s)
-/* handles guitar chords " ... " */
-char* s;
-{
-  splitstring(s, ';', event_handle_gchord);
-}
-
-void event_instruction(s)
-/* handles a ! ... ! event in the abc */
-char* s;
-{
-  splitstring(s, ';', event_handle_instruction);
-}
-
-void event_slur(t)
-int t;
-/* handles old 's' notation for slur on/slur off */
-{
-  if (t) {
-    event_sluron(1);
-  } else {
-    event_sluroff(0);
-  };
-}
-
-void event_reserved(char s)
-/* handles H - Z encountered in abc */
-{
-  char *expansion;
-
-  expansion = lookup_abbreviation(s);
-  if (expansion != NULL) {
-    event_handle_instruction(expansion);
-  } else {
-    event_x_reserved(s);
-  };
-}
+/* parser2.c - further parsing */
+/* part of abc2midi and yaps */
+/* implements event_info, event_instruction, event_gchord and event_slur */
+/* also implements event_reserved */
+/* parser2 requires parseabc, but parseabc does not need parser2 */
+
+#include <stdio.h>
+#include "abc.h"
+#include "parseabc.h"
+#include "parser2.h"
+
+void event_info(s)
+char* s;
+/* An I: field has been encountered. This routine scans the following */
+/* text to extract items of the form key=value  */
+{
+  char* key = NULL;
+  char* endkey = NULL;
+  char* value = NULL;
+  char* endvalue =  NULL;
+  char* lastendvalue;
+  char* newword = NULL;
+  char* lastnewword;
+  char* ptr;
+  int doval;
+
+  ptr = s;
+  doval = 0;
+  while (*ptr != '\0') {
+    if (doval == 0) {
+      /* look for key */
+      skipspace(&ptr);
+      key = ptr;
+      while ((*ptr != '\0') && (*ptr != ' ') && (*ptr != '=')) {
+        ptr = ptr + 1;
+      };
+      endkey = ptr;
+      skipspace(&ptr);
+      if (*ptr == '=') {
+        doval = 1;
+        ptr = ptr + 1;
+        skipspace(&ptr);
+        value = ptr;
+        newword = ptr;
+        endvalue = NULL;
+        lastendvalue = NULL;
+      } else {
+        key = ptr;
+      };
+    } else {
+      /* look for value */
+      skipspace(&ptr);
+      while ((*ptr != '\0') && (*ptr != ' ') && (*ptr != '=')) {
+        ptr = ptr + 1;
+      };
+      lastendvalue = endvalue;
+      endvalue = ptr;
+      skipspace(&ptr);
+      lastnewword = newword;
+      newword = ptr;
+      if (*ptr == '\0') {
+        *endkey = '\0';
+        *endvalue = '\0';
+        event_info_key(key, value);
+      } else {
+        if (*ptr == '=') {
+          *endkey = '\0';
+          if (lastendvalue == NULL) {
+            event_error("missing key or value in I: field");
+          } else {
+            *lastendvalue = '\0';
+            event_info_key(key, value);
+          };
+          key = lastnewword;
+          endkey = endvalue; 
+          doval = 1;
+          ptr = ptr + 1;
+          skipspace(&ptr);
+          value = ptr;
+          endvalue = NULL;
+          lastendvalue = NULL;
+        };
+      };
+    };
+  };
+}
+
+
+static void splitstring(s, sep, handler)
+/* breaks up string into fields with sep as the field separator */
+/* and calls handler() for each sub-string */
+char* s;
+char sep;
+void (*handler)();
+{
+  char* out;
+  char* p;
+  int fieldcoming;
+
+  p = s;
+  fieldcoming = 1;
+  while (fieldcoming) {
+    out = p;
+    while ((*p != '\0') && (*p != sep)) p = p + 1;
+    if (*p == sep) {
+      *p = '\0';
+      p = p + 1;
+    } else {
+      fieldcoming = 0;
+    };
+    (*handler)(out);
+  };
+}
+
+void event_gchord(s)
+/* handles guitar chords " ... " */
+char* s;
+{
+  splitstring(s, ';', event_handle_gchord);
+}
+
+void event_instruction(s)
+/* handles a ! ... ! event in the abc */
+char* s;
+{
+  splitstring(s, ';', event_handle_instruction);
+}
+
+void event_slur(t)
+int t;
+/* handles old 's' notation for slur on/slur off */
+{
+  if (t) {
+    event_sluron(1);
+  } else {
+    event_sluroff(0);
+  };
+}
+
+void event_reserved(char s)
+/* handles H - Z encountered in abc */
+{
+  char *expansion;
+
+  expansion = lookup_abbreviation(s);
+  if (expansion != NULL) {
+    event_handle_instruction(expansion);
+  } else {
+    event_x_reserved(s);
+  };
+}
--- abcmidi-20070318.orig/yapstree.c
+++ abcmidi-20070318/yapstree.c
@@ -1,2979 +1,2983 @@
-/*
- * yaps - program to convert abc files to PostScript.
- * Copyright (C) 1999 James Allwright
- * e-mail: J.R.Allwright@westminster.ac.uk
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/* yapstree.c - back-end for abc parser. */
-/* generates a data structure suitable for typeset music */
-
-#define VERSION "1.49 December 21 2006"
-#include <stdio.h>
-#ifdef USE_INDEX
-#define strchr index
-#endif
-
-/* for Microsoft VC 6++ or higher */
-#ifdef _MSC_VER
-#define ANSILIBS
-#endif
-
-#ifdef ANSILIBS
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#else
-char* strchr();
-#endif
-#include "abc.h"
-#include "parseabc.h"
-#include "parser2.h"
-#include "structs.h"
-#include "drawtune.h"
-
-extern void setscaling(char *s);
-extern void font_command();
-extern void setup_fonts();
-extern void printtune(struct tune *t);
-extern void set_keysig(struct key *k, struct key *newval);
-
-programname fileprogram = YAPS;
-extern int oldchordconvention; /* for handling +..+ chords */
-
-struct voice* cv;
-struct tune thetune;
-
-char outputname[256];
-char outputroot[256];
-char matchstring[256];
-int fileopen;
-
-int repcheck;
-int xinhead;
-int xinbody;
-int suppress;
-int debugging;
-int pagenumbering;
-int separate_voices;
-int print_xref;
-int landscape;
-int barnums,nnbars;
-extern int gchords_above;
-extern int decorators_passback[DECSIZE]; /* a kludge for passing
-information from the event_handle_instruction to parsenote
-in parseabc.c */
-
-enum linestattype {fresh, midmusic, endmusicline, postfield};
-enum linestattype linestat;
- 
-int dummydecorator[DECSIZE]; /* used in event_chord */
-
-void setfract(f, a, b)
-struct fract* f;
-int a, b;
-/* assign value to fraction */
-{
-  f->num = a;
-  f->denom = b;
-}
-
-void reducef(f)
-struct fract* f;
-/* reducef fraction to smallest terms */
-{
-  int t, n, m;
-
-  /* find HCF using Euclid's algorithm */
-  if (f->num > f->denom) {
-    n = f->num;
-    m = f->denom;
-  } else {
-    n = f->denom;
-    m = f->num;
-  };
-  while (m != 0) {
-    t = n % m;
-    n = m;
-    m = t;
-  };
-  f->num = f->num/n;
-  f->denom = f->denom/n;
-}
-
-static struct fract* newfract(int a, int b)
-/* create an initialized fraction */
-{
-  struct fract* f;
-
-  f = (struct fract*)checkmalloc(sizeof(struct fract));
-  f->num = a;
-  f->denom = b;
-  return(f);
-}
-
-static struct slurtie* newslurtie()
-/* create a new slur/tie data structure */
-{
-  struct slurtie* f;
-
-  f = (struct slurtie*)checkmalloc(sizeof(struct slurtie));
-  f->begin = NULL;
-  f->end = NULL;
-  f->crossline = 0;
-  return(f);
-}
-
-static struct atempo* newtempo(int count, int n, int m, int relative,
-                               char *pre, char *post)
-/* create an initialized tempo data structure */
-{
-  struct atempo* t;
-
-  t = (struct atempo*)checkmalloc(sizeof(struct atempo));
-  t->count = count;
-  t->basenote.num = n;
-  t->basenote.denom = m;
-  t->relative = relative;
-  if (pre == NULL) {
-    t->pre = NULL;
-  } else {
-    t->pre = addstring(pre);
-  };
-  if (post == NULL) {
-    t->post = NULL;
-  } else {
-    t->post = addstring(post);
-  };
-  return(t);
-}
-
-static struct vertspacing* newvertspacing()
-/* create new vertspacing structure */
-{
-  struct vertspacing* p;
-
-  p = (struct vertspacing*)checkmalloc(sizeof(struct vertspacing));
-  p->height = 0.0;
-  p->descender = 0.0;
-  p->yend = 0.0;
-  p->yinstruct = 0.0;
-  p->ygchord = 0.0;
-  p->ywords = 0.0;
-  return(p);
-}
-
-static struct tuple* newtuple(int n, int q, int r, int label)
-/* create tuple data structure */
-{
-  struct tuple* f;
-
-  f = (struct tuple*)checkmalloc(sizeof(struct tuple));
-  f->n = n;
-  f->q = q;
-  f->r = r;
-  f->label = label;
-  f->beamed = 1;
-  return(f);
-}
-
-static struct chord* newchord()
-/* create chord data structure */
-{
-  struct chord* f;
-
-  f = (struct chord*)checkmalloc(sizeof(struct chord));
-  f->ytop = 0;
-  f->ybot = 0;
-  return(f);
-}
-
-struct aclef* newclef(enum cleftype t, int octave)
-/* create and initialize clef data structure */
-{
-  struct aclef* f;
-
-  f = (struct aclef*)checkmalloc(sizeof(struct aclef));
-  f->type = t;
-  f->octave = octave;
-  return(f);
-}
-
-struct key* newkey(char* name, int sharps, char accidental[], int mult[])
-/* create and initialize key signature */
-{
-  struct key* k;
-  int i;
-
-  k = (struct key*)checkmalloc(sizeof(struct key));
-  k->name = addstring(name);
-  k->sharps = sharps;
-  for (i=0; i<7; i++) {
-    k->map[i] = accidental[i];
-    k->mult[i] = mult[i];
-  };
-  return(k);
-}
-
-void init_llist(struct llist* l)
-/* initialize a linked list */
-{
-  l->first = NULL;
-  l->last = NULL;
-  l->place = NULL;
-}
-
-void addtolist(struct llist* p, void* item)
-/* append an item to a linked list */
-{
-  struct el* x;
-
-  x = (struct el*)checkmalloc(sizeof(struct el));
-  x->next = NULL;
-  x->datum = item;
-  if (p->first == NULL) {
-    p->first = x;
-    p->last = x;
-  } else {
-    p->last->next = x;
-    p->last = x;
-  };
-}
-
-void* firstitem(struct llist* p)
-/* find the first item in the list */
-/* also initialize for a traversal using nextitem() */
-{
-  if (p == NULL) {
-    return(NULL);
-  };
-  p->place = p->first;
-  if (p->place == NULL) {
-    return(NULL);
-  } else {
-    return(p->place->datum);
-  };
-}
-
-void* nextitem(struct llist* p)
-/* return 'next' item in the list. Successive calls return successive    */
-/* items or NULL after the end of the list has been reached. firstitem() */
-/* must be called prior to the first call to nextitem()                  */
-{
-  if (p->place == NULL) {
-    return(NULL);
-  } else {
-    p->place = p->place->next;
-    if (p->place == NULL) {
-      return(NULL);
-    } else {
-      return(p->place->datum);
-    };
-  };
-}
-
-void freellist(struct llist* l)
-/* frees up all dynamically allocated memory used to build the linked list */
-{
-  void* p;
-  struct el* e;
-  struct el* olde;
-
-  /* printf("freellist\n"); */
-  if (l != NULL) {
-    p = firstitem(l);
-    while (p != NULL) {
-      free(p);
-      p = nextitem(l);
-    };
-    e = l->first;
-    while (e != NULL) {
-      olde = e;
-      e = e->next;
-      free(olde);
-    };
-    init_llist(l);
-  };
-}
-
-static void closebeam(struct voice* v)
-/* called after a run of notes to be beamed together */
-{
-  struct note* n;
-  struct feature* ft;
-  int stemup;
-  int ingrace;
-
-  if (cv->tuplenotes > 0) {
-    cv->thistuple->beamed = 0;
-  };
-  if (v->beamroot == v->beamend) {
-    ft = v->beamroot;
-    n = ft->item;
-    n->beaming = single;
-    v->beamroot = NULL;
-    return;
-  }; 
-  if (v->beammax + v->beammin > 2*4) {
-    stemup = 0;
-  } else {
-    stemup = 1;
-  };
-  ft = v->beamroot;
-  ingrace = 0;
-  while ((ft != NULL) && (ft != v->beamend)) {
-    switch (ft->type) {
-    case NOTE:
-      if (ingrace == 0) {
-        n = ft->item;
-        n->stemup = stemup;
-      };
-      break;
-    case GRACEON:
-      ingrace = 1;
-      break;
-    case GRACEOFF:
-      ingrace = 0;
-      break;
-    default:
-      break;
-    };
-    ft = ft->next;
-  };
-  if (ft == v->beamend) {
-    n = ft->item;
-    n->stemup = stemup;
-    n->beaming = endbeam;
-  } else {
-    printf("closebeam: internal data error\n");
-    exit(1);
-  };
-  v->beamroot = NULL;
-}
-
-static void closegracebeam(struct voice* v)
-/* called after a run of grace notes to be beamed together */
-{
-  struct note* n;
-  struct feature* ft;
-
-  ft = v->gracebeamend;
-  if (ft == NULL) {
-    event_error("Missing grace notes");
-  } else {
-    n = ft->item;
-    if (v->gracebeamroot == v->gracebeamend) {
-      n->beaming = single;
-    } else {
-      n->beaming = endbeam;
-    }; 
-  };
-}
-
-static void insertnote(struct feature* chordplace, struct feature* newfeature)
-/* place NOTE in decreasing pitch order within chord */
-{
-  struct note* n;
-  struct note* newnote;
-  struct feature* f;
-  struct feature* previous;
-  int foundplace;
-
-  newnote = newfeature->item;
-  previous = chordplace;
-  f = chordplace->next;
-  foundplace = 0;
-  n = NULL;
-  while ((f != NULL)&&(f->type==NOTE)&&(foundplace == 0)) {
-    n = f->item;
-    if (newnote->y > n->y) {
-      foundplace = 1;
-    } else {
-      previous = f;
-      f = f->next;
-    };
-  };
-  /* printvoiceline in drawtune.c expects the gchord or
-   * instructions to be associated with the first note in
-   * chord. If the notes are reordered then we need
-   * to move these fields.
-   * if previous == chordplace then move n->gchords and
-   * n->instructions to newnote->gchords and newnote->instructions
-   */
-  if (previous == chordplace && n != NULL) {
-	  newnote->gchords = n->gchords;
-	  newnote->instructions = n->instructions;
-	  n->gchords = NULL;
-	  n->instructions = NULL;
-  }
-  newfeature->next = previous->next;
-  previous->next = newfeature;
-  if (newfeature->next == NULL) {
-    cv->last = newfeature;
-  };
-}
-
-static void beamitem(featuretype mytype, void* newitem, struct feature* x)
-/* This routine is responsible for working out which notes are to be */
-/* beamed together and recording this in the note structure record */
-{
-  struct note* n;
-
-  /* deal with beaming here */
-  if (cv->ingrace) {
-    if (mytype == NOTE) {
-      n = newitem;
-      n->stemup = 1;
-      if (cv->gracebeamroot == NULL) {
-        cv->gracebeamroot = x;
-        cv->gracebeamend = x;
-        n->beaming = startbeam;
-      } else {
-        cv->gracebeamend = x;
-        n->beaming = midbeam;
-      };
-    };
-  } else {
-    if (cv->beamroot != NULL) {
-      switch (mytype) {
-      case NOTE:
-        n = newitem;
-        if (n->base_exp >= -2) {
-          n->beaming = single;
-          closebeam(cv);
-        } else {
-          /* extend beam */
-          if (n->y > cv->beammax) {
-            cv->beammax = n->y;
-          };
-          if (n->y < cv->beammin) {
-            cv->beammin = n->y;
-          };
-          cv->beamend = x;
-          n->beaming = midbeam;
-        };
-        break;
-      case KEY:
-      case REST:
-      case NOBEAM:
-      case SINGLE_BAR:
-      case DOUBLE_BAR:
-      case BAR_REP:
-      case REP_BAR:
-      case BAR1:
-      case REP_BAR2:
-      case DOUBLE_REP:
-      case THICK_THIN:
-      case THIN_THICK:
-      case TUPLE:
-      case MUSICSTOP:
-        /* closebeam */
-        closebeam(cv);
-        break;
-      default:
-        break;
-      };
-    } else {
-      if (mytype == NOTE) {
-        n = newitem;
-        if (n->base_exp >= -2) {
-          n->beaming = single;
-        } else {
-          n->beaming = startbeam;
-          cv->beammax = n->y;
-          cv->beammin = n->y;
-          cv->beamroot = x;
-          cv->beamend = x;
-        };
-      };
-    };
-  };
-}
-
-static struct feature* addfeature(featuretype mytype, void* newitem)
-/* append a new data element to the linked list for the current voice */
-/* The element can be a note or lots of other things */
-{
-  struct voice* p;
-  struct feature* x;
-
-  p = cv;
-  /* printf("in addfeature type=%d\n", mytype); */
-  if (cv == NULL) {
-    printf("ERROR: no current voice in addfeature type=%d\n", mytype);
-    printf("xinhead = %d xinbody = %d\n", xinhead, xinbody);
-    exit(0);
-  };
-  x = (struct feature*)checkmalloc(sizeof(struct feature));
-  x->next = NULL;
-  x->type = mytype;
-  x->item = newitem;
-  x->xleft = 0;
-  x->xright = 0;
-  x->yup = 0;
-  x->ydown = 0;
-  if (cv->first == NULL) {
-    cv->first = x;
-    cv->last = x;
-    beamitem(mytype, newitem, x);
-  } else {
-    if ((cv->last == NULL)||(cv->last->next != NULL)) {
-      printf("expecting NULL at list end!\n");
-      exit(0);
-    };
-    if ((cv->inchord)&&(mytype==NOTE)) {
-      insertnote(cv->chordplace, x);
-    } else {
-      cv->last->next = x;
-      cv->last = x;
-      beamitem(mytype, newitem, x);
-    };
-  };
-  return(x);
-}
-
-struct llist* newlist()
-/* create and initialize a new linked list */
-{
-  struct llist* l;
-
-  l = (struct llist*)checkmalloc(sizeof(struct llist));
-  init_llist(l);
-  return(l);
-}
-
-static int notenum(int octave, char ch, enum cleftype clef, int clefoctave)
-/* converts note to number for stave position */
-/* note E is zero (bottom line of stave) */
-{
-  int n;
-
-  n = 5 + (7 + ch -'c')%7 + 7*(octave-1);
-  switch (clef) {
-  case treble:
-    break;
-  case soprano:
-    n = n + 2;
-    break;
-  case mezzo:
-    n = n + 4;
-    break;
-  case alto:
-    n = n + 6;
-    break;
-  case tenor:
-    n = n + 8;
-    break;
-  case baritone:
-    n = n + 10;
-    break;
-  case bass:
-    n = n + 12;
-    break;
-  };
-  switch (clefoctave) {
-  case -22:
-    n = n + 21;
-    break;
-  case -15:
-    n = n + 14;
-    break;
-  case -8:
-    n = n + 7;
-    break;
-  case 8:
-    n = n - 7;
-    break;
-  case 15:
-    n = n - 14;
-    break;
-  case 22:
-    n = n - 21;
-    break;
-  default:
-    break;
-  };
-  return(n);
-}
-
-int count_dots(int *base, int *base_exp, int n, int m)
-/* convert fraction to 2^base_exp followed by dots */
-/* previously used 1/base instead of 2^base_exp */
-/* -1 indicates a note value which is impossible to represent */
-{
-  int dots;
-  int start;
-  int a, b;
-
-  *base = 1; /* set default value if we fail */
-  *base_exp = 0;
-  if ((n<1)||(m<1)) {
-    return(-1);
-  };
-  /* check denominator is power of 2 */
-  a = m;
-  while (a>1) {
-    if (a%2 == 1) {
-      return(-1);
-    };
-    a = a/2;
-  };
-  dots = 0;
-  start = m;
-  while (start < n) {
-    start = start*2;
-    *base_exp = *base_exp + 1;
-  };
-  while (start > n) {
-    start = start/2;
-    *base_exp = *base_exp - 1;
-  };
-  if (start == 0) {
-    printf("Problem with %d / %d\n", n, m);
-    exit(0);
-  };
-  *base = m/start;
-  a = n - start;
-  b = start;
-  while (a>0) {
-    dots = dots + 1; 
-    b = b/2;
-    a = a - b;
-    if (a< 0) {
-      return(-1);
-    };
-  };
-  return(dots);
-}
-
-static char* decstring(int decorators[])
-/* creates a string of decorators (ornament, staccato, roll, up-bow etc.) */
-/* from a boolean array */
-{
-  int i, j;
-  char decs[DECSIZE+1];
-
-  j = 0;
-  for (i=0; i<DECSIZE; i++) {
-    if (decorators[i]) {
-      decs[j] = decorations[i];
-      j = j + 1;
-    };
-  };
-  decs[j] = '\0';
-  if (j==0) {
-    return(NULL);
-  } else {
-    return(addstring(decs));
-  };
-}
-
-static struct note* newnote(decorators, xaccidental, xmult, xnote, xoctave, 
-                            a, b)
-int decorators[DECSIZE];
-int xmult;
-char xaccidental, xnote;
-int xoctave;
-int a, b;
-/* create and set up the fields for a note structure */
-{
-  struct note* n;
-
-  n = (struct note*)checkmalloc(sizeof(struct note));
-  setfract(&n->len, a, b);
-  reducef(&n->len);
-  n->dots = count_dots(&n->base, &n->base_exp, n->len.num, n->len.denom);
-/*
-  if (n->dots == -1) {
-    event_error("Illegal note length");
-  };
-*/
-  n->accents = decstring(decorators);
-  n->accidental = xaccidental;
-  n->acc_offset = 0;
-  n->fliphead = 0;
-  n->mult = xmult; 
-  n->octave = xoctave;
-  n->pitch = xnote;
-  n->y = notenum(xoctave, xnote, cv->clef->type, cv->clef->octave);
-  if (n->y < 4) {
-    n->stemup = 1;
-  } else {
-    n->stemup = 0;
-  };
-  n->stemlength = 0.0;
-  n->syllables = NULL;
-  if (cv->ingrace) {
-    n->gchords = NULL;
-    n->instructions = NULL;
-  } else {
-    n->gchords = cv->gchords_pending;
-    cv->gchords_pending = NULL;
-    n->instructions = cv->instructions_pending;
-    cv->instructions_pending = NULL;
-  };
-  return(n);
-}
-
-static struct rest* newrest(int a, int b, int multi)
-/* create and set up a new rest structure */
-{
-  struct rest* n;
-
-  n = (struct rest*)checkmalloc(sizeof(struct rest));
-  setfract(&n->len, a, b);
-  n->dots = count_dots(&n->base, &n->base_exp, a, b);
-  if (n->dots == -1) {
-    event_error("Illegal rest length");
-  };
-  n->multibar = multi;
-  if (cv->ingrace) {
-    n->gchords = NULL;
-    n->instructions = NULL;
-  } else {
-    n->gchords = cv->gchords_pending;
-    cv->gchords_pending = NULL;
-    n->instructions = cv->instructions_pending;
-    cv->instructions_pending = NULL;
-  };
-  return(n);
-}
-
-static void addunits(f, n, m)
-struct fract* f;
-int n, m;
-/* add n/m to fraction pointed to by f */
-{
-  f->num = n*f->denom*(cv->unitlen.num) + f->num*(m*cv->unitlen.denom);
-  f->denom = (m*cv->unitlen.denom)*f->denom;
-  reducef(f);
-}
-
-static void addfractions(f,n,m)
-struct fract* f;
-int n,m;
-{
-  f->num = n*f->denom + f->num*m;
-  f->denom = m*f->denom;
-  reducef(f);
-}
-
-
-
-static struct voice* newvoice(int n)
-/* create and set up a new voice data structure */
-{
-  struct voice* v;
-
-  v = (struct voice*)checkmalloc(sizeof(struct voice));
-  v->first = NULL;
-  v->last = NULL;
-  v->voiceno = n;
-  v->octaveshift = thetune.octaveshift;
-  setfract(&v->unitlen, thetune.unitlen.num, thetune.unitlen.denom);
-  v->changetime = 0;
-  v->inslur = 0;
-  v->ingrace = 0;
-  v->inchord = 0;
-  v->expect_repeat = 0;
-  v->tuplenotes = 0;
-  v->thistuple = NULL;
-  v->tuple_count = 0;
-  v->brokenpending = -1;
-  v->tiespending = 0;
-  v->slurpending = 0;
-  v->slurcount = 0;
-  v->barno = 0;
-  v->barchecking = thetune.barchecking;
-  setfract(&v->barlen, thetune.meter.num, thetune.meter.denom);
-  v->clef = newclef(thetune.clef.type, thetune.clef.octave);
-  if (thetune.keysig == NULL) {
-    printf("Trying to set up voice with no key signature\n");
-    exit(0);
-  } else {
-    v->keysig = newkey(thetune.keysig->name, thetune.keysig->sharps,
-                       thetune.keysig->map, thetune.keysig->mult);
-  };
-  v->tempo = NULL;
-  setfract(&v->barcount, 0, 1);
-  setfract(&v->meter, thetune.meter.num, thetune.meter.denom);
-  v->lastnote = NULL;
-  v->laststart = NULL;
-  v->lastend = NULL;
-  v->line = header;
-  v->thisstart = NULL;
-  v->thisend = NULL;
-  v->gchords_pending = NULL;
-  v->instructions_pending = NULL;
-  v->beamed_tuple_pending = 0;
-  v->linestart = NULL;
-  v->lineend = NULL;
-  v->more_lyrics = 0;
-  v->lyric_errors = 0;
-  v->thischord = NULL;
-  v->chordplace = NULL;
-  v->beamroot = NULL;
-  v->beamend = NULL;
-  v->gracebeamroot = NULL;
-  v->gracebeamend = NULL;
-  return(v);
-}
-
-static void setvoice(int n)
-/* set current voice to voice n. If voice n does not exist, create it */
-{
-  struct voice* v;
-  struct el* l;
-  int done;
-
-  if (thetune.voices.first == NULL) {
-    cv = newvoice(n);
-    v = cv;
-    addtolist(&thetune.voices, (void*)v);
-  } else {
-    l = thetune.voices.first;
-    done = 0;
-    while ((done == 0) && (l != NULL)) {
-      if (((struct voice*)l->datum)->voiceno == n) {
-        done = 1;
-        cv = (struct voice*)l->datum;
-      } else {
-       l = l->next;
-      };
-    };
-    if (done == 0) {
-      cv = newvoice(n);
-      v = cv;
-      addtolist(&thetune.voices, (void*)v);
-    };
-  };
-}
-
-static void init_tune(struct tune* t, int x) 
-/* initialize tune structure */
-{
-  t->no = x;
-  t->octaveshift = 0;
-  init_llist(&t->title);
-  t->composer = NULL;
-  t->origin = NULL;
-  t->parts = NULL;
-  init_llist(&t->notes);
-  init_llist(&t->voices);
-  setfract(&t->meter, 0, 1);
-  setfract(&t->unitlen, 0, 1);
-  t->cv = NULL;
-  t->keysig = NULL;
-  t->clef.type = treble;
-  t->clef.octave = 0;
-  t->tempo = NULL;
-  init_llist(&t->words);
-};
-
-static void freekey(struct key* k)
-/* free up memory allocated for key data structure */
-{
-  if (k != NULL) { 
-    if (k->name != NULL) {
-      free(k->name);
-    };
-    free(k);
-  };
-}
-
-static void freetempo(struct atempo *t)
-/* free up memory allocated for temp data structure */
-{
-  if (t->pre != NULL) {
-    free(t->pre);
-  };
-  if (t->post != NULL) {
-    free(t->post);
-  };
-}
-
-static void freefeature(void* item, featuretype type)
-/* free memory allocated for feature in voice */
-{
-  struct note *n;
-  struct rest *r;
-
-  switch(type) {
-  case NOTE:
-    n = item;
-    if (n->accents != NULL) {
-      free(n->accents);
-    };
-    if (n->syllables != NULL) {
-      freellist(n->syllables);
-      free(n->syllables);
-    };
-    if (n->gchords != NULL) {
-      freellist(n->gchords);
-      free(n->gchords);
-    };
-    if (n->instructions != NULL) {
-      freellist(n->instructions);
-      free(n->instructions);
-    };
-    free(n);
-    break;
-  case REST:
-    r = item;
-    if (r->gchords != NULL) {
-      freellist(r->gchords);
-      free(r->gchords);
-    };
-    if (r->instructions != NULL) {
-      freellist(r->instructions);
-      free(r->instructions);
-    };
-    free(r);
-    break;
-  case KEY:
-    freekey(item);
-    break;
-  case TEMPO:
-    freetempo(item);
-    break;
-  case CLEF:
-  case TIME:
-  case PART:
-  case CHORDON:
-  case TUPLE:
-  case SLUR_ON:
-  case TIE:
-  case PLAY_ON_REP:
-  case LEFT_TEXT:
-  case PRINTLINE:
-    if (item != NULL) {
-      free(item);
-    };
-    break;
-  default:
-    break;
-  };
-}
-
-static void freevoice(struct voice* v)
-/* free up memory allocated for voice data structure and voice data */
-{
-  struct feature* ft;
-  struct feature* oldft;
-
-  ft = v->first;
-  while (ft != NULL) {
-    freefeature(ft->item, ft->type);
-    oldft = ft;
-    ft = ft->next;
-    free(oldft);
-  };
-  if (v->keysig != NULL) {
-    freekey(v->keysig);
-    v->keysig = NULL;
-  };
-  if (v->tempo != NULL) {
-    freetempo(v->tempo);
-    v->tempo = NULL;
-  };
-  if (v->clef != NULL) {
-    free(v->clef);
-  };
-  v->clef = NULL;
-}
-
-static void freetune(struct tune* t)
-/* free up all dynamically allocated memory associated with tune */
-{
-  struct voice* v;
-
-  if (t->composer != NULL) {
-    free(t->composer);
-    t->composer = NULL;
-  };
-  if (t->origin != NULL) {
-    free(t->origin);
-    t->origin = NULL;
-  };
-  if (t->parts != NULL) {
-    free(t->parts);
-    t->parts = NULL;
-  };
-  freellist(&t->title);
-  freellist(&t->notes);
-  if (t->keysig != NULL) {
-    freekey(t->keysig);
-    t->keysig = NULL;
-  };
-  if (t->tempo != NULL) {
-    freetempo(t->tempo);
-    t->tempo = NULL;
-  };
-  v = firstitem(&t->voices);
-  while (v != NULL) {
-    freevoice(v);
-    v = nextitem(&t->voices);
-  };
-  freellist(&t->voices);
-  freellist(&t->words);
-}
-
-static int checkmatch(int refno)
-/* compares current reference number against list of numbers */
-/* following -e argument */
-/* returns 1 if tune has been selected and 0 otherwise */
-{
-  int select;
-  int n1, n2;
-  char* place;
-
-  place = matchstring;
-  if (strlen(matchstring)==0) {
-    select = 1;
-  } else {
-    select = 0;
-    while ((select==0)&&(*place >= '0')&&(*place <='9')) {
-      n1 = readnump(&place);
-      if (n1 == refno) {
-        select = 1;
-      } else {
-        if (*place == ',') {
-          place = place+1;
-        } else {
-          if (*place == '-') {
-            place = place+1;
-            n2 = readnump(&place);
-            if ((refno >= n1)&&(refno <= n2)) {
-              select = 1;
-            } else {
-              if (*place == ',') {
-                place = place+1;
-              };
-            };
-          };
-        };
-      };
-    };
-    if ((select==0)&&(*place != '\0')) {
-      event_warning("Number list after -e not fully parsed");
-    };
-  };    
-  return(select);
-}
-
-void event_init(argc, argv, filename)
-int argc;
-char* argv[];
-char** filename;
-/* initialization routine - called once at the start of the program */
-/* interprets the parameters in argv */
-{
-  char* place;
-  int filearg;
-  int refmatch;
-  int papsize, margins, newscale;
-  int ier;
-  int j;
-
-  if (getarg("-ver",argc, argv) != -1) {
-	  printf("%s\n",VERSION);
-	  exit(0);
-  }
-  if (getarg("-d", argc, argv) != -1) {
-    debugging = 1;
-  } else {
-    debugging = 0;
-  };
-  if (getarg("-E", argc, argv) != -1) {
-    eps_out = 1;
-  } else {
-    eps_out = 0;
-  };
-  if (getarg("-OCC",argc,argv) != -1) oldchordconvention=1;
-  if (getarg("-V", argc, argv) != -1) {
-    separate_voices = 1;
-  } else {
-    separate_voices = 0;
-  };
-  if (getarg("-x", argc, argv) != -1) {
-    print_xref = 1;
-  } else {
-    print_xref = 0;
-  };
-  if (getarg("-N", argc, argv) != -1) {
-    pagenumbering = 1;
-  } else {
-    pagenumbering = 0;
-  };
-  if (getarg("-l", argc, argv) != -1) {
-    landscape = 1;
-  } else {
-    landscape = 0;
-  };
-  newscale = getarg("-s", argc, argv);
-  if ((newscale != -1) && (argc >= newscale)) {
-    setscaling(argv[newscale]);
-  } else {
-    setscaling("");
-  };
-  margins = getarg("-M", argc, argv);
-  if ((margins != -1) && (argc >= margins)) {
-    setmargins(argv[margins]);
-  } else {
-    setmargins("");
-  };
-  papsize = getarg("-P", argc, argv);
-  if ((papsize != -1) && (argc >= papsize)) {
-    setpagesize(argv[papsize]);
-  } else {
-    setpagesize("");
-  };
-  barnums = getarg("-k",argc,argv);
-  ier = 0;
-  if ((barnums != -1) && (argc > barnums)) ier = sscanf(argv[barnums],"%d",&nnbars);
-  if ((barnums != -1) && (ier <1)) nnbars = 1;
-
-  refmatch = getarg("-e", argc, argv);
-  if (refmatch == -1) {
-    *matchstring = '\0';
-  } else {
-    if (strlen(argv[refmatch]) < 255) {
-      strcpy(matchstring, argv[refmatch]);
-    } else {
-      event_error("Exceeded character limit for -e string");
-      exit(1);
-    };
-  };
-  if ((getarg("-h", argc, argv) != -1) || (argc < 2)) {
-    printf("yaps version %s\n",VERSION);
-    printf("Usage:  yaps <abc file> [<options>]\n");
-    printf("  possible options are -\n");
-    printf("  -ver          :prints version number and exits\n");
-    printf("  -d            : debug - display data structure\n");
-    printf("  -e <list>     : draw tunes with reference numbers in list\n");
-    printf("     list is comma-separated and may contain ranges\n");
-    printf("     but no spaces e.g. 1,3,7-20\n");
-    printf("  -E            : generate Encapsulated PostScript\n");
-    printf("  -l            : landscape mode\n");
-    printf("  -M XXXxYYY    : set margin sizes in points\n");
-    printf("     28.3 points = 1cm, 72 points = 1 inch\n");
-    printf("  -N            : add page numbering\n");
-    printf("  -k [nn]       : number every nn bars\n");
-    printf("  -o <filename> : specify output file\n");
-    printf("  -P ss         : paper size; 0 is A4, 1 is US Letter\n");
-    printf("     or XXXxYYY to set size in points\n");
-    printf("  -s XX         : scaling factor (default is 0.7)\n");
-    printf("  -V            : separate voices in multi-voice tune\n");
-    printf("  -x            : print tune number in X: field\n");
-    printf("  -OCC          : old chord convention (eg. +CE+)\n");
-    printf("Takes an abc music file and converts it to PostScript.\n");
-    printf("If no output filename is given, then by default it is\n");
-    printf("the input filename but with extension .ps .\n");
-    exit(0);
-  } else {
-    *filename = argv[1];
-  };
-  fileopen = 0;
-  filearg = getarg("-o", argc, argv);
-  if (filearg != -1) { 
-    /*strcpy(outputname, argv[filearg]); security risk buffer overflow */
-    strncpy(outputname, argv[filearg],256);
-  } else {
-    /* strcpy(outputname, argv[1]); security risk: buffer overflow */
-    strncpy(outputname, argv[1],256);
-    place = strchr(outputname, '.');
-    if (place == NULL) {
-      strcat(outputname, ".ps");
-    } else {
-      strcpy(place, ".ps");
-    };
-    if (strcmp(argv[1], outputname)==0) {
-      printf("argument must be abc file, not PostScript file\n");
-      exit(1);
-    };
-  };
-  /* create filename root for EPS output */
-  strcpy(outputroot, outputname);
-  place = strchr(outputroot, '.');
-  if (place != NULL) {
-    *place = '\0';
-  };
-  xinbody =0;
-  xinhead = 0;
-  suppress = 0;
-  init_tune(&thetune, -1);
-  setup_fonts();
-  /* open_output_file(outputname); */
-  for (j=0;j<DECSIZE;j++)  dummydecorator[j] = 0;
-}
-
-static void check_voice_end(struct voice* v)
-/* make sure there are no unfinished structures */
-{
-  if (v->inchord) {
-    event_error("incomplete chord at end of voice");
-    v->inchord = 0;
-  };
-  if (v->brokenpending != -1) {
-    event_error("incomplete broken rhythm at end of voice");
-    v->brokenpending = -1;
-  };
-  if ((v->slurcount > 0)||(v->slurpending)) {
-    event_error("incomplete slur at end of voice");
-    v->slurcount = 0;
-    v->slurpending = 0;
-  };
-  if (v->tiespending) {
-    event_error("incomplete ties at end of voice");
-    v->tiespending = 0;
-  };
-  if (v->gchords_pending != NULL) {
-    freellist(v->gchords_pending);
-    free(v->gchords_pending);
-    v->gchords_pending = NULL;
-  };
-  if (v->instructions_pending != NULL) {
-    freellist(v->instructions_pending);
-    free(v->instructions_pending);
-    v->instructions_pending = NULL;
-  };
-  if (v->tuplenotes > 0) {
-    event_error("incomplete tuple at end of voice");
-    v->tuplenotes = 0;
-  };
-}
-
-static void check_tune_end(struct tune* t)
-/* check that all voices have been completed properly */
-{
-  struct voice* v;
-
-  v = firstitem(&t->voices);
-  while (v != NULL) {
-    check_voice_end(v);
-    v = nextitem(&t->voices);
-  };
-}
-
-void event_eof()
-/* end of input file has been encountered */
-{
-  if (xinbody) {
-    check_tune_end(&thetune);
-    printtune(&thetune);
-  };
-  freetune(&thetune);
-  close_output_file();
-}
-
-void event_blankline()
-/* A blank line has been encountered */
-{
-  if (xinbody) {
-    check_tune_end(&thetune);
-    printtune(&thetune);
-  };
-  freetune(&thetune);
-  xinbody = 0;
-  xinhead = 0;
-  suppress = 0;
-  parseroff();
-}
-
-void event_text(p)
-/* Text outside an abc tune has been encountered */
-char *p;
-{
-}
-
-void event_x_reserved(p)
-char p;
-{
-}
-
-void event_abbreviation(symbol, string, container)
-/* abbreviation declaratiion - handled by parser. Ignore it here */
-char symbol;
-char *string;
-char container;
-{
-}
-
-void event_acciaccatura()
-{
-/* does nothing but outputs a / in toabc.c */
-return;
-}
-
-void event_split_voice()
-{
-addfeature(SPLITVOICE, (void*) lineno);
-event_error("voice split not implemented in yaps");
-}
-
-void event_tex(s)
-char *s;
-/* A TeX command has been found in the abc */
-{
-}
-
-void event_linebreak()
-/* A linebreak has been encountered */
-{
-  if (xinbody) {
-    addfeature(LINENUM, (void*)lineno);
-  };
-}
-
-static void tidy_ties()
-/* create CLOSE_TIE features for ties straddling two lines of music */
-/* CLOSE_TIE appears in the new music line */
-{
-  struct feature* ft;
-  struct slurtie* s;
-  int i;
-
-  for (i=0; i<cv->tiespending; i++) {
-    ft = cv->tie_place[i]; /* pointer to TIE feature */
-    s = ft->item;
-    addfeature(CLOSE_TIE, s);
-  };
-}
-
-void event_startmusicline()
-/* We are at the start of a line of abc notes */
-{
-  cv->linestart = addfeature(MUSICLINE, (void*)NULL);
-  if (cv->more_lyrics != 0) {
-    event_error("Missing continuation w: field");
-    cv->more_lyrics = 0;
-  };
-  if ((cv->line == header) || (cv->line == newline)) {
-    addfeature(CLEF, newclef(cv->clef->type, cv->clef->octave));
-    addfeature(KEY, newkey(cv->keysig->name, cv->keysig->sharps,
-                           cv->keysig->map, cv->keysig->mult));
-    if ((cv->line == header)||(cv->changetime)) {
-      addfeature(TIME, newfract(cv->meter.num, cv->meter.denom));
-      cv->changetime = 0;
-    };
-    cv->line = midline;
-    tidy_ties();
-  };
-  cv->lineend = NULL;
-}
-
-static void divide_ties()
-/* mark unresolved ties and slurs as straddling two lines of music */
-{
-  struct feature* ft;
-  struct slurtie* s;
-  int i;
-
-  for (i=0; i<cv->tiespending; i++) {
-    ft = cv->tie_place[i]; /* pointer to TIE feature */
-    s = ft->item;
-    s->crossline = 1;
-  };
-  for (i=0; i<cv->slurcount; i++) {
-    s = cv->slur_place[i];
-    s->crossline = 1;
-  };
-}
-
-void event_endmusicline(endchar)
-char endchar;
-/* We are at the end of a line of abc notes */
-{
-  cv->lineend = addfeature(MUSICSTOP, (void*)NULL);
-  if ((endchar == ' ') || (endchar == '!')) {
-    addfeature(PRINTLINE, newvertspacing());
-    cv->line = newline;
-    divide_ties();
-  };
-}
-
-void event_error(s)
-char *s;
-/* report any error message */
-{
-  printf("Error in line %d : %s\n", lineno, s);
-}
-
-void event_warning(s)
-char *s;
-/* report any warning message */
-{
-  printf("Warning in line %d : %s\n", lineno, s);
-}
-
-void event_comment(s)
-char *s;
-/* A comment has been encountered in the input */
-{
-}
-
-int make_open()
-/* called as   fileopen = make_open()                    */
-/* if file is not already open, open it and set fileopen */
-{
-  if (fileopen == 0) {
-    open_output_file(outputname, (void*)NULL);
-    fileopen = 1;
-  };
-  return(1);
-}
-
-void event_specific(p, str)
-char *p;   /* first word after %% */
-char *str; /* string following first word */
-/* The special comment %% has been found */
-/* abc2midi uses it for the %%MIDI commands */
-/* yaps implements some of the abc2ps commands */
-{
-  char* s;
-  double vspace;
-  char units[80];
-  int count;
-
-  /* ensure file has been opened since most commands require this */
-  if (!eps_out) {
-    fileopen = make_open();
-  };
-  s = str;
-  skipspace(&s);
-  if (strcmp(p, "newpage") == 0) {
-    if (xinbody == 0) {
-      if (fileopen) {
-        newpage();
-      };
-    } else {
-      addfeature(NEWPAGE, (void*)NULL);
-    };
-  };
-  if (strcmp(p, "text") == 0) {
-    if (xinbody == 0) {
-      if (fileopen) {
-        lefttext(s);
-      };
-    } else {
-      addfeature(LEFT_TEXT, addstring(s));
-    };
-  };
-  if ((strcmp(p, "centre") == 0) || (strcmp(p, "center") == 0)) {
-    if (xinbody == 0) {
-      if (fileopen) {
-        centretext(s);
-      };
-    } else {
-      addfeature(CENTRE_TEXT, addstring(s));
-    };
-  };
-  if (strcmp(p, "vskip") == 0) {
-    count = sscanf(s, "%lf%s", &vspace, units);
-    if (count > 0) {
-      if ((count >= 2) && (strncmp(units, "cm", 2) == 0)) {
-        vspace = vspace*28.3;
-      };
-      if ((count >= 2) && (strncmp(units, "in", 2) == 0)) {
-        vspace = vspace*72.0 ;
-      };
-      if (xinbody == 0) {
-        if (fileopen) {
-          vskip(vspace);
-        };
-      } else {
-        addfeature(VSKIP, (void*)((int)vspace));
-      };
-    };
-  };
-  if (strcmp(p, "chordsabove") == 0) {
-    gchords_above = 1;
-  };
-  if (strcmp(p, "chordsbelow") == 0) {
-    gchords_above = 0;
-  };
-  /* look for font-related commands */
-  font_command(p, s);
-}
-
-void event_field(k, f)
-char k;
-char *f;
-/* A field line has been encountered in the input abc */
-{
-  switch (k) {
-  case 'T':
-    if (debugging) {
-      printf("T:%s\n", f);
-    };
-    addtolist(&thetune.title, addstring(f));
-    break;
-  case 'C':
-    if (thetune.composer != NULL) {
-      event_error("More than one C: field in tune");
-    } else {
-      thetune.composer = addstring(f);
-    };
-    break;
-  case 'O':
-    if (thetune.origin != NULL) {
-      event_error("More than one O: field in tune");
-    } else {
-      thetune.origin = addstring(f);
-    };
-    break;
-  case 'W':
-    if (debugging) {
-      printf("W:%s\n", f);
-    };
-    addtolist(&thetune.words, addstring(f));
-    break;
-  case 'N':
-    addtolist(&thetune.notes, addstring(f));
-    break;
-  default:
-    break;
-  };
-}
-
-struct feature* findbar(struct feature* wordplace, int* errors)
-/* hunts through voice to find next bar data structure */
-{
-  struct feature* ft;
-
-  ft = wordplace;
-  while ((ft != NULL) && (ft != cv->lineend) && (ft->type != MUSICSTOP) &&
-         (ft->type != SINGLE_BAR) && (ft->type != DOUBLE_BAR) &&
-         (ft->type != BAR_REP) && (ft->type != REP_BAR) &&
-         (ft->type != DOUBLE_REP) && (ft->type != THICK_THIN) &&
-         (ft->type != THIN_THICK) && (ft->type != BAR1) &&
-         (ft->type != REP_BAR2)) {
-    ft = ft->next;
-  };
-  if ((ft == NULL) || (ft == cv->lineend) || (ft->type == MUSICSTOP)) {
-    *errors = *errors + 1;
-  } else {
-    ft = ft->next;
-  };
-  return(ft);
-}
-
-struct feature* apply_syll(char* s, struct feature* wordplace, int* errors)
-/* attaches a syllable from the lyrics to the appropriate note */
-{
-  struct note* n;
-  struct feature* ft;
-  int inchord;
-
-  ft = wordplace;
-  inchord = 0;
-  while ((ft != NULL) && (ft != cv->lineend) &&
-         (ft->type != NOTE)) {
-    if (ft->type == CHORDON) {
-      inchord = 1;
-    };
-    ft = ft->next;
-    /* skip over any grace notes */
-    if ((ft != NULL) && (ft->type == GRACEON)) {
-      while ((ft != NULL) && (ft != cv->lineend) &&
-         (ft->type != GRACEOFF)) {
-        ft = ft->next;
-      };
-    };
-  };
-  if ((ft == NULL) || (ft == cv->lineend)) {
-    *errors = *errors + 1;
-    return(ft);
-  };
-  if (ft->type == NOTE) {
-    n = ft->item;
-    if (n->syllables == NULL) {
-      n->syllables = newlist();
-    };
-/*
-    if (strlen(s) < 80) {
-      ISOdecode(s, isocode);
-      addtolist(n->syllables, addstring(isocode));
-    } else {
-*/
-      addtolist(n->syllables, addstring(s));
-/*
-    };
-*/
-  };
-  ft = ft->next;
-  /* skip over any chord */
-  if (inchord) {
-    while ((ft != NULL) && (ft->type != CHORDOFF) && (ft != cv->lineend)) {
-      ft = ft->next;
-    };
-  };
-  return(ft);
-}
-
-void event_words(p, continuation)
-char* p;
-int continuation;
-/* A line of lyrics (w: ) has been encountered in the abc */
-{
-  struct vstring syll;
-  char* q;
-  struct feature* wordplace;
-  unsigned char ch;
-  int errors;
-
-  if (!xinbody) {
-    if (!suppress) {
-      event_error("w: field outside tune body");
-    };
-    return;
-  };
-  wordplace = cv->linestart;
-  if (cv->more_lyrics) {
-    errors = cv->lyric_errors;
-  } else {
-    errors = 0;
-  };
-  if (wordplace == NULL) {
-    event_error("No notes to match words");
-    return;
-  };
-  initvstring(&syll);
-  q = p;
-  skipspace(&q);
-  while (*q != '\0') {
-    clearvstring(&syll);
-    ch = *q;
-    while(ch=='|') {
-      wordplace = findbar(wordplace, &errors);
-      q++;
-      ch = *q;
-    };
-    while (((ch>127)||isalnum(ch)||ispunct(ch))&&
-           (ch != '_')&&(ch != '-')&&(ch != '*')&& (ch != '|')) {
-      if (ch == '~') {
-        ch = ' ';
-      };
-      if ((ch == '\\') && (*(q+1)=='-')) {
-        ch = '-';
-        q++;
-      };
-      /* syllable[i] = ch; */
-      addch(ch, &syll);
-      q++;
-      ch = *q;
-    };
-    skipspace(&q);
-    if (ch == '-') {
-      addch(ch, &syll);
-      while (isspace(ch)||(ch=='-')) {
-        q++;
-        ch = *q;
-      };
-    };
-    if (syll.len > 0) {
-      wordplace = apply_syll(syll.st, wordplace, &errors);
-    } else {
-      if (ch=='_') {
-        clearvstring(&syll);
-        addch('_', &syll);
-        wordplace = apply_syll(syll.st, wordplace, &errors);
-        q++;
-        ch = *q;
-      };
-      if (ch=='*') {
-        clearvstring(&syll);
-        addch(' ', &syll);
-        wordplace = apply_syll(syll.st, wordplace, &errors);
-        q++;
-        ch = *q;
-      };
-    }; 
-  };
-  if (continuation) {
-    cv->more_lyrics = 1;
-    cv->lyric_errors = errors;
-    cv->linestart = wordplace;
-  } else {
-    cv->more_lyrics = 0;
-    if (errors > 0) {
-      event_error("Lyric line too long for music");
-    } else {
-      clearvstring(&syll);
-      wordplace = apply_syll(syll.st, wordplace, &errors);
-      if (errors == 0) {
-        event_error("Lyric line too short for music");
-      };
-    };
-  };
-  freevstring(&syll);
-}
-
-void event_part(s)
-char* s;
-/* A part field (P: ) has been encountered in the abc */
-{
-  char label[20];
-
-  if (xinhead) {
-    if (thetune.parts != NULL) {
-      event_error("Multiple P: fields in header");
-    } else {
-      thetune.parts = addstring(s);
-    };
-  };
-  if (xinbody) {
-    /* addfeature(PART, addstring(s)); */
-    /* PART is handled like an instruction */
-    if (cv->instructions_pending == NULL) {
-      cv->instructions_pending = newlist();
-    };
-    sprintf(label, ":p%s", s);
-    addtolist(cv->instructions_pending, addstring(label));
-  };
-}
-
-void event_voice(n, s, vp)
-int n;
-char *s;
-struct voice_params *vp;
-/* A voice field (V: ) has been encountered */
-{
-  if (xinbody) {
-    setvoice(n);
-  } else {
-    if (!suppress) {
-      event_error("V: field outside tune body");
-    };
-  };
-}
-
-void event_length(n)
-int n;
-/* A length field (L: ) has been encountered */
-{
-  if (xinhead) {
-    setfract(&thetune.unitlen, 1, n);
-  } else {
-    if (xinbody) {
-      setfract(&cv->unitlen, 1, n);
-    } else {
-      if (!suppress) {
-        event_warning("L: field outside tune ignored");
-      };
-    };
-  };
-}
-
-void event_refno(n)
-int n;
-/* A reference field (X: ) has been encountered. This indicates the start */
-/* of a new tune */
-{
-  if (xinhead) {
-    event_error("incomplete tune");
-  };
-  if (xinbody) {
-    check_tune_end(&thetune);
-    printtune(&thetune);
-  };
-  freetune(&thetune);
-  xinbody = 0;
-  xinhead = 0;
-  suppress = 0;
-  parseroff();
-  if (debugging) {
-    printf("X:%d\n", n);
-  };
-  if (checkmatch(n)) {
-    parseron();
-    /* fileopen = make_open(); */
-    xinhead = 1;
-    xinbody = 0;
-    init_tune(&thetune, n);
-  } else {
-    suppress = 1;
-  };
-}
-
-void event_tempo(n, a, b, relative, pre, post)
-int n, a, b;
-int relative;
-char *pre; /* text before tempo */
-char *post; /* text after tempo */
-/* A tempo field Q: has been encountered in the abc */
-/* Q:a/b=N will have relative = 0    */
-/* Q:N will have a=0 and b=0         */
-/* Q:Ca/b = N will have relative = 1 */
-{
-  if (xinhead) {
-    thetune.tempo = newtempo(n, a, b, relative, pre, post);
-  } else {
-    if (xinbody) {
-      if ((a == 0) && (b == 0)) {
-        addfeature(TEMPO, newtempo(n, cv->unitlen.num, cv->unitlen.denom, 0,
-                                pre, post));
-      } else {
-        addfeature(TEMPO, newtempo(n, a, b, relative, pre, post));
-      };
-    } else {
-      if (!suppress) {
-        event_warning("Q: field outside tune ignored");
-      };
-    };
-  };
-}
-
-void event_timesig(n, m, checkbars)
-int n, m, checkbars;
-/* A time signature (M: ) has been encountered in the abc */
-{
-  if (xinhead) {
-    setfract(&thetune.meter, n, m);
-    thetune.barchecking = checkbars;
-  } else {
-    if (xinbody) {
-      if (checkbars == 1) {
-        addfeature(TIME, newfract(n,m));
-        setfract(&cv->meter, n, m);
-        setfract(&cv->barlen, n, m);
-        if (cv->line != midline) {
-          cv->changetime = 1;
-        };
-        cv->barchecking = 1;
-      } else {
-        cv->barchecking = 0;
-      };
-    } else {
-      if (!suppress) {
-        event_warning("M: field outside tune ignored");
-      };
-    };
-  };
-}
-
-enum cleftype findclef(clefstr, oct)
-char* clefstr;
-int* oct;
-/* converts a clef name string to an enumerated type */
-/* also looks for +8 +15 +22 -8 -15 -22 octave shift */
-{
-  enum cleftype type;
-  char* p;
-  int interval;
-
-  type = noclef;
-  p = clefstr;
-  if (strncmp(clefstr, "treble", 6)==0) {
-    type = treble;
-    p = p + 6;
-  };
-  if (strncmp(clefstr, "bass", 4)==0) {
-    type = bass;
-    p = p + 4;
-  };
-  if (strncmp(clefstr, "baritone", 8)==0) {
-    type = baritone;
-    p = p + 8;
-  };
-  if (strncmp(clefstr, "tenor", 5)==0) {
-    type = tenor;
-    p = p + 5;
-  };
-  if (strncmp(clefstr, "alto", 4)==0) {
-    type = alto;
-    p = p + 4;
-  };
-  if (strncmp(clefstr, "mezzo", 5)==0) {
-    type = mezzo;
-    p = p + 5;
-  };
-  if (strncmp(clefstr, "mezzo-soprano", 13)==0) {
-    type = mezzo;
-    p = p + 13;
-  };
-  if (strncmp(clefstr, "soprano", 7)==0) {
-    type = soprano;
-    p = p + 7;
-  };
-  interval = 0;
-  if ((type != noclef) && ((*p == '+') || (*p == '-'))) {
-    sscanf(p+1, "%d", &interval);
-    if ((interval == 8) || (interval == 15) || (interval == 22)) {
-      if (*p == '-') {
-        interval = -interval;
-      };
-    } else {
-      interval = 0;
-    };
-  };
-  *oct = interval;
-  return(type);
-}
-
-void event_clef(char* clefstr)
-/* a clef has been encountered in the abc */
-{
-  enum cleftype clef;
-  int num;
-
-  clef = findclef(clefstr, &num);
-  if (xinbody) {
-    cv->clef->type = clef;
-    cv->clef->octave = num;
-    addfeature(CLEF, newclef(clef, num));
-  };
-  if ((xinhead) && (!xinbody)) {
-    if (clef != noclef) {
-       thetune.clef.type = clef;
-       thetune.clef.octave = num;
-    };
-  };
-}
-
-void setmap(sf, map, mult)
-/* work out accidentals to be applied to each note */
-int sf; /* number of sharps in key signature -7 to +7 */
-char map[7];
-int mult[7];
-{
-  int j;
-
-  for (j=0; j<7; j++) {
-    map[j] = '=';
-    mult[j] = 1;
-  };
-  if (sf >= 1) map['f'-'a'] = '^';
-  if (sf >= 2) map['c'-'a'] = '^';
-  if (sf >= 3) map['g'-'a'] = '^';
-  if (sf >= 4) map['d'-'a'] = '^';
-  if (sf >= 5) map['a'-'a'] = '^';
-  if (sf >= 6) map['e'-'a'] = '^';
-  if (sf >= 7) map['b'-'a'] = '^';
-  if (sf <= -1) map['b'-'a'] = '_';
-  if (sf <= -2) map['e'-'a'] = '_';
-  if (sf <= -3) map['a'-'a'] = '_';
-  if (sf <= -4) map['d'-'a'] = '_';
-  if (sf <= -5) map['g'-'a'] = '_';
-  if (sf <= -6) map['c'-'a'] = '_';
-  if (sf <= -7) map['f'-'a'] = '_';
-}
-
-void altermap(basemap, basemul, modmap, modmul)
-/* apply modifiers to a set of accidentals */
-char basemap[7], modmap[7];
-int basemul[7], modmul[7];
-{
-  int i;
-
-  for (i=0; i<7; i++) {
-    if (modmap[i] != ' ') {
-      basemap[i] = modmap[i];
-      basemul[i] = modmul[i];
-    };
-  };
-}
-
-
-void resolve_tempo(struct atempo* t, struct fract* unitlen)
-/* Tempo may be given relative to the unit note length. At the start of */
-/* the tune, we will know what this is and can deduce the tempo value.  */
-/* Can also deduce tempo if it has been given as a number only.         */
-{
-  if (t->relative==1) {
-    setfract(&t->basenote, t->basenote.num*unitlen->num, 
-                           t->basenote.denom*unitlen->denom);
-    reducef(&t->basenote);
-    t->relative = 0;
-  };
-  if ((t->basenote.num == 0) && (t->basenote.denom == 0)) {
-    setfract(&t->basenote, unitlen->num, unitlen->denom);
-    reducef(&t->basenote);
-  };
-}
-
-static void start_body()
-/* We have reached the end of the header section and need to set */
-/* default values for anything not explicitly declared */
-{
-  parseron();
-  if (thetune.meter.num == 0) {
-    event_warning("no M: field, assuming 4/4");
-    /* generate missing time signature */
-    event_timesig(4, 4, 1);
-    event_linebreak();
-  };
-  if (thetune.unitlen.num == 0) {
-    event_warning("no L: field, using default rule");
-    if ((double) thetune.meter.num / (double) thetune.meter.denom < 0.75) {
-      /*setfract(&thetune.unitlen, 1, 16); [SS] 2004-09-06 */
-      event_length(16);
-    } else {
-     /* setfract(&thetune.unitlen, 1, 8); */
-      event_length(8);
-    };
-  };
-  if (thetune.tempo != NULL) {
-    resolve_tempo(thetune.tempo, &thetune.unitlen);
-  };
-}
-
-void event_true_key(sharps, s, modeindex, modmap, modmul)
-int sharps;
-char *s;
-int modeindex; /* 0 major, 1,2,3 minor, 4 locrian, etc.  */
-char modmap[7];
-int modmul[7];
-/* key detected in K: field */
-{
-  char basemap[7];
-  int basemul[7];
-  struct key* akey;
-  int minor;
-  minor =0;
-  if (modeindex >0 && modeindex <4) minor = 1;
-
-  setmap(sharps, basemap, basemul);
-  altermap(basemap, basemul, modmap, modmul);
-  if (xinbody) {
-    akey = newkey(s, sharps, basemap, basemul);
-    addfeature(KEY, akey);
-    set_keysig(cv->keysig, akey);
-  };
-  if (xinhead) {
-    if (thetune.keysig == NULL) {
-      thetune.keysig = newkey(s, sharps, basemap, basemul);
-    } else {
-      event_warning("Key specified twice");
-    };
-    xinbody = 1;
-    xinhead = 0;
-    setvoice(1);
-    start_body();
-  };
-}
-
-void event_octave(int num, int local)
-/* deals with the special command I:octave=N */
-{
-  if (xinhead) {
-    thetune.octaveshift = num;
-  };
-  if (xinbody) {
-    cv->octaveshift = num;
-  };
-}
-
-void event_key(sharps, s, minor, modmap, modmul, gotkey, gotclef, clefstr,
-          octave, transpose, gotoctave, gottranspose)
-int sharps;
-char *s;
-int minor;
-char modmap[7];
-int modmul[7];
-int gotkey, gotclef;
-char* clefstr;
-int octave, transpose, gotoctave, gottranspose;
-/* A key field (K: ) has been encountered */
-{
-  if (xinhead || xinbody) {
-    if (gotclef==1) {
-      event_clef(clefstr);
-    };
-    if (gotkey==1) {
-      event_true_key(sharps, s, minor, modmap, modmul);
-    };
-  };
-  if (gotoctave) {
-    event_octave(octave,0);
-  };
-}
-
-static void checkbar(int type)
-/* Make sure that bar lasts for the correct musical time */
-{
-  int valid;
-  char msg[80];
-  int a1, a2;
-
-  valid = 0;
-  a1 = cv->barlen.num*cv->barcount.denom;
-  a2 = cv->barcount.num*cv->barlen.denom;
-  if (a1 == a2) {
-    cv->barcount.num = 0;
-    cv->barcount.denom = 1;
-    cv->barno = cv->barno + 1;
-  } else {
-    if (((type==BAR_REP)||(type==REP_BAR)||(type==DOUBLE_REP)) &&
-        (a1 > a2)) {
-      /* do nothing */
-    } else {
-      if ((cv->barno > 0) && (cv->barcount.num != 0) &&
-          (cv->barchecking != 0)) {
-        sprintf(msg, "Bar %d is %d/%d not %d/%d", cv->barno, 
-           cv->barcount.num, cv->barcount.denom,
-           cv->barlen.num, cv->barlen.denom);
-        event_warning(msg);
-        cv->barcount.num = 0;
-        cv->barcount.denom = 1;
-        cv->barno = cv->barno + 1;
-      } else {
-        cv->barcount.num = 0;
-        cv->barcount.denom = 1;
-        cv->barno = cv->barno + 1;
-      };
-    };
-  };
-}
-
-void event_bar(type, playonrep_list)
-int type;
-char* playonrep_list;
-/* A bar has been encountered in the abc */
-{
-  if (cv->inchord) {
-    event_warning("Bar line not permitted within chord");
-    return;
-  };
-  checkbar(type); /* increment bar number if bar complete */
-  addfeature(type, (void*)cv->barno); /* save bar number */
-  switch(type) {
-  case SINGLE_BAR:
-    break;
-  case DOUBLE_BAR:
-    break;
-  case THIN_THICK:
-    break;
-  case THICK_THIN:
-    break;
-  case BAR_REP:
-    if ((cv->expect_repeat) && (repcheck)) {
-      event_error("Expecting repeat, found |:");
-    };
-    cv->expect_repeat = 1;
-    break;
-  case REP_BAR:
-    if ((!cv->expect_repeat) && (repcheck)) {
-      event_error("No repeat expected, found :|");
-    };
-    cv->expect_repeat = 0;
-    break;
-  case BAR1:
-    if ((!cv->expect_repeat) && (repcheck)) {
-      event_error("found |1 in non-repeat section");
-    };
-    break;
-  case REP_BAR2:
-    if ((!cv->expect_repeat) && (repcheck)) {
-      event_error("No repeat expected, found :|2");
-    };
-    cv->expect_repeat = 0;
-    break;
-  case DOUBLE_REP:
-    if ((!cv->expect_repeat) && (repcheck)) {
-      event_error("No repeat expected, found ::");
-    };
-    cv->expect_repeat = 1;
-    break;
-  };
-  if ((playonrep_list != NULL) && (strlen(playonrep_list) > 0)) {
-    event_playonrep(playonrep_list);
-  };
-}
-
-void event_space()
-/* A region of whitespace has been encountered */
-{
-  addfeature(NOBEAM, NULL);
-}
-
-void event_graceon()
-/* start of grace note(s) */
-{
-  if (cv->inchord) {
-    event_error("grace notes not allowed within chord");
-    return;
-  };
-  if (cv->ingrace) {
-    event_error("nested grace notes not allowed");
-    return;
-  };
-  cv->gracebeamroot = NULL;
-  cv->gracebeamend = NULL;
-  cv->ingrace = 1;
-  addfeature(GRACEON, NULL);
-}
-
-void event_graceoff()
-/* end of grace note(s) */
-{
-  if (!cv->ingrace) {
-    event_error("No grace notes to close");
-    return;
-  };
-  if (cv->inchord) {
-    event_error("cannot close grace notes within chord");
-    return;
-  };
-  addfeature(GRACEOFF, NULL);
-  closegracebeam(cv);
-  cv->ingrace = 0;
-  cv->gracebeamroot = NULL;
-  cv->gracebeamend = NULL;
-}
-
-void event_rep1()
-/* start of first repeat */
-{
-  addfeature(REP1, NULL);
-}
-
-void event_rep2()
-/* start of second repeat */
-{
-  addfeature(REP2, NULL);
-}
-
-void event_playonrep(s)
-char* s;
-/* play on repeat(s) X - where X can be a list */
-{
-  addfeature(PLAY_ON_REP, addstring(s));
-}
-
-void event_broken(type, mult)
-/* handles > >> >>> < << <<< in the abc */
-int type, mult;
-{
-  if (cv->inchord) {
-    event_error("Broken rhythm not allowed in chord");
-  } else {
-    if (cv->ingrace) {
-      event_error("Broken rhythm not allowed in grace notes");
-    } else {
-      cv->brokentype = type;
-      cv->brokenmult = mult;
-      cv->brokenpending = 0;
-    };
-  };
-}
-
-void event_tuple(n, q, r)
-int n, q, r;
-/* Start of a tuple has been  encountered (e.g. triplet) */
-/* Meaning is "play next r notes at q/n of notated value" */
-/* where all 3 exist, otherwise r defaults to n and ratio */
-/* is deduced from standard rules if q is missing */
-{
-  if (cv->tuplenotes != 0) {
-    event_error("tuple within tuple not allowed");
-    return;
-  };
-  if (r != 0) {
-    cv->tuplenotes = r;
-  } else {
-    cv->tuplenotes = n;
-  };
-  if (q != 0) {
-    cv->tuplefactor.num = q;
-    cv->tuplefactor.denom = n;
-  } else {
-    cv->tuplefactor.denom = n;
-    if ((n == 2) || (n == 4) || (n == 8)) cv->tuplefactor.num = 3;
-    if ((n == 3) || (n == 6)) cv->tuplefactor.num = 2;
-    if ((n == 5) || (n == 7) || (n == 9)) {
-      if ((cv->barlen.num % 3) == 0) {
-        cv->tuplefactor.num = 3;
-      } else {
-        cv->tuplefactor.num = 2;
-      };
-    };
-  };
-  cv->thistuple = newtuple(cv->tuplefactor.denom, cv->tuplefactor.num, 
-                           cv->tuplenotes, n);
-  addfeature(TUPLE, cv->thistuple);
-}
-
-void event_startinline()
-{
-}
-
-void event_closeinline()
-{
-}
-
-void event_handle_gchord(s)
-char* s;
-/* Guitar/Accompaniment chord placed in linked list for association */
-/* with next suitable note */
-{
-  if (cv->gchords_pending == NULL) {
-    cv->gchords_pending = newlist();
-  };
-  if (*s == '_') {
-  if (cv->instructions_pending == NULL) {
-    cv->instructions_pending = newlist();
-    };
-  addtolist(cv->instructions_pending, addstring(s+1));
-  } else {
-    addtolist(cv->gchords_pending, addstring(s));
-  };
-}
-
-void event_handle_instruction(s)
-char* s;
-/* An instruction (! !) has been encountered */
-{
-  char* inst;
-  static char segno[3] = ":s";
-  static char coda[3] = ":c";
-  struct dynamic *psaction;
-  int done;
- 
-  done = 0;
-  inst = s;
-  if (strcmp(s, "fermata") == 0)
-     {
-     decorators_passback[4] =1;
-/*   don't show !fermata!. Treat it like H in music line */
-     return;
-     }
-
-  if (strcmp(s, "trill") == 0)
-     {
-     decorators_passback[6] =1;
-/*   don't show !trill!. Treat it like T in music line */
-     return;
-     }
-
-  if (strcmp(s, "segno") == 0) {
-    inst = segno;
-    done = 1;
-  };
-  if (strcmp(s, "coda") == 0) {
-    inst = coda;
-    done = 1;
-  };
-
-  if (done == 1) {
-    if (cv->instructions_pending == NULL) {
-      cv->instructions_pending = newlist();
-     };
-    addtolist(cv->instructions_pending, addstring(inst));
-    return;
-    }
-  if (strcmp(s,"red") == 0)
-   {     
-   psaction = (struct dynamic*) checkmalloc(sizeof(struct note));
-   psaction->color = 'r';
-   addfeature(DYNAMIC,psaction);
-   }
-  if (strcmp(s,"black") == 0)
-   {     
-   psaction = (struct dynamic*) checkmalloc(sizeof(struct note));
-   psaction->color = 'b';
-   addfeature(DYNAMIC,psaction);
-   }
-}
-
-struct slurtie* resolve_slur(struct feature* lastnote)
-/* when an end-of-slur marker ')' is found, this routine works out */
-/* where the other end of the slur was */
-{
-  int i;
-  int resolved;
-  struct slurtie* s;
-
-  resolved = 0;
-  if (lastnote != NULL) {
-    for (i=0; i<cv->slurcount; i++) {
-      if ((resolved == 0) && (cv->slur_place[i]->begin != NULL) &&
-          (cv->slur_place[i]->begin != lastnote)) {
-        resolved = 1;
-        cv->slur_place[i]->end = lastnote;
-        s = cv->slur_place[i];
-        cv->slur_place[i] = cv->slur_place[cv->slurcount-1];
-        cv->slurcount = cv->slurcount - 1;
-      };
-    };  
-  };
-  if (resolved == 0) {
-    event_error("Could not find start of slur to match close slur");
-    s = NULL;
-  };
-  return(s);
-}
-
-static void startslurs(struct feature* firstnote)
-/* When a note is found after a (, set note to be start of slur */
-/* Note may be the start of more than one slur */
-{
-  int i;
-
-  for (i=0; i<cv->slurcount; i++) {
-    if (cv->slur_place[i]->begin == NULL) {
-      cv->slur_place[i]->begin = firstnote;
-    };
-  };
-}
-
-void event_sluron(t)
-int t;
-/* start of slur */
-{
-  struct slurtie* s;
-
-  s = newslurtie();
-  addfeature(SLUR_ON, s);
-  cv->slurpending = 1;
-  if (cv->slurcount < MAX_SLURS) {
-    cv->slur_place[cv->slurcount] = s;
-    cv->slurcount = cv->slurcount+1;
-  } else {
-    event_error("Static limit on number of slurs exceeded");
-  };
-}
-
-void event_sluroff(t)
-int t;
-/* end of slur */
-{
-  struct slurtie* s;
-
-  s = resolve_slur(cv->lastnote);
-  addfeature(SLUR_OFF, s);
-}
-
-static void resolve_ties(struct feature* f)
-/* try to match up note to previous tied note */
-{
-  struct feature* ft;
-  struct slurtie* s;
-  struct note* m;
-  struct note* n;
-  int i, j;
-
-  n = f->item;
-  for (i=0; i<cv->tiespending; i++) {
-    ft = cv->tie_place[i]; /* pointer to TIE feature */
-    s = ft->item;
-    ft = s->begin; /* pointer to NOTE feature */
-    m = ft->item;
-    if (m->y == n->y) { /* pitch match found */
-      s->end = f;
-      j = cv->tiespending;
-      cv->tie_place[i] = cv->tie_place[j-1];
-      cv->tie_status[i] = cv->tie_status[j-1];
-      cv->tiespending = j-1;
-    };
-  };
-}
-
-static void advance_ties()
-/* deal with unresolved tied notes as musical time advances */
-{
-  int i, j;
-
-  for (i=0; i<cv->tiespending; i++) {
-    cv->tie_status[i]++;
-  };
-  i = 0;
-  j = cv->tiespending;
-  while (i < j) {
-    if (cv->tie_status[i] >= 2) {
-      event_error("No note to tie to");
-      cv->tie_place[i] = cv->tie_place[j-1];
-      cv->tie_status[i] = cv->tie_status[j-1];
-      j = j - 1;
-    } else {
-      i = i + 1;
-    };
-  };
-  cv->tiespending = j;
-}
-
-void event_tie()
-/* tie encountered in the abc */
-{
-  struct slurtie* s;
-  struct feature* place;
-  int i;
-
-  if ((cv->lastnote == NULL)||(cv->lastnote->type != NOTE)) {
-    event_error("No note to tie");
-  } else {
-    s = newslurtie();
-    place = addfeature(TIE, s);
-    s->begin = cv->lastnote;
-    cv->lastnote = NULL;
-    i = cv->tiespending;
-    if (i < MAX_TIES) {
-      cv->tie_place[i] = place;
-      cv->tie_status[i] = 0;
-      cv->tiespending = cv->tiespending + 1;
-    } else {
-      event_error("Internal limit on ties exceeded");
-    };
-  };
-}
-
-void event_lineend(ch, n)
-char ch;
-int n;
-/* Line ending with n copies of special character ch */
-{
-}
-
-static void lenmul(n, a, b)
-/* multiply note length by a/b */
-struct feature* n;
-int a, b;
-{
-  struct note *anote;
-  struct rest* arest;
-  struct fract* afract;
-
-  if (n->type == NOTE) {
-    anote =  n->item;
-    afract = &anote->len;
-    afract->num = afract->num * a;
-    afract->denom = afract->denom * b;
-    reducef(afract);
-    /* re-calculate base, base_exp and dots */
-    anote->dots = count_dots(&anote->base, &anote->base_exp, 
-                             anote->len.num, anote->len.denom);
-  };
-  if (n->type == REST) {
-    arest =  n->item;
-    afract = &arest->len;
-    afract->num = afract->num * a;
-    afract->denom = afract->denom * b;
-    reducef(afract);
-    /* re-calculate base, base_exp and dots */
-    arest->dots = count_dots(&arest->base, &arest->base_exp, 
-                             arest->len.num, arest->len.denom);
-  };
-}
-
-struct fract* getlenfract(struct feature *f)
-/* find fractional length of NOTE or REST */
-{
-  struct fract *len;
-  struct note *anote;
-  struct rest *arest;
-
-  len = NULL;
-  if (f->type == NOTE) {
-    anote = f->item;
-    len = &(anote->len);
-  };
-  if (f->type == REST) {
-    arest = f->item;
-    len = &(arest->len);
-  };
-  return(len);
-}
-
-static void brokenadjust()
-/* adjust lengths of broken notes */
-{
-  int num1, num2, denom12;
-  struct feature* j;
-  struct fract* fr1;
-  struct fract* fr2;
-  int temp;
-  int failed;
-  int done;
-
-  switch(cv->brokenmult) {
-    case 1:
-      num1 = 3;
-      num2 = 1;
-      break;
-    case 2:
-      num1 = 7;
-      num2 = 1;
-      break;
-    case 3:
-      num1 = 15;
-      num2 = 1;
-      break;
-  };
-  denom12 = (num1 + num2)/2;
-  if (cv->brokentype == LT) {
-    temp = num1;
-    num1 = num2;
-    num2 = temp;
-  };
-  failed = 0;
-  if ((cv->laststart == NULL) || (cv->lastend == NULL) || 
-      (cv->thisstart == NULL) || (cv->thisend == NULL)) {
-    failed = 1;
-  } else {
-    /* check for same length notes */
-    fr1 = getlenfract(cv->laststart);
-    fr2 = getlenfract(cv->thisstart);
-/*
-    fr1 = cv->laststart->item;
-    fr2 = cv->thisstart->item;
-*/
-    if ((fr1->num * fr2->denom) != (fr2->num * fr1->denom)) {
-      failed = 1;
-    };
-  };
-  if (failed) {
-    event_error("Cannot apply broken rhythm");
-  } else {
-/*
-    printf("Adjusting %d to %d and %d to %d\n",
-           cv->laststart, cv->lastend, cv->thisstart, cv->thisend);
-*/
-    j = cv->laststart;
-    done = 0;
-    while (done == 0) {
-      lenmul(j, num1, denom12);
-      done = (j == cv->lastend);
-      j = j->next; 
-    };
-    j = cv->thisstart;
-    done = 0;
-    while (done == 0) {
-      lenmul(j, num2, denom12);
-      done = (j == cv->thisend);
-      j = j->next; 
-    };
-  };
-}
-
-static void marknotestart(struct feature* place)
-/* voice data structure keeps a record of last few notes encountered */
-/* in order to process broken rhythm. This is called at the start of */
-/* a note or chord */
-{
-  cv->laststart = cv->thisstart;
-  cv->lastend = cv->thisend;
-  cv->thisstart = place;
-}
-
-static void marknoteend(struct feature* place)
-/* voice data structure keeps a record of last few notes encountered */
-/* in order to process broken rhythm. This is called at the end of */
-/* a note or chord */
-{
-  cv->thisend = place;
-  if (cv->brokenpending != -1) {
-    cv->brokenpending = cv->brokenpending + 1;
-    if (cv->brokenpending == 1) {
-      brokenadjust();
-      cv->brokenpending = -1;
-    };
-  };
-}
-
-static void marknote(struct feature* place)
-/* when handling a single note, not a chord, marknotestart() and */
-/* marknoteend() can be called together */
-{
-  marknotestart(place);
-  marknoteend(place);
-}
-
-static void markchord(struct feature* chordplace)
-/* find start and end of chord for applying broken rhythm */
-{
-  struct feature* first;
-  struct feature* last;
-
-  first = chordplace->next;
-  last = first;
-  while ((last->next != NULL)&&(last->next->type==NOTE)) {
-    last = last->next;
-  };
-  marknotestart(first);
-  marknoteend(last);
-}
-
-void event_chord()
-/* handles old '+' notation which marks the start and end of each chord */
-{
-    if (cv->inchord) {
-      event_chordoff(1,1);
-    } else {
-      event_chordon(dummydecorator);
-    };
-}
-
-void event_chordon(int chorddecorators[])
-/* start of a chord */
-/* the array chorddecorators is not used yet. */
-{
-  if (cv->inchord) {
-    event_error("nested chords found");
-    return;
-  };
-  cv->inchord = 1;
-  cv->chordcount = 0;
-  cv->thischord = newchord();
-  cv->chordplace = addfeature(CHORDON, cv->thischord);
-}
-
-
-void fix_enclosed_note_lengths(struct feature* chordplace,
-      int chord_n, int chord_m, int * base, int * base_exp)
-{
-struct feature* f;
-struct note* anote;
-if (chord_n ==1 && chord_m ==1) return;
-f = chordplace->next;
-anote = f->item;
-/* remove old note length from barcount */
-addfractions(&cv->barcount, -anote->len.num, anote->len.denom);
-while ((f != NULL)&&((f->type==NOTE)||(f->type=CHORDNOTE))) {
-   anote = f->item;
-   /* remove old note length from barcount */
-   setfract(&anote->len, chord_n*cv->unitlen.num, chord_m*cv->unitlen.denom);
-   reducef(&anote->len);
-   /*printf("NOTE %c%c %d / %d\n", anote->accidental, anote->pitch, 
-               anote->len.num, anote->len.denom);                 
-   */
-   anote->dots = count_dots(&anote->base, &anote->base_exp,
-         anote->len.num, anote->len.denom);
-   f = f->next;
-   *base = anote->base;
-   *base_exp = anote->base_exp;
-   }
-   /* and new note length to barcount */
-   addfractions(&cv->barcount, anote->len.num, anote->len.denom);
-}
-
-
-void event_chordoff(int chord_n, int chord_m)
-/* end of a chord */
-{
-  struct feature* ft;
-  struct chord* thechord;
-  struct note* firstnote;
-  int base,base_exp;
-
-  if (!cv->inchord) {
-    event_error("no chord to close");
-    return;
-  };
-  ft = cv->chordplace;
-  if ((ft != NULL) && (ft->next != NULL) && (ft->next->type == NOTE)) {
-    thechord = ft->item;
-    firstnote = ft->next->item;
-    /* beaming for 1st note in chord */
-    beamitem(NOTE, firstnote, ft->next);
-    markchord(ft);
-    thechord->base = firstnote->base;
-    thechord->base_exp = firstnote->base_exp;
-  } else {
-    event_error("mis-formed chord");
-  };
-  
-  if (cv->chordplace) {
-      fix_enclosed_note_lengths(cv->chordplace,chord_n,chord_m,&base,&base_exp);
-      if (chord_n != 1 || chord_m != 1) {
-         thechord->base = base;
-         thechord->base_exp = base_exp;
-         }
-      }
-  cv->inchord = 0;
-  cv->thischord = NULL;
-  cv->chordplace = NULL;
-  advance_ties();
-  addfeature(CHORDOFF, NULL);
-}
-
-/* just a stub to ignore 'y' */
-void event_spacing(n, m)
-int n,m;
-{
-}
-
-void xevent_rest(n, m, multi)
-int n, m, multi;
-/* A rest has been encountered in the abc */
-/* multi is 0 for ordinary rests or count for multibar rests */
-{
-  struct feature* restplace;
-
-  if (cv->ingrace) {
-    event_warning("rest in grace notes ignored");
-    return;
-  };
-  if (cv->inchord) {
-    event_warning("rest in chord ignored");
-    return;
-  };
-  if ((multi > 0) && (cv->tuplenotes > 0)) {
-    event_error("Multiple bar rest not allowed in tuple");
-  };
-  advance_ties();
-  restplace = addfeature(REST, newrest(n*cv->unitlen.num, 
-                                         m*cv->unitlen.denom, multi));
-  if (cv->slurpending) {
-    startslurs(restplace);
-    cv->slurpending = 0;
-  };
-  cv->lastnote = restplace;
-  if (cv->inchord) {
-    cv->chordcount = cv->chordcount + 1;
-  } else {
-    marknote(restplace); 
-  };
-  if ((!cv->ingrace) && (!cv->inchord || (cv->chordcount == 1))) {
-    if (cv->tuplenotes == 0) {
-      if (multi == 0) {
-        addunits(&cv->barcount, n, m);
-      };
-    } else {
-      addunits(&cv->barcount, n*cv->tuplefactor.num, m*cv->tuplefactor.denom);
-      cv->thistuple->beamed = 0;
-      cv->tuplenotes = cv->tuplenotes - 1;
-      if (cv->tuplenotes == 0) {
-        cv->thistuple = NULL;
-      };
-    };
-  };
-}
-
-void event_rest(decorators,n,m,type)
-int n, m,type;
-int decorators[DECSIZE];
-/* A rest has been encountered in the abc */
-{
-  xevent_rest(n, m, 0);
-}
-
-void event_mrest(n,m)
-int n, m;
-/* A multiple bar rest has been encountered in the abc */
-{
-  xevent_rest(1, 1, n);
-}
-
-void event_note(decorators, xaccidental, xmult, xnote, xoctave, n, m)
-int decorators[DECSIZE];
-int xmult;
-char xaccidental, xnote;
-int xoctave, n, m;
-/* note found in abc */
-{
-  struct note* nt;
-  struct feature* noteplace;
-  struct chord* thechord;
-  int pitchval;
-
-  nt = newnote(decorators, xaccidental, xmult, xnote, xoctave+cv->octaveshift, 
-               n * cv->unitlen.num, m * cv->unitlen.denom);
-  nt->tuplenotes = cv->tuplenotes;
-  noteplace = addfeature(NOTE, nt);
-  cv->lastnote = noteplace;
-  resolve_ties(noteplace);
-  if (cv->slurpending) {
-    startslurs(noteplace);
-    cv->slurpending = 0;
-  };
-  if (!cv->inchord) {
-    marknote(noteplace);
-    advance_ties();
-  } else {
-    thechord = cv->thischord;
-    pitchval = notenum(xoctave, xnote, cv->clef->type, cv->clef->octave);
-    if (cv->chordcount == 0) {
-      thechord->ytop = pitchval;
-      thechord->ybot = pitchval;
-    } else {
-      if (pitchval > thechord->ytop) {
-        thechord->ytop = pitchval;
-      };
-      if (pitchval < thechord->ybot) {
-        thechord->ybot = pitchval;
-      };
-    };
-    cv->chordcount = cv->chordcount + 1;
-  };
-  if ((!cv->ingrace) && 
-      (!cv->inchord || (cv->chordcount == 1))) {
-    if (cv->tuplenotes == 0) {
-      addunits(&cv->barcount, n, m);
-    } else {
-      addunits(&cv->barcount, n*cv->tuplefactor.num, m*cv->tuplefactor.denom);
-      if (nt->base_exp > -3) {
-        cv->thistuple->beamed = 0;
-      };
-      cv->tuplenotes = cv->tuplenotes - 1;
-      if (cv->tuplenotes == 0) {
-        cv->thistuple = NULL;
-        /* prevent beaming from tuple to non-tuple notes */
-        addfeature(NOBEAM, NULL);
-      };
-    };
-  };
-}
-
-/* these functions are here to satisfy the linker */
-void event_microtone(int dir, int a, int b)
-{
-}
-
-void event_normal_tone()
-{
-}
-
-
-
-void event_info_key(key, value)
-char* key;
-char* value;
-/* handles a (key,value) pair found in an I: field */
-{
-  int num;
-
-  if (strcmp(key, "clef")==0) {
-    event_clef(value);
-  };
-  if (strcmp(key, "octave")==0) {
-    num = readsnumf(value);
-    event_octave(num,0);
-  };
-}
-
-
-int main(argc,argv)
-int argc;
-char *argv[];
-{
-  char *filename;
-  int i;
-
-  oldchordconvention = 0;
-  for (i=0;i<DECSIZE;i++) decorators_passback[i]=0;
-
-  event_init(argc, argv, &filename);
-  if (argc < 2) {
-    /* printf("argc = %d\n", argc); */
-  } else {
-    init_abbreviations();
-    parsefile(filename);
-    free_abbreviations();
-  };
-  return(0);
-}
-
+/*
+ * yaps - program to convert abc files to PostScript.
+ * Copyright (C) 1999 James Allwright
+ * e-mail: J.R.Allwright@westminster.ac.uk
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/* yapstree.c - back-end for abc parser. */
+/* generates a data structure suitable for typeset music */
+
+#define VERSION "1.49 December 21 2006"
+#include <stdio.h>
+#ifdef USE_INDEX
+#define strchr index
+#endif
+
+/* for Microsoft VC 6++ or higher */
+#ifdef _MSC_VER
+#define ANSILIBS
+#endif
+
+#if defined(ANSILIBS) || defined(__STDC__)
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#else
+char* strchr();
+#endif
+#include "abc.h"
+#include "parseabc.h"
+#include "parser2.h"
+#include "structs.h"
+#include "drawtune.h"
+
+extern void setscaling(char *s);
+extern void font_command();
+extern void setup_fonts();
+extern void printtune(struct tune *t);
+extern void set_keysig(struct key *k, struct key *newval);
+
+programname fileprogram = YAPS;
+extern int oldchordconvention; /* for handling +..+ chords */
+
+struct voice* cv;
+struct tune thetune;
+
+char outputname[256];
+char outputroot[256];
+char matchstring[256];
+int fileopen;
+
+int repcheck;
+int xinhead;
+int xinbody;
+int suppress;
+int debugging;
+int pagenumbering;
+int separate_voices;
+int print_xref;
+int landscape;
+int barnums,nnbars;
+extern int gchords_above;
+extern int decorators_passback[DECSIZE]; /* a kludge for passing
+information from the event_handle_instruction to parsenote
+in parseabc.c */
+
+enum linestattype {fresh, midmusic, endmusicline, postfield};
+enum linestattype linestat;
+ 
+int dummydecorator[DECSIZE]; /* used in event_chord */
+
+void setfract(f, a, b)
+struct fract* f;
+int a, b;
+/* assign value to fraction */
+{
+  f->num = a;
+  f->denom = b;
+}
+
+void reducef(f)
+struct fract* f;
+/* reducef fraction to smallest terms */
+{
+  int t, n, m;
+
+  /* find HCF using Euclid's algorithm */
+  if (f->num > f->denom) {
+    n = f->num;
+    m = f->denom;
+  } else {
+    n = f->denom;
+    m = f->num;
+  };
+  while (m != 0) {
+    t = n % m;
+    n = m;
+    m = t;
+  };
+  f->num = f->num/n;
+  f->denom = f->denom/n;
+}
+
+static struct fract* newfract(int a, int b)
+/* create an initialized fraction */
+{
+  struct fract* f;
+
+  f = (struct fract*)checkmalloc(sizeof(struct fract));
+  f->num = a;
+  f->denom = b;
+  return(f);
+}
+
+static struct slurtie* newslurtie()
+/* create a new slur/tie data structure */
+{
+  struct slurtie* f;
+
+  f = (struct slurtie*)checkmalloc(sizeof(struct slurtie));
+  f->begin = NULL;
+  f->end = NULL;
+  f->crossline = 0;
+  return(f);
+}
+
+static struct atempo* newtempo(int count, int n, int m, int relative,
+                               char *pre, char *post)
+/* create an initialized tempo data structure */
+{
+  struct atempo* t;
+
+  t = (struct atempo*)checkmalloc(sizeof(struct atempo));
+  t->count = count;
+  t->basenote.num = n;
+  t->basenote.denom = m;
+  t->relative = relative;
+  if (pre == NULL) {
+    t->pre = NULL;
+  } else {
+    t->pre = addstring(pre);
+  };
+  if (post == NULL) {
+    t->post = NULL;
+  } else {
+    t->post = addstring(post);
+  };
+  return(t);
+}
+
+static struct vertspacing* newvertspacing()
+/* create new vertspacing structure */
+{
+  struct vertspacing* p;
+
+  p = (struct vertspacing*)checkmalloc(sizeof(struct vertspacing));
+  p->height = 0.0;
+  p->descender = 0.0;
+  p->yend = 0.0;
+  p->yinstruct = 0.0;
+  p->ygchord = 0.0;
+  p->ywords = 0.0;
+  return(p);
+}
+
+static struct tuple* newtuple(int n, int q, int r, int label)
+/* create tuple data structure */
+{
+  struct tuple* f;
+
+  f = (struct tuple*)checkmalloc(sizeof(struct tuple));
+  f->n = n;
+  f->q = q;
+  f->r = r;
+  f->label = label;
+  f->beamed = 1;
+  return(f);
+}
+
+static struct chord* newchord()
+/* create chord data structure */
+{
+  struct chord* f;
+
+  f = (struct chord*)checkmalloc(sizeof(struct chord));
+  f->ytop = 0;
+  f->ybot = 0;
+  return(f);
+}
+
+struct aclef* newclef(enum cleftype t, int octave)
+/* create and initialize clef data structure */
+{
+  struct aclef* f;
+
+  f = (struct aclef*)checkmalloc(sizeof(struct aclef));
+  f->type = t;
+  f->octave = octave;
+  return(f);
+}
+
+struct key* newkey(char* name, int sharps, char accidental[], int mult[])
+/* create and initialize key signature */
+{
+  struct key* k;
+  int i;
+
+  k = (struct key*)checkmalloc(sizeof(struct key));
+  k->name = addstring(name);
+  k->sharps = sharps;
+  for (i=0; i<7; i++) {
+    k->map[i] = accidental[i];
+    k->mult[i] = mult[i];
+  };
+  return(k);
+}
+
+void init_llist(struct llist* l)
+/* initialize a linked list */
+{
+  l->first = NULL;
+  l->last = NULL;
+  l->place = NULL;
+}
+
+void addtolist(struct llist* p, void* item)
+/* append an item to a linked list */
+{
+  struct el* x;
+
+  x = (struct el*)checkmalloc(sizeof(struct el));
+  x->next = NULL;
+  x->datum = item;
+  if (p->first == NULL) {
+    p->first = x;
+    p->last = x;
+  } else {
+    p->last->next = x;
+    p->last = x;
+  };
+}
+
+void* firstitem(struct llist* p)
+/* find the first item in the list */
+/* also initialize for a traversal using nextitem() */
+{
+  if (p == NULL) {
+    return(NULL);
+  };
+  p->place = p->first;
+  if (p->place == NULL) {
+    return(NULL);
+  } else {
+    return(p->place->datum);
+  };
+}
+
+void* nextitem(struct llist* p)
+/* return 'next' item in the list. Successive calls return successive    */
+/* items or NULL after the end of the list has been reached. firstitem() */
+/* must be called prior to the first call to nextitem()                  */
+{
+  if (p->place == NULL) {
+    return(NULL);
+  } else {
+    p->place = p->place->next;
+    if (p->place == NULL) {
+      return(NULL);
+    } else {
+      return(p->place->datum);
+    };
+  };
+}
+
+void freellist(struct llist* l)
+/* frees up all dynamically allocated memory used to build the linked list */
+{
+  void* p;
+  struct el* e;
+  struct el* olde;
+
+  /* printf("freellist\n"); */
+  if (l != NULL) {
+    p = firstitem(l);
+    while (p != NULL) {
+      free(p);
+      p = nextitem(l);
+    };
+    e = l->first;
+    while (e != NULL) {
+      olde = e;
+      e = e->next;
+      free(olde);
+    };
+    init_llist(l);
+  };
+}
+
+static void closebeam(struct voice* v)
+/* called after a run of notes to be beamed together */
+{
+  struct note* n;
+  struct feature* ft;
+  int stemup;
+  int ingrace;
+
+  if (cv->tuplenotes > 0) {
+    cv->thistuple->beamed = 0;
+  };
+  if (v->beamroot == v->beamend) {
+    ft = v->beamroot;
+    n = ft->item;
+    n->beaming = single;
+    v->beamroot = NULL;
+    return;
+  }; 
+  if (v->beammax + v->beammin > 2*4) {
+    stemup = 0;
+  } else {
+    stemup = 1;
+  };
+  ft = v->beamroot;
+  ingrace = 0;
+  while ((ft != NULL) && (ft != v->beamend)) {
+    switch (ft->type) {
+    case NOTE:
+      if (ingrace == 0) {
+        n = ft->item;
+        n->stemup = stemup;
+      };
+      break;
+    case GRACEON:
+      ingrace = 1;
+      break;
+    case GRACEOFF:
+      ingrace = 0;
+      break;
+    default:
+      break;
+    };
+    ft = ft->next;
+  };
+  if (ft == v->beamend) {
+    n = ft->item;
+    n->stemup = stemup;
+    n->beaming = endbeam;
+  } else {
+    printf("closebeam: internal data error\n");
+    exit(1);
+  };
+  v->beamroot = NULL;
+}
+
+static void closegracebeam(struct voice* v)
+/* called after a run of grace notes to be beamed together */
+{
+  struct note* n;
+  struct feature* ft;
+
+  ft = v->gracebeamend;
+  if (ft == NULL) {
+    event_error("Missing grace notes");
+  } else {
+    n = ft->item;
+    if (v->gracebeamroot == v->gracebeamend) {
+      n->beaming = single;
+    } else {
+      n->beaming = endbeam;
+    }; 
+  };
+}
+
+static void insertnote(struct feature* chordplace, struct feature* newfeature)
+/* place NOTE in decreasing pitch order within chord */
+{
+  struct note* n;
+  struct note* newnote;
+  struct feature* f;
+  struct feature* previous;
+  int foundplace;
+
+  newnote = newfeature->item;
+  previous = chordplace;
+  f = chordplace->next;
+  foundplace = 0;
+  n = NULL;
+  while ((f != NULL)&&(f->type==NOTE)&&(foundplace == 0)) {
+    n = f->item;
+    if (newnote->y > n->y) {
+      foundplace = 1;
+    } else {
+      previous = f;
+      f = f->next;
+    };
+  };
+  /* printvoiceline in drawtune.c expects the gchord or
+   * instructions to be associated with the first note in
+   * chord. If the notes are reordered then we need
+   * to move these fields.
+   * if previous == chordplace then move n->gchords and
+   * n->instructions to newnote->gchords and newnote->instructions
+   */
+  if (previous == chordplace && n != NULL) {
+	  newnote->gchords = n->gchords;
+	  newnote->instructions = n->instructions;
+	  n->gchords = NULL;
+	  n->instructions = NULL;
+  }
+  newfeature->next = previous->next;
+  previous->next = newfeature;
+  if (newfeature->next == NULL) {
+    cv->last = newfeature;
+  };
+}
+
+static void beamitem(featuretype mytype, void* newitem, struct feature* x)
+/* This routine is responsible for working out which notes are to be */
+/* beamed together and recording this in the note structure record */
+{
+  struct note* n;
+
+  /* deal with beaming here */
+  if (cv->ingrace) {
+    if (mytype == NOTE) {
+      n = newitem;
+      n->stemup = 1;
+      if (cv->gracebeamroot == NULL) {
+        cv->gracebeamroot = x;
+        cv->gracebeamend = x;
+        n->beaming = startbeam;
+      } else {
+        cv->gracebeamend = x;
+        n->beaming = midbeam;
+      };
+    };
+  } else {
+    if (cv->beamroot != NULL) {
+      switch (mytype) {
+      case NOTE:
+        n = newitem;
+        if (n->base_exp >= -2) {
+          n->beaming = single;
+          closebeam(cv);
+        } else {
+          /* extend beam */
+          if (n->y > cv->beammax) {
+            cv->beammax = n->y;
+          };
+          if (n->y < cv->beammin) {
+            cv->beammin = n->y;
+          };
+          cv->beamend = x;
+          n->beaming = midbeam;
+        };
+        break;
+      case KEY:
+      case REST:
+      case NOBEAM:
+      case SINGLE_BAR:
+      case DOUBLE_BAR:
+      case BAR_REP:
+      case REP_BAR:
+      case BAR1:
+      case REP_BAR2:
+      case DOUBLE_REP:
+      case THICK_THIN:
+      case THIN_THICK:
+      case TUPLE:
+      case MUSICSTOP:
+        /* closebeam */
+        closebeam(cv);
+        break;
+      default:
+        break;
+      };
+    } else {
+      if (mytype == NOTE) {
+        n = newitem;
+        if (n->base_exp >= -2) {
+          n->beaming = single;
+        } else {
+          n->beaming = startbeam;
+          cv->beammax = n->y;
+          cv->beammin = n->y;
+          cv->beamroot = x;
+          cv->beamend = x;
+        };
+      };
+    };
+  };
+}
+
+static struct feature* addfeature(featuretype mytype, void* newitem)
+/* append a new data element to the linked list for the current voice */
+/* The element can be a note or lots of other things */
+{
+  struct voice* p;
+  struct feature* x;
+
+  p = cv;
+  /* printf("in addfeature type=%d\n", mytype); */
+  if (cv == NULL) {
+    printf("ERROR: no current voice in addfeature type=%d\n", mytype);
+    printf("xinhead = %d xinbody = %d\n", xinhead, xinbody);
+    exit(0);
+  };
+  x = (struct feature*)checkmalloc(sizeof(struct feature));
+  x->next = NULL;
+  x->type = mytype;
+  x->item = newitem;
+  x->xleft = 0;
+  x->xright = 0;
+  x->yup = 0;
+  x->ydown = 0;
+  if (cv->first == NULL) {
+    cv->first = x;
+    cv->last = x;
+    beamitem(mytype, newitem, x);
+  } else {
+    if ((cv->last == NULL)||(cv->last->next != NULL)) {
+      printf("expecting NULL at list end!\n");
+      exit(0);
+    };
+    if ((cv->inchord)&&(mytype==NOTE)) {
+      insertnote(cv->chordplace, x);
+    } else {
+      cv->last->next = x;
+      cv->last = x;
+      beamitem(mytype, newitem, x);
+    };
+  };
+  return(x);
+}
+
+struct llist* newlist()
+/* create and initialize a new linked list */
+{
+  struct llist* l;
+
+  l = (struct llist*)checkmalloc(sizeof(struct llist));
+  init_llist(l);
+  return(l);
+}
+
+static int notenum(int octave, char ch, enum cleftype clef, int clefoctave)
+/* converts note to number for stave position */
+/* note E is zero (bottom line of stave) */
+{
+  int n;
+
+  n = 5 + (7 + ch -'c')%7 + 7*(octave-1);
+  switch (clef) {
+  default:
+    event_error("unknown clef type");
+  case treble:
+    break;
+  case soprano:
+    n = n + 2;
+    break;
+  case mezzo:
+    n = n + 4;
+    break;
+  case alto:
+    n = n + 6;
+    break;
+  case tenor:
+    n = n + 8;
+    break;
+  case baritone:
+    n = n + 10;
+    break;
+  case bass:
+    n = n + 12;
+    break;
+  };
+  switch (clefoctave) {
+  case -22:
+    n = n + 21;
+    break;
+  case -15:
+    n = n + 14;
+    break;
+  case -8:
+    n = n + 7;
+    break;
+  case 8:
+    n = n - 7;
+    break;
+  case 15:
+    n = n - 14;
+    break;
+  case 22:
+    n = n - 21;
+    break;
+  default:
+    break;
+  };
+  return(n);
+}
+
+int count_dots(int *base, int *base_exp, int n, int m)
+/* convert fraction to 2^base_exp followed by dots */
+/* previously used 1/base instead of 2^base_exp */
+/* -1 indicates a note value which is impossible to represent */
+{
+  int dots;
+  int start;
+  int a, b;
+
+  *base = 1; /* set default value if we fail */
+  *base_exp = 0;
+  if ((n<1)||(m<1)) {
+    return(-1);
+  };
+  /* check denominator is power of 2 */
+  a = m;
+  while (a>1) {
+    if (a%2 == 1) {
+      return(-1);
+    };
+    a = a/2;
+  };
+  dots = 0;
+  start = m;
+  while (start < n) {
+    start = start*2;
+    *base_exp = *base_exp + 1;
+  };
+  while (start > n) {
+    start = start/2;
+    *base_exp = *base_exp - 1;
+  };
+  if (start == 0) {
+    printf("Problem with %d / %d\n", n, m);
+    exit(0);
+  };
+  *base = m/start;
+  a = n - start;
+  b = start;
+  while (a>0) {
+    dots = dots + 1; 
+    b = b/2;
+    a = a - b;
+    if (a< 0) {
+      return(-1);
+    };
+  };
+  return(dots);
+}
+
+static char* decstring(int decorators[])
+/* creates a string of decorators (ornament, staccato, roll, up-bow etc.) */
+/* from a boolean array */
+{
+  int i, j;
+  char decs[DECSIZE+1];
+
+  j = 0;
+  for (i=0; i<DECSIZE; i++) {
+    if (decorators[i]) {
+      decs[j] = decorations[i];
+      j = j + 1;
+    };
+  };
+  decs[j] = '\0';
+  if (j==0) {
+    return(NULL);
+  } else {
+    return(addstring(decs));
+  };
+}
+
+static struct note* newnote(decorators, xaccidental, xmult, xnote, xoctave, 
+                            a, b)
+int decorators[DECSIZE];
+int xmult;
+char xaccidental, xnote;
+int xoctave;
+int a, b;
+/* create and set up the fields for a note structure */
+{
+  struct note* n;
+
+  n = (struct note*)checkmalloc(sizeof(struct note));
+  setfract(&n->len, a, b);
+  reducef(&n->len);
+  n->dots = count_dots(&n->base, &n->base_exp, n->len.num, n->len.denom);
+/*
+  if (n->dots == -1) {
+    event_error("Illegal note length");
+  };
+*/
+  n->accents = decstring(decorators);
+  n->accidental = xaccidental;
+  n->acc_offset = 0;
+  n->fliphead = 0;
+  n->mult = xmult; 
+  n->octave = xoctave;
+  n->pitch = xnote;
+  n->y = notenum(xoctave, xnote, cv->clef->type, cv->clef->octave);
+  if (n->y < 4) {
+    n->stemup = 1;
+  } else {
+    n->stemup = 0;
+  };
+  n->stemlength = 0.0;
+  n->syllables = NULL;
+  if (cv->ingrace) {
+    n->gchords = NULL;
+    n->instructions = NULL;
+  } else {
+    n->gchords = cv->gchords_pending;
+    cv->gchords_pending = NULL;
+    n->instructions = cv->instructions_pending;
+    cv->instructions_pending = NULL;
+  };
+  return(n);
+}
+
+static struct rest* newrest(int a, int b, int multi)
+/* create and set up a new rest structure */
+{
+  struct rest* n;
+
+  n = (struct rest*)checkmalloc(sizeof(struct rest));
+  setfract(&n->len, a, b);
+  n->dots = count_dots(&n->base, &n->base_exp, a, b);
+  if (n->dots == -1) {
+    event_error("Illegal rest length");
+  };
+  n->multibar = multi;
+  if (cv->ingrace) {
+    n->gchords = NULL;
+    n->instructions = NULL;
+  } else {
+    n->gchords = cv->gchords_pending;
+    cv->gchords_pending = NULL;
+    n->instructions = cv->instructions_pending;
+    cv->instructions_pending = NULL;
+  };
+  return(n);
+}
+
+static void addunits(f, n, m)
+struct fract* f;
+int n, m;
+/* add n/m to fraction pointed to by f */
+{
+  f->num = n*f->denom*(cv->unitlen.num) + f->num*(m*cv->unitlen.denom);
+  f->denom = (m*cv->unitlen.denom)*f->denom;
+  reducef(f);
+}
+
+static void addfractions(f,n,m)
+struct fract* f;
+int n,m;
+{
+  f->num = n*f->denom + f->num*m;
+  f->denom = m*f->denom;
+  reducef(f);
+}
+
+
+
+static struct voice* newvoice(int n)
+/* create and set up a new voice data structure */
+{
+  struct voice* v;
+
+  v = (struct voice*)checkmalloc(sizeof(struct voice));
+  v->first = NULL;
+  v->last = NULL;
+  v->voiceno = n;
+  v->octaveshift = thetune.octaveshift;
+  setfract(&v->unitlen, thetune.unitlen.num, thetune.unitlen.denom);
+  v->changetime = 0;
+  v->inslur = 0;
+  v->ingrace = 0;
+  v->inchord = 0;
+  v->expect_repeat = 0;
+  v->tuplenotes = 0;
+  v->thistuple = NULL;
+  v->tuple_count = 0;
+  v->brokenpending = -1;
+  v->tiespending = 0;
+  v->slurpending = 0;
+  v->slurcount = 0;
+  v->barno = 0;
+  v->barchecking = thetune.barchecking;
+  setfract(&v->barlen, thetune.meter.num, thetune.meter.denom);
+  v->clef = newclef(thetune.clef.type, thetune.clef.octave);
+  if (thetune.keysig == NULL) {
+    printf("Trying to set up voice with no key signature\n");
+    exit(0);
+  } else {
+    v->keysig = newkey(thetune.keysig->name, thetune.keysig->sharps,
+                       thetune.keysig->map, thetune.keysig->mult);
+  };
+  v->tempo = NULL;
+  setfract(&v->barcount, 0, 1);
+  setfract(&v->meter, thetune.meter.num, thetune.meter.denom);
+  v->lastnote = NULL;
+  v->laststart = NULL;
+  v->lastend = NULL;
+  v->line = header;
+  v->thisstart = NULL;
+  v->thisend = NULL;
+  v->gchords_pending = NULL;
+  v->instructions_pending = NULL;
+  v->beamed_tuple_pending = 0;
+  v->linestart = NULL;
+  v->lineend = NULL;
+  v->more_lyrics = 0;
+  v->lyric_errors = 0;
+  v->thischord = NULL;
+  v->chordplace = NULL;
+  v->beamroot = NULL;
+  v->beamend = NULL;
+  v->gracebeamroot = NULL;
+  v->gracebeamend = NULL;
+  return(v);
+}
+
+static void setvoice(int n)
+/* set current voice to voice n. If voice n does not exist, create it */
+{
+  struct voice* v;
+  struct el* l;
+  int done;
+
+  if (thetune.voices.first == NULL) {
+    cv = newvoice(n);
+    v = cv;
+    addtolist(&thetune.voices, (void*)v);
+  } else {
+    l = thetune.voices.first;
+    done = 0;
+    while ((done == 0) && (l != NULL)) {
+      if (((struct voice*)l->datum)->voiceno == n) {
+        done = 1;
+        cv = (struct voice*)l->datum;
+      } else {
+       l = l->next;
+      };
+    };
+    if (done == 0) {
+      cv = newvoice(n);
+      v = cv;
+      addtolist(&thetune.voices, (void*)v);
+    };
+  };
+}
+
+static void init_tune(struct tune* t, int x) 
+/* initialize tune structure */
+{
+  t->no = x;
+  t->octaveshift = 0;
+  init_llist(&t->title);
+  t->composer = NULL;
+  t->origin = NULL;
+  t->parts = NULL;
+  init_llist(&t->notes);
+  init_llist(&t->voices);
+  setfract(&t->meter, 0, 1);
+  setfract(&t->unitlen, 0, 1);
+  t->cv = NULL;
+  t->keysig = NULL;
+  t->clef.type = treble;
+  t->clef.octave = 0;
+  t->tempo = NULL;
+  init_llist(&t->words);
+};
+
+static void freekey(struct key* k)
+/* free up memory allocated for key data structure */
+{
+  if (k != NULL) { 
+    if (k->name != NULL) {
+      free(k->name);
+    };
+    free(k);
+  };
+}
+
+static void freetempo(struct atempo *t)
+/* free up memory allocated for temp data structure */
+{
+  if (t->pre != NULL) {
+    free(t->pre);
+  };
+  if (t->post != NULL) {
+    free(t->post);
+  };
+}
+
+static void freefeature(void* item, featuretype type)
+/* free memory allocated for feature in voice */
+{
+  struct note *n;
+  struct rest *r;
+
+  switch(type) {
+  case NOTE:
+    n = item;
+    if (n->accents != NULL) {
+      free(n->accents);
+    };
+    if (n->syllables != NULL) {
+      freellist(n->syllables);
+      free(n->syllables);
+    };
+    if (n->gchords != NULL) {
+      freellist(n->gchords);
+      free(n->gchords);
+    };
+    if (n->instructions != NULL) {
+      freellist(n->instructions);
+      free(n->instructions);
+    };
+    free(n);
+    break;
+  case REST:
+    r = item;
+    if (r->gchords != NULL) {
+      freellist(r->gchords);
+      free(r->gchords);
+    };
+    if (r->instructions != NULL) {
+      freellist(r->instructions);
+      free(r->instructions);
+    };
+    free(r);
+    break;
+  case KEY:
+    freekey(item);
+    break;
+  case TEMPO:
+    freetempo(item);
+    break;
+  case CLEF:
+  case TIME:
+  case PART:
+  case CHORDON:
+  case TUPLE:
+  case SLUR_ON:
+  case TIE:
+  case PLAY_ON_REP:
+  case LEFT_TEXT:
+  case PRINTLINE:
+    if (item != NULL) {
+      free(item);
+    };
+    break;
+  default:
+    break;
+  };
+}
+
+static void freevoice(struct voice* v)
+/* free up memory allocated for voice data structure and voice data */
+{
+  struct feature* ft;
+  struct feature* oldft;
+
+  ft = v->first;
+  while (ft != NULL) {
+    freefeature(ft->item, ft->type);
+    oldft = ft;
+    ft = ft->next;
+    free(oldft);
+  };
+  if (v->keysig != NULL) {
+    freekey(v->keysig);
+    v->keysig = NULL;
+  };
+  if (v->tempo != NULL) {
+    freetempo(v->tempo);
+    v->tempo = NULL;
+  };
+  if (v->clef != NULL) {
+    free(v->clef);
+  };
+  v->clef = NULL;
+}
+
+static void freetune(struct tune* t)
+/* free up all dynamically allocated memory associated with tune */
+{
+  struct voice* v;
+
+  if (t->composer != NULL) {
+    free(t->composer);
+    t->composer = NULL;
+  };
+  if (t->origin != NULL) {
+    free(t->origin);
+    t->origin = NULL;
+  };
+  if (t->parts != NULL) {
+    free(t->parts);
+    t->parts = NULL;
+  };
+  freellist(&t->title);
+  freellist(&t->notes);
+  if (t->keysig != NULL) {
+    freekey(t->keysig);
+    t->keysig = NULL;
+  };
+  if (t->tempo != NULL) {
+    freetempo(t->tempo);
+    t->tempo = NULL;
+  };
+  v = firstitem(&t->voices);
+  while (v != NULL) {
+    freevoice(v);
+    v = nextitem(&t->voices);
+  };
+  freellist(&t->voices);
+  freellist(&t->words);
+}
+
+static int checkmatch(int refno)
+/* compares current reference number against list of numbers */
+/* following -e argument */
+/* returns 1 if tune has been selected and 0 otherwise */
+{
+  int select;
+  int n1, n2;
+  char* place;
+
+  place = matchstring;
+  if (strlen(matchstring)==0) {
+    select = 1;
+  } else {
+    select = 0;
+    while ((select==0)&&(*place >= '0')&&(*place <='9')) {
+      n1 = readnump(&place);
+      if (n1 == refno) {
+        select = 1;
+      } else {
+        if (*place == ',') {
+          place = place+1;
+        } else {
+          if (*place == '-') {
+            place = place+1;
+            n2 = readnump(&place);
+            if ((refno >= n1)&&(refno <= n2)) {
+              select = 1;
+            } else {
+              if (*place == ',') {
+                place = place+1;
+              };
+            };
+          };
+        };
+      };
+    };
+    if ((select==0)&&(*place != '\0')) {
+      event_warning("Number list after -e not fully parsed");
+    };
+  };    
+  return(select);
+}
+
+void event_init(argc, argv, filename)
+int argc;
+char* argv[];
+char** filename;
+/* initialization routine - called once at the start of the program */
+/* interprets the parameters in argv */
+{
+  char* place;
+  int filearg;
+  int refmatch;
+  int papsize, margins, newscale;
+  int ier;
+  int j;
+
+  if (getarg("-ver",argc, argv) != -1) {
+	  printf("%s\n",VERSION);
+	  exit(0);
+  }
+  if (getarg("-d", argc, argv) != -1) {
+    debugging = 1;
+  } else {
+    debugging = 0;
+  };
+  if (getarg("-E", argc, argv) != -1) {
+    eps_out = 1;
+  } else {
+    eps_out = 0;
+  };
+  if (getarg("-OCC",argc,argv) != -1) oldchordconvention=1;
+  if (getarg("-V", argc, argv) != -1) {
+    separate_voices = 1;
+  } else {
+    separate_voices = 0;
+  };
+  if (getarg("-x", argc, argv) != -1) {
+    print_xref = 1;
+  } else {
+    print_xref = 0;
+  };
+  if (getarg("-N", argc, argv) != -1) {
+    pagenumbering = 1;
+  } else {
+    pagenumbering = 0;
+  };
+  if (getarg("-l", argc, argv) != -1) {
+    landscape = 1;
+  } else {
+    landscape = 0;
+  };
+  newscale = getarg("-s", argc, argv);
+  if ((newscale != -1) && (argc >= newscale)) {
+    setscaling(argv[newscale]);
+  } else {
+    setscaling("");
+  };
+  margins = getarg("-M", argc, argv);
+  if ((margins != -1) && (argc >= margins)) {
+    setmargins(argv[margins]);
+  } else {
+    setmargins("");
+  };
+  papsize = getarg("-P", argc, argv);
+  if ((papsize != -1) && (argc >= papsize)) {
+    setpagesize(argv[papsize]);
+  } else {
+    setpagesize("");
+  };
+  barnums = getarg("-k",argc,argv);
+  ier = 0;
+  if ((barnums != -1) && (argc > barnums)) ier = sscanf(argv[barnums],"%d",&nnbars);
+  if ((barnums != -1) && (ier <1)) nnbars = 1;
+
+  refmatch = getarg("-e", argc, argv);
+  if (refmatch == -1) {
+    *matchstring = '\0';
+  } else {
+    if (strlen(argv[refmatch]) < 255) {
+      strcpy(matchstring, argv[refmatch]);
+    } else {
+      event_error("Exceeded character limit for -e string");
+      exit(1);
+    };
+  };
+  if ((getarg("-h", argc, argv) != -1) || (argc < 2)) {
+    printf("yaps version %s\n",VERSION);
+    printf("Usage:  yaps <abc file> [<options>]\n");
+    printf("  possible options are -\n");
+    printf("  -ver          :prints version number and exits\n");
+    printf("  -d            : debug - display data structure\n");
+    printf("  -e <list>     : draw tunes with reference numbers in list\n");
+    printf("     list is comma-separated and may contain ranges\n");
+    printf("     but no spaces e.g. 1,3,7-20\n");
+    printf("  -E            : generate Encapsulated PostScript\n");
+    printf("  -l            : landscape mode\n");
+    printf("  -M XXXxYYY    : set margin sizes in points\n");
+    printf("     28.3 points = 1cm, 72 points = 1 inch\n");
+    printf("  -N            : add page numbering\n");
+    printf("  -k [nn]       : number every nn bars\n");
+    printf("  -o <filename> : specify output file\n");
+    printf("  -P ss         : paper size; 0 is A4, 1 is US Letter\n");
+    printf("     or XXXxYYY to set size in points\n");
+    printf("  -s XX         : scaling factor (default is 0.7)\n");
+    printf("  -V            : separate voices in multi-voice tune\n");
+    printf("  -x            : print tune number in X: field\n");
+    printf("  -OCC          : old chord convention (eg. +CE+)\n");
+    printf("Takes an abc music file and converts it to PostScript.\n");
+    printf("If no output filename is given, then by default it is\n");
+    printf("the input filename but with extension .ps .\n");
+    exit(0);
+  } else {
+    *filename = argv[1];
+  };
+  fileopen = 0;
+  filearg = getarg("-o", argc, argv);
+  if (filearg != -1) { 
+    /*strcpy(outputname, argv[filearg]); security risk buffer overflow */
+    strncpy(outputname, argv[filearg],256);
+  } else {
+    /* strcpy(outputname, argv[1]); security risk: buffer overflow */
+    strncpy(outputname, argv[1],256);
+    place = strchr(outputname, '.');
+    if (place == NULL) {
+      strcat(outputname, ".ps");
+    } else {
+      strcpy(place, ".ps");
+    };
+    if (strcmp(argv[1], outputname)==0) {
+      printf("argument must be abc file, not PostScript file\n");
+      exit(1);
+    };
+  };
+  /* create filename root for EPS output */
+  strcpy(outputroot, outputname);
+  place = strchr(outputroot, '.');
+  if (place != NULL) {
+    *place = '\0';
+  };
+  xinbody =0;
+  xinhead = 0;
+  suppress = 0;
+  init_tune(&thetune, -1);
+  setup_fonts();
+  /* open_output_file(outputname); */
+  for (j=0;j<DECSIZE;j++)  dummydecorator[j] = 0;
+}
+
+static void check_voice_end(struct voice* v)
+/* make sure there are no unfinished structures */
+{
+  if (v->inchord) {
+    event_error("incomplete chord at end of voice");
+    v->inchord = 0;
+  };
+  if (v->brokenpending != -1) {
+    event_error("incomplete broken rhythm at end of voice");
+    v->brokenpending = -1;
+  };
+  if ((v->slurcount > 0)||(v->slurpending)) {
+    event_error("incomplete slur at end of voice");
+    v->slurcount = 0;
+    v->slurpending = 0;
+  };
+  if (v->tiespending) {
+    event_error("incomplete ties at end of voice");
+    v->tiespending = 0;
+  };
+  if (v->gchords_pending != NULL) {
+    freellist(v->gchords_pending);
+    free(v->gchords_pending);
+    v->gchords_pending = NULL;
+  };
+  if (v->instructions_pending != NULL) {
+    freellist(v->instructions_pending);
+    free(v->instructions_pending);
+    v->instructions_pending = NULL;
+  };
+  if (v->tuplenotes > 0) {
+    event_error("incomplete tuple at end of voice");
+    v->tuplenotes = 0;
+  };
+}
+
+static void check_tune_end(struct tune* t)
+/* check that all voices have been completed properly */
+{
+  struct voice* v;
+
+  v = firstitem(&t->voices);
+  while (v != NULL) {
+    check_voice_end(v);
+    v = nextitem(&t->voices);
+  };
+}
+
+void event_eof()
+/* end of input file has been encountered */
+{
+  if (xinbody) {
+    check_tune_end(&thetune);
+    printtune(&thetune);
+  };
+  freetune(&thetune);
+  close_output_file();
+}
+
+void event_blankline()
+/* A blank line has been encountered */
+{
+  if (xinbody) {
+    check_tune_end(&thetune);
+    printtune(&thetune);
+  };
+  freetune(&thetune);
+  xinbody = 0;
+  xinhead = 0;
+  suppress = 0;
+  parseroff();
+}
+
+void event_text(p)
+/* Text outside an abc tune has been encountered */
+char *p;
+{
+}
+
+void event_x_reserved(p)
+char p;
+{
+}
+
+void event_abbreviation(symbol, string, container)
+/* abbreviation declaratiion - handled by parser. Ignore it here */
+char symbol;
+char *string;
+char container;
+{
+}
+
+void event_acciaccatura()
+{
+/* does nothing but outputs a / in toabc.c */
+return;
+}
+
+void event_split_voice()
+{
+addfeature(SPLITVOICE, (void*) lineno);
+event_error("voice split not implemented in yaps");
+}
+
+void event_tex(s)
+char *s;
+/* A TeX command has been found in the abc */
+{
+}
+
+void event_linebreak()
+/* A linebreak has been encountered */
+{
+  if (xinbody) {
+    addfeature(LINENUM, (void*)lineno);
+  };
+}
+
+static void tidy_ties()
+/* create CLOSE_TIE features for ties straddling two lines of music */
+/* CLOSE_TIE appears in the new music line */
+{
+  struct feature* ft;
+  struct slurtie* s;
+  int i;
+
+  for (i=0; i<cv->tiespending; i++) {
+    ft = cv->tie_place[i]; /* pointer to TIE feature */
+    s = ft->item;
+    addfeature(CLOSE_TIE, s);
+  };
+}
+
+void event_startmusicline()
+/* We are at the start of a line of abc notes */
+{
+  cv->linestart = addfeature(MUSICLINE, (void*)NULL);
+  if (cv->more_lyrics != 0) {
+    event_error("Missing continuation w: field");
+    cv->more_lyrics = 0;
+  };
+  if ((cv->line == header) || (cv->line == newline)) {
+    addfeature(CLEF, newclef(cv->clef->type, cv->clef->octave));
+    addfeature(KEY, newkey(cv->keysig->name, cv->keysig->sharps,
+                           cv->keysig->map, cv->keysig->mult));
+    if ((cv->line == header)||(cv->changetime)) {
+      addfeature(TIME, newfract(cv->meter.num, cv->meter.denom));
+      cv->changetime = 0;
+    };
+    cv->line = midline;
+    tidy_ties();
+  };
+  cv->lineend = NULL;
+}
+
+static void divide_ties()
+/* mark unresolved ties and slurs as straddling two lines of music */
+{
+  struct feature* ft;
+  struct slurtie* s;
+  int i;
+
+  for (i=0; i<cv->tiespending; i++) {
+    ft = cv->tie_place[i]; /* pointer to TIE feature */
+    s = ft->item;
+    s->crossline = 1;
+  };
+  for (i=0; i<cv->slurcount; i++) {
+    s = cv->slur_place[i];
+    s->crossline = 1;
+  };
+}
+
+void event_endmusicline(endchar)
+char endchar;
+/* We are at the end of a line of abc notes */
+{
+  cv->lineend = addfeature(MUSICSTOP, (void*)NULL);
+  if ((endchar == ' ') || (endchar == '!')) {
+    addfeature(PRINTLINE, newvertspacing());
+    cv->line = newline;
+    divide_ties();
+  };
+}
+
+void event_error(s)
+char *s;
+/* report any error message */
+{
+  printf("Error in line %d : %s\n", lineno, s);
+}
+
+void event_warning(s)
+char *s;
+/* report any warning message */
+{
+  printf("Warning in line %d : %s\n", lineno, s);
+}
+
+void event_comment(s)
+char *s;
+/* A comment has been encountered in the input */
+{
+}
+
+int make_open()
+/* called as   fileopen = make_open()                    */
+/* if file is not already open, open it and set fileopen */
+{
+  if (fileopen == 0) {
+    open_output_file(outputname, (void*)NULL);
+    fileopen = 1;
+  };
+  return(1);
+}
+
+void event_specific(p, str)
+char *p;   /* first word after %% */
+char *str; /* string following first word */
+/* The special comment %% has been found */
+/* abc2midi uses it for the %%MIDI commands */
+/* yaps implements some of the abc2ps commands */
+{
+  char* s;
+  double vspace;
+  char units[80];
+  int count;
+
+  /* ensure file has been opened since most commands require this */
+  if (!eps_out) {
+    fileopen = make_open();
+  };
+  s = str;
+  skipspace(&s);
+  if (strcmp(p, "newpage") == 0) {
+    if (xinbody == 0) {
+      if (fileopen) {
+        newpage();
+      };
+    } else {
+      addfeature(NEWPAGE, (void*)NULL);
+    };
+  };
+  if (strcmp(p, "text") == 0) {
+    if (xinbody == 0) {
+      if (fileopen) {
+        lefttext(s);
+      };
+    } else {
+      addfeature(LEFT_TEXT, addstring(s));
+    };
+  };
+  if ((strcmp(p, "centre") == 0) || (strcmp(p, "center") == 0)) {
+    if (xinbody == 0) {
+      if (fileopen) {
+        centretext(s);
+      };
+    } else {
+      addfeature(CENTRE_TEXT, addstring(s));
+    };
+  };
+  if (strcmp(p, "vskip") == 0) {
+    count = sscanf(s, "%lf%79s", &vspace, units);
+    if (count > 0) {
+      if ((count >= 2) && (strncmp(units, "cm", 2) == 0)) {
+        vspace = vspace*28.3;
+      };
+      if ((count >= 2) && (strncmp(units, "in", 2) == 0)) {
+        vspace = vspace*72.0 ;
+      };
+      if (xinbody == 0) {
+        if (fileopen) {
+          vskip(vspace);
+        };
+      } else {
+        addfeature(VSKIP, (void*)((int)vspace));
+      };
+    };
+  };
+  if (strcmp(p, "chordsabove") == 0) {
+    gchords_above = 1;
+  };
+  if (strcmp(p, "chordsbelow") == 0) {
+    gchords_above = 0;
+  };
+  /* look for font-related commands */
+  font_command(p, s);
+}
+
+void event_field(k, f)
+char k;
+char *f;
+/* A field line has been encountered in the input abc */
+{
+  switch (k) {
+  case 'T':
+    if (debugging) {
+      printf("T:%s\n", f);
+    };
+    addtolist(&thetune.title, addstring(f));
+    break;
+  case 'C':
+    if (thetune.composer != NULL) {
+      event_error("More than one C: field in tune");
+    } else {
+      thetune.composer = addstring(f);
+    };
+    break;
+  case 'O':
+    if (thetune.origin != NULL) {
+      event_error("More than one O: field in tune");
+    } else {
+      thetune.origin = addstring(f);
+    };
+    break;
+  case 'W':
+    if (debugging) {
+      printf("W:%s\n", f);
+    };
+    addtolist(&thetune.words, addstring(f));
+    break;
+  case 'N':
+    addtolist(&thetune.notes, addstring(f));
+    break;
+  default:
+    break;
+  };
+}
+
+struct feature* findbar(struct feature* wordplace, int* errors)
+/* hunts through voice to find next bar data structure */
+{
+  struct feature* ft;
+
+  ft = wordplace;
+  while ((ft != NULL) && (ft != cv->lineend) && (ft->type != MUSICSTOP) &&
+         (ft->type != SINGLE_BAR) && (ft->type != DOUBLE_BAR) &&
+         (ft->type != BAR_REP) && (ft->type != REP_BAR) &&
+         (ft->type != DOUBLE_REP) && (ft->type != THICK_THIN) &&
+         (ft->type != THIN_THICK) && (ft->type != BAR1) &&
+         (ft->type != REP_BAR2)) {
+    ft = ft->next;
+  };
+  if ((ft == NULL) || (ft == cv->lineend) || (ft->type == MUSICSTOP)) {
+    *errors = *errors + 1;
+  } else {
+    ft = ft->next;
+  };
+  return(ft);
+}
+
+struct feature* apply_syll(char* s, struct feature* wordplace, int* errors)
+/* attaches a syllable from the lyrics to the appropriate note */
+{
+  struct note* n;
+  struct feature* ft;
+  int inchord;
+
+  ft = wordplace;
+  inchord = 0;
+  while ((ft != NULL) && (ft != cv->lineend) &&
+         (ft->type != NOTE)) {
+    if (ft->type == CHORDON) {
+      inchord = 1;
+    };
+    ft = ft->next;
+    /* skip over any grace notes */
+    if ((ft != NULL) && (ft->type == GRACEON)) {
+      while ((ft != NULL) && (ft != cv->lineend) &&
+         (ft->type != GRACEOFF)) {
+        ft = ft->next;
+      };
+    };
+  };
+  if ((ft == NULL) || (ft == cv->lineend)) {
+    *errors = *errors + 1;
+    return(ft);
+  };
+  if (ft->type == NOTE) {
+    n = ft->item;
+    if (n->syllables == NULL) {
+      n->syllables = newlist();
+    };
+/*
+    if (strlen(s) < 80) {
+      ISOdecode(s, isocode);
+      addtolist(n->syllables, addstring(isocode));
+    } else {
+*/
+      addtolist(n->syllables, addstring(s));
+/*
+    };
+*/
+  };
+  ft = ft->next;
+  /* skip over any chord */
+  if (inchord) {
+    while ((ft != NULL) && (ft->type != CHORDOFF) && (ft != cv->lineend)) {
+      ft = ft->next;
+    };
+  };
+  return(ft);
+}
+
+void event_words(p, continuation)
+char* p;
+int continuation;
+/* A line of lyrics (w: ) has been encountered in the abc */
+{
+  struct vstring syll;
+  char* q;
+  struct feature* wordplace;
+  unsigned char ch;
+  int errors;
+
+  if (!xinbody) {
+    if (!suppress) {
+      event_error("w: field outside tune body");
+    };
+    return;
+  };
+  wordplace = cv->linestart;
+  if (cv->more_lyrics) {
+    errors = cv->lyric_errors;
+  } else {
+    errors = 0;
+  };
+  if (wordplace == NULL) {
+    event_error("No notes to match words");
+    return;
+  };
+  initvstring(&syll);
+  q = p;
+  skipspace(&q);
+  while (*q != '\0') {
+    clearvstring(&syll);
+    ch = *q;
+    while(ch=='|') {
+      wordplace = findbar(wordplace, &errors);
+      q++;
+      ch = *q;
+    };
+    while (((ch>127)||isalnum(ch)||ispunct(ch))&&
+           (ch != '_')&&(ch != '-')&&(ch != '*')&& (ch != '|')) {
+      if (ch == '~') {
+        ch = ' ';
+      };
+      if ((ch == '\\') && (*(q+1)=='-')) {
+        ch = '-';
+        q++;
+      };
+      /* syllable[i] = ch; */
+      addch(ch, &syll);
+      q++;
+      ch = *q;
+    };
+    skipspace(&q);
+    if (ch == '-') {
+      addch(ch, &syll);
+      while (isspace(ch)||(ch=='-')) {
+        q++;
+        ch = *q;
+      };
+    };
+    if (syll.len > 0) {
+      wordplace = apply_syll(syll.st, wordplace, &errors);
+    } else {
+      if (ch=='_') {
+        clearvstring(&syll);
+        addch('_', &syll);
+        wordplace = apply_syll(syll.st, wordplace, &errors);
+        q++;
+        ch = *q;
+      };
+      if (ch=='*') {
+        clearvstring(&syll);
+        addch(' ', &syll);
+        wordplace = apply_syll(syll.st, wordplace, &errors);
+        q++;
+        ch = *q;
+      };
+    }; 
+  };
+  if (continuation) {
+    cv->more_lyrics = 1;
+    cv->lyric_errors = errors;
+    cv->linestart = wordplace;
+  } else {
+    cv->more_lyrics = 0;
+    if (errors > 0) {
+      event_error("Lyric line too long for music");
+    } else {
+      clearvstring(&syll);
+      wordplace = apply_syll(syll.st, wordplace, &errors);
+      if (errors == 0) {
+        event_error("Lyric line too short for music");
+      };
+    };
+  };
+  freevstring(&syll);
+}
+
+void event_part(s)
+char* s;
+/* A part field (P: ) has been encountered in the abc */
+{
+  char label[20];
+
+  if (xinhead) {
+    if (thetune.parts != NULL) {
+      event_error("Multiple P: fields in header");
+    } else {
+      thetune.parts = addstring(s);
+    };
+  };
+  if (xinbody) {
+    /* addfeature(PART, addstring(s)); */
+    /* PART is handled like an instruction */
+    if (cv->instructions_pending == NULL) {
+      cv->instructions_pending = newlist();
+    };
+    sprintf(label, ":p%s", s);
+    addtolist(cv->instructions_pending, addstring(label));
+  };
+}
+
+void event_voice(n, s, vp)
+int n;
+char *s;
+struct voice_params *vp;
+/* A voice field (V: ) has been encountered */
+{
+  if (xinbody) {
+    setvoice(n);
+  } else {
+    if (!suppress) {
+      event_error("V: field outside tune body");
+    };
+  };
+}
+
+void event_length(n)
+int n;
+/* A length field (L: ) has been encountered */
+{
+  if (xinhead) {
+    setfract(&thetune.unitlen, 1, n);
+  } else {
+    if (xinbody) {
+      setfract(&cv->unitlen, 1, n);
+    } else {
+      if (!suppress) {
+        event_warning("L: field outside tune ignored");
+      };
+    };
+  };
+}
+
+void event_refno(n)
+int n;
+/* A reference field (X: ) has been encountered. This indicates the start */
+/* of a new tune */
+{
+  if (xinhead) {
+    event_error("incomplete tune");
+  };
+  if (xinbody) {
+    check_tune_end(&thetune);
+    printtune(&thetune);
+  };
+  freetune(&thetune);
+  xinbody = 0;
+  xinhead = 0;
+  suppress = 0;
+  parseroff();
+  if (debugging) {
+    printf("X:%d\n", n);
+  };
+  if (checkmatch(n)) {
+    parseron();
+    /* fileopen = make_open(); */
+    xinhead = 1;
+    xinbody = 0;
+    init_tune(&thetune, n);
+  } else {
+    suppress = 1;
+  };
+}
+
+void event_tempo(n, a, b, relative, pre, post)
+int n, a, b;
+int relative;
+char *pre; /* text before tempo */
+char *post; /* text after tempo */
+/* A tempo field Q: has been encountered in the abc */
+/* Q:a/b=N will have relative = 0    */
+/* Q:N will have a=0 and b=0         */
+/* Q:Ca/b = N will have relative = 1 */
+{
+  if (xinhead) {
+    thetune.tempo = newtempo(n, a, b, relative, pre, post);
+  } else {
+    if (xinbody) {
+      if ((a == 0) && (b == 0)) {
+        addfeature(TEMPO, newtempo(n, cv->unitlen.num, cv->unitlen.denom, 0,
+                                pre, post));
+      } else {
+        addfeature(TEMPO, newtempo(n, a, b, relative, pre, post));
+      };
+    } else {
+      if (!suppress) {
+        event_warning("Q: field outside tune ignored");
+      };
+    };
+  };
+}
+
+void event_timesig(n, m, checkbars)
+int n, m, checkbars;
+/* A time signature (M: ) has been encountered in the abc */
+{
+  if (xinhead) {
+    setfract(&thetune.meter, n, m);
+    thetune.barchecking = checkbars;
+  } else {
+    if (xinbody) {
+      if (checkbars == 1) {
+        addfeature(TIME, newfract(n,m));
+        setfract(&cv->meter, n, m);
+        setfract(&cv->barlen, n, m);
+        if (cv->line != midline) {
+          cv->changetime = 1;
+        };
+        cv->barchecking = 1;
+      } else {
+        cv->barchecking = 0;
+      };
+    } else {
+      if (!suppress) {
+        event_warning("M: field outside tune ignored");
+      };
+    };
+  };
+}
+
+enum cleftype findclef(clefstr, oct)
+char* clefstr;
+int* oct;
+/* converts a clef name string to an enumerated type */
+/* also looks for +8 +15 +22 -8 -15 -22 octave shift */
+{
+  enum cleftype type;
+  char* p;
+  int interval;
+
+  type = noclef;
+  p = clefstr;
+  if (strncmp(clefstr, "treble", 6)==0) {
+    type = treble;
+    p = p + 6;
+  };
+  if (strncmp(clefstr, "bass", 4)==0) {
+    type = bass;
+    p = p + 4;
+  };
+  if (strncmp(clefstr, "baritone", 8)==0) {
+    type = baritone;
+    p = p + 8;
+  };
+  if (strncmp(clefstr, "tenor", 5)==0) {
+    type = tenor;
+    p = p + 5;
+  };
+  if (strncmp(clefstr, "alto", 4)==0) {
+    type = alto;
+    p = p + 4;
+  };
+  if (strncmp(clefstr, "mezzo", 5)==0) {
+    type = mezzo;
+    p = p + 5;
+  };
+  if (strncmp(clefstr, "mezzo-soprano", 13)==0) {
+    type = mezzo;
+    p = p + 13;
+  };
+  if (strncmp(clefstr, "soprano", 7)==0) {
+    type = soprano;
+    p = p + 7;
+  };
+  interval = 0;
+  if ((type != noclef) && ((*p == '+') || (*p == '-'))) {
+    sscanf(p+1, "%d", &interval);
+    if ((interval == 8) || (interval == 15) || (interval == 22)) {
+      if (*p == '-') {
+        interval = -interval;
+      };
+    } else {
+      interval = 0;
+    };
+  };
+  *oct = interval;
+  return(type);
+}
+
+void event_clef(char* clefstr)
+/* a clef has been encountered in the abc */
+{
+  enum cleftype clef;
+  int num;
+
+  clef = findclef(clefstr, &num);
+  if (xinbody) {
+    cv->clef->type = clef;
+    cv->clef->octave = num;
+    addfeature(CLEF, newclef(clef, num));
+  };
+  if ((xinhead) && (!xinbody)) {
+    if (clef != noclef) {
+       thetune.clef.type = clef;
+       thetune.clef.octave = num;
+    };
+  };
+}
+
+void setmap(sf, map, mult)
+/* work out accidentals to be applied to each note */
+int sf; /* number of sharps in key signature -7 to +7 */
+char map[7];
+int mult[7];
+{
+  int j;
+
+  for (j=0; j<7; j++) {
+    map[j] = '=';
+    mult[j] = 1;
+  };
+  if (sf >= 1) map['f'-'a'] = '^';
+  if (sf >= 2) map['c'-'a'] = '^';
+  if (sf >= 3) map['g'-'a'] = '^';
+  if (sf >= 4) map['d'-'a'] = '^';
+  if (sf >= 5) map['a'-'a'] = '^';
+  if (sf >= 6) map['e'-'a'] = '^';
+  if (sf >= 7) map['b'-'a'] = '^';
+  if (sf <= -1) map['b'-'a'] = '_';
+  if (sf <= -2) map['e'-'a'] = '_';
+  if (sf <= -3) map['a'-'a'] = '_';
+  if (sf <= -4) map['d'-'a'] = '_';
+  if (sf <= -5) map['g'-'a'] = '_';
+  if (sf <= -6) map['c'-'a'] = '_';
+  if (sf <= -7) map['f'-'a'] = '_';
+}
+
+void altermap(basemap, basemul, modmap, modmul)
+/* apply modifiers to a set of accidentals */
+char basemap[7], modmap[7];
+int basemul[7], modmul[7];
+{
+  int i;
+
+  for (i=0; i<7; i++) {
+    if (modmap[i] != ' ') {
+      basemap[i] = modmap[i];
+      basemul[i] = modmul[i];
+    };
+  };
+}
+
+
+void resolve_tempo(struct atempo* t, struct fract* unitlen)
+/* Tempo may be given relative to the unit note length. At the start of */
+/* the tune, we will know what this is and can deduce the tempo value.  */
+/* Can also deduce tempo if it has been given as a number only.         */
+{
+  if (t->relative==1) {
+    setfract(&t->basenote, t->basenote.num*unitlen->num, 
+                           t->basenote.denom*unitlen->denom);
+    reducef(&t->basenote);
+    t->relative = 0;
+  };
+  if ((t->basenote.num == 0) && (t->basenote.denom == 0)) {
+    setfract(&t->basenote, unitlen->num, unitlen->denom);
+    reducef(&t->basenote);
+  };
+}
+
+static void start_body()
+/* We have reached the end of the header section and need to set */
+/* default values for anything not explicitly declared */
+{
+  parseron();
+  if (thetune.meter.num == 0) {
+    event_warning("no M: field, assuming 4/4");
+    /* generate missing time signature */
+    event_timesig(4, 4, 1);
+    event_linebreak();
+  };
+  if (thetune.unitlen.num == 0) {
+    event_warning("no L: field, using default rule");
+    if ((double) thetune.meter.num / (double) thetune.meter.denom < 0.75) {
+      /*setfract(&thetune.unitlen, 1, 16); [SS] 2004-09-06 */
+      event_length(16);
+    } else {
+     /* setfract(&thetune.unitlen, 1, 8); */
+      event_length(8);
+    };
+  };
+  if (thetune.tempo != NULL) {
+    resolve_tempo(thetune.tempo, &thetune.unitlen);
+  };
+}
+
+void event_true_key(sharps, s, modeindex, modmap, modmul)
+int sharps;
+char *s;
+int modeindex; /* 0 major, 1,2,3 minor, 4 locrian, etc.  */
+char modmap[7];
+int modmul[7];
+/* key detected in K: field */
+{
+  char basemap[7];
+  int basemul[7];
+  struct key* akey;
+  int minor;
+  minor =0;
+  if (modeindex >0 && modeindex <4) minor = 1;
+
+  setmap(sharps, basemap, basemul);
+  altermap(basemap, basemul, modmap, modmul);
+  if (xinbody) {
+    akey = newkey(s, sharps, basemap, basemul);
+    addfeature(KEY, akey);
+    set_keysig(cv->keysig, akey);
+  };
+  if (xinhead) {
+    if (thetune.keysig == NULL) {
+      thetune.keysig = newkey(s, sharps, basemap, basemul);
+    } else {
+      event_warning("Key specified twice");
+    };
+    xinbody = 1;
+    xinhead = 0;
+    setvoice(1);
+    start_body();
+  };
+}
+
+void event_octave(int num, int local)
+/* deals with the special command I:octave=N */
+{
+  if (xinhead) {
+    thetune.octaveshift = num;
+  };
+  if (xinbody) {
+    cv->octaveshift = num;
+  };
+}
+
+void event_key(sharps, s, minor, modmap, modmul, gotkey, gotclef, clefstr,
+          octave, transpose, gotoctave, gottranspose)
+int sharps;
+char *s;
+int minor;
+char modmap[7];
+int modmul[7];
+int gotkey, gotclef;
+char* clefstr;
+int octave, transpose, gotoctave, gottranspose;
+/* A key field (K: ) has been encountered */
+{
+  if (xinhead || xinbody) {
+    if (gotclef==1) {
+      event_clef(clefstr);
+    };
+    if (gotkey==1) {
+      event_true_key(sharps, s, minor, modmap, modmul);
+    };
+  };
+  if (gotoctave) {
+    event_octave(octave,0);
+  };
+}
+
+static void checkbar(int type)
+/* Make sure that bar lasts for the correct musical time */
+{
+  int valid;
+  char msg[80];
+  int a1, a2;
+
+  valid = 0;
+  a1 = cv->barlen.num*cv->barcount.denom;
+  a2 = cv->barcount.num*cv->barlen.denom;
+  if (a1 == a2) {
+    cv->barcount.num = 0;
+    cv->barcount.denom = 1;
+    cv->barno = cv->barno + 1;
+  } else {
+    if (((type==BAR_REP)||(type==REP_BAR)||(type==DOUBLE_REP)) &&
+        (a1 > a2)) {
+      /* do nothing */
+    } else {
+      if ((cv->barno > 0) && (cv->barcount.num != 0) &&
+          (cv->barchecking != 0)) {
+        sprintf(msg, "Bar %d is %d/%d not %d/%d", cv->barno, 
+           cv->barcount.num, cv->barcount.denom,
+           cv->barlen.num, cv->barlen.denom);
+        event_warning(msg);
+        cv->barcount.num = 0;
+        cv->barcount.denom = 1;
+        cv->barno = cv->barno + 1;
+      } else {
+        cv->barcount.num = 0;
+        cv->barcount.denom = 1;
+        cv->barno = cv->barno + 1;
+      };
+    };
+  };
+}
+
+void event_bar(type, playonrep_list)
+int type;
+char* playonrep_list;
+/* A bar has been encountered in the abc */
+{
+  if (cv->inchord) {
+    event_warning("Bar line not permitted within chord");
+    return;
+  };
+  checkbar(type); /* increment bar number if bar complete */
+  addfeature(type, (void*)cv->barno); /* save bar number */
+  switch(type) {
+  case SINGLE_BAR:
+    break;
+  case DOUBLE_BAR:
+    break;
+  case THIN_THICK:
+    break;
+  case THICK_THIN:
+    break;
+  case BAR_REP:
+    if ((cv->expect_repeat) && (repcheck)) {
+      event_error("Expecting repeat, found |:");
+    };
+    cv->expect_repeat = 1;
+    break;
+  case REP_BAR:
+    if ((!cv->expect_repeat) && (repcheck)) {
+      event_error("No repeat expected, found :|");
+    };
+    cv->expect_repeat = 0;
+    break;
+  case BAR1:
+    if ((!cv->expect_repeat) && (repcheck)) {
+      event_error("found |1 in non-repeat section");
+    };
+    break;
+  case REP_BAR2:
+    if ((!cv->expect_repeat) && (repcheck)) {
+      event_error("No repeat expected, found :|2");
+    };
+    cv->expect_repeat = 0;
+    break;
+  case DOUBLE_REP:
+    if ((!cv->expect_repeat) && (repcheck)) {
+      event_error("No repeat expected, found ::");
+    };
+    cv->expect_repeat = 1;
+    break;
+  };
+  if ((playonrep_list != NULL) && (strlen(playonrep_list) > 0)) {
+    event_playonrep(playonrep_list);
+  };
+}
+
+void event_space()
+/* A region of whitespace has been encountered */
+{
+  addfeature(NOBEAM, NULL);
+}
+
+void event_graceon()
+/* start of grace note(s) */
+{
+  if (cv->inchord) {
+    event_error("grace notes not allowed within chord");
+    return;
+  };
+  if (cv->ingrace) {
+    event_error("nested grace notes not allowed");
+    return;
+  };
+  cv->gracebeamroot = NULL;
+  cv->gracebeamend = NULL;
+  cv->ingrace = 1;
+  addfeature(GRACEON, NULL);
+}
+
+void event_graceoff()
+/* end of grace note(s) */
+{
+  if (!cv->ingrace) {
+    event_error("No grace notes to close");
+    return;
+  };
+  if (cv->inchord) {
+    event_error("cannot close grace notes within chord");
+    return;
+  };
+  addfeature(GRACEOFF, NULL);
+  closegracebeam(cv);
+  cv->ingrace = 0;
+  cv->gracebeamroot = NULL;
+  cv->gracebeamend = NULL;
+}
+
+void event_rep1()
+/* start of first repeat */
+{
+  addfeature(REP1, NULL);
+}
+
+void event_rep2()
+/* start of second repeat */
+{
+  addfeature(REP2, NULL);
+}
+
+void event_playonrep(s)
+char* s;
+/* play on repeat(s) X - where X can be a list */
+{
+  addfeature(PLAY_ON_REP, addstring(s));
+}
+
+void event_broken(type, mult)
+/* handles > >> >>> < << <<< in the abc */
+int type, mult;
+{
+  if (cv->inchord) {
+    event_error("Broken rhythm not allowed in chord");
+  } else {
+    if (cv->ingrace) {
+      event_error("Broken rhythm not allowed in grace notes");
+    } else {
+      cv->brokentype = type;
+      cv->brokenmult = mult;
+      cv->brokenpending = 0;
+    };
+  };
+}
+
+void event_tuple(n, q, r)
+int n, q, r;
+/* Start of a tuple has been  encountered (e.g. triplet) */
+/* Meaning is "play next r notes at q/n of notated value" */
+/* where all 3 exist, otherwise r defaults to n and ratio */
+/* is deduced from standard rules if q is missing */
+{
+  if (cv->tuplenotes != 0) {
+    event_error("tuple within tuple not allowed");
+    return;
+  };
+  if (r != 0) {
+    cv->tuplenotes = r;
+  } else {
+    cv->tuplenotes = n;
+  };
+  if (q != 0) {
+    cv->tuplefactor.num = q;
+    cv->tuplefactor.denom = n;
+  } else {
+    cv->tuplefactor.denom = n;
+    if ((n == 2) || (n == 4) || (n == 8)) cv->tuplefactor.num = 3;
+    if ((n == 3) || (n == 6)) cv->tuplefactor.num = 2;
+    if ((n == 5) || (n == 7) || (n == 9)) {
+      if ((cv->barlen.num % 3) == 0) {
+        cv->tuplefactor.num = 3;
+      } else {
+        cv->tuplefactor.num = 2;
+      };
+    };
+  };
+  cv->thistuple = newtuple(cv->tuplefactor.denom, cv->tuplefactor.num, 
+                           cv->tuplenotes, n);
+  addfeature(TUPLE, cv->thistuple);
+}
+
+void event_startinline()
+{
+}
+
+void event_closeinline()
+{
+}
+
+void event_handle_gchord(s)
+char* s;
+/* Guitar/Accompaniment chord placed in linked list for association */
+/* with next suitable note */
+{
+  if (cv->gchords_pending == NULL) {
+    cv->gchords_pending = newlist();
+  };
+  if (*s == '_') {
+  if (cv->instructions_pending == NULL) {
+    cv->instructions_pending = newlist();
+    };
+  addtolist(cv->instructions_pending, addstring(s+1));
+  } else {
+    addtolist(cv->gchords_pending, addstring(s));
+  };
+}
+
+void event_handle_instruction(s)
+char* s;
+/* An instruction (! !) has been encountered */
+{
+  char* inst;
+  static char segno[3] = ":s";
+  static char coda[3] = ":c";
+  struct dynamic *psaction;
+  int done;
+ 
+  done = 0;
+  inst = s;
+  if (strcmp(s, "fermata") == 0)
+     {
+     decorators_passback[4] =1;
+/*   don't show !fermata!. Treat it like H in music line */
+     return;
+     }
+
+  if (strcmp(s, "trill") == 0)
+     {
+     decorators_passback[6] =1;
+/*   don't show !trill!. Treat it like T in music line */
+     return;
+     }
+
+  if (strcmp(s, "segno") == 0) {
+    inst = segno;
+    done = 1;
+  };
+  if (strcmp(s, "coda") == 0) {
+    inst = coda;
+    done = 1;
+  };
+
+  if (done == 1) {
+    if (cv->instructions_pending == NULL) {
+      cv->instructions_pending = newlist();
+     };
+    addtolist(cv->instructions_pending, addstring(inst));
+    return;
+    }
+  if (strcmp(s,"red") == 0)
+   {     
+   psaction = (struct dynamic*) checkmalloc(sizeof(struct note));
+   psaction->color = 'r';
+   addfeature(DYNAMIC,psaction);
+   }
+  if (strcmp(s,"black") == 0)
+   {     
+   psaction = (struct dynamic*) checkmalloc(sizeof(struct note));
+   psaction->color = 'b';
+   addfeature(DYNAMIC,psaction);
+   }
+}
+
+struct slurtie* resolve_slur(struct feature* lastnote)
+/* when an end-of-slur marker ')' is found, this routine works out */
+/* where the other end of the slur was */
+{
+  int i;
+  int resolved;
+  struct slurtie* s = NULL;
+
+  resolved = 0;
+  if (lastnote != NULL) {
+    for (i=0; i<cv->slurcount; i++) {
+      if ((resolved == 0) && (cv->slur_place[i]->begin != NULL) &&
+          (cv->slur_place[i]->begin != lastnote)) {
+        resolved = 1;
+        cv->slur_place[i]->end = lastnote;
+        s = cv->slur_place[i];
+        cv->slur_place[i] = cv->slur_place[cv->slurcount-1];
+        cv->slurcount = cv->slurcount - 1;
+      };
+    };  
+  };
+  if (resolved == 0) {
+    event_error("Could not find start of slur to match close slur");
+    s = NULL;
+  };
+  return(s);
+}
+
+static void startslurs(struct feature* firstnote)
+/* When a note is found after a (, set note to be start of slur */
+/* Note may be the start of more than one slur */
+{
+  int i;
+
+  for (i=0; i<cv->slurcount; i++) {
+    if (cv->slur_place[i]->begin == NULL) {
+      cv->slur_place[i]->begin = firstnote;
+    };
+  };
+}
+
+void event_sluron(t)
+int t;
+/* start of slur */
+{
+  struct slurtie* s;
+
+  s = newslurtie();
+  addfeature(SLUR_ON, s);
+  cv->slurpending = 1;
+  if (cv->slurcount < MAX_SLURS) {
+    cv->slur_place[cv->slurcount] = s;
+    cv->slurcount = cv->slurcount+1;
+  } else {
+    event_error("Static limit on number of slurs exceeded");
+  };
+}
+
+void event_sluroff(t)
+int t;
+/* end of slur */
+{
+  struct slurtie* s;
+
+  s = resolve_slur(cv->lastnote);
+  addfeature(SLUR_OFF, s);
+}
+
+static void resolve_ties(struct feature* f)
+/* try to match up note to previous tied note */
+{
+  struct feature* ft;
+  struct slurtie* s;
+  struct note* m;
+  struct note* n;
+  int i, j;
+
+  n = f->item;
+  for (i=0; i<cv->tiespending; i++) {
+    ft = cv->tie_place[i]; /* pointer to TIE feature */
+    s = ft->item;
+    ft = s->begin; /* pointer to NOTE feature */
+    m = ft->item;
+    if (m->y == n->y) { /* pitch match found */
+      s->end = f;
+      j = cv->tiespending;
+      cv->tie_place[i] = cv->tie_place[j-1];
+      cv->tie_status[i] = cv->tie_status[j-1];
+      cv->tiespending = j-1;
+    };
+  };
+}
+
+static void advance_ties()
+/* deal with unresolved tied notes as musical time advances */
+{
+  int i, j;
+
+  for (i=0; i<cv->tiespending; i++) {
+    cv->tie_status[i]++;
+  };
+  i = 0;
+  j = cv->tiespending;
+  while (i < j) {
+    if (cv->tie_status[i] >= 2) {
+      event_error("No note to tie to");
+      cv->tie_place[i] = cv->tie_place[j-1];
+      cv->tie_status[i] = cv->tie_status[j-1];
+      j = j - 1;
+    } else {
+      i = i + 1;
+    };
+  };
+  cv->tiespending = j;
+}
+
+void event_tie()
+/* tie encountered in the abc */
+{
+  struct slurtie* s;
+  struct feature* place;
+  int i;
+
+  if ((cv->lastnote == NULL)||(cv->lastnote->type != NOTE)) {
+    event_error("No note to tie");
+  } else {
+    s = newslurtie();
+    place = addfeature(TIE, s);
+    s->begin = cv->lastnote;
+    cv->lastnote = NULL;
+    i = cv->tiespending;
+    if (i < MAX_TIES) {
+      cv->tie_place[i] = place;
+      cv->tie_status[i] = 0;
+      cv->tiespending = cv->tiespending + 1;
+    } else {
+      event_error("Internal limit on ties exceeded");
+    };
+  };
+}
+
+void event_lineend(ch, n)
+char ch;
+int n;
+/* Line ending with n copies of special character ch */
+{
+}
+
+static void lenmul(n, a, b)
+/* multiply note length by a/b */
+struct feature* n;
+int a, b;
+{
+  struct note *anote;
+  struct rest* arest;
+  struct fract* afract;
+
+  if (n->type == NOTE) {
+    anote =  n->item;
+    afract = &anote->len;
+    afract->num = afract->num * a;
+    afract->denom = afract->denom * b;
+    reducef(afract);
+    /* re-calculate base, base_exp and dots */
+    anote->dots = count_dots(&anote->base, &anote->base_exp, 
+                             anote->len.num, anote->len.denom);
+  };
+  if (n->type == REST) {
+    arest =  n->item;
+    afract = &arest->len;
+    afract->num = afract->num * a;
+    afract->denom = afract->denom * b;
+    reducef(afract);
+    /* re-calculate base, base_exp and dots */
+    arest->dots = count_dots(&arest->base, &arest->base_exp, 
+                             arest->len.num, arest->len.denom);
+  };
+}
+
+struct fract* getlenfract(struct feature *f)
+/* find fractional length of NOTE or REST */
+{
+  struct fract *len;
+  struct note *anote;
+  struct rest *arest;
+
+  len = NULL;
+  if (f->type == NOTE) {
+    anote = f->item;
+    len = &(anote->len);
+  };
+  if (f->type == REST) {
+    arest = f->item;
+    len = &(arest->len);
+  };
+  return(len);
+}
+
+static void brokenadjust()
+/* adjust lengths of broken notes */
+{
+  int num1, num2, denom12;
+  struct feature* j;
+  struct fract* fr1;
+  struct fract* fr2;
+  int temp;
+  int failed;
+  int done;
+
+  switch(cv->brokenmult) {
+    default:
+      event_error("invalid type of broken rhythm");
+    case 1:
+      num1 = 3;
+      num2 = 1;
+      break;
+    case 2:
+      num1 = 7;
+      num2 = 1;
+      break;
+    case 3:
+      num1 = 15;
+      num2 = 1;
+      break;
+  };
+  denom12 = (num1 + num2)/2;
+  if (cv->brokentype == LT) {
+    temp = num1;
+    num1 = num2;
+    num2 = temp;
+  };
+  failed = 0;
+  if ((cv->laststart == NULL) || (cv->lastend == NULL) || 
+      (cv->thisstart == NULL) || (cv->thisend == NULL)) {
+    failed = 1;
+  } else {
+    /* check for same length notes */
+    fr1 = getlenfract(cv->laststart);
+    fr2 = getlenfract(cv->thisstart);
+/*
+    fr1 = cv->laststart->item;
+    fr2 = cv->thisstart->item;
+*/
+    if ((fr1->num * fr2->denom) != (fr2->num * fr1->denom)) {
+      failed = 1;
+    };
+  };
+  if (failed) {
+    event_error("Cannot apply broken rhythm");
+  } else {
+/*
+    printf("Adjusting %d to %d and %d to %d\n",
+           cv->laststart, cv->lastend, cv->thisstart, cv->thisend);
+*/
+    j = cv->laststart;
+    done = 0;
+    while (done == 0) {
+      lenmul(j, num1, denom12);
+      done = (j == cv->lastend);
+      j = j->next; 
+    };
+    j = cv->thisstart;
+    done = 0;
+    while (done == 0) {
+      lenmul(j, num2, denom12);
+      done = (j == cv->thisend);
+      j = j->next; 
+    };
+  };
+}
+
+static void marknotestart(struct feature* place)
+/* voice data structure keeps a record of last few notes encountered */
+/* in order to process broken rhythm. This is called at the start of */
+/* a note or chord */
+{
+  cv->laststart = cv->thisstart;
+  cv->lastend = cv->thisend;
+  cv->thisstart = place;
+}
+
+static void marknoteend(struct feature* place)
+/* voice data structure keeps a record of last few notes encountered */
+/* in order to process broken rhythm. This is called at the end of */
+/* a note or chord */
+{
+  cv->thisend = place;
+  if (cv->brokenpending != -1) {
+    cv->brokenpending = cv->brokenpending + 1;
+    if (cv->brokenpending == 1) {
+      brokenadjust();
+      cv->brokenpending = -1;
+    };
+  };
+}
+
+static void marknote(struct feature* place)
+/* when handling a single note, not a chord, marknotestart() and */
+/* marknoteend() can be called together */
+{
+  marknotestart(place);
+  marknoteend(place);
+}
+
+static void markchord(struct feature* chordplace)
+/* find start and end of chord for applying broken rhythm */
+{
+  struct feature* first;
+  struct feature* last;
+
+  first = chordplace->next;
+  last = first;
+  while ((last->next != NULL)&&(last->next->type==NOTE)) {
+    last = last->next;
+  };
+  marknotestart(first);
+  marknoteend(last);
+}
+
+void event_chord()
+/* handles old '+' notation which marks the start and end of each chord */
+{
+    if (cv->inchord) {
+      event_chordoff(1,1);
+    } else {
+      event_chordon(dummydecorator);
+    };
+}
+
+void event_chordon(int chorddecorators[])
+/* start of a chord */
+/* the array chorddecorators is not used yet. */
+{
+  if (cv->inchord) {
+    event_error("nested chords found");
+    return;
+  };
+  cv->inchord = 1;
+  cv->chordcount = 0;
+  cv->thischord = newchord();
+  cv->chordplace = addfeature(CHORDON, cv->thischord);
+}
+
+
+void fix_enclosed_note_lengths(struct feature* chordplace,
+      int chord_n, int chord_m, int * base, int * base_exp)
+{
+struct feature* f;
+struct note* anote;
+if (chord_n ==1 && chord_m ==1) return;
+f = chordplace->next;
+anote = f->item;
+/* remove old note length from barcount */
+addfractions(&cv->barcount, -anote->len.num, anote->len.denom);
+while ((f != NULL)&&((f->type==NOTE)||(f->type=CHORDNOTE))) {
+   anote = f->item;
+   /* remove old note length from barcount */
+   setfract(&anote->len, chord_n*cv->unitlen.num, chord_m*cv->unitlen.denom);
+   reducef(&anote->len);
+   /*printf("NOTE %c%c %d / %d\n", anote->accidental, anote->pitch, 
+               anote->len.num, anote->len.denom);                 
+   */
+   anote->dots = count_dots(&anote->base, &anote->base_exp,
+         anote->len.num, anote->len.denom);
+   f = f->next;
+   *base = anote->base;
+   *base_exp = anote->base_exp;
+   }
+   /* and new note length to barcount */
+   addfractions(&cv->barcount, anote->len.num, anote->len.denom);
+}
+
+
+void event_chordoff(int chord_n, int chord_m)
+/* end of a chord */
+{
+  struct feature* ft;
+  struct chord* thechord = NULL;
+  struct note* firstnote;
+  int base,base_exp;
+
+  if (!cv->inchord) {
+    event_error("no chord to close");
+    return;
+  };
+  ft = cv->chordplace;
+  if ((ft != NULL) && (ft->next != NULL) && (ft->next->type == NOTE)) {
+    thechord = ft->item;
+    firstnote = ft->next->item;
+    /* beaming for 1st note in chord */
+    beamitem(NOTE, firstnote, ft->next);
+    markchord(ft);
+    thechord->base = firstnote->base;
+    thechord->base_exp = firstnote->base_exp;
+  } else {
+    event_error("mis-formed chord");
+  };
+  
+  if (cv->chordplace) {
+      fix_enclosed_note_lengths(cv->chordplace,chord_n,chord_m,&base,&base_exp);
+      if (chord_n != 1 || chord_m != 1) {
+         thechord->base = base;
+         thechord->base_exp = base_exp;
+         }
+      }
+  cv->inchord = 0;
+  cv->thischord = NULL;
+  cv->chordplace = NULL;
+  advance_ties();
+  addfeature(CHORDOFF, NULL);
+}
+
+/* just a stub to ignore 'y' */
+void event_spacing(n, m)
+int n,m;
+{
+}
+
+void xevent_rest(n, m, multi)
+int n, m, multi;
+/* A rest has been encountered in the abc */
+/* multi is 0 for ordinary rests or count for multibar rests */
+{
+  struct feature* restplace;
+
+  if (cv->ingrace) {
+    event_warning("rest in grace notes ignored");
+    return;
+  };
+  if (cv->inchord) {
+    event_warning("rest in chord ignored");
+    return;
+  };
+  if ((multi > 0) && (cv->tuplenotes > 0)) {
+    event_error("Multiple bar rest not allowed in tuple");
+  };
+  advance_ties();
+  restplace = addfeature(REST, newrest(n*cv->unitlen.num, 
+                                         m*cv->unitlen.denom, multi));
+  if (cv->slurpending) {
+    startslurs(restplace);
+    cv->slurpending = 0;
+  };
+  cv->lastnote = restplace;
+  if (cv->inchord) {
+    cv->chordcount = cv->chordcount + 1;
+  } else {
+    marknote(restplace); 
+  };
+  if ((!cv->ingrace) && (!cv->inchord || (cv->chordcount == 1))) {
+    if (cv->tuplenotes == 0) {
+      if (multi == 0) {
+        addunits(&cv->barcount, n, m);
+      };
+    } else {
+      addunits(&cv->barcount, n*cv->tuplefactor.num, m*cv->tuplefactor.denom);
+      cv->thistuple->beamed = 0;
+      cv->tuplenotes = cv->tuplenotes - 1;
+      if (cv->tuplenotes == 0) {
+        cv->thistuple = NULL;
+      };
+    };
+  };
+}
+
+void event_rest(decorators,n,m,type)
+int n, m,type;
+int decorators[DECSIZE];
+/* A rest has been encountered in the abc */
+{
+  xevent_rest(n, m, 0);
+}
+
+void event_mrest(n,m)
+int n, m;
+/* A multiple bar rest has been encountered in the abc */
+{
+  xevent_rest(1, 1, n);
+}
+
+void event_note(decorators, xaccidental, xmult, xnote, xoctave, n, m)
+int decorators[DECSIZE];
+int xmult;
+char xaccidental, xnote;
+int xoctave, n, m;
+/* note found in abc */
+{
+  struct note* nt;
+  struct feature* noteplace;
+  struct chord* thechord;
+  int pitchval;
+
+  nt = newnote(decorators, xaccidental, xmult, xnote, xoctave+cv->octaveshift, 
+               n * cv->unitlen.num, m * cv->unitlen.denom);
+  nt->tuplenotes = cv->tuplenotes;
+  noteplace = addfeature(NOTE, nt);
+  cv->lastnote = noteplace;
+  resolve_ties(noteplace);
+  if (cv->slurpending) {
+    startslurs(noteplace);
+    cv->slurpending = 0;
+  };
+  if (!cv->inchord) {
+    marknote(noteplace);
+    advance_ties();
+  } else {
+    thechord = cv->thischord;
+    pitchval = notenum(xoctave, xnote, cv->clef->type, cv->clef->octave);
+    if (cv->chordcount == 0) {
+      thechord->ytop = pitchval;
+      thechord->ybot = pitchval;
+    } else {
+      if (pitchval > thechord->ytop) {
+        thechord->ytop = pitchval;
+      };
+      if (pitchval < thechord->ybot) {
+        thechord->ybot = pitchval;
+      };
+    };
+    cv->chordcount = cv->chordcount + 1;
+  };
+  if ((!cv->ingrace) && 
+      (!cv->inchord || (cv->chordcount == 1))) {
+    if (cv->tuplenotes == 0) {
+      addunits(&cv->barcount, n, m);
+    } else {
+      addunits(&cv->barcount, n*cv->tuplefactor.num, m*cv->tuplefactor.denom);
+      if (nt->base_exp > -3) {
+        cv->thistuple->beamed = 0;
+      };
+      cv->tuplenotes = cv->tuplenotes - 1;
+      if (cv->tuplenotes == 0) {
+        cv->thistuple = NULL;
+        /* prevent beaming from tuple to non-tuple notes */
+        addfeature(NOBEAM, NULL);
+      };
+    };
+  };
+}
+
+/* these functions are here to satisfy the linker */
+void event_microtone(int dir, int a, int b)
+{
+}
+
+void event_normal_tone()
+{
+}
+
+
+
+void event_info_key(key, value)
+char* key;
+char* value;
+/* handles a (key,value) pair found in an I: field */
+{
+  int num;
+
+  if (strcmp(key, "clef")==0) {
+    event_clef(value);
+  };
+  if (strcmp(key, "octave")==0) {
+    num = readsnumf(value);
+    event_octave(num,0);
+  };
+}
+
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+  char *filename;
+  int i;
+
+  oldchordconvention = 0;
+  for (i=0;i<DECSIZE;i++) decorators_passback[i]=0;
+
+  event_init(argc, argv, &filename);
+  if (argc < 2) {
+    /* printf("argc = %d\n", argc); */
+  } else {
+    init_abbreviations();
+    parsefile(filename);
+    free_abbreviations();
+  };
+  return(0);
+}
+
--- abcmidi-20070318.orig/position.c
+++ abcmidi-20070318/position.c
@@ -1,495 +1,495 @@
-/*
- * yaps - program to convert abc files to PostScript.
- * Copyright (C) 1999 James Allwright
- * e-mail: J.R.Allwright@westminster.ac.uk
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/* position.c */
-/* part of YAPS - abc to PostScript converter */
-/* This file contains routines to calculate symbol positions within */
-/* a line of music. */
-
-/* for Microsoft Visual C++ 6.0 and higher */
-#ifdef _MSC_VER
-#define ANSILIBS
-#endif
-
-#include <stdio.h>
-#ifdef ANSILIBS
-#include <stdlib.h>
-#endif
-#include "abc.h"
-#include "structs.h"
-#include "sizes.h"
-
-extern struct tune thetune;
-extern double scaledwidth;
-
-static void addfract(f, n, m)
-struct fract* f;
-int n, m;
-/* add n/m to fraction pointed to by f */
-/* like addunits(), but does not use unitlength */
-{
-  f->num = n*f->denom + m*f->num;
-  f->denom = m*f->denom;
-  reducef(f);
-}
-
-static void mulfract(f, n, m)
-struct fract* f;
-int n, m;
-/* multiply  n/m to fraction pointed to by f */
-/* like addunits(), but does not use unitlength */
-{
-  f->num =   n*f->num;
-  f->denom = m*f->denom;
-  reducef(f);
-}
-
-static void advance(struct voice* v, int phase, int* items, double* itemspace, double x)
-/* move on one symbol in the specified voice */
-{
-  struct feature* p;
-  struct rest* arest;
-  struct note* anote;
-  struct fract tuplefactor, notelen;
-  int done;
-  int stepon;
-  int zerotime, newline;
-
-  switch(phase) {
-  case 1:
-    zerotime = 1;
-    newline=0;
-    break;
-  case 2:
-    zerotime = 0;
-    newline=0;
-    break;
-  case 3:
-    zerotime = 0;
-    newline=1;
-    break;
-  default:
-    printf("Internal error: phase = %d\n", phase);
-    exit(1);
-    break;
-  };
-
-  *itemspace = 0.0;
-  *items = 0;
-  p = v->place;
-  if (p == NULL) {
-    v->atlineend = 1;
-  };
-  done = 0;
-  while ((p != NULL) && (done==0)) {
-    p->x = (float) (x + p->xleft);
-    stepon = 1;
-    switch(p->type) {
-    case MUSICLINE:
-      v->inmusic = 1;
-      break;
-    case PRINTLINE:
-      v->inmusic = 0;
-      done = 1;
-      if (!newline) {
-        v->atlineend = 1;
-        stepon = 0;
-      };
-      break;
-    case CLEF:
-    case KEY:
-    case TIME:
-      if (!v->inmusic) {
-        break;
-      };
-    case SINGLE_BAR:
-    case DOUBLE_BAR:
-    case BAR_REP:
-    case REP_BAR:
-    case BAR1:
-    case REP_BAR2:
-    case DOUBLE_REP:
-    case THICK_THIN:
-    case THIN_THICK:
-      *itemspace = *itemspace +  p->xleft + p->xright;
-      *items = *items + 1;
-      if (!newline) {
-        done = 1;
-      };
-      break;
-    case REST:
-    case NOTE:
-      tuplefactor = v->tuplefactor;
-      if ((zerotime==1) && (!v->ingrace)) {
-        done = 1;
-        stepon = 0;
-      } else {
-        if ((!v->inchord)&&(!newline)) {
-          done = 1;
-        };
-        *itemspace = *itemspace +  p->xleft + p->xright;
-        *items = *items + 1;
-        if (p->type == REST) {
-          arest = p->item;
-          addfract(&v->time, arest->len.num, arest->len.denom);
-        };
-        if ((p->type == NOTE) && (!v->ingrace)) {
-          anote = p->item;
-	  notelen = anote->len;
-
- 	 if (anote->tuplenotes >0) {
-		  mulfract(&notelen,tuplefactor.num,tuplefactor.denom);
-	           }
-
-
-          addfract(&v->time, notelen.num, notelen.denom);
-/*	  printf("%c %d/%d %d/%d\n",anote->pitch,notelen.num,notelen.denom,
-			  v->time.num,v->time.denom);
-*/
-        };
-      };
-      break;
-    case CHORDON:
-      if ((zerotime==1)&&(!v->ingrace)) {
-        done = 1;
-        stepon = 0;
-      } else {
-        v->inchord = 1;
-      };
-      break;
-    case CHORDOFF:
-      if (v->inchord == 1) {
-        v->inchord = 0;
-        if ((!v->ingrace)&&(!newline)) {
-          done = 1;
-        };
-      };
-      break;
-    case GRACEON:
-      v->ingrace = 1;
-      break;
-    case GRACEOFF:
-      v->ingrace = 0;
-      break;
-    default:
-      break;
-    };
-    if (stepon) {
-      p = p->next;
-    } else {
-      done = 1;
-    };
-  };
-  v->place = p;
-  if (p == NULL) {
-    v->atlineend = 1;
-  };
-}
-
-static int gefract(struct fract* a, struct fract* b)
-/* compare two fractions  a greater than or equal to b */
-/* returns   (a >= b)                                  */
-{
-  if ((a->num*b->denom) >= (b->num*a->denom)) {
-    return(1);
-  } else {
-    return(0);
-  };
-}
-
-static int gtfract(struct fract* a, struct fract* b)
-/* compare two fractions  a greater than b */
-/* returns   (a > b)                       */
-{
-  if ((a->num*b->denom) > (b->num*a->denom)) {
-    return(1);
-  } else {
-    return(0);
-  };
-}
-
-static int spacemultiline(struct fract* mastertime, struct tune* t)
-/* calculate spacing for one line (but possibly multiple voices) */
-{
-  int i;
-  int items, thisitems, maxitems;
-  int totalitems;
-  double thiswidth, maxwidth;
-  double totalwidth;
-  double x, gap;
-  int done;
-  struct voice* v;
-  struct fract minlen;
-
-  /* two passes - on the second pass, inter-symbol spacing is */
-  /* known so elements can be given their correct x position */
-  gap = 0.0;
-  for (i=0; i<2; i++) {
-    setfract(mastertime, 0, 1);
-    v = firstitem(&t->voices);
-    while (v != NULL) {
-      v->place = v->lineplace;
-      v->ingrace = 0;
-      v->atlineend = 0;
-      setfract(&v->time, 0, 1);
-      v = nextitem(&t->voices);
-    };
-    done = 0;
-    items = 0;
-    x = 0.0;
-    totalitems = 0;
-    totalwidth = 0.0;
-    /* count up items in a line */
-    while (done == 0) {
-      maxitems = 0;
-      maxwidth = 0.0;
-      /* first do zero-time symbols */
-      v = firstitem(&t->voices);
-      while (v != NULL) {
-        if ((!v->atlineend)&&(gefract(mastertime, &v->time))) {
-          advance(v, 1, &thisitems, &thiswidth, x);
-          if (thisitems > maxitems) {
-            maxitems = thisitems;
-          };
-          if (thiswidth > maxwidth) {
-            maxwidth = thiswidth;
-          };
-        };
-        v = nextitem(&t->voices);
-      };
-      if (maxitems == 0) {
-        /* now try moving forward in time */
-        /* advance all voices at or before mastertime */
-        v = firstitem(&t->voices);
-        while (v != NULL) {
-          if ((!v->atlineend)&&(gefract(mastertime, &v->time))) {
-            advance(v, 2, &thisitems, &thiswidth, x);
-            if (thisitems > maxitems) {
-              maxitems = thisitems;
-            };
-            if (thiswidth > maxwidth) {
-              maxwidth = thiswidth;
-            };
-          };
-          v = nextitem(&t->voices);
-        };
-        /* calculate new mastertime */
-        v = firstitem(&t->voices);
-        setfract(&minlen, 0, 1);
-        done = 1;
-        while (v != NULL) {
-          if (!v->atlineend) {
-            done = 0;
-            if (minlen.num == 0) {
-              setfract(&minlen, v->time.num, v->time.denom);
-            } else {
-              if (gtfract(&minlen, &v->time)) {
-                setfract(&minlen, v->time.num, v->time.denom);
-              };
-            };
-          };
-          v = nextitem(&t->voices);
-        };
-        setfract(mastertime, minlen.num, minlen.denom);
-      };
-      totalitems = totalitems + maxitems;
-      totalwidth = totalwidth + maxwidth;
-      if (maxitems > 0) {
-        x = x + maxwidth + gap;
-      };
-    };
-    /* now calculate inter-symbol gap */
-    if (totalitems > 1) {
-      gap = (scaledwidth - totalwidth)/(totalitems-1);
-    } else {
-      gap = 1.0;
-    };
-    if (gap < 0.0) {
-      event_error("Overfull music line");
-    };
-    if (gap > MAXGAP) {
-      event_error("Underfull music line");
-      gap = MAXGAP;
-    };
-  };
-  if (totalitems == 0) {
-    return(1);
-  } else {
-    return(0);
-  };
-}
-
-void spacevoices(struct tune* t)
-{
-  struct fract mastertime;
-  int donelines;
-  struct voice* v;
-  int items;
-  double x1;
-
-  /* initialize voices */
-  v = firstitem(&t->voices);
-  while (v != NULL) {
-    v->lineplace = v->first;
-    v->inmusic=0;
-    v = nextitem(&t->voices);
-  };
-  donelines = 0;
-  while(donelines == 0) {
-    donelines = spacemultiline(&mastertime, t);
-    v = firstitem(&t->voices);
-    while (v != NULL) {
-      v->lineplace = v->place;
-      advance(v, 3, &items, &x1, 0.0);
-      v->lineplace = v->place;
-      v = nextitem(&t->voices);
-    };
-  };
-}
-
-static int spaceline(struct voice* v)
-/* allocate spare space across the width of a single stave line  */
-/* thereby fixing the x position of all notes and other elements */
-/* returns 0 when the end of the voice is reached, 1 otherwise   */
-{
-  struct feature* p;
-  double x, lastx;
-  int inmusic, items;
-  double itemspace;
-  double gap;
-
-  itemspace = 0.0;
-  items = 0;
-  inmusic = 0;
-  p = v->place;
-  while ((p != NULL) && (p->type != PRINTLINE)) {
-    switch(p->type) {
-    case MUSICLINE:
-      inmusic = 1;
-      break;
-    case PRINTLINE:
-      inmusic = 0;
-      break;
-    case CLEF:
-    case KEY:
-    case TIME:
-      if (!inmusic) {
-        break;
-      };
-    case SINGLE_BAR:
-    case DOUBLE_BAR:
-    case BAR_REP:
-    case REP_BAR:
-    case BAR1:
-    case REP_BAR2:
-    case DOUBLE_REP:
-    case THICK_THIN:
-    case THIN_THICK:
-    case REST:
-    case NOTE:
-      itemspace = itemspace +  p->xleft + p->xright;
-      items = items + 1;
-      break;
-    default:
-      break;
-    };
-    p = p->next;
-  };
-  if (items > 1) {
-    gap = (scaledwidth - itemspace)/((double)(items-1));
-  } else {
-    gap = 1.0;
-  };
-  if (gap < 0.0) {
-    event_error("Overfull music line");
-  };
-  if (gap > MAXGAP) {
-    event_error("Underfull music line");
-    gap = MAXGAP;
-  };
-  /* now assign positions */
-  x = 0.0; 
-  p = v->place;
-  inmusic = 0;
-  while ((p != NULL) && (p->type != PRINTLINE)) {
-    switch(p->type) {
-    case MUSICLINE:
-      inmusic = 1;
-      break;
-    case PRINTLINE:
-      inmusic = 0;
-      break;
-    case CHORDNOTE:
-      p->x = (float) lastx;
-      break;
-    case CLEF:
-    case KEY:
-    case TIME:
-      if (!inmusic) {
-        break;
-      };
-    case SINGLE_BAR:
-    case DOUBLE_BAR:
-    case BAR_REP:
-    case REP_BAR:
-    case BAR1:
-    case REP_BAR2:
-    case DOUBLE_REP:
-    case THICK_THIN:
-    case THIN_THICK:
-    case REST:
-    case NOTE:
-      x = x + p->xleft;
-      p->x = (float) x;
-      lastx = x;
-      x = x + p->xright + gap;
-      break;
-    default:
-      break;
-    };
-    p = p->next;
-  };
-  while ((p!=NULL)&&((p->type == PRINTLINE)||(p->type==LINENUM))) {
-    p = p->next;
-  };
-  v->place = p;
-  if (p == NULL) {
-    return(0);
-  } else {
-    return(1);
-  };
-}
-
-void monospace(struct tune* t)
-{
-  int doneline;
-  struct voice* v;
-
-  v = firstitem(&t->voices);
-  while (v != NULL) {
-    doneline = 1;
-    v->place = v->first;
-    while (doneline == 1) {
-      doneline = spaceline(v);
-    };
-    v = nextitem(&t->voices);
-  };
-}
+/*
+ * yaps - program to convert abc files to PostScript.
+ * Copyright (C) 1999 James Allwright
+ * e-mail: J.R.Allwright@westminster.ac.uk
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/* position.c */
+/* part of YAPS - abc to PostScript converter */
+/* This file contains routines to calculate symbol positions within */
+/* a line of music. */
+
+/* for Microsoft Visual C++ 6.0 and higher */
+#ifdef _MSC_VER
+#define ANSILIBS
+#endif
+
+#include <stdio.h>
+#if defined(ANSILIBS) || defined(__STDC__)
+#include <stdlib.h>
+#endif
+#include "abc.h"
+#include "structs.h"
+#include "sizes.h"
+
+extern struct tune thetune;
+extern double scaledwidth;
+
+static void addfract(f, n, m)
+struct fract* f;
+int n, m;
+/* add n/m to fraction pointed to by f */
+/* like addunits(), but does not use unitlength */
+{
+  f->num = n*f->denom + m*f->num;
+  f->denom = m*f->denom;
+  reducef(f);
+}
+
+static void mulfract(f, n, m)
+struct fract* f;
+int n, m;
+/* multiply  n/m to fraction pointed to by f */
+/* like addunits(), but does not use unitlength */
+{
+  f->num =   n*f->num;
+  f->denom = m*f->denom;
+  reducef(f);
+}
+
+static void advance(struct voice* v, int phase, int* items, double* itemspace, double x)
+/* move on one symbol in the specified voice */
+{
+  struct feature* p;
+  struct rest* arest;
+  struct note* anote;
+  struct fract tuplefactor, notelen;
+  int done;
+  int stepon;
+  int zerotime, newline;
+
+  switch(phase) {
+  case 1:
+    zerotime = 1;
+    newline=0;
+    break;
+  case 2:
+    zerotime = 0;
+    newline=0;
+    break;
+  case 3:
+    zerotime = 0;
+    newline=1;
+    break;
+  default:
+    printf("Internal error: phase = %d\n", phase);
+    exit(1);
+    break;
+  };
+
+  *itemspace = 0.0;
+  *items = 0;
+  p = v->place;
+  if (p == NULL) {
+    v->atlineend = 1;
+  };
+  done = 0;
+  while ((p != NULL) && (done==0)) {
+    p->x = (float) (x + p->xleft);
+    stepon = 1;
+    switch(p->type) {
+    case MUSICLINE:
+      v->inmusic = 1;
+      break;
+    case PRINTLINE:
+      v->inmusic = 0;
+      done = 1;
+      if (!newline) {
+        v->atlineend = 1;
+        stepon = 0;
+      };
+      break;
+    case CLEF:
+    case KEY:
+    case TIME:
+      if (!v->inmusic) {
+        break;
+      };
+    case SINGLE_BAR:
+    case DOUBLE_BAR:
+    case BAR_REP:
+    case REP_BAR:
+    case BAR1:
+    case REP_BAR2:
+    case DOUBLE_REP:
+    case THICK_THIN:
+    case THIN_THICK:
+      *itemspace = *itemspace +  p->xleft + p->xright;
+      *items = *items + 1;
+      if (!newline) {
+        done = 1;
+      };
+      break;
+    case REST:
+    case NOTE:
+      tuplefactor = v->tuplefactor;
+      if ((zerotime==1) && (!v->ingrace)) {
+        done = 1;
+        stepon = 0;
+      } else {
+        if ((!v->inchord)&&(!newline)) {
+          done = 1;
+        };
+        *itemspace = *itemspace +  p->xleft + p->xright;
+        *items = *items + 1;
+        if (p->type == REST) {
+          arest = p->item;
+          addfract(&v->time, arest->len.num, arest->len.denom);
+        };
+        if ((p->type == NOTE) && (!v->ingrace)) {
+          anote = p->item;
+	  notelen = anote->len;
+
+ 	 if (anote->tuplenotes >0) {
+		  mulfract(&notelen,tuplefactor.num,tuplefactor.denom);
+	           }
+
+
+          addfract(&v->time, notelen.num, notelen.denom);
+/*	  printf("%c %d/%d %d/%d\n",anote->pitch,notelen.num,notelen.denom,
+			  v->time.num,v->time.denom);
+*/
+        };
+      };
+      break;
+    case CHORDON:
+      if ((zerotime==1)&&(!v->ingrace)) {
+        done = 1;
+        stepon = 0;
+      } else {
+        v->inchord = 1;
+      };
+      break;
+    case CHORDOFF:
+      if (v->inchord == 1) {
+        v->inchord = 0;
+        if ((!v->ingrace)&&(!newline)) {
+          done = 1;
+        };
+      };
+      break;
+    case GRACEON:
+      v->ingrace = 1;
+      break;
+    case GRACEOFF:
+      v->ingrace = 0;
+      break;
+    default:
+      break;
+    };
+    if (stepon) {
+      p = p->next;
+    } else {
+      done = 1;
+    };
+  };
+  v->place = p;
+  if (p == NULL) {
+    v->atlineend = 1;
+  };
+}
+
+static int gefract(struct fract* a, struct fract* b)
+/* compare two fractions  a greater than or equal to b */
+/* returns   (a >= b)                                  */
+{
+  if ((a->num*b->denom) >= (b->num*a->denom)) {
+    return(1);
+  } else {
+    return(0);
+  };
+}
+
+static int gtfract(struct fract* a, struct fract* b)
+/* compare two fractions  a greater than b */
+/* returns   (a > b)                       */
+{
+  if ((a->num*b->denom) > (b->num*a->denom)) {
+    return(1);
+  } else {
+    return(0);
+  };
+}
+
+static int spacemultiline(struct fract* mastertime, struct tune* t)
+/* calculate spacing for one line (but possibly multiple voices) */
+{
+  int i;
+  int items, thisitems, maxitems;
+  int totalitems;
+  double thiswidth, maxwidth;
+  double totalwidth;
+  double x, gap;
+  int done;
+  struct voice* v;
+  struct fract minlen;
+
+  /* two passes - on the second pass, inter-symbol spacing is */
+  /* known so elements can be given their correct x position */
+  gap = 0.0;
+  for (i=0; i<2; i++) {
+    setfract(mastertime, 0, 1);
+    v = firstitem(&t->voices);
+    while (v != NULL) {
+      v->place = v->lineplace;
+      v->ingrace = 0;
+      v->atlineend = 0;
+      setfract(&v->time, 0, 1);
+      v = nextitem(&t->voices);
+    };
+    done = 0;
+    items = 0;
+    x = 0.0;
+    totalitems = 0;
+    totalwidth = 0.0;
+    /* count up items in a line */
+    while (done == 0) {
+      maxitems = 0;
+      maxwidth = 0.0;
+      /* first do zero-time symbols */
+      v = firstitem(&t->voices);
+      while (v != NULL) {
+        if ((!v->atlineend)&&(gefract(mastertime, &v->time))) {
+          advance(v, 1, &thisitems, &thiswidth, x);
+          if (thisitems > maxitems) {
+            maxitems = thisitems;
+          };
+          if (thiswidth > maxwidth) {
+            maxwidth = thiswidth;
+          };
+        };
+        v = nextitem(&t->voices);
+      };
+      if (maxitems == 0) {
+        /* now try moving forward in time */
+        /* advance all voices at or before mastertime */
+        v = firstitem(&t->voices);
+        while (v != NULL) {
+          if ((!v->atlineend)&&(gefract(mastertime, &v->time))) {
+            advance(v, 2, &thisitems, &thiswidth, x);
+            if (thisitems > maxitems) {
+              maxitems = thisitems;
+            };
+            if (thiswidth > maxwidth) {
+              maxwidth = thiswidth;
+            };
+          };
+          v = nextitem(&t->voices);
+        };
+        /* calculate new mastertime */
+        v = firstitem(&t->voices);
+        setfract(&minlen, 0, 1);
+        done = 1;
+        while (v != NULL) {
+          if (!v->atlineend) {
+            done = 0;
+            if (minlen.num == 0) {
+              setfract(&minlen, v->time.num, v->time.denom);
+            } else {
+              if (gtfract(&minlen, &v->time)) {
+                setfract(&minlen, v->time.num, v->time.denom);
+              };
+            };
+          };
+          v = nextitem(&t->voices);
+        };
+        setfract(mastertime, minlen.num, minlen.denom);
+      };
+      totalitems = totalitems + maxitems;
+      totalwidth = totalwidth + maxwidth;
+      if (maxitems > 0) {
+        x = x + maxwidth + gap;
+      };
+    };
+    /* now calculate inter-symbol gap */
+    if (totalitems > 1) {
+      gap = (scaledwidth - totalwidth)/(totalitems-1);
+    } else {
+      gap = 1.0;
+    };
+    if (gap < 0.0) {
+      event_error("Overfull music line");
+    };
+    if (gap > MAXGAP) {
+      event_error("Underfull music line");
+      gap = MAXGAP;
+    };
+  };
+  if (totalitems == 0) {
+    return(1);
+  } else {
+    return(0);
+  };
+}
+
+void spacevoices(struct tune* t)
+{
+  struct fract mastertime;
+  int donelines;
+  struct voice* v;
+  int items;
+  double x1;
+
+  /* initialize voices */
+  v = firstitem(&t->voices);
+  while (v != NULL) {
+    v->lineplace = v->first;
+    v->inmusic=0;
+    v = nextitem(&t->voices);
+  };
+  donelines = 0;
+  while(donelines == 0) {
+    donelines = spacemultiline(&mastertime, t);
+    v = firstitem(&t->voices);
+    while (v != NULL) {
+      v->lineplace = v->place;
+      advance(v, 3, &items, &x1, 0.0);
+      v->lineplace = v->place;
+      v = nextitem(&t->voices);
+    };
+  };
+}
+
+static int spaceline(struct voice* v)
+/* allocate spare space across the width of a single stave line  */
+/* thereby fixing the x position of all notes and other elements */
+/* returns 0 when the end of the voice is reached, 1 otherwise   */
+{
+  struct feature* p;
+  double x, lastx = 0.0;
+  int inmusic, items;
+  double itemspace;
+  double gap;
+
+  itemspace = 0.0;
+  items = 0;
+  inmusic = 0;
+  p = v->place;
+  while ((p != NULL) && (p->type != PRINTLINE)) {
+    switch(p->type) {
+    case MUSICLINE:
+      inmusic = 1;
+      break;
+    case PRINTLINE:
+      inmusic = 0;
+      break;
+    case CLEF:
+    case KEY:
+    case TIME:
+      if (!inmusic) {
+        break;
+      };
+    case SINGLE_BAR:
+    case DOUBLE_BAR:
+    case BAR_REP:
+    case REP_BAR:
+    case BAR1:
+    case REP_BAR2:
+    case DOUBLE_REP:
+    case THICK_THIN:
+    case THIN_THICK:
+    case REST:
+    case NOTE:
+      itemspace = itemspace +  p->xleft + p->xright;
+      items = items + 1;
+      break;
+    default:
+      break;
+    };
+    p = p->next;
+  };
+  if (items > 1) {
+    gap = (scaledwidth - itemspace)/((double)(items-1));
+  } else {
+    gap = 1.0;
+  };
+  if (gap < 0.0) {
+    event_error("Overfull music line");
+  };
+  if (gap > MAXGAP) {
+    event_error("Underfull music line");
+    gap = MAXGAP;
+  };
+  /* now assign positions */
+  x = 0.0; 
+  p = v->place;
+  inmusic = 0;
+  while ((p != NULL) && (p->type != PRINTLINE)) {
+    switch(p->type) {
+    case MUSICLINE:
+      inmusic = 1;
+      break;
+    case PRINTLINE:
+      inmusic = 0;
+      break;
+    case CHORDNOTE:
+      p->x = (float) lastx;
+      break;
+    case CLEF:
+    case KEY:
+    case TIME:
+      if (!inmusic) {
+        break;
+      };
+    case SINGLE_BAR:
+    case DOUBLE_BAR:
+    case BAR_REP:
+    case REP_BAR:
+    case BAR1:
+    case REP_BAR2:
+    case DOUBLE_REP:
+    case THICK_THIN:
+    case THIN_THICK:
+    case REST:
+    case NOTE:
+      x = x + p->xleft;
+      p->x = (float) x;
+      lastx = x;
+      x = x + p->xright + gap;
+      break;
+    default:
+      break;
+    };
+    p = p->next;
+  };
+  while ((p!=NULL)&&((p->type == PRINTLINE)||(p->type==LINENUM))) {
+    p = p->next;
+  };
+  v->place = p;
+  if (p == NULL) {
+    return(0);
+  } else {
+    return(1);
+  };
+}
+
+void monospace(struct tune* t)
+{
+  int doneline;
+  struct voice* v;
+
+  v = firstitem(&t->voices);
+  while (v != NULL) {
+    doneline = 1;
+    v->place = v->first;
+    while (doneline == 1) {
+      doneline = spaceline(v);
+    };
+    v = nextitem(&t->voices);
+  };
+}
--- abcmidi-20070318.orig/toabc.c
+++ abcmidi-20070318/toabc.c
@@ -1,2370 +1,2373 @@
-/*
- * toabc.c - part of abc2abc - program to manipulate abc files.
- * Copyright (C) 1999 James Allwright
- * e-mail: J.R.Allwright@westminster.ac.uk
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/* back-end for outputting (possibly modified) abc */
-
-#define VERSION "1.56 December 21 2006"
-
-/* for Microsoft Visual C++ 6.0 or higher */
-#ifdef _MSC_VER
-#define ANSILIBS
-#endif
-
-#include "abc.h"
-#include "parseabc.h"
-#include <stdio.h>
-
-/* define USE_INDEX if your C libraries have index() instead of strchr() */
-#ifdef USE_INDEX
-#define strchr index
-#endif
-
-#ifdef ANSILIBS
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#else
-extern char* strchr();
-#endif
-
-#define MAX_VOICES 30
-/* should be plenty! */
-
-programname fileprogram = ABC2ABC;
-extern int oldchordconvention; /* for handling +..+ chords */
-
-struct fract {
-  int num;
-  int denom;
-};
-struct fract barlen; /* length of a bar as given by the time signature */
-struct fract unitlen; /* unit length as given by the L: field */
-struct fract count; /* length of bar so far */
-struct fract prevcount; /* length of bar before last increment */
-struct fract tuplefactor; /* factor associated with a tuple (N */
-struct fract breakpoint; /* used to break bar into beamed sets of notes */
-int barno; /* number of bar within tune */
-int newspacing; /* was -s option selected ? */
-int barcheck, repcheck; /* indicate -b and -r options selected */
-int echeck; /* was error-checking turned off ? (-e option) */
-int newbreaks; /* was -n option selected ? */
-int nodouble_accidentals;
-int totalnotes, notecount; 
-int bars_per_line; /* number supplied after -n option */
-int barcount;
-int expect_repeat;
-int tuplenotes, barend;
-int xinhead, xinbody; /* are we in head or body of abc tune ? */
-int inmusic; /* are we in a line of notes (in the tune body) ? */
-int startline, blankline;
-int transpose; /* number of semitones to transpose by (-t option) */
-struct fract lenfactor; /* fraction to scale note lengths; -v,-d options */
-int newkey; /* key after transposition (expressed as no. of sharps) */
-int lines; /* used by transposition */
-int orig_key_number; /* used for gchord transposition */
-int new_key_number;  /* used for gchord transposition */
-int oldtable[7], newtable[7]; /* for handling transposition */
-int inchord; /* are we in a chord [ ] ? */
-int ingrace; /* are we in a grace note set { } ? */
-int chordcount; /* number of notes or rests in current chord */
-int inlinefield; /* boolean - are we in [<field>: ] ? */
-int cleanup; /* boolean to indicate -u option (update notation) */
-char tmp[2000]; /* buffer to hold abc output being assembled */
-int output_on = 1;  /* if 0 suppress output */
-int selected_voice = -1; /* no voice was selected */
-int newrefnos; /* boolean for -X option (renumber X: fields) */
-int newref; /* next new number for X: field */
-int useflats=0; /* flag associated with nokey.*/ 
-int adapt_useflats_to_gchords = 1; /* experimental flag */
-int usekey = 0;
-int drumchan=0; /* flag to suppress transposition */
-
-extern int nokey; /* signals no key signature assumed */
-extern int voicecodes ;  /* from parseabc.c */
-extern char voicecode[16][30]; /*for interpreting V: string */
- 
-struct voicetype { /* information needed for each voice */
-  int number; /* voice number from V: field */
-  int barcount;
-  int foundbar;
-  struct abctext* currentline;
-  int bars_remaining;
-  int bars_complete;
-  int drumchan;
-} voice[MAX_VOICES];
-int voicecount, this_voice, next_voice;
-enum abctype {field, bar, barline};
-/* linestat is used by -n for deciding when to generate a newline */
-enum linestattype {fresh, midmusic, endmusicline, postfield};
-enum linestattype linestat; 
-/* struct abctext is used to store abc lines for re-formatting (-n option) */
-struct lyricwords{
-  struct lyricwords* nextverse;
-  char* words;
-};  
-struct abctext{ /* linked list used to store output before re-formatting */
-  struct abctext* next;
-  char* text;
-  enum abctype type;
-  int notes;
-  struct lyricwords* lyrics;
-};
-struct abctext* head;
-struct abctext* tail;
-
-extern char *mode[];
-extern int modekeyshift[];
-int basemap[7], workmap[7]; /* for -nokey and pitchof() */
-int  workmul[7];
-void copymap();
-void printpitch(int);
-void setup_sharps_flats (int sf);
-int pitchof(char note,int accidental,int mult,int octave);
-
-
-static int purgespace(p)
-char* p;
-/* if string p is empty or consists of spaces, set p to the empty string */
-/* and return 1, otherwise return 0. Used to test tmp */
-/* part of new linebreak option (-n) */
-{
-  int blank;
-  char *s;
-
-  blank = 1;
-  s = p;
-  while (*s != '\0') {
-    if (*s != ' ') blank = 0;
-    s = s + 1;
-  };
-  if (blank) {
-    *p = '\0';
-  };
-  return(blank);
-}
-
-int zero_barcount(foundbar)
-/* initialize bar counter for abctext elements */
-/* part of new linebreak option (-n) */
-int *foundbar;
-{
-  *foundbar = 0;
-  return(0);
-}
-
-int new_barcount(type, foundbar, oldcount)
-enum abctype type;
-int *foundbar;
-int oldcount;
-/* work out whether we have reached the end of a bar in abctext elements */
-/* and increment barcount if we have */
-/* part of new linebreak option (-n) */
-{
-  int new_value;
-
-  new_value = oldcount;
-  if (type == bar) {
-    *foundbar = 1;
-  };
-  if ((type == barline) && (*foundbar == 1)) {
-    new_value = new_value + 1;
-    *foundbar = 0;
-  };
-  return(new_value);
-}
-
-
-static void setline(t)
-enum linestattype t;
-/* generates newline, or continuation, or nothing at all */
-/* part of new linebreak option (-n) */
-{
-  if ((t == fresh) && ((linestat == postfield) || (linestat == endmusicline))) {
-    printf("\n");
-  };
-  if ((t == fresh) && (linestat == midmusic)) {
-    printf("\\\n");
-  };
-  linestat = t;
-}
-
-static int flush_abctext(bars, termination)
-int bars;
-enum linestattype termination;
-/* outputs up to the specified number of bars of stored music */
-/* and frees up the storage allocated for those bars. */
-/* returns the number of bars actually output */
-/* part of new linebreak option (-n) */
-{
-  struct abctext *p, *nextp;
-  struct lyricwords *q, *r;
-  struct lyricwords *barlyrics;
-  int count, donewords, wordline;
-  int i, foundtext;
-  int foundbar;
-
-  /* printf("flush_abctext called\n"); */
-  /* print music */
-  p = head;
-  count = zero_barcount(&foundbar);
-  while ((p != NULL) && (count < bars)) {
-    if (p->type == field) {
-      setline(fresh);
-    };
-    printf("%s", p->text);
-    if (p->type == field) {
-      setline(postfield);
-      setline(fresh);
-    } else {
-      setline(midmusic);
-    };
-    count = new_barcount(p->type, &foundbar, count);
-    if ((count == bars) && (p->type == barline)) {
-      setline(endmusicline);
-    };
-    p = p->next;
-  };
-  if (linestat == midmusic) {
-    setline(termination);
-  };
-  if (bars > 0) {
-    /* print out any w: lines */
-    donewords = 0;
-    wordline = 0;
-    while (donewords == 0) {
-      p = head;
-      foundtext = 0;
-      count = zero_barcount(&foundbar);
-      while ((p != NULL) && (count < bars)) {
-        barlyrics = p->lyrics;
-        for (i=0; i<wordline; i++) {
-          if (barlyrics != NULL) {
-            barlyrics = barlyrics->nextverse;
-          };
-        };
-        if (barlyrics != NULL) {
-          if (foundtext == 0) {
-            setline(fresh);
-            printf("w:");
-            foundtext = 1;
-          };
-          printf(barlyrics->words);
-        };
-        count = new_barcount(p->type, &foundbar, count);
-        p = p->next;
-      };
-      if (foundtext == 0) {
-        donewords = 1;
-      } else {
-        setline(postfield);
-        setline(fresh);
-      };
-      wordline = wordline + 1;
-    };
-  };
-  /* move head on and free up space used by stuff printed out */
-  count = zero_barcount(&foundbar);
-  p = head;
-  foundbar = 0;
-  while ((p != NULL) && (count < bars)) {
-    if (p != NULL) {
-      free(p->text);
-      q = p->lyrics;
-      while (q != NULL) {
-        free(q->words);
-        r = q->nextverse;
-        free(q);
-        q = r;
-      };
-      count = new_barcount(p->type, &foundbar, count);
-      nextp = p->next;
-      free(p);
-      p = nextp;
-    };
-    head = p;
-  };
-  if (head == NULL) {
-    tail = NULL;
-  };
-  return(count);
-}
-
-void complete_bars(v)
-/* mark all bars as completed (i.e. having associated w: fields parsed) */
-/* and out put all music lines which contain the full set of bars */
-/* part of new linebreak option (-n) */
-struct voicetype *v;
-{
-  int bars_done;
-
-  v->bars_complete = v->bars_complete + v->barcount;
-  v->barcount = 0;
-  while (v->bars_complete > v->bars_remaining) {
-    bars_done = flush_abctext(v->bars_remaining, endmusicline);
-    setline(fresh);
-    v->bars_complete = v->bars_complete - bars_done;
-    v->bars_remaining = v->bars_remaining - bars_done;
-    if (v->bars_remaining == 0) {
-      v->bars_remaining = bars_per_line;
-    };
-  };
-}
-
-void complete_all(v, termination)
-struct voicetype *v;
-enum linestattype termination;
-/* output all remaining music and fields */
-/* part of new linebreak option (-n) */
-{
-  int bars_done;
-
-  complete_bars(v);
-  bars_done = flush_abctext(v->bars_remaining+1, termination);
-  v->bars_complete = v->bars_complete - bars_done;
-  v->bars_remaining = v->bars_remaining - bars_done;
-  if (v->bars_remaining == 0) {
-    v->bars_remaining = bars_per_line;
-  };
-  head = NULL;
-  tail = NULL;
-  voice[this_voice].currentline = NULL;
-}
-
-static struct abctext* newabctext(t)
-enum abctype t;
-/* called at newlines and barlines */
-/* adds current output text to linked list structure */
-/* part of new linebreak option (-n) */
-{
-  struct abctext* p;
-
-  if (output_on == 0) {
-    p = NULL;
-    return(p);
-  };
-  if (newbreaks) {
-/*
-    if ((t == field) && (!xinbody || (this_voice != next_voice))) {
-*/
-    if (t == field) {
-      complete_all(&voice[this_voice], midmusic);
-      this_voice = next_voice;
-    };
-    p = (struct abctext*) checkmalloc(sizeof(struct abctext));
-    p->text = addstring(tmp);
-    tmp[0] = '\0';
-    p->next = NULL;
-    p->type = t;
-    p->lyrics = NULL;
-    if (t == bar) {
-      p->notes = notecount;
-      totalnotes = totalnotes + notecount;
-      notecount = 0;
-    } else {
-      p->notes = 0;
-    };
-    if (xinbody) {
-      voice[this_voice].barcount = new_barcount(t, 
-                       &voice[this_voice].foundbar, 
-                        voice[this_voice].barcount);
-    };
-    if (head == NULL) {
-      head = p;
-      tail = p;
-    } else {
-      tail->next = p;
-      tail = p;
-    };
-    if ((t != field) && (voice[this_voice].currentline == NULL)) {
-      voice[this_voice].currentline = p;
-    };
-  } else {
-    printf("%s", tmp);
-    tmp[0] = '\0';
-    p = NULL;
-  };
-  inmusic = 1;
-  return(p);
-}
-
-static int nextnotes()
-/* return the number of notes in the next bar */
-/* part of new linebreak option (-n) */
-{
-  int n, got;
-  struct abctext* p;
-
-  p = head;
-  n = 100;
-  got = 0;
-  while ((p != NULL) && (!got)) {
-    if (p->type == bar) {
-      n = p->notes;
-      got = 1;
-    } else {
-      p = p->next;
-    };
-  };
-  return(n);
-}
-
-static void reduce(a, b)
-int *a, *b;
-{
-  int t, n, m;
-
-  /* find HCF using Euclid's algorithm */
-  if (*a > *b) {
-    n = *a;
-    m = *b;
-  } else {
-    n = *b;
-    m = *a;
-  };
-  while (m != 0) {
-    t = n % m;
-    n = m;
-    m = t;
-  };
-  *a = *a/n;
-  *b = *b/n;
-}
-
-
-static void addunits(n, m)
-int n, m;
-/* add fraction n/m to count */
-{
-  prevcount = count;  /* in case of chord extension eg [CE]3/2 */
-  count.num = n*count.denom + count.num*(m*unitlen.denom);
-  count.denom = (m*unitlen.denom)*count.denom;
-  reduce(&count.num, &count.denom);
-}
-
-static void repudiate_lastaddunits()
-{
-  count = prevcount;
-}
-
-void event_init(argc, argv, filename)
-int argc;
-char* argv[];
-char** filename;
-/* routine called on program start-up */
-{
-  int targ, narg;
-
-  if ((getarg("-h", argc, argv) != -1) || (argc < 2)) {
-    printf("abc2abc version %s\n",VERSION);
-    printf("Usage: abc2abc <filename> [-s] [-n X] [-b] [-r] [-e] [-t X]\n");
-    printf("       [-u] [-d] [-v] [-V X] [-ver] [-X n]\n");
-    printf("  -s for new spacing\n");
-    printf("  -n X to re-format the abc with a new linebreak every X bars\n");
-    printf("  -b to remove bar checking\n");
-    printf("  -r to remove repeat checking\n");
-    printf("  -e to remove all error reports\n");
-    printf("  -t X to transpose X semitones\n");
-    printf("  -nda No double accidentals in guitar chords\n");
-    printf("  -nokeys No key signature. Use sharps\n");
-    printf("  -nokeyf No key signature. Use flats\n");
-    printf("  -u to update notation ([] for chords and () for slurs)\n");
-    printf("  -usekey n Use key signature sf (sharps/flats)\n");
-    printf("  -d to notate with doubled note lengths\n");
-    printf("  -v to notate with halved note lengths\n");
-    printf("  -V X to output only voice X\n");
-    printf("  -ver  prints version number and exits\n");
-    printf("  -X n renumber the all X: fields as n, n+1, ..\n");
-    printf("  -OCC old chord convention (eg. +CE+)\n");
-
-    exit(0);
-  } else {
-    *filename = argv[1];
-  };
-  nodouble_accidentals = 0;   /* use correct guitar chords */
-  if (getarg("-ver",argc,argv) != -1) {
-	  printf("%s\n",VERSION);
-	  exit(0);
-  }
-  if (getarg("-u", argc, argv) == -1) {
-    cleanup = 0;
-  } else {
-    cleanup = 1;
-    oldchordconvention = 1;
-  };
-  if (getarg("-s", argc, argv) == -1) {
-    newspacing = 0;
-  } else {
-    newspacing = 1;
-  };
-  narg = getarg("-X", argc, argv);
-  if (narg == -1) {
-    newrefnos = 0;
-  } else {
-    newrefnos = 1;
-    if (narg < argc) {
-      newref = readnumf(argv[narg]);
-    } else {
-      newref = 1;
-    };
-  };
-  if (getarg("-e", argc, argv) == -1) {
-    echeck = 1;
-  } else {
-    echeck = 0;
-  };
-  narg = getarg("-n", argc, argv);
-  if (narg == -1) {
-    newbreaks = 0;
-  } else {
-    newbreaks = 1;
-    if (narg >= argc) {
-      event_error("No value for bars per line after -n");
-      bars_per_line = 4;
-    } else {
-      bars_per_line = readnumf(argv[narg]);
-      if (bars_per_line < 1) {
-        bars_per_line = 4;
-      };
-    };
-  };
-  if (getarg("-b", argc, argv) != -1) {
-    barcheck = 0;
-  } else {
-    barcheck = 1;
-  };
-  if (getarg("-r", argc, argv) != -1) {
-    repcheck = 0;
-  } else {
-    repcheck = 1;
-  };
-  if (getarg("-v", argc, argv) != -1) {
-    lenfactor.num = 1;
-    lenfactor.denom = 2;
-  } else {
-    if (getarg("-d", argc, argv) != -1) {
-      lenfactor.num = 2;
-      lenfactor.denom = 1;
-    } else {
-      lenfactor.num = 1;
-      lenfactor.denom = 1;
-    };
-  };
-  targ = getarg("-t", argc, argv);
-  if (targ == -1) {
-    transpose = 0;
-  } else {
-    if (targ >= argc) {
-      event_error("No tranpose value supplied");
-    } else {
-      if (*argv[targ] == '-') {
-        transpose = -readnumf(argv[targ]+1);
-      } else {
-        transpose = readnumf(argv[targ]);
-      };
-    };
-  };
-  targ = getarg("-nda",argc,argv);
-  if (targ != -1) nodouble_accidentals = 1;
-
-  targ = getarg("-nokeys",argc,argv);
-  if (targ != -1) nokey=1;
-
-  targ = getarg("-nokeyf",argc,argv);
-  if (targ != -1) {nokey=1; useflats=1;}
-
-  targ = getarg("-V", argc, argv);
-  if (targ != -1) {
-    selected_voice  = readnumf(argv[targ]);
-  };
-
-  targ = getarg("-usekey",argc,argv);
-  if (targ != -1) {
-     usekey = readsnumf(argv[targ]);
-     nokey = 1;
-     if (usekey < 0) useflats=1;
-     if (usekey <-5) usekey = -5;
-     if (usekey >5) usekey = 5;
-     setup_sharps_flats (usekey);
-     }
-  if (getarg("-OCC",argc,argv) != -1) oldchordconvention=1;
-
-  /* printf("%% output from abc2abc\n"); */
-  startline = 1;
-  blankline = 0;
-  xinbody =0;
-  inmusic = 0;
-  inchord = 0;
-  ingrace = 0;
-  head = NULL;
-  tail = NULL;
-  tmp[0] = '\0';
-  totalnotes = 0;
-}
-
-void emit_string(s)
-char *s;
-/* output string */
-{
-  if (output_on) {
-    strcpy(tmp+strlen(tmp), s);
-  };
-}
-
-void emit_char(ch)
-char ch;
-/* output single character */
-{
-  char *place;
-
-  if (output_on) {
-    place = tmp+strlen(tmp);
-    *place = ch;
-    *(place+1) = '\0';
-  };
-}
-
-void emit_int(n)
-int n;
-/* output integer */
-{
-  if (output_on) {
-    sprintf(tmp+strlen(tmp), "%d", n);
-  };
-}
-
-void emit_string_sprintf(s1, s2)
-char *s1;
-char *s2;
-/* output string containing string expression %s */
-{
-  if (output_on) {
-    sprintf(tmp+strlen(tmp), s1, s2);
-  };
-}
-
-void emit_int_sprintf(s, n)
-char *s;
-int n;
-/* output string containing int expression %d */
-{
-  if (output_on) {
-    sprintf(tmp+strlen(tmp), s, n);
-  };
-}
-
-void unemit_inline()
-/* remove previously output start of inline field */
-/* needed for -V voice selection option           */
-{
-  int len;
-
-  len = strlen(tmp);
-  if ((len > 0) && (tmp[len-1] == '[')) {
-    tmp[len-1] = '\0'; /* delete last character */
-  } else {
-    event_error("Internal error - Could not delete [");
-  };
-}
-
-static void close_newabc()
-/* output all remaining abc_text elements */
-/* part of new linebreak option (-n) */
-{
-  if (newbreaks) {
-    complete_all(&voice[this_voice], endmusicline);
-    if (linestat == midmusic) setline(endmusicline);
-    setline(fresh);
-  };
-}
-
-void event_eof()
-{
-  close_newabc();
-}
-
-void event_blankline()
-{
-  output_on = 1;
-  close_newabc();
-/*  if (newbreaks) [SS] 2006-09-23 */  printf("\n");
-  xinbody = 0;
-  xinhead = 0;
-  parseroff();
-  blankline = 1;
-}
-
-void event_text(p)
-char *p;
-{
-  emit_string_sprintf("%%%s", p);
-  inmusic = 0;
-}
-
-void event_reserved(p)
-char p;
-{
-  emit_char(p);
-  inmusic = 0;
-}
-
-void event_tex(s)
-char *s;
-{
-  emit_string(s);
-  inmusic = 0;
-}
-
-void event_linebreak()
-{
-  if (newbreaks) {
-    if (!purgespace(tmp)) {
-      if (inmusic) {
-        newabctext(bar);
-      } else {
-        newabctext(field);
-      };
-    };
-  } else {
-    newabctext(bar);
-    if (output_on) {
-      printf("\n");
-    };
-    /* don't output new line if voice is already suppressed
-       otherwise we will get lots of blank lines where we
-       are suppressing output. [SS] feb-10-2002.
-     */
-  };
-}
-
-void event_startmusicline()
-/* encountered the start of a line of notes */
-{
-  voice[this_voice].currentline = NULL;
-  complete_bars(&voice[this_voice]);
-}
-
-void event_endmusicline(endchar)
-char endchar;
-/* encountered the end of a line of notes */
-{
-}
-
-void event_error(s)
-char *s;
-{
-  if (echeck) {
-   printf("\n%%Error : %s\n", s);
-  };
-}
-
-void event_warning(s)
-char *s;
-{
-  if (echeck) {
-   printf("\n%%Warning : %s\n", s);
-  };
-}
-
-void event_comment(s)
-char *s;
-{
-  if (newbreaks && (!purgespace(tmp))) {
-    if (inmusic) {
-      newabctext(bar);
-    } else {
-      newabctext(field);
-    };
-  };
-  emit_string_sprintf("%%%s", s);
-  inmusic = 0;
-}
-
-void event_specific(package, s)
-char *package, *s;
-{
-  char command[40];
-  int ch;
-  char *p;
-  emit_string("%%");
-  emit_string(package);
-  emit_string(s);
-  inmusic = 0;
-/* detect drum channel by searching for %%MIDI channel 10 */
-  if (strcmp(package,"MIDI") != 0) return;
-  p = s;
-  skipspace(&p);
-  readstr(command, &p, 40);
-  if (strcmp(command, "channel") != 0) return;
-  skipspace(&p);
-  ch = readnump(&p);
-  if(ch == 10) {
-               voice[next_voice].drumchan = 1;
-               drumchan = 1;
-               }
-/*  printf("event_specific: next_voice = %d\n",next_voice); */
-}
-
-void event_info(f)
-/* handles info field I: */
-char *f;
-{
-  emit_string_sprintf("I:%s", f);
-  inmusic = 0;
-}
-
-
-void event_field(k, f)
-char k;
-char *f;
-{
-  emit_char(k);
-  emit_char(':');
-  emit_string(f);
-  inmusic = 0;
-}
-
-struct abctext* getbar(place)
-struct abctext *place;
-/* find first element in list which is a bar of music */
-{
-  struct abctext *newplace;
-
-  newplace = place;
-  while ((newplace != NULL) &&
-         ((newplace->type != bar) || 
-          (newplace->notes == 0))) {
-    newplace = newplace->next;
-  };
-  return(newplace);    
-}
-
-struct abctext* getnextbar(place)
-struct abctext *place;
-/* find next element in list which is a bar of music */
-{
-  struct abctext *newplace;
-
-  newplace = place;
-  if (newplace != NULL) {
-    newplace = getbar(newplace->next);
-  };
-  return(newplace);
-};
-
-void append_lyrics(place, newwords)
-struct abctext *place;
-char *newwords;
-/* add lyrics to end of lyric list associated with bar */
-{
-  struct lyricwords* new_words;
-  struct lyricwords *new_place;
-
-  if (place == NULL) {
-    return;
-  };
-  /* printf("append_lyrics has %s at %s\n", newwords, place->text); */
-  new_words = (struct lyricwords*)checkmalloc(sizeof(struct lyricwords));
-  /* add words to bar */
-  new_words->nextverse = NULL;
-  new_words->words = addstring(newwords);
-  if (place->lyrics == NULL) {
-    place->lyrics = new_words;
-  } else {
-    new_place = place->lyrics;
-    /* find end of list */
-    while (new_place->nextverse != NULL) {
-      new_place = new_place->nextverse;
-    };
-    new_place->nextverse = new_words;
-  };
-}
-
-struct abctext* apply_bar(syll, place, notesleft, barwords)
-/* advance to next bar (on finding '|' in a w: field) */
-char* syll;
-struct abctext *place;
-int *notesleft;
-struct vstring *barwords;
-{
-  struct abctext* new_place;
-
-  if (place == NULL) {
-    return(NULL);
-  };
-  new_place = place;
-  addtext(syll, barwords);
-  append_lyrics(place, barwords->st);
-  /* go on to next bar */
-  clearvstring(barwords);
-  new_place = getnextbar(place);
-  if (new_place != NULL) {
-    *notesleft = new_place->notes;
-  };
-  return(new_place); 
-}
-
-struct abctext* apply_syllable(syll, place, notesleft, barwords)
-/* attach syllable to appropriate place in abctext structure */
-char* syll;
-struct abctext *place;
-int *notesleft;
-struct vstring *barwords;
-{
-  struct abctext* new_place;
-  char msg[80];
-
-  if (place == NULL) {
-    sprintf(msg, "Cannot find note to match \"%s\"", syll);
-    event_error(msg);
-    return(NULL);
-  };
-  new_place = place;
-  addtext(syll, barwords);
-  *notesleft = *notesleft - 1;
-  if (*notesleft == 0) {
-    append_lyrics(place, barwords->st);
-    /* go on to next bar */
-    clearvstring(barwords);
-    new_place = getnextbar(place);
-    if (new_place != NULL) {
-      *notesleft = new_place->notes;
-    };
-  };
-  return(new_place); 
-}
-
-void parse_words(p)
-char* p;
-/* Break up a line of lyrics (w: ) into component syllables */
-{
-  struct vstring syll;
-  struct vstring barwords;
-  char* q;
-  unsigned char ch;
-  int errors;
-  int found_hyphen;
-
-  struct abctext *place;
-  int notesleft;
-
-  if (!xinbody) {
-    event_error("w: field outside tune body");
-    return;
-  };
-  place = getbar(voice[this_voice].currentline);
-  if (place == NULL) {
-    event_error("No music to match w: line to");
-    return;
-  };
-  notesleft = voice[this_voice].currentline->notes;
-  initvstring(&barwords);
-  errors = 0;
-  if (place == NULL) {
-    event_error("No notes to match words");
-    return;
-  };
-  initvstring(&syll);
-  q = p;
-  skipspace(&q);
-  while (*q != '\0') {
-    found_hyphen = 0;
-    clearvstring(&syll);
-    ch = *q;
-    while(ch=='|') {
-      addch('|', &syll);
-      addch(' ', &syll);
-      place = apply_bar(syll.st, place, &notesleft, &barwords);
-      clearvstring(&syll);
-      q++;
-      ch = *q;
-    };
-    /* PCC seems to require (ch != ' ') on the next line */
-    /* presumably PCC's version of ispunct() thinks ' ' is punctuation */
-    while (((ch>127)||isalnum(ch)||ispunct(ch))&&(ch != ' ')&&
-           (ch != '_')&&(ch != '-')&&(ch != '*')&& (ch != '|')) {
-      if ((ch == '\\') && (*(q+1)=='-')) {
-        addch('\\', &syll);
-        ch = '-';
-        q++;
-      };
-      /* syllable[i] = ch; */
-      addch(ch, &syll);
-      q++;
-      ch = *q;
-    };
-    skipspace(&q);
-    if (ch == '-') {
-      found_hyphen = 1;
-      addch(ch, &syll);
-      while (isspace(ch)||(ch=='-')) {
-        q++;
-        ch = *q;
-      };
-    };
-    if (syll.len > 0) {
-      if (!found_hyphen) {
-        addch(' ', &syll);
-      };
-      place = apply_syllable(syll.st, place, &notesleft, &barwords);
-    } else {
-      if (ch=='_') {
-        clearvstring(&syll);
-        addch('_', &syll);
-        addch(' ', &syll);
-        place = apply_syllable(syll.st, place, &notesleft, &barwords);
-        q++;
-        ch = *q;
-      };
-      if (ch=='*') {
-        clearvstring(&syll);
-        addch('*', &syll);
-        addch(' ', &syll);
-        place = apply_syllable(syll.st, place, &notesleft, &barwords);
-        q++;
-        ch = *q;
-      };
-    }; 
-  };
-  if (errors > 0) {
-    event_error("Lyric line too long for music");
-  } else {
-    clearvstring(&syll);
-  };
-  freevstring(&syll);
-}
-
-void event_words(p, continuation)
-char* p;
-int continuation;
-/* a w: field has been encountered */
-{
-  struct vstring afield;
-
-  if (xinbody && newbreaks) {
-    parse_words(p);
-  } else {
-    initvstring(&afield);
-    addtext(p, &afield);
-    if (continuation) {
-      addch(' ', &afield);
-      addch('\\', &afield);
-    };
-    event_field('w', afield.st);
-  };
-}
-
-void event_part(s)
-char* s;
-{
-  if (xinbody) {
-    complete_bars(&voice[this_voice]);
-  };
-  emit_string_sprintf("P:%s", s);
-  inmusic = 0;
-}
-
-int setvoice(num)
-int num;
-/* we need to keep track of current voice for new linebreak handling (-n) */
-/* change voice to num. If voice does not exist, start new one */
-{
-  int i, voice_index;
-
-  i = 0;
-  while ((i < voicecount) && (voice[i].number != num)) {
-    i = i + 1;
-  };
-  if ((i < voicecount) && (voice[i].number == num)) {
-    voice_index = i;
-    drumchan = voice[voice_index].drumchan;
-/*    printf("voice_index = %d drumchan = %d\n",voice_index,drumchan); */
-  } else {
-    voice_index = voicecount;
-    if (voicecount < MAX_VOICES) {
-      voicecount = voicecount + 1;
-    } else {
-      event_error("Number of voices exceeds static limit MAX_VOICES");
-    };
-    voice[voice_index].number = num;
-    voice[voice_index].barcount = zero_barcount(&voice[voice_index].foundbar);
-    voice[voice_index].bars_complete = 0;
-    voice[voice_index].bars_remaining = bars_per_line;
-    voice[voice_index].drumchan = 0;
-  };
-  voice[voice_index].currentline = NULL;
-  return(voice_index);
-}
-
-void event_voice(n, s, vp)
-int n;
-char *s;
-struct voice_params *vp;
-{
-  char output[32];
-  if (xinbody) {
-    next_voice = setvoice(n);
-  };
-  if ((selected_voice != -1) && (n != selected_voice)) {
-    if ((inlinefield) && (output_on == 1)) { 
-      unemit_inline();
-    }; 
-    output_on = 0;
-  } else { 
-    if (output_on == 0) { 
-      output_on = 1; 
-      if (inlinefield) { 
-        emit_string("["); /* regenerate missing [ */
-      }; 
-    }; 
-  }; 
-  if (strlen(s) == 0) {
-    if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]);
-    else emit_int_sprintf("V:%d", n);
-    if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname);
-	    emit_string(output);}
-    if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave);
-	    emit_string(output);}
-    if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose);
-	    emit_string(output);}
-     if (vp->gotname) {sprintf(output," name=%s", vp->namestring);
-            emit_string(output);}
-     if (vp->gotsname) {sprintf(output," sname=%s", vp->snamestring);
-            emit_string(output);}
-     if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring);
-            emit_string(output);}
-  } else {
-    if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]);
-    emit_int_sprintf("V:%d ", n);
-    if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname);
-	    emit_string(output);}
-    if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave);
-	    emit_string(output);}
-    if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose);
-	    emit_string(output);}
-     if (vp->gotname) {sprintf(output," name=%s", vp->namestring);
-            emit_string(output);}
-     if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring);
-            emit_string(output);}
-    emit_string(s);
-  };
-  inmusic = 0;
-}
-
-void event_length(n)
-int n;
-{
-  struct fract newunit;
-
-  newunit.num = lenfactor.denom;
-  newunit.denom = lenfactor.num * n;
-  reduce(&newunit.num, &newunit.denom);
-  emit_int_sprintf("L:%d/", newunit.num);
-  emit_int(newunit.denom);
-  unitlen.num = 1;
-  unitlen.denom = n;
-  inmusic = 0;
-}
-
-void event_refno(n)
-int n;
-{
-  if (xinbody) {
-    close_newabc();
-  };
-  output_on = 1;
-  if (newrefnos) {
-    emit_int_sprintf("X: %d", newref);
-    newref = newref + 1;
-  } else {
-    emit_int_sprintf("X: %d", n);
-  };
-  parseron();
-  xinhead = 1;
-  notecount = 0;
-  unitlen.num = 0;
-  unitlen.denom = 1;
-  barlen.num = 0;
-  barlen.denom = 1;
-  inmusic = 0;
-  barcount = 0;
-}
-
-void event_tempo(n, a, b, relative, pre, post)
-int n, a, b;
-int relative;
-char *pre;
-char *post;
-{
-  struct fract newlen;
-
-  emit_string("Q:");
-  if (pre != NULL) {
-    emit_string_sprintf("\"%s\"", pre);
-  };
-  if (n != 0) {
-    if ((a == 0) && (b == 0)) {
-      emit_int(n);
-    } else {
-      if (relative) {
-        newlen.num = a * lenfactor.num;
-        newlen.denom = b * lenfactor.denom;
-        reduce(&newlen.num, &newlen.denom);
-        emit_int_sprintf("C%d/", newlen.num);
-        emit_int(newlen.denom);
-        emit_int_sprintf("=%d", n);
-      } else {
-        emit_int_sprintf("%d/", a);
-        emit_int(b);
-        emit_int_sprintf("=%d", n);
-      };
-    };
-  };
-  if (post != NULL) {
-    emit_string_sprintf("\"%s\"", post);
-  };
-  inmusic = 0;
-}
-
-void event_timesig(n, m, checkbars)
-int n, m, checkbars;
-{
-  if (checkbars == 1) {
-    emit_int_sprintf("M:%d/", n);
-    emit_int(m);
-  } else {
-    emit_string("M:none");
-    barcheck = 0;
-  };
-  barlen.num = n;
-  barlen.denom = m;
-  breakpoint.num = n;
-  breakpoint.denom = m;
-  if ((n == 9) || (n == 6)) {
-    breakpoint.num = 3;
-    breakpoint.denom = barlen.denom;
-  };
-  if (n%2 == 0) {
-    breakpoint.num = barlen.num/2;
-    breakpoint.denom = barlen.denom;
-  };
-  barend = n/breakpoint.num;
-  inmusic = 0;
-}
-
-static void setmap(sf, map)
-int sf;
-int map[7];
-{
-/* map[0] to map[7] corresponds to keys a to g and indicates
-   whether they are flattened or sharpened. sf encodes the
-   key signature by indicating the number of sharps (positive
-   numbers) or flats (negative numbers)
-*/
-  int j;
-
-  for (j=0; j<7; j++) {
-    map[j] = 0;
-  };
-  if (sf >= 1) map['f'-'a'] = 1;
-  if (sf >= 2) map['c'-'a'] = 1;
-  if (sf >= 3) map['g'-'a'] = 1;
-  if (sf >= 4) map['d'-'a'] = 1;
-  if (sf >= 5) map['a'-'a'] = 1;
-  if (sf >= 6) map['e'-'a'] = 1;
-  if (sf >= 7) map['b'-'a'] = 1;
-  if (sf <= -1) map['b'-'a'] = -1;
-  if (sf <= -2) map['e'-'a'] = -1;
-  if (sf <= -3) map['a'-'a'] = -1;
-  if (sf <= -4) map['d'-'a'] = -1;
-  if (sf <= -5) map['g'-'a'] = -1;
-  if (sf <= -6) map['c'-'a'] = -1;
-  if (sf <= -7) map['f'-'a'] = -1;
-}
-
-static void start_tune()
-{
-  parseron();
-  count.num =0;
-  count.denom = 1;
-  barno = 0;
-  tuplenotes = 0;
-  expect_repeat = 0;
-  inlinefield = 0;
-  if (barlen.num == 0) {
-    /* generate missing time signature */
-    event_linebreak();
-    event_timesig(4, 4, 1);
-    inmusic = 0;
-  };
-  if (unitlen.num == 0) {
-    if ((float) barlen.num / (float) barlen.denom < 0.75) {
-      unitlen.num = 1;
-      unitlen.denom = 16;
-    } else {
-      unitlen.num = 1;
-      unitlen.denom = 8;
-    };
-  };
-  voicecount = 0;
-  this_voice = setvoice(1);
-  next_voice = this_voice;
-}
-
-void compute_keysignature (int sf,int modeindex, char * keysignature)
-{
-char  *notes[7] = {"A","B","C","D","E","F","G"};
-int sf2note[12] = {3,0,4,1,5,2,6,3,0,4,1,5};
-char *flatsharp[2] = {"b","#"};
-int index0,index1,index;
-int map[7];
-
-index0 = sf+5; /* -5 <sf < 4 */
-index1 = sf2note[index0]; /* major key */
-index =index1 + modekeyshift[modeindex]; /* key for mode */
-setmap(sf,map); /* determine the flats and sharps for major key */
-if (index > 6) index -=7;
-strcpy(keysignature,notes[index]);
-/* propogate sharp or flat to key signature of mode */
-if (map[index] == -1) strcat(keysignature,flatsharp[0]);
-if (map[index] == 1) strcat(keysignature,flatsharp[1]);
-/* add mode name */
-strcat(keysignature,mode[modeindex]);
-}
-
-
-
-void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname,
-          octave, xtranspose, gotoctave, gottranspose)
-int sharps;
-char *s;
-int modeindex;
-char modmap[7];
-int modmul[7];
-int gotkey, gotclef;
-char* clefname;
-int octave, xtranspose, gotoctave, gottranspose;
-{
-  static char* keys[12] = {"Db", "Ab", "Eb", "Bb", "F", "C", 
-                           "G", "D", "A", "E", "B", "F#"};
-  char signature[10];
- 
-  if (gotkey) {
-    setmap(sharps, basemap); /* required by copymap and pitchof */
-    setmap(sharps, oldtable);
-    copymap();
-    newkey = (sharps+7*transpose)%12;
-    if (sharps < -5) orig_key_number = (int) keys[sharps+17][0] - (int) 'A';
-    else if (sharps > 6) orig_key_number = (int)keys[sharps-7][0] - (int) 'A';
-    else    orig_key_number = (int) keys[sharps+5][0] - (int) 'A';
-    lines = (sharps+7*transpose)/12;
-    if (newkey > 6) {
-      newkey = newkey - 12;
-      lines = lines + 1;
-    };
-    if (newkey < -5) {
-      newkey = newkey + 12;
-      lines = lines - 1;
-    };
-    setmap(newkey, newtable);  /* used by event_note1 */
-    new_key_number = (int) keys[newkey+5][0] - (int) 'A';
-  };
-  emit_string("K:");
-  if (transpose == 0 && !nokey) {
-    emit_string(s); 
-  } else {
-    if (gotkey) {
-      if (!nokey) {
-        /*  emit_string(keys[newkey+5]); */
-        compute_keysignature(newkey,modeindex,signature); /* [SS] 2006-07-30*/
-        emit_string(signature); /* [SS] 2006-07-30 */
-        }
-
-      else if (usekey == 0) emit_string("none"); 
-      else emit_string(keys[usekey+5]);
-      if (gotclef) {
-        emit_string(" ");
-      };
-    };
-    if (gotclef) {
-      emit_string_sprintf("clef=%s", clefname);
-    };
-    if (gotoctave) {
-      emit_int_sprintf(" octave=%d", octave);
-    };
-    if (gottranspose) {
-      emit_int_sprintf(" transpose=%d", xtranspose);
-    };
-  };
-  if ((xinhead) && (!xinbody)) {
-    xinbody = 1;
-    start_tune();
-  };
-  inmusic = 0;
-}
-
-static void printlen(a, b)
-int a, b;
-{
-  if (a != 1) {
-    emit_int(a);
-  };
-  if (b != 1) {
-    emit_int_sprintf("/%d", b);
-  };
-}
-
-void event_spacing(n, m)
-int n, m;
-{
-  emit_string("y");
-  printlen(n, m);
-}
-
-
-void event_rest(decorators,n,m,type)
-int n, m, type;
-int decorators[DECSIZE];
-{
-  struct fract newlen;
-
-  inmusic = 1;
-  if( type == 1) emit_string("x");
-  else emit_string("z");
-  newlen.num = n * lenfactor.num;
-  newlen.denom = m * lenfactor.denom;
-  reduce(&newlen.num, &newlen.denom);
-  printlen(newlen.num, newlen.denom);
-  if (inchord) {
-    chordcount = chordcount + 1;
-  };
-  if ((!ingrace) && (!inchord || (chordcount == 1))) {
-    if (!tuplenotes) addunits(n, m);
-    else {
-      addunits(n*tuplefactor.num, m*tuplefactor.denom);
-      tuplenotes = tuplenotes - 1;
-      }
-  };
-}
-
-void event_mrest(n,m)
-int n, m;
-{
-  inmusic = 1;
-  emit_string("Z");
-  printlen(n,m);
-  if (inchord) {
-    event_error("Multiple bar rest not allowed in chord");
-  };
-  if (tuplenotes != 0) {
-    event_error("Multiple bar rest not allowed in tuple");
-  };
-}
-
-void event_bar(type, replist)
-int type;
-char* replist;
-{
-  char msg[40];
-
-  if (!purgespace(tmp)) {
-    if (inmusic) {
-      newabctext(bar);
-    } else {
-      newabctext(field);
-    };
-  };
-  switch(type) {
-  case SINGLE_BAR:
-    emit_string_sprintf("|%s", replist);
-    break;
-  case DOUBLE_BAR:
-    emit_string("||");
-    break;
-  case THIN_THICK:
-    emit_string("|]");
-    break;
-  case THICK_THIN:
-    emit_string("[|");
-    break;
-  case BAR_REP:
-    emit_string("|:");
-    if ((expect_repeat) && (repcheck)) {
-      event_error("Expecting repeat, found |:");
-    };
-    expect_repeat = 1;
-    break;
-  case REP_BAR:
-    emit_string_sprintf(":|%s", replist);
-    if ((!expect_repeat) && (repcheck)) {
-      event_warning("No repeat expected, found :|");
-    };
-    expect_repeat = 0;
-    break;
-  case BAR1:
-    emit_string("|1");
-    if ((!expect_repeat) && (repcheck)) {
-      event_warning("found |1 in non-repeat section");
-    };
-    break;
-  case REP_BAR2:
-    emit_string(":|2");
-    if ((!expect_repeat) && (repcheck)) {
-      event_warning("No repeat expected, found :|2");
-    };
-    expect_repeat = 0;
-    break;
-  case DOUBLE_REP:
-    emit_string("::");
-    if ((!expect_repeat) && (repcheck)) {
-      event_error("No repeat expected, found ::");
-    };
-    expect_repeat = 1;
-    break;
-  };
-  if ((count.num*barlen.denom != barlen.num*count.denom) &&
-      (count.num != 0) && (barno != 0) && (barcheck)) {
-    sprintf(msg, "Bar %d is %d/%d not %d/%d", barno, 
-           count.num, count.denom,
-           barlen.num, barlen.denom );
-    event_error(msg);
-  };
-  newabctext(barline);
-  barno = barno + 1;
-  count.num = 0;
-  count.denom = 1;
-  copymap();
-}
-
-void event_space()
-{
-  if (!newspacing) {
-    emit_string(" ");
-  };
-}
-
-void event_graceon()
-{
-  emit_string("{");
-  ingrace = 1;
-}
-
-void event_graceoff()
-{
-  emit_string("}");
-  ingrace = 0;
-}
-
-void event_rep1()
-{
-  emit_string(" [1");
-}
-
-void event_rep2()
-{
-  emit_string(" [2");
-}
-
-void event_playonrep(s)
-char*s;
-{
-  emit_string_sprintf(" [%s", s);
-}
-
-void event_broken(type, n)
-int type, n;
-{
-  int i;
-
-  if (type == GT) {
-    for (i=0; i<n; i++) {
-      emit_char('>');
-    };
-  } else {
-    for (i=0; i<n; i++) {
-      emit_char('<');
-    };
-  };
-}
-
-void event_tuple(n, q, r)
-int n, q, r;
-{
-  emit_int_sprintf("(%d", n);
-  if (tuplenotes != 0) {
-    event_error("tuple within tuple not allowed");
-  };
-  if (q != 0) {
-    emit_int_sprintf(":%d", q);
-    tuplefactor.num = q;
-    tuplefactor.denom = n;
-    if (r != 0) {
-      emit_int_sprintf(":%d", r);
-      tuplenotes = r;
-    } else {
-      tuplenotes = n;
-    };
-  } else {
-    tuplenotes = n;
-    tuplefactor.denom = n;
-    if ((n == 2) || (n == 4) || (n == 8)) tuplefactor.num = 3;
-    if ((n == 3) || (n == 6)) tuplefactor.num = 2;
-    if ((n == 5) || (n == 7) || (n == 9)) {
-      if ((barlen.num % 3) == 0) {
-        tuplefactor.num = 3;
-      } else {
-        tuplefactor.num = 2;
-      };
-    };
-  };
-}
-
-void event_startinline()
-{
-  emit_string("[");
-  inlinefield = 1;
-}
-
-void event_closeinline()
-{
-  emit_string("]");
-  inmusic = 1;
-  inlinefield = 0;
-}
-
-void event_chord()
-{
-  if (cleanup) {
-    if (inchord) {
-      emit_string("]");
-    } else {
-      emit_string("[");
-    };
-  } else {
-    emit_string("+");
-  };
-  inmusic = 1;
-  inchord = 1 - inchord;
-  chordcount = 0;
-}
-
-void event_chordon(int chorddecorators[])
-{
-  int i;
-  for (i=0; i<DECSIZE; i++) {
-    if (chorddecorators[i]) 
-      emit_char(decorations[i]);
-    }
-  emit_string("[");
-  inmusic = 1;
-  inchord = 1;
-  chordcount = 0;
-}
-
-void event_chordoff(int chord_n, int chord_m)
-{
-  char string[16];
-  emit_string("]");
-  if(chord_n !=1 && chord_m !=1)
-     {
-     sprintf(string,"%d/%d",chord_n,chord_m);
-     emit_string(string);
-     }
-  else if(chord_n !=1)
-     {
-     sprintf(string,"%d",chord_n);
-     emit_string(string);
-     }
-  else if(chord_m !=1)
-     {
-     sprintf(string,"/%d",chord_m);
-     emit_string(string);
-     }
-  inmusic = 1;
-  inchord = 0;
-  if(chord_n !=1 || chord_m !=1)
-    {
-    repudiate_lastaddunits();
-    addunits(chord_n,chord_m);
-    }
-}
-
-static void splitstring(s, sep, handler)
-char* s;
-char sep;
-void (*handler)();
-/* this routine splits the string into fields using semi-colon */
-/* and calls handler for each sub-string                       */
-{
-  char* out;
-  char* p;
-  int fieldcoming;
-
-  p = s;
-  fieldcoming = 1;
-  while (fieldcoming) {
-    out = p;
-    while ((*p != '\0') && (*p != sep)) p = p + 1;
-    if (*p == sep) {
-      *p = '\0';
-      p = p + 1;
-    } else {
-      fieldcoming = 0;
-    };
-    (*handler)(out);
-  };
-}
-
-void event_handle_gchord(s)
-/* deals with an accompaniment (guitar) chord */
-/* either copies it straight out or transposes it */
-char* s;
-{
-  char newchord[50];
-  static int offset[7] = {9, 11, 0, 2, 4, 5, 7};
-  static char* sharproots[12] = {"C", "C#", "D", "D#", "E", "F",
-                            "F#", "G", "G#", "A", "A#", "B"};
-  static char* flatroots[12] = {"C", "Db", "D", "Eb", "E", "F",
-                            "Gb", "G", "Ab", "A", "Bb", "B"};
-  static char* sharpbases[12] = {"c", "c#", "d", "d#", "e", "f",
-                            "f#", "g", "g#", "a", "a#", "b"};
-  static char* flatbases[12] = {"c", "db", "d", "eb", "e", "f",
-                            "gb", "g", "ab", "a", "bb", "b"};
-  char** roots;
-  char** bases;
-  int chordstart;
-  int key_number;
-  int old_triad_number;
-  int new_triad_number;
-  int triad_diff;
-
-  if ((transpose == 0) || (*s == '_') || (*s == '^') || (*s == '<') ||
-      (*s == '>') || (*s == '@')) {
-    emit_string_sprintf("\"%s\"", s);
-  } else {
-    char* p;
-    int pitch;
-    int j;
-
-    if (newkey >= 0) {
-      roots = sharproots;
-      bases = sharpbases;
-    } else {
-      roots = flatroots;
-      bases = flatbases;
-    };
-    p = s;
-    chordstart = 1;
-    j = 0;
-    while (*p != '\0') {
-      if (chordstart) {
-        if ((*p >= 'A') && (*p <= 'G')) {
-          key_number = (int) *p - ((int) 'A');
-	  old_triad_number = key_number - orig_key_number+1;
-	  if (old_triad_number < 1) old_triad_number += 7;
-          pitch = (offset[key_number] + transpose)%12;
-          p = p + 1;
-          if (*p == 'b') {
-            pitch = pitch - 1;
-            p = p + 1;
-            };
-          if (*p == '#') {
-            pitch = pitch + 1;
-            p = p + 1;
-            };
-          pitch = (pitch + 12)%12;
-	  key_number = (int) roots[pitch][0] - (int) 'A';
-	  new_triad_number = key_number - new_key_number +1;
-	  if (new_triad_number < 1) new_triad_number += 7;
-	  triad_diff = new_triad_number - old_triad_number;
-	  if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) {
-		  /*      printf("*** %d  old chord = %s (%d) new chord = %s (%d)\n",
-		        triad_diff,s,old_triad_number,roots[pitch],new_triad_number); */
-	                pitch = pitch+1;
-                        pitch = (pitch+12)%12;
-                        strcpy(&newchord[j],roots[pitch]);
-                        j = strlen(newchord);
-                        strcpy(&newchord[j],"b");
-                        j = j+1;
-                        if (adapt_useflats_to_gchords) useflats=1;
-	                } else
-          if (!nodouble_accidentals && (triad_diff  ==1 || triad_diff == -6)) {
-  	         /*	   printf("*** %d old chord = %s (%d) new chord = %s (%d)\n",
-		         triad_diff,s,old_triad_number,roots[pitch],new_triad_number);  */
-
-                        pitch = pitch-1;
-                        pitch = (pitch+12)%12;
-                        strcpy(&newchord[j],roots[pitch]);
-                        j = strlen(newchord);
-                        strcpy(&newchord[j],"#");
-                        j = j+1;
-                        if (adapt_useflats_to_gchords) useflats=0;
-                        } else  
-/* no extra flats or sharps needed */
-                        {
-                        strcpy(&newchord[j], roots[pitch]);
-                        j = strlen(newchord);
-                        }
-
-          chordstart = 0;
-        } else {
-          if ((*p >= 'a') && (*p <= 'g')) {
-            key_number = (int) *p - ((int) 'a');
-	    old_triad_number = key_number - orig_key_number+1;
-	    if (old_triad_number < 1) old_triad_number += 7;
-            pitch = (offset[key_number] + transpose)%12;
-            p = p + 1;
-            if (*p == 'b') {
-              pitch = pitch - 1;
-              p = p + 1;
-              };
-            if (*p == '#') {
-              pitch = pitch + 1;
-              p = p + 1;
-              };
-            pitch = (pitch + 12)%12;
-	    key_number = (int) bases[pitch][0] - (int) 'a';
-	    new_triad_number = key_number - new_key_number +1;
-	    if (new_triad_number < 1) new_triad_number += 7;
-	    triad_diff = new_triad_number - old_triad_number;
-	  if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) {
-          /*              printf("*** %d  old chord = %s (%d) new chord = %s (%d)\n",
-			 triad_diff,s,old_triad_number,bases[pitch],new_triad_number); */
-	                pitch = pitch+1;
-                        pitch = (pitch+12)%12;
-			strcpy(&newchord[j],bases[pitch]);
-			j = strlen(newchord);
-			strcpy(&newchord[j],"b");
-			j = j+1;
-	                } else
-          if (!nodouble_accidentals && (triad_diff  ==1 || triad_diff == -6)) {
-	/*	        printf("*** %d old chord = %s (%d) new chord = %s (%d)\n",
-			 triad_diff,s,old_triad_number,bases[pitch],new_triad_number);*/
-			 pitch = pitch-1;
-			 pitch = (pitch+12)%12;
-			 strcpy(&newchord[j],bases[pitch]);
-			 j = strlen(newchord);
-			 strcpy(&newchord[j],"#");
-			 j = j+1;
-                         } else
-	                 {
-                         strcpy(&newchord[j], bases[pitch]);
-                         j = strlen(newchord);
-			 }
-            chordstart = 0;
-          } else {
-            if (isalpha(*p)) {
-              chordstart = 0;
-            };
-            newchord[j] = *p;
-            p = p + 1;
-            j = j + 1;
-            newchord[j] = '\0';
-          };
-        };
-      } else {
-        if ((*p == '/') || (*p == '(') || (*p == ' ')) {
-          chordstart = 1;
-        };
-
-        newchord[j] = *p;
-        p = p + 1;
-        j = j + 1;
-        newchord[j] = '\0';
-      };
-      if (j >= 49) {
-        event_error("guitar chord contains too much text");
-        while (*p != '\0') {
-          p = p + 1;
-        };
-      };
-    };
-    emit_string_sprintf("\"%s\"", newchord);
-  };
-}
-
-void event_gchord(s)
-char* s;
-{
-  splitstring(s, ';', event_handle_gchord);
-}
-
-void event_instruction(s)
-char* s;
-{
-  if (oldchordconvention) emit_string_sprintf("!%s!", s);
-  else emit_string_sprintf("+%s+", s);
-}
-
-void event_slur(t)
-int t;
-{
-  if (cleanup) {
-    if (t) {
-      emit_string("(");
-    } else {
-      emit_string(")");
-    };
-  } else {
-    emit_string("s");
-  };
-}
-
-void event_sluron(t)
-int t;
-{
-  emit_string("(");
-}
-
-void event_sluroff(t)
-int t;
-{
-  emit_string(")");
-}
-
-void event_tie()
-{
-  emit_string("-");
-}
-
-void event_lineend(ch, n)
-char ch;
-int n;
-{
-  int i;
-
-  if (!newbreaks) {
-    for (i = 0; i<n; i++) {
-      emit_char(ch);
-    };
-  };
-}
-
-
-
-void event_note1(decorators, xaccidental, xmult, xnote, xoctave, n, m)
-int decorators[DECSIZE];
-int xmult;
-char xaccidental, xnote;
-int xoctave, n, m;
-{
-  int t;
-  struct fract barpoint;
-  struct fract newlen;
-  int mult;
-  char accidental, note;
-  int octave;
-
-  mult = 0;  /* [SS] 2006-10-27 */
-  if (transpose == 0 || drumchan) {
-    accidental = xaccidental;
-    mult = xmult;
-    note = xnote;
-    octave = xoctave;
-  } else {
-    int val, newval;
-    int acc;
-    char *anoctave = "cdefgab";
-
-    octave = xoctave;
-    val = (int) ((long) strchr(anoctave, xnote) - (long) anoctave);
-    newval = val + lines;
-    octave = octave + (newval/7);
-    newval = newval % 7;
-    if (newval < 0) {
-      newval = newval + 7;
-      octave = octave - 1;
-    };
-    note = *(anoctave+newval);
-    if (xaccidental == ' ') {
-      accidental = ' ';
-    } else {
-      switch (xaccidental) {
-      case '_':
-        acc = -xmult;
-        break;
-      case '^':
-        acc = xmult;
-        break;
-      case '=':
-        acc = 0;
-        break;
-      default:
-        event_error("Internal error");
-      };
-      acc = acc - oldtable[(int)anoctave[val] - (int)'a'] + 
-                  newtable[(int)anoctave[newval] - (int)'a'];
-      mult = 1;
-      accidental = '=';
-      if (acc > 0) {
-        accidental = '^';
-        mult = acc;
-      };
-      if (acc < 0) {
-        accidental = '_';
-        mult = -acc;
-      };
-    };
-  };    
-  if (!ingrace) {
-    notecount = notecount + 1;
-  };
-  for (t=0; t<DECSIZE; t++) {
-    if (decorators[t]) {
-      emit_char(decorations[t]);
-    };
-  };
-  if (mult == 2) {
-    emit_char(accidental);
-  };
-  if (accidental != ' ') {
-    emit_char(accidental);
-  };
-  if (octave >= 1) {
-    emit_char(note);
-    t = octave;
-    while (t > 1) {
-      emit_string("'");
-      t = t - 1;
-    };
-  } else {
-    emit_char((char) ((int)note + 'C' - 'c'));
-    t = octave;
-    while (t < 0) {
-      emit_string(",");
-      t = t + 1;
-    };
-  };
-  newlen.num = n * lenfactor.num;
-  newlen.denom = m * lenfactor.denom;
-  reduce(&newlen.num, &newlen.denom);
-  printlen(newlen.num, newlen.denom);
-  if (inchord) {
-    chordcount = chordcount + 1;
-  };
-  if ((!ingrace) && (!inchord || (chordcount == 1))) {
-    if (tuplenotes == 0) {
-      addunits(n, m);
-    } else {
-      addunits(n*tuplefactor.num, m*tuplefactor.denom);
-      tuplenotes = tuplenotes - 1;
-    };
-  };
-  if (newspacing) {
-    barpoint.num = count.num * breakpoint.denom;
-    barpoint.denom = breakpoint.num * count.denom;
-    reduce(&barpoint.num, &barpoint.denom);
-    if ((barpoint.denom == 1) && (barpoint.num != 0) && 
-        (barpoint.num != barend)) {
-      emit_string(" ");
-    };
-  };
-}
-
-/* these functions are here to satisfy the linker */
-void event_microtone(int dir, int a, int b)
-{
-}
-
-void event_normal_tone()
-{
-}
-
-
-
-int accidental_to_code (char xaccidental)
-{
- switch (xaccidental) {
- case ' ':
-   return 10;
-   break;
- case '_':
-   return -1;
-   break;
- case '^':
-   return 1;
-   break;
-  case '=':
-    return 0;
-    break;
-  default:
-    return 10;
-  }
-}
-
-
-void event_note2(decorators, xaccidental, xmult, xnote, xoctave, n, m)
-/* this function is called if flag nokey is set */
-int decorators[DECSIZE];
-int xmult;
-char xaccidental, xnote;
-int xoctave, n, m;
-{
-  int t;
-  struct fract barpoint;
-  struct fract newlen;
-
-  int acc,assumed_acc;
-  int propogate;
-  int val;
-  char *anoctave = "cdefgab";
-  int midipitch;
-
- for (t=0; t<DECSIZE; t++) 
-    if (decorators[t]) emit_char(decorations[t]);
-
-  acc = accidental_to_code(xaccidental);
-  if (acc == -1 || acc == 1) acc = xmult*acc;
-  val = (int) ((long) strchr(anoctave, xnote) - (long) anoctave);
-
-  /* if no accidental precedes, then get accidental from key signature */
-  assumed_acc = oldtable[(int)anoctave[val] - (int)'a']; 
-  propogate=0;
-  midipitch = pitchof(xnote, acc, xmult, xoctave);
-  if (drumchan) printpitch(midipitch);
-  else printpitch(midipitch+transpose);
-
-  if (!ingrace) {
-    notecount = notecount + 1;
-  };
-
-  newlen.num = n * lenfactor.num;
-  newlen.denom = m * lenfactor.denom;
-  reduce(&newlen.num, &newlen.denom);
-  printlen(newlen.num, newlen.denom);
-  if (inchord) {
-    chordcount = chordcount + 1;
-  };
-  if ((!ingrace) && (!inchord || (chordcount == 1))) {
-    if (tuplenotes == 0) {
-      addunits(n, m);
-    } else {
-      addunits(n*tuplefactor.num, m*tuplefactor.denom);
-      tuplenotes = tuplenotes - 1;
-    };
-  };
-  if (newspacing) {
-    barpoint.num = count.num * breakpoint.denom;
-    barpoint.denom = breakpoint.num * count.denom;
-    reduce(&barpoint.num, &barpoint.denom);
-    if ((barpoint.denom == 1) && (barpoint.num != 0) && 
-        (barpoint.num != barend)) {
-      emit_string(" ");
-    };
-  };
-}
-
-
-void event_note(decorators, xaccidental, xmult, xnote, xoctave, n, m)
-int decorators[DECSIZE];
-int xmult;
-char xaccidental, xnote;
-int xoctave, n, m;
-{
-if (nokey)
-  event_note2(decorators, xaccidental, xmult, xnote, xoctave, n, m);
-else
-  event_note1(decorators, xaccidental, xmult, xnote, xoctave, n, m);
-}
-
-
-void event_abbreviation(char symbol, char *string, char container)
-/* a U: field has been found in the abc */
-{
-  if (container == '!') {
-    emit_string("U:");
-    emit_char(symbol);
-    emit_string_sprintf(" = !%s!", string);
-  } else {
-    emit_string("U:");
-    emit_char(symbol);
-    emit_string_sprintf(" = %s", string);
-  };
-  inmusic = 0;
-}
-
-void event_acciaccatura()
-{
-/* to handle / in front of note in grace notes eg {/A} */
-/* abcm2ps compatability feature [SS] 2005-03-28 */
-emit_string("/");
-}
-
-void event_split_voice ()
-{
-emit_string("&");
-}
-
-/* The following functions provide an alternative
-   method for transposing. The note is converted
-   to MIDI representation. It is transposed and
-   then converted back. These functions were
-   borrowed from store.c and midi2abc with
-   some minor modifications.
-*/
-
-
-int pitchof(char note, int accidental, int mult, int octave)
-/* finds MIDI pitch value for a given note taking into account the  */
-/* key signature if any and propogation of accidentals across a bar.*/
-/* accidental = 0  implies a natural specified.                     */
-/* accidental = 1  implies one or more sharps indicated by mult.    */
-/* accidental =-1  implies one or more flats indicated by mult.     */
-/* accidental = 10 nothing specified, determine from context        */
-{
-  int p;
-  int mul, noteno;
-  static int scale[7] = {0, 2, 4, 5, 7, 9, 11};
-  char *anoctave = "cdefgab";
-  int middle_c = 60;
-
-  p = (int) ((long) strchr(anoctave, note) - (long) anoctave);
-  p = scale[p];
-  mul = mult;
-  noteno = (int)note - 'a';
-  if (accidental==10) {        /* propagate accidentals  */
-    mul = workmul[noteno];
-  } else {
-      workmap[noteno] = accidental;
-      workmul[noteno] = mul;
-  };
-  p = p + workmap[noteno]*workmul[noteno];
-  return p + 12*octave + middle_c;
-}
-
-int lastaccidental[7];
-
-void copymap()
-/* sets up working map at the start of each bar */
-{
-  int j;
-
-  for (j=0; j<7; j++) {
-    workmap[j] = basemap[j];
-    workmul[j] = 1;
-    lastaccidental[j] = 0;
-  };
-}
-
-#define MIDDLE 72
-
-
-int sharpmap[12] =  { 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6};
-int flatmap[12]  =  { 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6};
-int sharpsym[12] =  { 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0};
-int flatsym[12]  =  { 0,-1, 0,-1, 0, 0,-1, 0,-1, 0,-1, 0};
-char hikey[7]    =  {'c','d','e','f','g','a','b'};
-char lowkey[7]   =  {'C','D','E','F','G','A','B'};
-char symlet[3]   =  {'=','^','_'};
-
-
-void setup_sharps_flats (int sf)
-{
-if (sf >=1) {sharpsym[6] = 0; sharpsym[5] = 2;}
-if (sf >=2) {sharpsym[1] = 0; sharpsym[0] = 2;}
-if (sf >=3) {sharpsym[8] = 0; sharpsym[7] = 2;}
-if (sf >=4) {sharpsym[3] = 0; sharpsym[2] = 2;}
-if (sf >=5) {sharpsym[10]= 0; sharpsym[9] = 2;}
-if (sf <= -1) {flatsym[10] = 0; flatsym[11] = 2;}
-if (sf <= -2) {flatsym[3]  = 0; flatsym[4]  =2;}
-if (sf <= -3) {flatsym[8]  = 0; flatsym[9]  =2;}
-if (sf <= -4) {flatsym[1]  = 0; flatsym[2]  =2;}
-if (sf <= -5) {flatsym[6]  = 0; flatsym[6]  =2;}
-}
-
-
-
-void printpitch(int pitch)
-/* convert midi pitch value to abc note */
-{
-int p;
-char keylet,symlet;
-int keynum,symcod;
-char string[16];
-p = pitch%12;
-if (useflats)
- {keynum = flatmap[p];
-  symcod = flatsym[p];
- } else
- {keynum = sharpmap[p];
-  symcod = sharpsym[p];
- }
-
-if (pitch<MIDDLE)
-  keylet = lowkey[keynum];
-else
-  keylet = hikey[keynum];
-
-switch (symcod) {
-  case 0:
-   symlet = '=';
-   break;
-  case 1:
-   symlet = '^';
-   break;
-  case -1:
-   symlet = '_';
-   break;
-  case 2:
-   symlet = '=';
-   break;
-}
- 
-if (lastaccidental[keynum] == symcod)
-   sprintf(string,"%c",keylet);
-else {
-   sprintf(string,"%c%c", symlet, keylet);
-   lastaccidental[keynum] = symcod;
-   }
-  emit_string(string);
-
-p = pitch;
-while (p >= MIDDLE + 12) {
-    emit_string("'");
-    p = p - 12;
-    };
-while (p < MIDDLE - 12) {
-    emit_string(",");
-    p = p + 12;
-    };
-}
-
-
-int main(argc,argv)
-int argc;
-char *argv[];
-{
-  char *filename;
-
-  oldchordconvention = 0; /* for handling +..+ chords */
-
-  /*for (i=0;i<DECSIZE;i++) decorators_passback[i]=0; */
-
-  event_init(argc, argv, &filename);
-  if (argc < 2) {
-    /* printf("argc = %d\n", argc); */
-  } else {
-    init_abbreviations();
-    parsefile(filename);
-    free_abbreviations();
-  };
-  return(0);
-}
-
+/*
+ * toabc.c - part of abc2abc - program to manipulate abc files.
+ * Copyright (C) 1999 James Allwright
+ * e-mail: J.R.Allwright@westminster.ac.uk
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/* back-end for outputting (possibly modified) abc */
+
+#define VERSION "1.56 December 21 2006"
+
+/* for Microsoft Visual C++ 6.0 or higher */
+#ifdef _MSC_VER
+#define ANSILIBS
+#endif
+
+#include "abc.h"
+#include "parseabc.h"
+#include <stdio.h>
+
+/* define USE_INDEX if your C libraries have index() instead of strchr() */
+#ifdef USE_INDEX
+#define strchr index
+#endif
+
+#if defined(ANSILIBS) || defined(__STDC__)
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#else
+extern char* strchr();
+#endif
+
+#define MAX_VOICES 30
+/* should be plenty! */
+
+programname fileprogram = ABC2ABC;
+extern int oldchordconvention; /* for handling +..+ chords */
+
+struct fract {
+  int num;
+  int denom;
+};
+struct fract barlen; /* length of a bar as given by the time signature */
+struct fract unitlen; /* unit length as given by the L: field */
+struct fract count; /* length of bar so far */
+struct fract prevcount; /* length of bar before last increment */
+struct fract tuplefactor; /* factor associated with a tuple (N */
+struct fract breakpoint; /* used to break bar into beamed sets of notes */
+int barno; /* number of bar within tune */
+int newspacing; /* was -s option selected ? */
+int barcheck, repcheck; /* indicate -b and -r options selected */
+int echeck; /* was error-checking turned off ? (-e option) */
+int newbreaks; /* was -n option selected ? */
+int nodouble_accidentals;
+int totalnotes, notecount; 
+int bars_per_line; /* number supplied after -n option */
+int barcount;
+int expect_repeat;
+int tuplenotes, barend;
+int xinhead, xinbody; /* are we in head or body of abc tune ? */
+int inmusic; /* are we in a line of notes (in the tune body) ? */
+int startline, blankline;
+int transpose; /* number of semitones to transpose by (-t option) */
+struct fract lenfactor; /* fraction to scale note lengths; -v,-d options */
+int newkey; /* key after transposition (expressed as no. of sharps) */
+int lines; /* used by transposition */
+int orig_key_number; /* used for gchord transposition */
+int new_key_number;  /* used for gchord transposition */
+int oldtable[7], newtable[7]; /* for handling transposition */
+int inchord; /* are we in a chord [ ] ? */
+int ingrace; /* are we in a grace note set { } ? */
+int chordcount; /* number of notes or rests in current chord */
+int inlinefield; /* boolean - are we in [<field>: ] ? */
+int cleanup; /* boolean to indicate -u option (update notation) */
+char tmp[2000]; /* buffer to hold abc output being assembled */
+int output_on = 1;  /* if 0 suppress output */
+int selected_voice = -1; /* no voice was selected */
+int newrefnos; /* boolean for -X option (renumber X: fields) */
+int newref; /* next new number for X: field */
+int useflats=0; /* flag associated with nokey.*/ 
+int adapt_useflats_to_gchords = 1; /* experimental flag */
+int usekey = 0;
+int drumchan=0; /* flag to suppress transposition */
+
+extern int nokey; /* signals no key signature assumed */
+extern int voicecodes ;  /* from parseabc.c */
+extern char voicecode[16][30]; /*for interpreting V: string */
+ 
+struct voicetype { /* information needed for each voice */
+  int number; /* voice number from V: field */
+  int barcount;
+  int foundbar;
+  struct abctext* currentline;
+  int bars_remaining;
+  int bars_complete;
+  int drumchan;
+} voice[MAX_VOICES];
+int voicecount, this_voice, next_voice;
+enum abctype {field, bar, barline};
+/* linestat is used by -n for deciding when to generate a newline */
+enum linestattype {fresh, midmusic, endmusicline, postfield};
+enum linestattype linestat; 
+/* struct abctext is used to store abc lines for re-formatting (-n option) */
+struct lyricwords{
+  struct lyricwords* nextverse;
+  char* words;
+};  
+struct abctext{ /* linked list used to store output before re-formatting */
+  struct abctext* next;
+  char* text;
+  enum abctype type;
+  int notes;
+  struct lyricwords* lyrics;
+};
+struct abctext* head;
+struct abctext* tail;
+
+extern char *mode[];
+extern int modekeyshift[];
+int basemap[7], workmap[7]; /* for -nokey and pitchof() */
+int  workmul[7];
+void copymap();
+void printpitch(int);
+void setup_sharps_flats (int sf);
+int pitchof(char note,int accidental,int mult,int octave);
+
+
+static int purgespace(p)
+char* p;
+/* if string p is empty or consists of spaces, set p to the empty string */
+/* and return 1, otherwise return 0. Used to test tmp */
+/* part of new linebreak option (-n) */
+{
+  int blank;
+  char *s;
+
+  blank = 1;
+  s = p;
+  while (*s != '\0') {
+    if (*s != ' ') blank = 0;
+    s = s + 1;
+  };
+  if (blank) {
+    *p = '\0';
+  };
+  return(blank);
+}
+
+int zero_barcount(foundbar)
+/* initialize bar counter for abctext elements */
+/* part of new linebreak option (-n) */
+int *foundbar;
+{
+  *foundbar = 0;
+  return(0);
+}
+
+int new_barcount(type, foundbar, oldcount)
+enum abctype type;
+int *foundbar;
+int oldcount;
+/* work out whether we have reached the end of a bar in abctext elements */
+/* and increment barcount if we have */
+/* part of new linebreak option (-n) */
+{
+  int new_value;
+
+  new_value = oldcount;
+  if (type == bar) {
+    *foundbar = 1;
+  };
+  if ((type == barline) && (*foundbar == 1)) {
+    new_value = new_value + 1;
+    *foundbar = 0;
+  };
+  return(new_value);
+}
+
+
+static void setline(t)
+enum linestattype t;
+/* generates newline, or continuation, or nothing at all */
+/* part of new linebreak option (-n) */
+{
+  if ((t == fresh) && ((linestat == postfield) || (linestat == endmusicline))) {
+    printf("\n");
+  };
+  if ((t == fresh) && (linestat == midmusic)) {
+    printf("\\\n");
+  };
+  linestat = t;
+}
+
+static int flush_abctext(bars, termination)
+int bars;
+enum linestattype termination;
+/* outputs up to the specified number of bars of stored music */
+/* and frees up the storage allocated for those bars. */
+/* returns the number of bars actually output */
+/* part of new linebreak option (-n) */
+{
+  struct abctext *p, *nextp;
+  struct lyricwords *q, *r;
+  struct lyricwords *barlyrics;
+  int count, donewords, wordline;
+  int i, foundtext;
+  int foundbar;
+
+  /* printf("flush_abctext called\n"); */
+  /* print music */
+  p = head;
+  count = zero_barcount(&foundbar);
+  while ((p != NULL) && (count < bars)) {
+    if (p->type == field) {
+      setline(fresh);
+    };
+    printf("%s", p->text);
+    if (p->type == field) {
+      setline(postfield);
+      setline(fresh);
+    } else {
+      setline(midmusic);
+    };
+    count = new_barcount(p->type, &foundbar, count);
+    if ((count == bars) && (p->type == barline)) {
+      setline(endmusicline);
+    };
+    p = p->next;
+  };
+  if (linestat == midmusic) {
+    setline(termination);
+  };
+  if (bars > 0) {
+    /* print out any w: lines */
+    donewords = 0;
+    wordline = 0;
+    while (donewords == 0) {
+      p = head;
+      foundtext = 0;
+      count = zero_barcount(&foundbar);
+      while ((p != NULL) && (count < bars)) {
+        barlyrics = p->lyrics;
+        for (i=0; i<wordline; i++) {
+          if (barlyrics != NULL) {
+            barlyrics = barlyrics->nextverse;
+          };
+        };
+        if (barlyrics != NULL) {
+          if (foundtext == 0) {
+            setline(fresh);
+            printf("w:");
+            foundtext = 1;
+          };
+          fputs(barlyrics->words, stdout);
+        };
+        count = new_barcount(p->type, &foundbar, count);
+        p = p->next;
+      };
+      if (foundtext == 0) {
+        donewords = 1;
+      } else {
+        setline(postfield);
+        setline(fresh);
+      };
+      wordline = wordline + 1;
+    };
+  };
+  /* move head on and free up space used by stuff printed out */
+  count = zero_barcount(&foundbar);
+  p = head;
+  foundbar = 0;
+  while ((p != NULL) && (count < bars)) {
+    if (p != NULL) {
+      free(p->text);
+      q = p->lyrics;
+      while (q != NULL) {
+        free(q->words);
+        r = q->nextverse;
+        free(q);
+        q = r;
+      };
+      count = new_barcount(p->type, &foundbar, count);
+      nextp = p->next;
+      free(p);
+      p = nextp;
+    };
+    head = p;
+  };
+  if (head == NULL) {
+    tail = NULL;
+  };
+  return(count);
+}
+
+void complete_bars(v)
+/* mark all bars as completed (i.e. having associated w: fields parsed) */
+/* and out put all music lines which contain the full set of bars */
+/* part of new linebreak option (-n) */
+struct voicetype *v;
+{
+  int bars_done;
+
+  v->bars_complete = v->bars_complete + v->barcount;
+  v->barcount = 0;
+  while (v->bars_complete > v->bars_remaining) {
+    bars_done = flush_abctext(v->bars_remaining, endmusicline);
+    setline(fresh);
+    v->bars_complete = v->bars_complete - bars_done;
+    v->bars_remaining = v->bars_remaining - bars_done;
+    if (v->bars_remaining == 0) {
+      v->bars_remaining = bars_per_line;
+    };
+  };
+}
+
+void complete_all(v, termination)
+struct voicetype *v;
+enum linestattype termination;
+/* output all remaining music and fields */
+/* part of new linebreak option (-n) */
+{
+  int bars_done;
+
+  complete_bars(v);
+  bars_done = flush_abctext(v->bars_remaining+1, termination);
+  v->bars_complete = v->bars_complete - bars_done;
+  v->bars_remaining = v->bars_remaining - bars_done;
+  if (v->bars_remaining == 0) {
+    v->bars_remaining = bars_per_line;
+  };
+  head = NULL;
+  tail = NULL;
+  voice[this_voice].currentline = NULL;
+}
+
+static struct abctext* newabctext(t)
+enum abctype t;
+/* called at newlines and barlines */
+/* adds current output text to linked list structure */
+/* part of new linebreak option (-n) */
+{
+  struct abctext* p;
+
+  if (output_on == 0) {
+    p = NULL;
+    return(p);
+  };
+  if (newbreaks) {
+/*
+    if ((t == field) && (!xinbody || (this_voice != next_voice))) {
+*/
+    if (t == field) {
+      complete_all(&voice[this_voice], midmusic);
+      this_voice = next_voice;
+    };
+    p = (struct abctext*) checkmalloc(sizeof(struct abctext));
+    p->text = addstring(tmp);
+    tmp[0] = '\0';
+    p->next = NULL;
+    p->type = t;
+    p->lyrics = NULL;
+    if (t == bar) {
+      p->notes = notecount;
+      totalnotes = totalnotes + notecount;
+      notecount = 0;
+    } else {
+      p->notes = 0;
+    };
+    if (xinbody) {
+      voice[this_voice].barcount = new_barcount(t, 
+                       &voice[this_voice].foundbar, 
+                        voice[this_voice].barcount);
+    };
+    if (head == NULL) {
+      head = p;
+      tail = p;
+    } else {
+      tail->next = p;
+      tail = p;
+    };
+    if ((t != field) && (voice[this_voice].currentline == NULL)) {
+      voice[this_voice].currentline = p;
+    };
+  } else {
+    printf("%s", tmp);
+    tmp[0] = '\0';
+    p = NULL;
+  };
+  inmusic = 1;
+  return(p);
+}
+
+/* This function is never actually used */
+#if 0
+static int nextnotes()
+/* return the number of notes in the next bar */
+/* part of new linebreak option (-n) */
+{
+  int n, got;
+  struct abctext* p;
+
+  p = head;
+  n = 100;
+  got = 0;
+  while ((p != NULL) && (!got)) {
+    if (p->type == bar) {
+      n = p->notes;
+      got = 1;
+    } else {
+      p = p->next;
+    };
+  };
+  return(n);
+}
+#endif 
+
+static void reduce(a, b)
+int *a, *b;
+{
+  int t, n, m;
+
+  /* find HCF using Euclid's algorithm */
+  if (*a > *b) {
+    n = *a;
+    m = *b;
+  } else {
+    n = *b;
+    m = *a;
+  };
+  while (m != 0) {
+    t = n % m;
+    n = m;
+    m = t;
+  };
+  *a = *a/n;
+  *b = *b/n;
+}
+
+
+static void addunits(n, m)
+int n, m;
+/* add fraction n/m to count */
+{
+  prevcount = count;  /* in case of chord extension eg [CE]3/2 */
+  count.num = n*count.denom + count.num*(m*unitlen.denom);
+  count.denom = (m*unitlen.denom)*count.denom;
+  reduce(&count.num, &count.denom);
+}
+
+static void repudiate_lastaddunits()
+{
+  count = prevcount;
+}
+
+void event_init(argc, argv, filename)
+int argc;
+char* argv[];
+char** filename;
+/* routine called on program start-up */
+{
+  int targ, narg;
+
+  if ((getarg("-h", argc, argv) != -1) || (argc < 2)) {
+    printf("abc2abc version %s\n",VERSION);
+    printf("Usage: abc2abc <filename> [-s] [-n X] [-b] [-r] [-e] [-t X]\n");
+    printf("       [-u] [-d] [-v] [-V X] [-ver] [-X n]\n");
+    printf("  -s for new spacing\n");
+    printf("  -n X to re-format the abc with a new linebreak every X bars\n");
+    printf("  -b to remove bar checking\n");
+    printf("  -r to remove repeat checking\n");
+    printf("  -e to remove all error reports\n");
+    printf("  -t X to transpose X semitones\n");
+    printf("  -nda No double accidentals in guitar chords\n");
+    printf("  -nokeys No key signature. Use sharps\n");
+    printf("  -nokeyf No key signature. Use flats\n");
+    printf("  -u to update notation ([] for chords and () for slurs)\n");
+    printf("  -usekey n Use key signature sf (sharps/flats)\n");
+    printf("  -d to notate with doubled note lengths\n");
+    printf("  -v to notate with halved note lengths\n");
+    printf("  -V X to output only voice X\n");
+    printf("  -ver  prints version number and exits\n");
+    printf("  -X n renumber the all X: fields as n, n+1, ..\n");
+    printf("  -OCC old chord convention (eg. +CE+)\n");
+
+    exit(0);
+  } else {
+    *filename = argv[1];
+  };
+  nodouble_accidentals = 0;   /* use correct guitar chords */
+  if (getarg("-ver",argc,argv) != -1) {
+	  printf("%s\n",VERSION);
+	  exit(0);
+  }
+  if (getarg("-u", argc, argv) == -1) {
+    cleanup = 0;
+  } else {
+    cleanup = 1;
+    oldchordconvention = 1;
+  };
+  if (getarg("-s", argc, argv) == -1) {
+    newspacing = 0;
+  } else {
+    newspacing = 1;
+  };
+  narg = getarg("-X", argc, argv);
+  if (narg == -1) {
+    newrefnos = 0;
+  } else {
+    newrefnos = 1;
+    if (narg < argc) {
+      newref = readnumf(argv[narg]);
+    } else {
+      newref = 1;
+    };
+  };
+  if (getarg("-e", argc, argv) == -1) {
+    echeck = 1;
+  } else {
+    echeck = 0;
+  };
+  narg = getarg("-n", argc, argv);
+  if (narg == -1) {
+    newbreaks = 0;
+  } else {
+    newbreaks = 1;
+    if (narg >= argc) {
+      event_error("No value for bars per line after -n");
+      bars_per_line = 4;
+    } else {
+      bars_per_line = readnumf(argv[narg]);
+      if (bars_per_line < 1) {
+        bars_per_line = 4;
+      };
+    };
+  };
+  if (getarg("-b", argc, argv) != -1) {
+    barcheck = 0;
+  } else {
+    barcheck = 1;
+  };
+  if (getarg("-r", argc, argv) != -1) {
+    repcheck = 0;
+  } else {
+    repcheck = 1;
+  };
+  if (getarg("-v", argc, argv) != -1) {
+    lenfactor.num = 1;
+    lenfactor.denom = 2;
+  } else {
+    if (getarg("-d", argc, argv) != -1) {
+      lenfactor.num = 2;
+      lenfactor.denom = 1;
+    } else {
+      lenfactor.num = 1;
+      lenfactor.denom = 1;
+    };
+  };
+  targ = getarg("-t", argc, argv);
+  if (targ == -1) {
+    transpose = 0;
+  } else {
+    if (targ >= argc) {
+      event_error("No tranpose value supplied");
+    } else {
+      if (*argv[targ] == '-') {
+        transpose = -readnumf(argv[targ]+1);
+      } else {
+        transpose = readnumf(argv[targ]);
+      };
+    };
+  };
+  targ = getarg("-nda",argc,argv);
+  if (targ != -1) nodouble_accidentals = 1;
+
+  targ = getarg("-nokeys",argc,argv);
+  if (targ != -1) nokey=1;
+
+  targ = getarg("-nokeyf",argc,argv);
+  if (targ != -1) {nokey=1; useflats=1;}
+
+  targ = getarg("-V", argc, argv);
+  if (targ != -1) {
+    selected_voice  = readnumf(argv[targ]);
+  };
+
+  targ = getarg("-usekey",argc,argv);
+  if (targ != -1) {
+     usekey = readsnumf(argv[targ]);
+     nokey = 1;
+     if (usekey < 0) useflats=1;
+     if (usekey <-5) usekey = -5;
+     if (usekey >5) usekey = 5;
+     setup_sharps_flats (usekey);
+     }
+  if (getarg("-OCC",argc,argv) != -1) oldchordconvention=1;
+
+  /* printf("%% output from abc2abc\n"); */
+  startline = 1;
+  blankline = 0;
+  xinbody =0;
+  inmusic = 0;
+  inchord = 0;
+  ingrace = 0;
+  head = NULL;
+  tail = NULL;
+  tmp[0] = '\0';
+  totalnotes = 0;
+}
+
+void emit_string(s)
+char *s;
+/* output string */
+{
+  if (output_on) {
+    strcpy(tmp+strlen(tmp), s);
+  };
+}
+
+void emit_char(ch)
+char ch;
+/* output single character */
+{
+  char *place;
+
+  if (output_on) {
+    place = tmp+strlen(tmp);
+    *place = ch;
+    *(place+1) = '\0';
+  };
+}
+
+void emit_int(n)
+int n;
+/* output integer */
+{
+  if (output_on) {
+    sprintf(tmp+strlen(tmp), "%d", n);
+  };
+}
+
+void emit_string_sprintf(s1, s2)
+char *s1;
+char *s2;
+/* output string containing string expression %s */
+{
+  if (output_on) {
+    sprintf(tmp+strlen(tmp), s1, s2);
+  };
+}
+
+void emit_int_sprintf(s, n)
+char *s;
+int n;
+/* output string containing int expression %d */
+{
+  if (output_on) {
+    sprintf(tmp+strlen(tmp), s, n);
+  };
+}
+
+void unemit_inline()
+/* remove previously output start of inline field */
+/* needed for -V voice selection option           */
+{
+  int len;
+
+  len = strlen(tmp);
+  if ((len > 0) && (tmp[len-1] == '[')) {
+    tmp[len-1] = '\0'; /* delete last character */
+  } else {
+    event_error("Internal error - Could not delete [");
+  };
+}
+
+static void close_newabc()
+/* output all remaining abc_text elements */
+/* part of new linebreak option (-n) */
+{
+  if (newbreaks) {
+    complete_all(&voice[this_voice], endmusicline);
+    if (linestat == midmusic) setline(endmusicline);
+    setline(fresh);
+  };
+}
+
+void event_eof()
+{
+  close_newabc();
+}
+
+void event_blankline()
+{
+  output_on = 1;
+  close_newabc();
+/*  if (newbreaks) [SS] 2006-09-23 */  printf("\n");
+  xinbody = 0;
+  xinhead = 0;
+  parseroff();
+  blankline = 1;
+}
+
+void event_text(p)
+char *p;
+{
+  emit_string_sprintf("%%%s", p);
+  inmusic = 0;
+}
+
+void event_reserved(p)
+char p;
+{
+  emit_char(p);
+  inmusic = 0;
+}
+
+void event_tex(s)
+char *s;
+{
+  emit_string(s);
+  inmusic = 0;
+}
+
+void event_linebreak()
+{
+  if (newbreaks) {
+    if (!purgespace(tmp)) {
+      if (inmusic) {
+        newabctext(bar);
+      } else {
+        newabctext(field);
+      };
+    };
+  } else {
+    newabctext(bar);
+    if (output_on) {
+      printf("\n");
+    };
+    /* don't output new line if voice is already suppressed
+       otherwise we will get lots of blank lines where we
+       are suppressing output. [SS] feb-10-2002.
+     */
+  };
+}
+
+void event_startmusicline()
+/* encountered the start of a line of notes */
+{
+  voice[this_voice].currentline = NULL;
+  complete_bars(&voice[this_voice]);
+}
+
+void event_endmusicline(endchar)
+char endchar;
+/* encountered the end of a line of notes */
+{
+}
+
+void event_error(s)
+char *s;
+{
+  if (echeck) {
+   printf("\n%%Error : %s\n", s);
+  };
+}
+
+void event_warning(s)
+char *s;
+{
+  if (echeck) {
+   printf("\n%%Warning : %s\n", s);
+  };
+}
+
+void event_comment(s)
+char *s;
+{
+  if (newbreaks && (!purgespace(tmp))) {
+    if (inmusic) {
+      newabctext(bar);
+    } else {
+      newabctext(field);
+    };
+  };
+  emit_string_sprintf("%%%s", s);
+  inmusic = 0;
+}
+
+void event_specific(package, s)
+char *package, *s;
+{
+  char command[40];
+  int ch;
+  char *p;
+  emit_string("%%");
+  emit_string(package);
+  emit_string(s);
+  inmusic = 0;
+/* detect drum channel by searching for %%MIDI channel 10 */
+  if (strcmp(package,"MIDI") != 0) return;
+  p = s;
+  skipspace(&p);
+  readstr(command, &p, 40);
+  if (strcmp(command, "channel") != 0) return;
+  skipspace(&p);
+  ch = readnump(&p);
+  if(ch == 10) {
+               voice[next_voice].drumchan = 1;
+               drumchan = 1;
+               }
+/*  printf("event_specific: next_voice = %d\n",next_voice); */
+}
+
+void event_info(f)
+/* handles info field I: */
+char *f;
+{
+  emit_string_sprintf("I:%s", f);
+  inmusic = 0;
+}
+
+
+void event_field(k, f)
+char k;
+char *f;
+{
+  emit_char(k);
+  emit_char(':');
+  emit_string(f);
+  inmusic = 0;
+}
+
+struct abctext* getbar(place)
+struct abctext *place;
+/* find first element in list which is a bar of music */
+{
+  struct abctext *newplace;
+
+  newplace = place;
+  while ((newplace != NULL) &&
+         ((newplace->type != bar) || 
+          (newplace->notes == 0))) {
+    newplace = newplace->next;
+  };
+  return(newplace);    
+}
+
+struct abctext* getnextbar(place)
+struct abctext *place;
+/* find next element in list which is a bar of music */
+{
+  struct abctext *newplace;
+
+  newplace = place;
+  if (newplace != NULL) {
+    newplace = getbar(newplace->next);
+  };
+  return(newplace);
+};
+
+void append_lyrics(place, newwords)
+struct abctext *place;
+char *newwords;
+/* add lyrics to end of lyric list associated with bar */
+{
+  struct lyricwords* new_words;
+  struct lyricwords *new_place;
+
+  if (place == NULL) {
+    return;
+  };
+  /* printf("append_lyrics has %s at %s\n", newwords, place->text); */
+  new_words = (struct lyricwords*)checkmalloc(sizeof(struct lyricwords));
+  /* add words to bar */
+  new_words->nextverse = NULL;
+  new_words->words = addstring(newwords);
+  if (place->lyrics == NULL) {
+    place->lyrics = new_words;
+  } else {
+    new_place = place->lyrics;
+    /* find end of list */
+    while (new_place->nextverse != NULL) {
+      new_place = new_place->nextverse;
+    };
+    new_place->nextverse = new_words;
+  };
+}
+
+struct abctext* apply_bar(syll, place, notesleft, barwords)
+/* advance to next bar (on finding '|' in a w: field) */
+char* syll;
+struct abctext *place;
+int *notesleft;
+struct vstring *barwords;
+{
+  struct abctext* new_place;
+
+  if (place == NULL) {
+    return(NULL);
+  };
+  new_place = place;
+  addtext(syll, barwords);
+  append_lyrics(place, barwords->st);
+  /* go on to next bar */
+  clearvstring(barwords);
+  new_place = getnextbar(place);
+  if (new_place != NULL) {
+    *notesleft = new_place->notes;
+  };
+  return(new_place); 
+}
+
+struct abctext* apply_syllable(syll, place, notesleft, barwords)
+/* attach syllable to appropriate place in abctext structure */
+char* syll;
+struct abctext *place;
+int *notesleft;
+struct vstring *barwords;
+{
+  struct abctext* new_place;
+  char msg[80];
+
+  if (place == NULL) {
+    sprintf(msg, "Cannot find note to match \"%s\"", syll);
+    event_error(msg);
+    return(NULL);
+  };
+  new_place = place;
+  addtext(syll, barwords);
+  *notesleft = *notesleft - 1;
+  if (*notesleft == 0) {
+    append_lyrics(place, barwords->st);
+    /* go on to next bar */
+    clearvstring(barwords);
+    new_place = getnextbar(place);
+    if (new_place != NULL) {
+      *notesleft = new_place->notes;
+    };
+  };
+  return(new_place); 
+}
+
+void parse_words(p)
+char* p;
+/* Break up a line of lyrics (w: ) into component syllables */
+{
+  struct vstring syll;
+  struct vstring barwords;
+  char* q;
+  unsigned char ch;
+  int errors;
+  int found_hyphen;
+
+  struct abctext *place;
+  int notesleft;
+
+  if (!xinbody) {
+    event_error("w: field outside tune body");
+    return;
+  };
+  place = getbar(voice[this_voice].currentline);
+  if (place == NULL) {
+    event_error("No music to match w: line to");
+    return;
+  };
+  notesleft = voice[this_voice].currentline->notes;
+  initvstring(&barwords);
+  errors = 0;
+  if (place == NULL) {
+    event_error("No notes to match words");
+    return;
+  };
+  initvstring(&syll);
+  q = p;
+  skipspace(&q);
+  while (*q != '\0') {
+    found_hyphen = 0;
+    clearvstring(&syll);
+    ch = *q;
+    while(ch=='|') {
+      addch('|', &syll);
+      addch(' ', &syll);
+      place = apply_bar(syll.st, place, &notesleft, &barwords);
+      clearvstring(&syll);
+      q++;
+      ch = *q;
+    };
+    /* PCC seems to require (ch != ' ') on the next line */
+    /* presumably PCC's version of ispunct() thinks ' ' is punctuation */
+    while (((ch>127)||isalnum(ch)||ispunct(ch))&&(ch != ' ')&&
+           (ch != '_')&&(ch != '-')&&(ch != '*')&& (ch != '|')) {
+      if ((ch == '\\') && (*(q+1)=='-')) {
+        addch('\\', &syll);
+        ch = '-';
+        q++;
+      };
+      /* syllable[i] = ch; */
+      addch(ch, &syll);
+      q++;
+      ch = *q;
+    };
+    skipspace(&q);
+    if (ch == '-') {
+      found_hyphen = 1;
+      addch(ch, &syll);
+      while (isspace(ch)||(ch=='-')) {
+        q++;
+        ch = *q;
+      };
+    };
+    if (syll.len > 0) {
+      if (!found_hyphen) {
+        addch(' ', &syll);
+      };
+      place = apply_syllable(syll.st, place, &notesleft, &barwords);
+    } else {
+      if (ch=='_') {
+        clearvstring(&syll);
+        addch('_', &syll);
+        addch(' ', &syll);
+        place = apply_syllable(syll.st, place, &notesleft, &barwords);
+        q++;
+        ch = *q;
+      };
+      if (ch=='*') {
+        clearvstring(&syll);
+        addch('*', &syll);
+        addch(' ', &syll);
+        place = apply_syllable(syll.st, place, &notesleft, &barwords);
+        q++;
+        ch = *q;
+      };
+    }; 
+  };
+  if (errors > 0) {
+    event_error("Lyric line too long for music");
+  } else {
+    clearvstring(&syll);
+  };
+  freevstring(&syll);
+}
+
+void event_words(p, continuation)
+char* p;
+int continuation;
+/* a w: field has been encountered */
+{
+  struct vstring afield;
+
+  if (xinbody && newbreaks) {
+    parse_words(p);
+  } else {
+    initvstring(&afield);
+    addtext(p, &afield);
+    if (continuation) {
+      addch(' ', &afield);
+      addch('\\', &afield);
+    };
+    event_field('w', afield.st);
+  };
+}
+
+void event_part(s)
+char* s;
+{
+  if (xinbody) {
+    complete_bars(&voice[this_voice]);
+  };
+  emit_string_sprintf("P:%s", s);
+  inmusic = 0;
+}
+
+int setvoice(num)
+int num;
+/* we need to keep track of current voice for new linebreak handling (-n) */
+/* change voice to num. If voice does not exist, start new one */
+{
+  int i, voice_index;
+
+  i = 0;
+  while ((i < voicecount) && (voice[i].number != num)) {
+    i = i + 1;
+  };
+  if ((i < voicecount) && (voice[i].number == num)) {
+    voice_index = i;
+    drumchan = voice[voice_index].drumchan;
+/*    printf("voice_index = %d drumchan = %d\n",voice_index,drumchan); */
+  } else {
+    voice_index = voicecount;
+    if (voicecount < MAX_VOICES) {
+      voicecount = voicecount + 1;
+    } else {
+      event_error("Number of voices exceeds static limit MAX_VOICES");
+    };
+    voice[voice_index].number = num;
+    voice[voice_index].barcount = zero_barcount(&voice[voice_index].foundbar);
+    voice[voice_index].bars_complete = 0;
+    voice[voice_index].bars_remaining = bars_per_line;
+    voice[voice_index].drumchan = 0;
+  };
+  voice[voice_index].currentline = NULL;
+  return(voice_index);
+}
+
+void event_voice(n, s, vp)
+int n;
+char *s;
+struct voice_params *vp;
+{
+  char output[32];
+  if (xinbody) {
+    next_voice = setvoice(n);
+  };
+  if ((selected_voice != -1) && (n != selected_voice)) {
+    if ((inlinefield) && (output_on == 1)) { 
+      unemit_inline();
+    }; 
+    output_on = 0;
+  } else { 
+    if (output_on == 0) { 
+      output_on = 1; 
+      if (inlinefield) { 
+        emit_string("["); /* regenerate missing [ */
+      }; 
+    }; 
+  }; 
+  if (strlen(s) == 0) {
+    if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]);
+    else emit_int_sprintf("V:%d", n);
+    if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname);
+	    emit_string(output);}
+    if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave);
+	    emit_string(output);}
+    if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose);
+	    emit_string(output);}
+     if (vp->gotname) {sprintf(output," name=%s", vp->namestring);
+            emit_string(output);}
+     if (vp->gotsname) {sprintf(output," sname=%s", vp->snamestring);
+            emit_string(output);}
+     if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring);
+            emit_string(output);}
+  } else {
+    if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]);
+    emit_int_sprintf("V:%d ", n);
+    if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname);
+	    emit_string(output);}
+    if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave);
+	    emit_string(output);}
+    if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose);
+	    emit_string(output);}
+     if (vp->gotname) {sprintf(output," name=%s", vp->namestring);
+            emit_string(output);}
+     if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring);
+            emit_string(output);}
+    emit_string(s);
+  };
+  inmusic = 0;
+}
+
+void event_length(n)
+int n;
+{
+  struct fract newunit;
+
+  newunit.num = lenfactor.denom;
+  newunit.denom = lenfactor.num * n;
+  reduce(&newunit.num, &newunit.denom);
+  emit_int_sprintf("L:%d/", newunit.num);
+  emit_int(newunit.denom);
+  unitlen.num = 1;
+  unitlen.denom = n;
+  inmusic = 0;
+}
+
+void event_refno(n)
+int n;
+{
+  if (xinbody) {
+    close_newabc();
+  };
+  output_on = 1;
+  if (newrefnos) {
+    emit_int_sprintf("X: %d", newref);
+    newref = newref + 1;
+  } else {
+    emit_int_sprintf("X: %d", n);
+  };
+  parseron();
+  xinhead = 1;
+  notecount = 0;
+  unitlen.num = 0;
+  unitlen.denom = 1;
+  barlen.num = 0;
+  barlen.denom = 1;
+  inmusic = 0;
+  barcount = 0;
+}
+
+void event_tempo(n, a, b, relative, pre, post)
+int n, a, b;
+int relative;
+char *pre;
+char *post;
+{
+  struct fract newlen;
+
+  emit_string("Q:");
+  if (pre != NULL) {
+    emit_string_sprintf("\"%s\"", pre);
+  };
+  if (n != 0) {
+    if ((a == 0) && (b == 0)) {
+      emit_int(n);
+    } else {
+      if (relative) {
+        newlen.num = a * lenfactor.num;
+        newlen.denom = b * lenfactor.denom;
+        reduce(&newlen.num, &newlen.denom);
+        emit_int_sprintf("C%d/", newlen.num);
+        emit_int(newlen.denom);
+        emit_int_sprintf("=%d", n);
+      } else {
+        emit_int_sprintf("%d/", a);
+        emit_int(b);
+        emit_int_sprintf("=%d", n);
+      };
+    };
+  };
+  if (post != NULL) {
+    emit_string_sprintf("\"%s\"", post);
+  };
+  inmusic = 0;
+}
+
+void event_timesig(n, m, checkbars)
+int n, m, checkbars;
+{
+  if (checkbars == 1) {
+    emit_int_sprintf("M:%d/", n);
+    emit_int(m);
+  } else {
+    emit_string("M:none");
+    barcheck = 0;
+  };
+  barlen.num = n;
+  barlen.denom = m;
+  breakpoint.num = n;
+  breakpoint.denom = m;
+  if ((n == 9) || (n == 6)) {
+    breakpoint.num = 3;
+    breakpoint.denom = barlen.denom;
+  };
+  if (n%2 == 0) {
+    breakpoint.num = barlen.num/2;
+    breakpoint.denom = barlen.denom;
+  };
+  barend = n/breakpoint.num;
+  inmusic = 0;
+}
+
+static void setmap(sf, map)
+int sf;
+int map[7];
+{
+/* map[0] to map[7] corresponds to keys a to g and indicates
+   whether they are flattened or sharpened. sf encodes the
+   key signature by indicating the number of sharps (positive
+   numbers) or flats (negative numbers)
+*/
+  int j;
+
+  for (j=0; j<7; j++) {
+    map[j] = 0;
+  };
+  if (sf >= 1) map['f'-'a'] = 1;
+  if (sf >= 2) map['c'-'a'] = 1;
+  if (sf >= 3) map['g'-'a'] = 1;
+  if (sf >= 4) map['d'-'a'] = 1;
+  if (sf >= 5) map['a'-'a'] = 1;
+  if (sf >= 6) map['e'-'a'] = 1;
+  if (sf >= 7) map['b'-'a'] = 1;
+  if (sf <= -1) map['b'-'a'] = -1;
+  if (sf <= -2) map['e'-'a'] = -1;
+  if (sf <= -3) map['a'-'a'] = -1;
+  if (sf <= -4) map['d'-'a'] = -1;
+  if (sf <= -5) map['g'-'a'] = -1;
+  if (sf <= -6) map['c'-'a'] = -1;
+  if (sf <= -7) map['f'-'a'] = -1;
+}
+
+static void start_tune()
+{
+  parseron();
+  count.num =0;
+  count.denom = 1;
+  barno = 0;
+  tuplenotes = 0;
+  expect_repeat = 0;
+  inlinefield = 0;
+  if (barlen.num == 0) {
+    /* generate missing time signature */
+    event_linebreak();
+    event_timesig(4, 4, 1);
+    inmusic = 0;
+  };
+  if (unitlen.num == 0) {
+    if ((float) barlen.num / (float) barlen.denom < 0.75) {
+      unitlen.num = 1;
+      unitlen.denom = 16;
+    } else {
+      unitlen.num = 1;
+      unitlen.denom = 8;
+    };
+  };
+  voicecount = 0;
+  this_voice = setvoice(1);
+  next_voice = this_voice;
+}
+
+void compute_keysignature (int sf,int modeindex, char * keysignature)
+{
+char  *notes[7] = {"A","B","C","D","E","F","G"};
+int sf2note[12] = {3,0,4,1,5,2,6,3,0,4,1,5};
+char *flatsharp[2] = {"b","#"};
+int index0,index1,index;
+int map[7];
+
+index0 = sf+5; /* -5 <sf < 4 */
+index1 = sf2note[index0]; /* major key */
+index =index1 + modekeyshift[modeindex]; /* key for mode */
+setmap(sf,map); /* determine the flats and sharps for major key */
+if (index > 6) index -=7;
+strcpy(keysignature,notes[index]);
+/* propogate sharp or flat to key signature of mode */
+if (map[index] == -1) strcat(keysignature,flatsharp[0]);
+if (map[index] == 1) strcat(keysignature,flatsharp[1]);
+/* add mode name */
+strcat(keysignature,mode[modeindex]);
+}
+
+
+
+void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname,
+          octave, xtranspose, gotoctave, gottranspose)
+int sharps;
+char *s;
+int modeindex;
+char modmap[7];
+int modmul[7];
+int gotkey, gotclef;
+char* clefname;
+int octave, xtranspose, gotoctave, gottranspose;
+{
+  static char* keys[12] = {"Db", "Ab", "Eb", "Bb", "F", "C", 
+                           "G", "D", "A", "E", "B", "F#"};
+  char signature[10];
+ 
+  if (gotkey) {
+    setmap(sharps, basemap); /* required by copymap and pitchof */
+    setmap(sharps, oldtable);
+    copymap();
+    newkey = (sharps+7*transpose)%12;
+    if (sharps < -5) orig_key_number = (int) keys[sharps+17][0] - (int) 'A';
+    else if (sharps > 6) orig_key_number = (int)keys[sharps-7][0] - (int) 'A';
+    else    orig_key_number = (int) keys[sharps+5][0] - (int) 'A';
+    lines = (sharps+7*transpose)/12;
+    if (newkey > 6) {
+      newkey = newkey - 12;
+      lines = lines + 1;
+    };
+    if (newkey < -5) {
+      newkey = newkey + 12;
+      lines = lines - 1;
+    };
+    setmap(newkey, newtable);  /* used by event_note1 */
+    new_key_number = (int) keys[newkey+5][0] - (int) 'A';
+  };
+  emit_string("K:");
+  if (transpose == 0 && !nokey) {
+    emit_string(s); 
+  } else {
+    if (gotkey) {
+      if (!nokey) {
+        /*  emit_string(keys[newkey+5]); */
+        compute_keysignature(newkey,modeindex,signature); /* [SS] 2006-07-30*/
+        emit_string(signature); /* [SS] 2006-07-30 */
+        }
+
+      else if (usekey == 0) emit_string("none"); 
+      else emit_string(keys[usekey+5]);
+      if (gotclef) {
+        emit_string(" ");
+      };
+    };
+    if (gotclef) {
+      emit_string_sprintf("clef=%s", clefname);
+    };
+    if (gotoctave) {
+      emit_int_sprintf(" octave=%d", octave);
+    };
+    if (gottranspose) {
+      emit_int_sprintf(" transpose=%d", xtranspose);
+    };
+  };
+  if ((xinhead) && (!xinbody)) {
+    xinbody = 1;
+    start_tune();
+  };
+  inmusic = 0;
+}
+
+static void printlen(a, b)
+int a, b;
+{
+  if (a != 1) {
+    emit_int(a);
+  };
+  if (b != 1) {
+    emit_int_sprintf("/%d", b);
+  };
+}
+
+void event_spacing(n, m)
+int n, m;
+{
+  emit_string("y");
+  printlen(n, m);
+}
+
+
+void event_rest(decorators,n,m,type)
+int n, m, type;
+int decorators[DECSIZE];
+{
+  struct fract newlen;
+
+  inmusic = 1;
+  if( type == 1) emit_string("x");
+  else emit_string("z");
+  newlen.num = n * lenfactor.num;
+  newlen.denom = m * lenfactor.denom;
+  reduce(&newlen.num, &newlen.denom);
+  printlen(newlen.num, newlen.denom);
+  if (inchord) {
+    chordcount = chordcount + 1;
+  };
+  if ((!ingrace) && (!inchord || (chordcount == 1))) {
+    if (!tuplenotes) addunits(n, m);
+    else {
+      addunits(n*tuplefactor.num, m*tuplefactor.denom);
+      tuplenotes = tuplenotes - 1;
+      }
+  };
+}
+
+void event_mrest(n,m)
+int n, m;
+{
+  inmusic = 1;
+  emit_string("Z");
+  printlen(n,m);
+  if (inchord) {
+    event_error("Multiple bar rest not allowed in chord");
+  };
+  if (tuplenotes != 0) {
+    event_error("Multiple bar rest not allowed in tuple");
+  };
+}
+
+void event_bar(type, replist)
+int type;
+char* replist;
+{
+  char msg[40];
+
+  if (!purgespace(tmp)) {
+    if (inmusic) {
+      newabctext(bar);
+    } else {
+      newabctext(field);
+    };
+  };
+  switch(type) {
+  case SINGLE_BAR:
+    emit_string_sprintf("|%s", replist);
+    break;
+  case DOUBLE_BAR:
+    emit_string("||");
+    break;
+  case THIN_THICK:
+    emit_string("|]");
+    break;
+  case THICK_THIN:
+    emit_string("[|");
+    break;
+  case BAR_REP:
+    emit_string("|:");
+    if ((expect_repeat) && (repcheck)) {
+      event_error("Expecting repeat, found |:");
+    };
+    expect_repeat = 1;
+    break;
+  case REP_BAR:
+    emit_string_sprintf(":|%s", replist);
+    if ((!expect_repeat) && (repcheck)) {
+      event_warning("No repeat expected, found :|");
+    };
+    expect_repeat = 0;
+    break;
+  case BAR1:
+    emit_string("|1");
+    if ((!expect_repeat) && (repcheck)) {
+      event_warning("found |1 in non-repeat section");
+    };
+    break;
+  case REP_BAR2:
+    emit_string(":|2");
+    if ((!expect_repeat) && (repcheck)) {
+      event_warning("No repeat expected, found :|2");
+    };
+    expect_repeat = 0;
+    break;
+  case DOUBLE_REP:
+    emit_string("::");
+    if ((!expect_repeat) && (repcheck)) {
+      event_error("No repeat expected, found ::");
+    };
+    expect_repeat = 1;
+    break;
+  };
+  if ((count.num*barlen.denom != barlen.num*count.denom) &&
+      (count.num != 0) && (barno != 0) && (barcheck)) {
+    sprintf(msg, "Bar %d is %d/%d not %d/%d", barno, 
+           count.num, count.denom,
+           barlen.num, barlen.denom );
+    event_error(msg);
+  };
+  newabctext(barline);
+  barno = barno + 1;
+  count.num = 0;
+  count.denom = 1;
+  copymap();
+}
+
+void event_space()
+{
+  if (!newspacing) {
+    emit_string(" ");
+  };
+}
+
+void event_graceon()
+{
+  emit_string("{");
+  ingrace = 1;
+}
+
+void event_graceoff()
+{
+  emit_string("}");
+  ingrace = 0;
+}
+
+void event_rep1()
+{
+  emit_string(" [1");
+}
+
+void event_rep2()
+{
+  emit_string(" [2");
+}
+
+void event_playonrep(s)
+char*s;
+{
+  emit_string_sprintf(" [%s", s);
+}
+
+void event_broken(type, n)
+int type, n;
+{
+  int i;
+
+  if (type == GT) {
+    for (i=0; i<n; i++) {
+      emit_char('>');
+    };
+  } else {
+    for (i=0; i<n; i++) {
+      emit_char('<');
+    };
+  };
+}
+
+void event_tuple(n, q, r)
+int n, q, r;
+{
+  emit_int_sprintf("(%d", n);
+  if (tuplenotes != 0) {
+    event_error("tuple within tuple not allowed");
+  };
+  if (q != 0) {
+    emit_int_sprintf(":%d", q);
+    tuplefactor.num = q;
+    tuplefactor.denom = n;
+    if (r != 0) {
+      emit_int_sprintf(":%d", r);
+      tuplenotes = r;
+    } else {
+      tuplenotes = n;
+    };
+  } else {
+    tuplenotes = n;
+    tuplefactor.denom = n;
+    if ((n == 2) || (n == 4) || (n == 8)) tuplefactor.num = 3;
+    if ((n == 3) || (n == 6)) tuplefactor.num = 2;
+    if ((n == 5) || (n == 7) || (n == 9)) {
+      if ((barlen.num % 3) == 0) {
+        tuplefactor.num = 3;
+      } else {
+        tuplefactor.num = 2;
+      };
+    };
+  };
+}
+
+void event_startinline()
+{
+  emit_string("[");
+  inlinefield = 1;
+}
+
+void event_closeinline()
+{
+  emit_string("]");
+  inmusic = 1;
+  inlinefield = 0;
+}
+
+void event_chord()
+{
+  if (cleanup) {
+    if (inchord) {
+      emit_string("]");
+    } else {
+      emit_string("[");
+    };
+  } else {
+    emit_string("+");
+  };
+  inmusic = 1;
+  inchord = 1 - inchord;
+  chordcount = 0;
+}
+
+void event_chordon(int chorddecorators[])
+{
+  int i;
+  for (i=0; i<DECSIZE; i++) {
+    if (chorddecorators[i]) 
+      emit_char(decorations[i]);
+    }
+  emit_string("[");
+  inmusic = 1;
+  inchord = 1;
+  chordcount = 0;
+}
+
+void event_chordoff(int chord_n, int chord_m)
+{
+  char string[16];
+  emit_string("]");
+  if(chord_n !=1 && chord_m !=1)
+     {
+     sprintf(string,"%d/%d",chord_n,chord_m);
+     emit_string(string);
+     }
+  else if(chord_n !=1)
+     {
+     sprintf(string,"%d",chord_n);
+     emit_string(string);
+     }
+  else if(chord_m !=1)
+     {
+     sprintf(string,"/%d",chord_m);
+     emit_string(string);
+     }
+  inmusic = 1;
+  inchord = 0;
+  if(chord_n !=1 || chord_m !=1)
+    {
+    repudiate_lastaddunits();
+    addunits(chord_n,chord_m);
+    }
+}
+
+static void splitstring(s, sep, handler)
+char* s;
+char sep;
+void (*handler)();
+/* this routine splits the string into fields using semi-colon */
+/* and calls handler for each sub-string                       */
+{
+  char* out;
+  char* p;
+  int fieldcoming;
+
+  p = s;
+  fieldcoming = 1;
+  while (fieldcoming) {
+    out = p;
+    while ((*p != '\0') && (*p != sep)) p = p + 1;
+    if (*p == sep) {
+      *p = '\0';
+      p = p + 1;
+    } else {
+      fieldcoming = 0;
+    };
+    (*handler)(out);
+  };
+}
+
+void event_handle_gchord(s)
+/* deals with an accompaniment (guitar) chord */
+/* either copies it straight out or transposes it */
+char* s;
+{
+  char newchord[50];
+  static int offset[7] = {9, 11, 0, 2, 4, 5, 7};
+  static char* sharproots[12] = {"C", "C#", "D", "D#", "E", "F",
+                            "F#", "G", "G#", "A", "A#", "B"};
+  static char* flatroots[12] = {"C", "Db", "D", "Eb", "E", "F",
+                            "Gb", "G", "Ab", "A", "Bb", "B"};
+  static char* sharpbases[12] = {"c", "c#", "d", "d#", "e", "f",
+                            "f#", "g", "g#", "a", "a#", "b"};
+  static char* flatbases[12] = {"c", "db", "d", "eb", "e", "f",
+                            "gb", "g", "ab", "a", "bb", "b"};
+  char** roots;
+  char** bases;
+  int chordstart;
+  int key_number;
+  int old_triad_number;
+  int new_triad_number;
+  int triad_diff;
+
+  if ((transpose == 0) || (*s == '_') || (*s == '^') || (*s == '<') ||
+      (*s == '>') || (*s == '@')) {
+    emit_string_sprintf("\"%s\"", s);
+  } else {
+    char* p;
+    int pitch;
+    int j;
+
+    if (newkey >= 0) {
+      roots = sharproots;
+      bases = sharpbases;
+    } else {
+      roots = flatroots;
+      bases = flatbases;
+    };
+    p = s;
+    chordstart = 1;
+    j = 0;
+    while (*p != '\0') {
+      if (chordstart) {
+        if ((*p >= 'A') && (*p <= 'G')) {
+          key_number = (int) *p - ((int) 'A');
+	  old_triad_number = key_number - orig_key_number+1;
+	  if (old_triad_number < 1) old_triad_number += 7;
+          pitch = (offset[key_number] + transpose)%12;
+          p = p + 1;
+          if (*p == 'b') {
+            pitch = pitch - 1;
+            p = p + 1;
+            };
+          if (*p == '#') {
+            pitch = pitch + 1;
+            p = p + 1;
+            };
+          pitch = (pitch + 12)%12;
+	  key_number = (int) roots[pitch][0] - (int) 'A';
+	  new_triad_number = key_number - new_key_number +1;
+	  if (new_triad_number < 1) new_triad_number += 7;
+	  triad_diff = new_triad_number - old_triad_number;
+	  if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) {
+		  /*      printf("*** %d  old chord = %s (%d) new chord = %s (%d)\n",
+		        triad_diff,s,old_triad_number,roots[pitch],new_triad_number); */
+	                pitch = pitch+1;
+                        pitch = (pitch+12)%12;
+                        strcpy(&newchord[j],roots[pitch]);
+                        j = strlen(newchord);
+                        strcpy(&newchord[j],"b");
+                        j = j+1;
+                        if (adapt_useflats_to_gchords) useflats=1;
+	                } else
+          if (!nodouble_accidentals && (triad_diff  ==1 || triad_diff == -6)) {
+  	         /*	   printf("*** %d old chord = %s (%d) new chord = %s (%d)\n",
+		         triad_diff,s,old_triad_number,roots[pitch],new_triad_number);  */
+
+                        pitch = pitch-1;
+                        pitch = (pitch+12)%12;
+                        strcpy(&newchord[j],roots[pitch]);
+                        j = strlen(newchord);
+                        strcpy(&newchord[j],"#");
+                        j = j+1;
+                        if (adapt_useflats_to_gchords) useflats=0;
+                        } else  
+/* no extra flats or sharps needed */
+                        {
+                        strcpy(&newchord[j], roots[pitch]);
+                        j = strlen(newchord);
+                        }
+
+          chordstart = 0;
+        } else {
+          if ((*p >= 'a') && (*p <= 'g')) {
+            key_number = (int) *p - ((int) 'a');
+	    old_triad_number = key_number - orig_key_number+1;
+	    if (old_triad_number < 1) old_triad_number += 7;
+            pitch = (offset[key_number] + transpose)%12;
+            p = p + 1;
+            if (*p == 'b') {
+              pitch = pitch - 1;
+              p = p + 1;
+              };
+            if (*p == '#') {
+              pitch = pitch + 1;
+              p = p + 1;
+              };
+            pitch = (pitch + 12)%12;
+	    key_number = (int) bases[pitch][0] - (int) 'a';
+	    new_triad_number = key_number - new_key_number +1;
+	    if (new_triad_number < 1) new_triad_number += 7;
+	    triad_diff = new_triad_number - old_triad_number;
+	  if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) {
+          /*              printf("*** %d  old chord = %s (%d) new chord = %s (%d)\n",
+			 triad_diff,s,old_triad_number,bases[pitch],new_triad_number); */
+	                pitch = pitch+1;
+                        pitch = (pitch+12)%12;
+			strcpy(&newchord[j],bases[pitch]);
+			j = strlen(newchord);
+			strcpy(&newchord[j],"b");
+			j = j+1;
+	                } else
+          if (!nodouble_accidentals && (triad_diff  ==1 || triad_diff == -6)) {
+	/*	        printf("*** %d old chord = %s (%d) new chord = %s (%d)\n",
+			 triad_diff,s,old_triad_number,bases[pitch],new_triad_number);*/
+			 pitch = pitch-1;
+			 pitch = (pitch+12)%12;
+			 strcpy(&newchord[j],bases[pitch]);
+			 j = strlen(newchord);
+			 strcpy(&newchord[j],"#");
+			 j = j+1;
+                         } else
+	                 {
+                         strcpy(&newchord[j], bases[pitch]);
+                         j = strlen(newchord);
+			 }
+            chordstart = 0;
+          } else {
+            if (isalpha(*p)) {
+              chordstart = 0;
+            };
+            newchord[j] = *p;
+            p = p + 1;
+            j = j + 1;
+            newchord[j] = '\0';
+          };
+        };
+      } else {
+        if ((*p == '/') || (*p == '(') || (*p == ' ')) {
+          chordstart = 1;
+        };
+
+        newchord[j] = *p;
+        p = p + 1;
+        j = j + 1;
+        newchord[j] = '\0';
+      };
+      if (j >= 49) {
+        event_error("guitar chord contains too much text");
+        while (*p != '\0') {
+          p = p + 1;
+        };
+      };
+    };
+    emit_string_sprintf("\"%s\"", newchord);
+  };
+}
+
+void event_gchord(s)
+char* s;
+{
+  splitstring(s, ';', event_handle_gchord);
+}
+
+void event_instruction(s)
+char* s;
+{
+  if (oldchordconvention) emit_string_sprintf("!%s!", s);
+  else emit_string_sprintf("+%s+", s);
+}
+
+void event_slur(t)
+int t;
+{
+  if (cleanup) {
+    if (t) {
+      emit_string("(");
+    } else {
+      emit_string(")");
+    };
+  } else {
+    emit_string("s");
+  };
+}
+
+void event_sluron(t)
+int t;
+{
+  emit_string("(");
+}
+
+void event_sluroff(t)
+int t;
+{
+  emit_string(")");
+}
+
+void event_tie()
+{
+  emit_string("-");
+}
+
+void event_lineend(ch, n)
+char ch;
+int n;
+{
+  int i;
+
+  if (!newbreaks) {
+    for (i = 0; i<n; i++) {
+      emit_char(ch);
+    };
+  };
+}
+
+
+
+void event_note1(decorators, xaccidental, xmult, xnote, xoctave, n, m)
+int decorators[DECSIZE];
+int xmult;
+char xaccidental, xnote;
+int xoctave, n, m;
+{
+  int t;
+  struct fract barpoint;
+  struct fract newlen;
+  int mult;
+  char accidental, note;
+  int octave;
+
+  mult = 0;  /* [SS] 2006-10-27 */
+  if (transpose == 0 || drumchan) {
+    accidental = xaccidental;
+    mult = xmult;
+    note = xnote;
+    octave = xoctave;
+  } else {
+    int val, newval;
+    int acc = 0;
+    char *anoctave = "cdefgab";
+
+    octave = xoctave;
+    val = (int) ((long) strchr(anoctave, xnote) - (long) anoctave);
+    newval = val + lines;
+    octave = octave + (newval/7);
+    newval = newval % 7;
+    if (newval < 0) {
+      newval = newval + 7;
+      octave = octave - 1;
+    };
+    note = *(anoctave+newval);
+    if (xaccidental == ' ') {
+      accidental = ' ';
+    } else {
+      switch (xaccidental) {
+      case '_':
+        acc = -xmult;
+        break;
+      case '^':
+        acc = xmult;
+        break;
+      case '=':
+        acc = 0;
+        break;
+      default:
+        event_error("Internal error");
+      };
+      acc = acc - oldtable[(int)anoctave[val] - (int)'a'] + 
+                  newtable[(int)anoctave[newval] - (int)'a'];
+      mult = 1;
+      accidental = '=';
+      if (acc > 0) {
+        accidental = '^';
+        mult = acc;
+      };
+      if (acc < 0) {
+        accidental = '_';
+        mult = -acc;
+      };
+    };
+  };    
+  if (!ingrace) {
+    notecount = notecount + 1;
+  };
+  for (t=0; t<DECSIZE; t++) {
+    if (decorators[t]) {
+      emit_char(decorations[t]);
+    };
+  };
+  if (mult == 2) {
+    emit_char(accidental);
+  };
+  if (accidental != ' ') {
+    emit_char(accidental);
+  };
+  if (octave >= 1) {
+    emit_char(note);
+    t = octave;
+    while (t > 1) {
+      emit_string("'");
+      t = t - 1;
+    };
+  } else {
+    emit_char((char) ((int)note + 'C' - 'c'));
+    t = octave;
+    while (t < 0) {
+      emit_string(",");
+      t = t + 1;
+    };
+  };
+  newlen.num = n * lenfactor.num;
+  newlen.denom = m * lenfactor.denom;
+  reduce(&newlen.num, &newlen.denom);
+  printlen(newlen.num, newlen.denom);
+  if (inchord) {
+    chordcount = chordcount + 1;
+  };
+  if ((!ingrace) && (!inchord || (chordcount == 1))) {
+    if (tuplenotes == 0) {
+      addunits(n, m);
+    } else {
+      addunits(n*tuplefactor.num, m*tuplefactor.denom);
+      tuplenotes = tuplenotes - 1;
+    };
+  };
+  if (newspacing) {
+    barpoint.num = count.num * breakpoint.denom;
+    barpoint.denom = breakpoint.num * count.denom;
+    reduce(&barpoint.num, &barpoint.denom);
+    if ((barpoint.denom == 1) && (barpoint.num != 0) && 
+        (barpoint.num != barend)) {
+      emit_string(" ");
+    };
+  };
+}
+
+/* these functions are here to satisfy the linker */
+void event_microtone(int dir, int a, int b)
+{
+}
+
+void event_normal_tone()
+{
+}
+
+
+
+int accidental_to_code (char xaccidental)
+{
+ switch (xaccidental) {
+ case ' ':
+   return 10;
+   break;
+ case '_':
+   return -1;
+   break;
+ case '^':
+   return 1;
+   break;
+  case '=':
+    return 0;
+    break;
+  default:
+    return 10;
+  }
+}
+
+
+void event_note2(decorators, xaccidental, xmult, xnote, xoctave, n, m)
+/* this function is called if flag nokey is set */
+int decorators[DECSIZE];
+int xmult;
+char xaccidental, xnote;
+int xoctave, n, m;
+{
+  int t;
+  struct fract barpoint;
+  struct fract newlen;
+
+  int acc,assumed_acc;
+  int propogate;
+  int val;
+  char *anoctave = "cdefgab";
+  int midipitch;
+
+ for (t=0; t<DECSIZE; t++) 
+    if (decorators[t]) emit_char(decorations[t]);
+
+  acc = accidental_to_code(xaccidental);
+  if (acc == -1 || acc == 1) acc = xmult*acc;
+  val = (int) ((long) strchr(anoctave, xnote) - (long) anoctave);
+
+  /* if no accidental precedes, then get accidental from key signature */
+  assumed_acc = oldtable[(int)anoctave[val] - (int)'a']; 
+  propogate=0;
+  midipitch = pitchof(xnote, acc, xmult, xoctave);
+  if (drumchan) printpitch(midipitch);
+  else printpitch(midipitch+transpose);
+
+  if (!ingrace) {
+    notecount = notecount + 1;
+  };
+
+  newlen.num = n * lenfactor.num;
+  newlen.denom = m * lenfactor.denom;
+  reduce(&newlen.num, &newlen.denom);
+  printlen(newlen.num, newlen.denom);
+  if (inchord) {
+    chordcount = chordcount + 1;
+  };
+  if ((!ingrace) && (!inchord || (chordcount == 1))) {
+    if (tuplenotes == 0) {
+      addunits(n, m);
+    } else {
+      addunits(n*tuplefactor.num, m*tuplefactor.denom);
+      tuplenotes = tuplenotes - 1;
+    };
+  };
+  if (newspacing) {
+    barpoint.num = count.num * breakpoint.denom;
+    barpoint.denom = breakpoint.num * count.denom;
+    reduce(&barpoint.num, &barpoint.denom);
+    if ((barpoint.denom == 1) && (barpoint.num != 0) && 
+        (barpoint.num != barend)) {
+      emit_string(" ");
+    };
+  };
+}
+
+
+void event_note(decorators, xaccidental, xmult, xnote, xoctave, n, m)
+int decorators[DECSIZE];
+int xmult;
+char xaccidental, xnote;
+int xoctave, n, m;
+{
+if (nokey)
+  event_note2(decorators, xaccidental, xmult, xnote, xoctave, n, m);
+else
+  event_note1(decorators, xaccidental, xmult, xnote, xoctave, n, m);
+}
+
+
+void event_abbreviation(char symbol, char *string, char container)
+/* a U: field has been found in the abc */
+{
+  if (container == '!') {
+    emit_string("U:");
+    emit_char(symbol);
+    emit_string_sprintf(" = !%s!", string);
+  } else {
+    emit_string("U:");
+    emit_char(symbol);
+    emit_string_sprintf(" = %s", string);
+  };
+  inmusic = 0;
+}
+
+void event_acciaccatura()
+{
+/* to handle / in front of note in grace notes eg {/A} */
+/* abcm2ps compatability feature [SS] 2005-03-28 */
+emit_string("/");
+}
+
+void event_split_voice ()
+{
+emit_string("&");
+}
+
+/* The following functions provide an alternative
+   method for transposing. The note is converted
+   to MIDI representation. It is transposed and
+   then converted back. These functions were
+   borrowed from store.c and midi2abc with
+   some minor modifications.
+*/
+
+
+int pitchof(char note, int accidental, int mult, int octave)
+/* finds MIDI pitch value for a given note taking into account the  */
+/* key signature if any and propogation of accidentals across a bar.*/
+/* accidental = 0  implies a natural specified.                     */
+/* accidental = 1  implies one or more sharps indicated by mult.    */
+/* accidental =-1  implies one or more flats indicated by mult.     */
+/* accidental = 10 nothing specified, determine from context        */
+{
+  int p;
+  int mul, noteno;
+  static int scale[7] = {0, 2, 4, 5, 7, 9, 11};
+  char *anoctave = "cdefgab";
+  int middle_c = 60;
+
+  p = (int) ((long) strchr(anoctave, note) - (long) anoctave);
+  p = scale[p];
+  mul = mult;
+  noteno = (int)note - 'a';
+  if (accidental==10) {        /* propagate accidentals  */
+    mul = workmul[noteno];
+  } else {
+      workmap[noteno] = accidental;
+      workmul[noteno] = mul;
+  };
+  p = p + workmap[noteno]*workmul[noteno];
+  return p + 12*octave + middle_c;
+}
+
+int lastaccidental[7];
+
+void copymap()
+/* sets up working map at the start of each bar */
+{
+  int j;
+
+  for (j=0; j<7; j++) {
+    workmap[j] = basemap[j];
+    workmul[j] = 1;
+    lastaccidental[j] = 0;
+  };
+}
+
+#define MIDDLE 72
+
+
+int sharpmap[12] =  { 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6};
+int flatmap[12]  =  { 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6};
+int sharpsym[12] =  { 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0};
+int flatsym[12]  =  { 0,-1, 0,-1, 0, 0,-1, 0,-1, 0,-1, 0};
+char hikey[7]    =  {'c','d','e','f','g','a','b'};
+char lowkey[7]   =  {'C','D','E','F','G','A','B'};
+char symlet[3]   =  {'=','^','_'};
+
+
+void setup_sharps_flats (int sf)
+{
+if (sf >=1) {sharpsym[6] = 0; sharpsym[5] = 2;}
+if (sf >=2) {sharpsym[1] = 0; sharpsym[0] = 2;}
+if (sf >=3) {sharpsym[8] = 0; sharpsym[7] = 2;}
+if (sf >=4) {sharpsym[3] = 0; sharpsym[2] = 2;}
+if (sf >=5) {sharpsym[10]= 0; sharpsym[9] = 2;}
+if (sf <= -1) {flatsym[10] = 0; flatsym[11] = 2;}
+if (sf <= -2) {flatsym[3]  = 0; flatsym[4]  =2;}
+if (sf <= -3) {flatsym[8]  = 0; flatsym[9]  =2;}
+if (sf <= -4) {flatsym[1]  = 0; flatsym[2]  =2;}
+if (sf <= -5) {flatsym[6]  = 0; flatsym[6]  =2;}
+}
+
+
+
+void printpitch(int pitch)
+/* convert midi pitch value to abc note */
+{
+int p;
+char keylet,symlet = 0;
+int keynum,symcod;
+char string[16];
+p = pitch%12;
+if (useflats)
+ {keynum = flatmap[p];
+  symcod = flatsym[p];
+ } else
+ {keynum = sharpmap[p];
+  symcod = sharpsym[p];
+ }
+
+if (pitch<MIDDLE)
+  keylet = lowkey[keynum];
+else
+  keylet = hikey[keynum];
+
+switch (symcod) {
+  case 0:
+   symlet = '=';
+   break;
+  case 1:
+   symlet = '^';
+   break;
+  case -1:
+   symlet = '_';
+   break;
+  case 2:
+   symlet = '=';
+   break;
+}
+ 
+if (lastaccidental[keynum] == symcod)
+   sprintf(string,"%c",keylet);
+else {
+   sprintf(string,"%c%c", symlet, keylet);
+   lastaccidental[keynum] = symcod;
+   }
+  emit_string(string);
+
+p = pitch;
+while (p >= MIDDLE + 12) {
+    emit_string("'");
+    p = p - 12;
+    };
+while (p < MIDDLE - 12) {
+    emit_string(",");
+    p = p + 12;
+    };
+}
+
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+  char *filename;
+
+  oldchordconvention = 0; /* for handling +..+ chords */
+
+  /*for (i=0;i<DECSIZE;i++) decorators_passback[i]=0; */
+
+  event_init(argc, argv, &filename);
+  if (argc < 2) {
+    /* printf("argc = %d\n", argc); */
+  } else {
+    init_abbreviations();
+    parsefile(filename);
+    free_abbreviations();
+  };
+  return(0);
+}
+
--- abcmidi-20070318.orig/mftext.c
+++ abcmidi-20070318/mftext.c
@@ -1,268 +1,268 @@
-/*
- * mftext
- * 
- * Convert a MIDI file to verbose text.
- *
- * modified for portability 22/6/98 - error checking on file open failure
- * removed.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef ANSILIBS
-#include <ctype.h>
-#endif
-#include "midifile.h"
-
-static FILE *F;
-int SECONDS;      /* global that tells whether to display seconds or ticks */
-int division;        /* from the file header */
-long tempo = 500000; /* the default tempo is 120 beats/minute */
-
-filegetc()
-{
-  return(getc(F));
-}
-
-/* for crack */
-extern int arg_index;
-
-main(argc,argv)
-char **argv;
-{
-  FILE *efopen();
-  char *ch;
-  char *crack();
-
-  SECONDS = 0;
-
-  while((ch = crack(argc,argv,"s",0)) != NULL){
-      switch(*ch){
-    case 's' : SECONDS = 1; break;
-    }
-      }
-
-  if ((argc < 2 && !SECONDS) || (argc < 3 && SECONDS))
-      F = stdin;
-  else
-      F = efopen(argv[arg_index],"rb");
-
-  initfuncs();
-  Mf_getc = filegetc;
-  midifile();
-  fclose(F);
-  exit(0);
-}
-
-FILE *
-efopen(name,mode)
-char *name;
-char *mode;
-{
-  FILE *f;
-
-  if ( (f=fopen(name,mode)) == NULL ) {
-    fprintf(stderr,"Error - Cannot open file %s\n",name);
-    exit(0);
-  }
-  return(f);
-}
-
-void error(s)
-char *s;
-{
-  fprintf(stderr,"Error: %s\n",s);
-}
-
-prtime()
-{
-    if(SECONDS)
-  printf("Time=%f   ",mf_ticks2sec(Mf_currtime,division,tempo));
-    else
-  printf("Time=%ld  ",Mf_currtime);
-}
-
-void txt_header(format,ntrks,ldivision)
-{
-        division = ldivision; 
-  printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division);
-}
-
-void txt_trackstart()
-{
-  printf("Track start\n");
-}
-
-void txt_trackend()
-{
-  printf("Track end\n");
-}
-
-void txt_noteon(chan,pitch,vol)
-{
-  prtime();
-  printf("Note on, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol);
-}
-
-void txt_noteoff(chan,pitch,vol)
-{
-  prtime();
-  printf("Note off, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol);
-}
-
-void txt_pressure(chan,pitch,press)
-{
-  prtime();
-  printf("Pressure, chan=%d pitch=%d press=%d\n",chan+1,pitch,press);
-}
-
-void txt_parameter(chan,control,value)
-{
-  prtime();
-  printf("Parameter, chan=%d c1=%d c2=%d\n",chan+1,control,value);
-}
-
-void txt_pitchbend(chan,msb,lsb)
-{
-  prtime();
-  printf("Pitchbend, chan=%d msb=%d lsb=%d\n",chan+1,msb,lsb);
-}
-
-void txt_program(chan,program)
-{
-  prtime();
-  printf("Program, chan=%d program=%d\n",chan+1,program);
-}
-
-void txt_chanpressure(chan,press)
-{
-  prtime();
-  printf("Channel pressure, chan=%d pressure=%d\n",chan+1,press);
-}
-
-void txt_sysex(leng,mess)
-char *mess;
-{
-  prtime();
-  printf("Sysex, leng=%d\n",leng);
-}
-
-void txt_metamisc(type,leng,mess)
-char *mess;
-{
-  prtime();
-  printf("Meta event, unrecognized, type=0x%02x leng=%d\n",type,leng);
-}
-
-void txt_metaspecial(type,leng,mess)
-char *mess;
-{
-  prtime();
-  printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",type,leng);
-}
-
-void txt_metatext(type,leng,mess)
-char *mess;
-{
-  static char *ttype[] = {
-    NULL,
-    "Text Event",    /* type=0x01 */
-    "Copyright Notice",  /* type=0x02 */
-    "Sequence/Track Name",
-    "Instrument Name",  /* ...       */
-    "Lyric",
-    "Marker",
-    "Cue Point",    /* type=0x07 */
-    "Unrecognized"
-  };
-  int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
-  register int n, c;
-  register char *p = mess;
-
-  if ( type < 1 || type > unrecognized )
-    type = unrecognized;
-  prtime();
-  printf("Meta Text, type=0x%02x (%s)  leng=%d\n",type,ttype[type],leng);
-  printf("     Text = <");
-  for ( n=0; n<leng; n++ ) {
-    c = (*p++) & 0xff;
-    printf( (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c);
-  }
-  printf(">\n");
-}
-
-void txt_metaseq(num)
-{
-  prtime();
-  printf("Meta event, sequence number = %d\n",num);
-}
-
-void txt_metaeot()
-{
-  prtime();
-  printf("Meta event, end of track\n");
-}
-
-void txt_keysig(sf,mi)
-{
-  prtime();
-  printf("Key signature, sharp/flats=%d  minor=%d\n",sf,mi);
-}
-
-void txt_tempo(ltempo)
-long ltempo;
-{
-  tempo = ltempo;
-  prtime();
-  printf("Tempo, microseconds-per-MIDI-quarter-note=%ld\n",tempo);
-}
-
-void txt_timesig(nn,dd,cc,bb)
-{
-  int denom = 1;
-  while ( dd-- > 0 )
-    denom *= 2;
-  prtime();
-  printf("Time signature=%d/%d  MIDI-clocks/click=%d  32nd-notes/24-MIDI-clocks=%d\n",
-    nn,denom,cc,bb);
-}
-
-void txt_smpte(hr,mn,se,fr,ff)
-{
-  prtime();
-  printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n",
-    hr,mn,se,fr,ff);
-}
-
-void txt_arbitrary(leng,mess)
-char *mess;
-{
-  prtime();
-  printf("Arbitrary bytes, leng=%d\n",leng);
-}
-
-initfuncs()
-{
-  Mf_error = error;
-  Mf_header =  txt_header;
-  Mf_trackstart =  txt_trackstart;
-  Mf_trackend =  txt_trackend;
-  Mf_noteon =  txt_noteon;
-  Mf_noteoff =  txt_noteoff;
-  Mf_pressure =  txt_pressure;
-  Mf_parameter =  txt_parameter;
-  Mf_pitchbend =  txt_pitchbend;
-  Mf_program =  txt_program;
-  Mf_chanpressure =  txt_chanpressure;
-  Mf_sysex =  txt_sysex;
-  Mf_metamisc =  txt_metamisc;
-  Mf_seqnum =  txt_metaseq;
-  Mf_eot =  txt_metaeot;
-  Mf_timesig =  txt_timesig;
-  Mf_smpte =  txt_smpte;
-  Mf_tempo =  txt_tempo;
-  Mf_keysig =  txt_keysig;
-  Mf_seqspecific =  txt_metaspecial;
-  Mf_text =  txt_metatext;
-  Mf_arbitrary =  txt_arbitrary;
-}
+/*
+ * mftext
+ * 
+ * Convert a MIDI file to verbose text.
+ *
+ * modified for portability 22/6/98 - error checking on file open failure
+ * removed.
+ */
+
+#include <stdio.h>
+#if defined(ANSILIBS) || defined(__STDC__)
+#include <stdlib.h>
+#include <ctype.h>
+#endif
+#include "midifile.h"
+
+static FILE *F;
+int SECONDS;      /* global that tells whether to display seconds or ticks */
+int division;        /* from the file header */
+long tempo = 500000; /* the default tempo is 120 beats/minute */
+
+filegetc()
+{
+  return(getc(F));
+}
+
+/* for crack */
+extern int arg_index;
+
+main(argc,argv)
+char **argv;
+{
+  FILE *efopen();
+  char *ch;
+  char *crack();
+
+  SECONDS = 0;
+
+  while((ch = crack(argc,argv,"s",0)) != NULL){
+      switch(*ch){
+    case 's' : SECONDS = 1; break;
+    }
+      }
+
+  if ((argc < 2 && !SECONDS) || (argc < 3 && SECONDS))
+      F = stdin;
+  else
+      F = efopen(argv[arg_index],"rb");
+
+  initfuncs();
+  Mf_getc = filegetc;
+  midifile();
+  fclose(F);
+  exit(0);
+}
+
+FILE *
+efopen(name,mode)
+char *name;
+char *mode;
+{
+  FILE *f;
+
+  if ( (f=fopen(name,mode)) == NULL ) {
+    fprintf(stderr,"Error - Cannot open file %s\n",name);
+    exit(0);
+  }
+  return(f);
+}
+
+void error(s)
+char *s;
+{
+  fprintf(stderr,"Error: %s\n",s);
+}
+
+prtime()
+{
+    if(SECONDS)
+  printf("Time=%f   ",mf_ticks2sec(Mf_currtime,division,tempo));
+    else
+  printf("Time=%ld  ",Mf_currtime);
+}
+
+void txt_header(format,ntrks,ldivision)
+{
+        division = ldivision; 
+  printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division);
+}
+
+void txt_trackstart()
+{
+  printf("Track start\n");
+}
+
+void txt_trackend()
+{
+  printf("Track end\n");
+}
+
+void txt_noteon(chan,pitch,vol)
+{
+  prtime();
+  printf("Note on, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol);
+}
+
+void txt_noteoff(chan,pitch,vol)
+{
+  prtime();
+  printf("Note off, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol);
+}
+
+void txt_pressure(chan,pitch,press)
+{
+  prtime();
+  printf("Pressure, chan=%d pitch=%d press=%d\n",chan+1,pitch,press);
+}
+
+void txt_parameter(chan,control,value)
+{
+  prtime();
+  printf("Parameter, chan=%d c1=%d c2=%d\n",chan+1,control,value);
+}
+
+void txt_pitchbend(chan,msb,lsb)
+{
+  prtime();
+  printf("Pitchbend, chan=%d msb=%d lsb=%d\n",chan+1,msb,lsb);
+}
+
+void txt_program(chan,program)
+{
+  prtime();
+  printf("Program, chan=%d program=%d\n",chan+1,program);
+}
+
+void txt_chanpressure(chan,press)
+{
+  prtime();
+  printf("Channel pressure, chan=%d pressure=%d\n",chan+1,press);
+}
+
+void txt_sysex(leng,mess)
+char *mess;
+{
+  prtime();
+  printf("Sysex, leng=%d\n",leng);
+}
+
+void txt_metamisc(type,leng,mess)
+char *mess;
+{
+  prtime();
+  printf("Meta event, unrecognized, type=0x%02x leng=%d\n",type,leng);
+}
+
+void txt_metaspecial(type,leng,mess)
+char *mess;
+{
+  prtime();
+  printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",type,leng);
+}
+
+void txt_metatext(type,leng,mess)
+char *mess;
+{
+  static char *ttype[] = {
+    NULL,
+    "Text Event",    /* type=0x01 */
+    "Copyright Notice",  /* type=0x02 */
+    "Sequence/Track Name",
+    "Instrument Name",  /* ...       */
+    "Lyric",
+    "Marker",
+    "Cue Point",    /* type=0x07 */
+    "Unrecognized"
+  };
+  int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1;
+  register int n, c;
+  register char *p = mess;
+
+  if ( type < 1 || type > unrecognized )
+    type = unrecognized;
+  prtime();
+  printf("Meta Text, type=0x%02x (%s)  leng=%d\n",type,ttype[type],leng);
+  printf("     Text = <");
+  for ( n=0; n<leng; n++ ) {
+    c = (*p++) & 0xff;
+    printf( (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c);
+  }
+  printf(">\n");
+}
+
+void txt_metaseq(num)
+{
+  prtime();
+  printf("Meta event, sequence number = %d\n",num);
+}
+
+void txt_metaeot()
+{
+  prtime();
+  printf("Meta event, end of track\n");
+}
+
+void txt_keysig(sf,mi)
+{
+  prtime();
+  printf("Key signature, sharp/flats=%d  minor=%d\n",sf,mi);
+}
+
+void txt_tempo(ltempo)
+long ltempo;
+{
+  tempo = ltempo;
+  prtime();
+  printf("Tempo, microseconds-per-MIDI-quarter-note=%ld\n",tempo);
+}
+
+void txt_timesig(nn,dd,cc,bb)
+{
+  int denom = 1;
+  while ( dd-- > 0 )
+    denom *= 2;
+  prtime();
+  printf("Time signature=%d/%d  MIDI-clocks/click=%d  32nd-notes/24-MIDI-clocks=%d\n",
+    nn,denom,cc,bb);
+}
+
+void txt_smpte(hr,mn,se,fr,ff)
+{
+  prtime();
+  printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n",
+    hr,mn,se,fr,ff);
+}
+
+void txt_arbitrary(leng,mess)
+char *mess;
+{
+  prtime();
+  printf("Arbitrary bytes, leng=%d\n",leng);
+}
+
+initfuncs()
+{
+  Mf_error = error;
+  Mf_header =  txt_header;
+  Mf_trackstart =  txt_trackstart;
+  Mf_trackend =  txt_trackend;
+  Mf_noteon =  txt_noteon;
+  Mf_noteoff =  txt_noteoff;
+  Mf_pressure =  txt_pressure;
+  Mf_parameter =  txt_parameter;
+  Mf_pitchbend =  txt_pitchbend;
+  Mf_program =  txt_program;
+  Mf_chanpressure =  txt_chanpressure;
+  Mf_sysex =  txt_sysex;
+  Mf_metamisc =  txt_metamisc;
+  Mf_seqnum =  txt_metaseq;
+  Mf_eot =  txt_metaeot;
+  Mf_timesig =  txt_timesig;
+  Mf_smpte =  txt_smpte;
+  Mf_tempo =  txt_tempo;
+  Mf_keysig =  txt_keysig;
+  Mf_seqspecific =  txt_metaspecial;
+  Mf_text =  txt_metatext;
+  Mf_arbitrary =  txt_arbitrary;
+}
--- abcmidi-20070318.orig/matchsup.c
+++ abcmidi-20070318/matchsup.c
@@ -1,1964 +1,1966 @@
-/*
-  matchsup.c  (abcmatch support functions)
-  Seymour Shlien
-
-  
-
-
- * originally store.c
- * abc2midi - program to convert abc files to MIDI files.
- * Copyright (C) 1999 James Allwright
- * e-mail: J.R.Allwright@westminster.ac.uk
-
-store.c was adapted for the purpose of analyzing the contents
-of abc tunes. The code is much the same except many functions
-related to the generation of midi files has been trimmed off.
-In particular: links to the code in genmidi.c and queue.c are gone.
-All the gchord stuff is removed. There are options to suppress
-all warning and error messages. Certain variables are no longer
-extern's (parts, partno, bar_num, global_transpose etc.).
-Output file generation stuff is gone. A new variable xrefno is
-added to pass the reference number to abcmatch. Event_init has
-been moved to the main program abcmatch.c and maxnotes has
-been raised to 3000 since there seems to be a problem with
-the autoextend procedure.  Some DEBUG statements were
-added to addfeature - (they can probably be removed). Support
-for text features and comments are gone. All the karaoke stuff
-is gone. Tempo stuff, slurs, grace notes, decorations, hornpipe
-indications  are all ignored. Event_note was changed to ignore
-trills and rolls.  When a [chord] is included, only the highest
-note is extracted from the chord. For debugging, a new function
-print_feature_list was introduced.etc.
-
-Essentially for comparing abc files, we want to ignore repeats,
-grace notes, staccato indications and midi indications. We are
-only interested in comparing the tunes. The main output 
-which is used is the feature[],pitch,num[],denom[] list which
-is used by abcmatch to create a new representation of the abc
-file.
-
-Some abc files with interleaved voices will not be treated
-propertly with this program. In general parts, repeats and
-voice indications are ignored.
- 
-
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-
-#define XTEN1 1
-
-#include "abc.h"
-#include "parseabc.h"
-#include "parser2.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef __MWERKS__
-#define __MACINTOSH__ 1
-#endif /* __MWERKS__ */
-
-#ifdef __MACINTOSH__
-int setOutFileCreator(char *fileName,unsigned long theType,
-                      unsigned long theCreator);
-#endif /* __MACINTOSH__ */
-/* define USE_INDEX if your C libraries have index() instead of strchr() */
-#ifdef USE_INDEX
-#define strchr index
-#endif
-
-#ifdef ANSILIBS
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#else
-extern char* strchr();
-extern void reduce();
-#endif
-
-#define MAXLINE 500
-#define INITTEXTS 20
-#define INITWORDS 20
-#define MAXCHANS 16
-
-/*#define DEBUG*/
-
-
-/* global variables grouped roughly by function */
-
-FILE *fp;
-
-programname fileprogram = ABCMATCH;
-
-
-/* parsing stage */
-int tuplecount, tfact_num, tfact_denom, tnote_num, tnote_denom;
-int specialtuple;
-int gracenotes;
-int headerpartlabel;
-int dotune, pastheader;
-int hornpipe, last_num, last_denom;
-int timesigset;
-int retain_accidentals;
-int ratio_a, ratio_b;
-
-struct voicecontext {
-  /* maps of accidentals for each stave line */
-  char basemap[7], workmap[7];
-  int  basemul[7], workmul[7];
-  int default_length;
-  int voiceno;
-  int indexno;
-  int hasgchords;
-  int haswords;
-  int inslur;
-  int ingrace;
-  int octaveshift;
-  /* chord handling */
-  int inchord, chordcount;
-  int chord_num, chord_denom;
-  /* details of last 2 notes/chords to apply length-modifiers to */
-  int laststart, lastend, thisstart, thisend;
-  /* broken rythm handling */
-  int brokentype, brokenmult, brokenpending;
-  int broken_stack[7];
-  struct voicecontext* next;
-};
-struct voicecontext global;
-struct voicecontext* v;
-struct voicecontext* head;
-int voicecount;
-
-/* storage structure for strings */
-int maxtexts = INITTEXTS;
-char** atext;
-int ntexts = 0;
-
-int note_unit_length=8;
-
-/* general purpose storage structure */
-int maxnotes;
-int *pitch, *num, *denom;
-featuretype *feature;
-int *pitchline;
-int notes;
-
-int verbose = 0;
-int nowarn=1;
-int noerror=1;
-int xmatch;
-int sf, mi;
-
-/* Part handling */
-struct vstring part;
-int parts, partno, partlabel;
-int part_start[26], part_count[26];
-
-int voicesused;
-
-/* Tempo handling (Q: field) */
-int time_num, time_denom;
-long tempo;
-int tempo_num, tempo_denom;
-int relative_tempo, Qtempo;
-extern int division;
-extern int div_factor;
-
-/* output file generation */
-int check;
-int ntracks;
-
-/* bar length checking */
-int bar_num, bar_denom;
-int barchecking;
-int beat;
-
-/* generating MIDI output */
-int middle_c;
-extern int channels[MAXCHANS + 3];
-
-int global_transpose;
-
-int additive;
-int gfact_num, gfact_denom;
-
-/* karaoke handling */
-int karaoke, wcount;
-char** words;
-int maxwords = INITWORDS;
-int xrefno;
-
-extern int intune; /* signals to parsetune that tune is finished */
-
-/* Many of these functions have been retained in order to link with parseabc.
-As I have been forced to also modifiy parseabc, now called abcparse, these
-functions can also be removed eventually.
- */
-
-char *featname[] = {
-"SINGLE_BAR", "DOUBLE_BAR", "BAR_REP", "REP_BAR",
-"PLAY_ON_REP", "REP1", "REP2", "BAR1",
-"REP_BAR2", "DOUBLE_REP", "THICK_THIN", "THIN_THICK",
-"PART", "TEMPO", "TIME", "KEY",
-"REST", "TUPLE", "NOTE", "NONOTE",
-"OLDTIE", "TEXT", "SLUR_ON", "SLUR_OFF",
-"TIE", "CLOSE_TIE", "TITLE", "CHANNEL",
-"TRANSPOSE", "RTRANSPOSE", "GTRANSPOSE", "GRACEON",
-"GRACEOFF", "SETGRACE", "SETC", "SETTRIM", "GCHORD",
-"GCHORDON", "GCHORDOFF", "VOICE", "CHORDON",
-"CHORDOFF", "CHORDOFFEX", "DRUMON", "DRUMOFF",
-"DRONEON", "DRONEOFF", "SLUR_TIE", "TNOTE",
-"LT", "GT", "DYNAMIC", "LINENUM",
-"MUSICLINE", "MUSICSTOP", "WORDLINE", "WORDSTOP",
-"INSTRUCTION", "NOBEAM", "CHORDNOTE", "CLEF",
-"PRINTLINE", "NEWPAGE", "LEFT_TEXT", "CENTRE_TEXT",
-"VSKIP", "COPYRIGHT", "COMPOSER", "ARPEGGIO",
-"SPLITVOICE"
-};
-
-
-
-void event_info (place)
-char * place;
-{
-}
-
-void event_gchord (chord)
-char * chord;
-{
-}
-
-void event_slur (t)
-int t;
-{
-}
-
-
-void event_instruction (s)
-char *s;
-{
-}
-
-
-void event_reserved (p)
-char p;
-{
-}
-
-int bar_num, bar_denom, barno, barsize;
-int b_num,b_denom;
-
-void reduce(a, b)
-/* elimate common factors in fraction a/b */
-int *a, *b;
-{
-  int sign;
-  int t, n, m;
-
-  if (*a < 0) {
-    sign = -1;
-    *a = -*a;
-  } else {
-    sign = 1;
-  };
-  /* find HCF using Euclid's algorithm */
-  if (*a > *b) {
-    n = *a;
-    m = *b;
-  } else {
-    n = *b;
-    m = *a;
-  };
-  while (m != 0) {
-    t = n % m;
-    n = m;
-    m = t;
-  };
-  *a = (*a/n)*sign;
-  *b = *b/n;
-}
-
-void addunits(a, b)
-/* add a/b to the count of units in the bar */
-int a, b;
-{
-  bar_num = bar_num*(b*b_denom) + (a*b_num)*bar_denom;
-  bar_denom = bar_denom * (b*b_denom);
-  reduce(&bar_num, &bar_denom);
-}
-
-
-void set_meter(n, m)
-/* set up variables associated with meter */
-int n, m;
-{
-  /* set up barsize */
-  barsize = n;
-  if (barsize % 3 == 0) {
-    beat = 3;
-  } else {
-    if (barsize % 2 == 0) {
-      beat = 2;
-    } else {
-      beat = barsize;
-    };
-  };
-  /* correction factor to make sure we count in the right units */
-  if (m > 4) {
-    b_num = m/4;
-    b_denom = 1;
-  } else {
-   b_num = 1;
-   b_denom = 4/m;
-  };
-}
-
-int dummydecorator[DECSIZE]; /* used in event_chord */
-
-
-static struct voicecontext* newvoice(n)
-/* allocate and initialize the data for a new voice */
-int n;
-{
-  struct voicecontext *s;
-  int i;
-
-  s = (struct voicecontext*) checkmalloc(sizeof(struct voicecontext));
-  voicecount = voicecount + 1;
-  s->voiceno = n;
-  s->indexno = voicecount;
-  s->default_length = global.default_length;
-  s->hasgchords = 0;
-  s->haswords = 0;
-  s->inslur = 0;
-  s->ingrace = 0;
-  s->inchord = 0;
-  s->chordcount = 0;
-  s->laststart = -1;
-  s->lastend = -1;
-  s->thisstart = -1;
-  s->thisend = -1;
-  s->brokenpending = -1;
-  s->next = NULL;
-  for (i=0; i<7; i++) {
-    s->basemap[i] = global.basemap[i];
-    s->basemul[i] = global.basemul[i];
-    s->workmap[i] = global.workmap[i];
-    s->workmul[i] = global.workmul[i];
-  };
-  s->octaveshift = global.octaveshift;
-  return(s);
-}
-
-static struct voicecontext* getvoicecontext(n)
-/* find the data structure for a given voice number */
-int n;
-{
-  struct voicecontext *p;
-  struct voicecontext *q;
-
-  p = head;
-  q = NULL;
-  while ((p != NULL) && (p->voiceno != n)) {
-    q = p;
-    p = p->next;
-  };
-  if (p == NULL) {
-    p = newvoice(n);
-    if (q != NULL) {
-      q->next = p;
-    };
-  };
-  if (head == NULL) {
-    head = p;
-  };
-  return(p);
-}
-
-static void clearvoicecontexts()
-/* free up all the memory allocated to voices */
-{
-  struct voicecontext *p;
-  struct voicecontext *q;
-
-  p = head;
-  while (p != NULL) {
-    q = p->next;
-    free(p);
-    p = q;
-  };
-  head = NULL;
-}
-
-
-
-
-void event_text(s)
-/* text found in abc file */
-char *s;
-{
-}
-
-
-void event_specific (package, s)
-char *package, *s;
-{
-}
-
-
-void event_x_reserved(p)
-/* reserved character H-Z found in abc file */
-char p;
-{
-}
-
-void event_abbreviation(symbol, string, container)
-/* abbreviation encountered - this is handled within the parser */
-char symbol;
-char *string;
-char container;
-{
-}
-
-
-void event_acciaccatura()
-{
-/* does nothing here but outputs a / in abc2abc */
-return;
-}
-
-void event_split_voice()
-{
-}
-
-
-
-void event_tex(s)
-/* TeX command found - ignore it */
-char *s;
-{
-}
-
-void event_fatal_error(s)
-/* print error message and halt */
-char *s;
-{
-  event_error(s);
-  exit(1);
-}
-
-void event_error(s)
-/* generic error handler */
-char *s;
-{
-if (noerror) return;
-#ifdef NOFTELL
-  extern int nullpass;
-
-  if (nullpass != 1) {
-    printf("Error in line %d : %s\n", lineno, s);
-  };
-#else
-  printf("Error in line %d : %s\n", lineno, s);
-#endif
-}
-
-void event_warning(s)
-/* generic warning handler - for flagging possible errors */
-char *s;
-{
-if (nowarn) return;
-#ifdef NOFTELL
-  extern int nullpass;
-
-  if (nullpass != 1) {
-    printf("Warning in line %d : %s\n", lineno, s);
-  };
-#else
-  printf("Warning in line %d : %s\n", lineno, s);
-#endif
-}
-
-static int autoextend(maxnotes)
-/* increase the number of abc elements the program can cope with */
-int maxnotes;
-{
-  int newlimit;
-  int *ptr;
-  featuretype *fptr;
-  int i;
-
-  if (verbose) {
-    event_warning("Extending note capacity");
-  };
-  newlimit = maxnotes*2;
-  fptr = (featuretype*) checkmalloc(newlimit*sizeof(featuretype));
-  for(i=0;i<maxnotes;i++){
-    fptr[i] = feature[i];
-  };
-  free(feature);
-  feature = fptr;
-  ptr = checkmalloc(newlimit*sizeof(int));
-  for(i=0;i<maxnotes;i++){
-    ptr[i] = pitch[i];
-  };
-  free(pitch);
-  pitch = ptr;
-  ptr = checkmalloc(newlimit*sizeof(int));
-  for(i=0;i<maxnotes;i++){
-    ptr[i] = pitchline[i];
-  };
-  free(pitchline);
-  pitchline = ptr;
-  ptr = checkmalloc(newlimit*sizeof(int));
-  for(i=0;i<maxnotes;i++){
-    ptr[i] = num[i];
-  };
-  free(num);
-  num = ptr;
-  ptr = checkmalloc(newlimit*sizeof(int));
-  for(i=0;i<maxnotes;i++){
-    ptr[i] = denom[i];
-  };
-  free(denom);
-  denom = ptr;
-  return(newlimit);
-}
-
-
-static void addfeature(f, p, n, d)
-/* place feature in internal table */
-int f, p, n, d;
-{
-  feature[notes] = f;
-  pitch[notes] = p;
-  num[notes] = n;
-  denom[notes] = d;
-  if ((f == NOTE) || (f == REST) || (f == CHORDOFF)) {
-    reduce(&num[notes], &denom[notes]);
-  };
-#ifdef DEBUG
-  if ((f == NOTE) || (f == REST)) {
-    fract = (float) num[notes]/ (float) denom[notes];
-    length = fract * 12.0 +0.1;
-    printf("%2d %2d %2d %2d\n",pitch[notes],num[notes],denom[notes],length);
-    }
-  if (f == TIME) printf("time signature = %d/%d\n",n,d);
-#endif 
-  notes = notes + 1;
-  if (notes >= maxnotes) {
-    maxnotes = autoextend(maxnotes);
-  };
-}
-
-void event_linebreak()
-/* reached end of line in abc */
-{
-  addfeature(LINENUM, lineno, 0, 0);
-}
-
-void event_startmusicline()
-/* starting to parse line of abc music */
-{
-  addfeature(MUSICLINE, 0, 0, 0);
-}
-
-void event_endmusicline(endchar)
-/* finished parsing line of abc music */
-char endchar;
-{
-  addfeature(MUSICSTOP, 0, 0, 0);
-}
-
-static void textfeature(type, s)
-/* called while parsing abc - stores an item which requires an */
-/* associared string */
-int type;
-char* s;
-{
-}
-
-void event_comment(s)
-/* comment found in abc */
-char *s;
-{
-}
-
-
-void event_startinline()
-/* start of in-line field in abc music line */
-{
-}
-
-void event_closeinline()
-/* end of in-line field in abc music line */
-{
-}
-
-void event_field(k, f)
-/* Handles R: T: and any other field not handled elsewhere */
-char k;
-char *f;
-{
-  if (dotune) {
-    switch (k) {
-    case 'R':
-      {
-        char* p;
-
-        p = f;
-        skipspace(&p);
-/******** if ((strncmp(p, "Hornpipe", 8) == 0) ||
-            (strncmp(p, "hornpipe", 8) == 0)) {
-          hornpipe = 1;
-        };
-********/
-      };
-      break;
-    default:
-      {
-      };
-    };
-  };
-}
-
-void event_words(p, continuation)
-/* handles a w: field in the abc */
-char* p;
-int continuation;
-{
-}
-
-
-static void checkbreak()
-/* check that we are in not in chord, grace notes or tuple */
-/* called at voice change */
-{
-  if (tuplecount != 0) {
-    event_error("Previous voice has an unfinished tuple");
-    tuplecount = 0;
-  };
-  if (v->inchord != 0) {
-    event_error("Previous voice has incomplete chord");
-    event_chordoff(1,1);
-  };
-  if (v->ingrace != 0) {
-    event_error("Previous voice has unfinished grace notes");
-    v->ingrace = 0;
-  };
-}
-
-
-static void read_spec(spec, part)
-/* converts a P: field to a list of part labels */
-/* e.g. P:A(AB)3(CD)2 becomes P:AABABABCDCD */
-/* A '+' indicates 'additive' behaviour (a part may include repeats).  */
-/* A '-' indicates 'non-additive' behaviour (repeat marks in the music */
-/* are ignored and only repeats implied by the part order statement    */
-/* are played).  */
-char spec[];
-struct vstring* part;
-{
-}
-
-void event_part(s)
-/* handles a P: field in the abc */
-char* s;
-{
-  char* p;
-
-  if (dotune) {
-    p = s;
-    skipspace(&p);
-    if (pastheader) {
-      if (((int)*p < 'A') || ((int)*p > 'Z')) {
-        event_error("Part must be one of A-Z");
-        return;
-      };
-      if ((headerpartlabel == 1) && (part.st[0] == *p)) {
-        /* P: field in header is not a label */
-        headerpartlabel = 0;
-        /* remove speculative part label */
-        feature[part_start[(int)*p - (int)'A']] = NONOTE;
-      } else {
-        if (part_start[(int)*p - (int)'A'] != -1) {
-          event_error("Part defined more than once");
-        };
-      };
-      part_start[(int)*p - (int)'A'] = notes;
-      addfeature(PART, (int)*p, 0, 0);
-      checkbreak();
-      v = getvoicecontext(1);
-    } else {
-      parts = 0;
-      read_spec(p, &part);
-      if (parts == 1) {
-        /* might be a label not a specificaton */
-        headerpartlabel = 1;
-      };
-    };
-  };
-}
-
-void event_voice(n, s, vp)
-/* handles a V: field in the abc */
-int n;
-char *s;
-struct voice_params *vp;
-{
-  if (pastheader || XTEN1) {
-    voicesused = 1;
-    if (pastheader)  checkbreak();
-    v = getvoicecontext(n);
-    addfeature(VOICE, v->indexno, 0, 0);
-    if (vp->gotoctave) {
-      event_octave(vp->octave,1);
-    };
-    if (vp->gottranspose) {
-      addfeature(TRANSPOSE, vp->transpose, 0, 0);
-    };
-  } else {
-    event_warning("V: in header ignored");
-  };
-}
-
-
-void event_length(n)
-/* handles an L: field in the abc */
-int n;
-{
-  note_unit_length = 8;
-  if (pastheader) {
-    v->default_length = n;
-  } else {
-    global.default_length = n;
-  };
-}
-
-static void tempounits(t_num, t_denom)
-/* interprets Q: once default length is known */
-int *t_num, *t_denom;
-{
-}
-
-void event_tempo(n, a, b, rel, pre, post)
-/* handles a Q: field e.g. Q: a/b = n  or  Q: Ca/b = n */
-/* strings before and after are ignored */
-int n;
-int a, b, rel;
-char *pre;
-char *post;
-{
-}
-
-
-void event_timesig(n, m, dochecking)
-/* handles an M: field  M:n/m */
-int n, m, dochecking;
-{
-  if (dotune) {
-    if (pastheader) {
-      addfeature(TIME, dochecking, n, m);
-   } else { 
-      time_num = n;
-      time_denom = m;
-      timesigset = 1;
-      barchecking = dochecking;
-    };
-  };
-}
-
-void event_octave(num, local)
-/* used internally by other routines when octave=N is encountered */
-/* in I: or K: fields */
-int num;
-{
-  if (dotune) {
-    if (pastheader || local) {
-      v->octaveshift = num;
-    } else {
-      global.octaveshift = num;
-    };
-  };
-}
-
-void event_info_key(key, value)
-char* key;
-char* value;
-{
-  int num;
-
-  if (strcmp(key, "octave")==0) {
-    num = readsnumf(value);
-    event_octave(num,0);
-  };
-}
-
-static void stack_broken(v)
-struct voicecontext* v;
-{
-  v->broken_stack[0] = v->laststart;
-  v->broken_stack[1] = v->lastend;
-  v->broken_stack[2] = v->thisstart;
-  v->broken_stack[3] = v->thisend;
-  v->broken_stack[4] = v->brokentype;
-  v->broken_stack[5] = v->brokenmult;
-  v->broken_stack[6] = v->brokenpending;
-  v->laststart = -1;
-  v->lastend = -1;
-  v->thisstart = -1;
-  v->thisend = -1;
-  v->brokenpending = -1;
-}
-
-static void restore_broken(v)
-struct voicecontext* v;
-{
-  if (v->brokenpending != -1) {
-    event_error("Unresolved broken rhythm in grace notes");
-  };
-  v->laststart = v->broken_stack[0];
-  v->lastend = v->broken_stack[1];
-  v->thisstart = v->broken_stack[2];
-  v->thisend = v->broken_stack[3];
-  v->brokentype = v->broken_stack[4];
-  v->brokenmult = v->broken_stack[5];
-  v->brokenpending = v->broken_stack[6];
-}
-
-void event_graceon()
-/* a { in the abc */
-{
-  if (gracenotes) {
-    event_error("Nested grace notes not allowed");
-  } else {
-    if (v->inchord) {
-      event_error("Grace notes not allowed in chord");
-    } else {
-      gracenotes = 1;
-      addfeature(GRACEON, 0, 0, 0);
-      v->ingrace = 1;
-      stack_broken(v);
-    };
-  };
-}
-
-void event_graceoff()
-/* a } in the abc */
-{
-  if (!gracenotes) {
-    event_error("} without matching {");
-  } else {
-    gracenotes = 0;
-    addfeature(GRACEOFF, 0, 0, 0);
-    v->ingrace = 0;
-    restore_broken(v);
-  };
-}
-
-void event_rep1()
-/* [1 in the abc */
-{
-  addfeature(PLAY_ON_REP, 0, 0, 1);
-/*
-  if ((notes == 0) || (feature[notes-1] != SINGLE_BAR)) {
-    event_error("[1 must follow a single bar");
-  } else {
-    feature[notes-1] = BAR1;
-  };
-*/
-}
-
-void event_rep2()
-/* [2 in the abc */
-{
-  addfeature(PLAY_ON_REP, 0, 0, 2);
-/*
-  if ((notes == 0) || (feature[notes-1] != REP_BAR)) {
-    event_error("[2 must follow a :| ");
-  } else {
-    feature[notes-1] = REP_BAR2;
-  };
-*/
-}
-
-void event_playonrep(s)
-char* s;
-/* [X in the abc, where X is a list of numbers */
-{
-  int num, converted;
-  char seps[2];
-
-  converted = sscanf(s, "%d%1[,-]", &num, seps);
-  if (converted == 0) {
-    event_error("corrupted variant ending");
-  } else {
-    if ((converted == 1) && (num != 0)) {
-      addfeature(PLAY_ON_REP, 0, 0, num);
-    } else {
-      textfeature(PLAY_ON_REP, s);
-    };
-  };
-}
-
-static void slurtotie()
-/* converts a pair of identical slurred notes to tied notes */
-{
-}
-
-void event_sluron(t)
-/* called when ( is encountered in the abc */
-int t;
-{
-  if (t == 1) {
-    addfeature(SLUR_ON, 0, 0, 0);
-    v->inslur = 1;
-  };
-}
-
-void event_sluroff(t)
-/* called when ) is encountered */
-int t;
-{
-  if (t == 0) {
-    slurtotie();
-    addfeature(SLUR_OFF, 0, 0, 0);
-    v->inslur = 0;
-  };
-}
-
-void event_tie()
-/* a tie - has been encountered in the abc */
-{
-  addfeature(TIE, 0, 0, 0);
-}
-
-void event_space()
-/* space character in the abc is ignored by abc2midi */
-{
-  /* ignore */
-  /* printf("Space event\n"); */
-}
-
-void event_lineend(ch, n)
-/* called when \ or ! or * or ** is encountered at the end of a line */
-char ch;
-int n;
-{
-  /* ignore */
-}
-
-void event_broken(type, mult)
-/* handles > >> >>> < << <<< in the abc */
-int type, mult;
-{
-  if (v->inchord) {
-    event_error("Broken rhythm not allowed in chord");
-  } else {
-    if (v->ingrace) {
-      event_error("Broken rhythm not allowed in grace notes");
-    } else {
-      v->brokentype = type;
-      v->brokenmult = mult;
-      v->brokenpending = 0;
-    };
-  };
-}
-
-void event_tuple(n, q, r)
-/* handles triplets (3 and general tuplets (n:q:r in the abc */
-int n, q, r;
-{
-  if (tuplecount > 0) {
-    event_error("nested tuples");
-  } else {
-    if (r == 0) {
-      specialtuple = 0;
-      tuplecount = n;
-    } else {
-      specialtuple = 1;
-      tuplecount = r;
-    };
-    if (q != 0) {
-      tfact_num = q;
-      tfact_denom = n;
-    } else {
-      if ((n < 2) || (n > 9)) {
-        event_error("Only tuples (2 - (9 allowed");
-        tfact_num = 1;
-        tfact_denom = 1;
-        tuplecount = 0;
-      } else {
-        /* deduce tfact_num using standard abc rules */
-        if ((n == 2) || (n == 4) || (n == 8)) tfact_num = 3;
-        if ((n == 3) || (n == 6)) tfact_num = 2;
-        if ((n == 5) || (n == 7) || (n == 9)) {
-          if ((time_num % 3) == 0) {
-            tfact_num = 3;
-          } else {
-            tfact_num = 2;
-          };
-        };
-        tfact_denom = n;
-      };
-    };
-    tnote_num = 0;
-    tnote_denom = 0;
-  };
-}
-
-void event_chord()
-/* a + has been encountered in the abc */
-{
-  if (v->inchord) {
-    event_chordoff(1,1);
-  } else {
-    event_chordon(dummydecorator);
-  };
-}
-
-static void lenmul(n, a, b)
-/* multiply note length by a/b */
-int n, a, b;
-{
-  if ((feature[n] == NOTE) || (feature[n] == REST) || 
-      (feature[n] == CHORDOFF)) {
-    num[n] = num[n] * a;
-    denom[n] = denom[n] * b;
-    reduce(&num[n], &denom[n]);
-  };
-}
-
-
-static void brokenadjust()
-/* adjust lengths of broken notes */
-{
-  int num1, num2, denom12;
-  int j;
-  int failed;
-
-  switch(v->brokenmult) {
-    case 1:
-      num1 = ratio_b;
-      num2 = ratio_a;
-      break;
-    case 2:
-      num1 = 7;
-      num2 = 1;
-      break;
-    case 3:
-      num1 = 15;
-      num2 = 1;
-      break;
-  };
-  denom12 = (num1 + num2)/2;
-  if (v->brokentype == LT) {
-    j = num1;
-    num1 = num2;
-    num2 = j;
-  };
-  failed = 0;
-  if ((v->laststart == -1) || (v->lastend == -1) || 
-      (v->thisstart == -1) || (v->thisend == -1)) {
-    failed = 1;
-  } else {
-    /* check for same length notes */
-    if ((num[v->laststart]*denom[v->thisstart]) != 
-             (num[v->thisstart]*denom[v->laststart])) {
-      failed = 1;
-    };
-  };
-  if (failed) {
-    event_error("Cannot apply broken rhythm");
-  } else {
-/*
-    printf("Adjusting %d to %d and %d to %d\n",
-           v->laststart, v->lastend, v->thisstart, v->thisend);
-*/
-    for (j=v->laststart; j<=v->lastend; j++) {
-      lenmul(j, num1, denom12);
-    };
-    for (j=v->thisstart; j<=v->thisend; j++) {
-      lenmul(j, num2, denom12);
-    };
-  };
-}
-
-static void marknotestart()
-/* voice data structure keeps a record of last few notes encountered */
-/* in order to process broken rhythm. This is called at the start of */
-/* a note or chord */
-{
-  v->laststart = v->thisstart;
-  v->lastend = v->thisend;
-  v->thisstart = notes-1;
-}
-
-static void marknoteend()
-/* voice data structure keeps a record of last few notes encountered */
-/* in order to process broken rhythm. This is called at the end of */
-/* a note or chord */
-{
-  v->thisend = notes-1;
-  if (v->brokenpending != -1) {
-    v->brokenpending = v->brokenpending + 1;
-    if (v->brokenpending == 1) {
-      brokenadjust();
-      v->brokenpending = -1;
-    };
-  };
-}
-
-static void marknote()
-/* when handling a single note, not a chord, marknotestart() and */
-/* marknoteend() can be called together */
-{
-  marknotestart();
-  marknoteend();
-}
-
-/* just a stub to ignore 'y' */
-void event_spacing(n, m)
-int n,m;
-{
-}
-
-void event_rest(decorators,n,m,type)
-/* rest of n/m in the abc */
-int n, m,type;
-int decorators[DECSIZE];
-{
-  int num, denom;
-
-  num = n;
-  denom = m;
-  if (v == NULL) {
-    event_fatal_error("Internal error : no voice allocated");
-  };
-  if (v->inchord) v->chordcount = v->chordcount + 1;
-  if (tuplecount > 0) {
-    num = num * tfact_num;
-    denom = denom * tfact_denom;
-    if (tnote_num == 0) {
-      tnote_num = num;
-      tnote_denom = denom;
-    } else {
-      if (tnote_num * denom != num * tnote_denom) {
-        if (!specialtuple) {
-          event_warning("Different length notes in tuple");
-        };
-      };
-    };
-    if ((!gracenotes) && (!v->inchord)) {
-      tuplecount = tuplecount - 1;
-    };
-  };
-  if (v->chordcount == 1) {
-    v->chord_num = num*4;
-    v->chord_denom = denom*(v->default_length);
-  };
-  if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) {
-    addunits(num, denom*(v->default_length));
-  };
-  last_num = 3; /* hornpiping (>) cannot follow rest */
-  addfeature(REST, 0, num*4, denom*(v->default_length));
-  if (!v->inchord ) {
-    marknote();
-  };
-}
-
-void event_mrest(n,m)
-/* multiple bar rest of n/m in the abc */
-/* we check for m == 1 in the parser */
-int n, m;
-{
-  int i;
-  int decorators[DECSIZE];
-  decorators[FERMATA]=0;
-/* it is not legal to pass a fermata to a multirest */
-
-  for (i=0; i<n; i++) {
-    event_rest(decorators,time_num*(v->default_length), time_denom,0);
-    if (i != n-1) {
-      event_bar(SINGLE_BAR, "");
-    };
-  };
-}
-
-
-
-void event_chordon(int chorddecorators[])
-/* handles a chord start [ in the abc */
-/* the array chorddecorators is needed in toabc.c and yapstree.c */
-/* but is not relevant here.                                    */
-
-{
-  if (v->inchord) {
-    event_error("Attempt to nest chords");
-  } else {
-    addfeature(CHORDON, 0, 0, 0);
-    v->inchord = 1;
-    v->chordcount = 0;
-    v->chord_num = 0;
-    v->chord_denom = 1;
-    marknotestart();
-  };
-}
-
-void event_chordoff(int chord_n, int chord_m)
-/* handles a chord close ] in the abc */
-{
-  if (!v->inchord) {
-    event_error("Chord already finished");
-  } else {
-
-    if(chord_m == 1 && chord_n == 1) /* chord length not set outside [] */
-      addfeature(CHORDOFF, 0, v->chord_num, v->chord_denom);
-    else
-      addfeature(CHORDOFFEX, 0, chord_n*4, chord_m*v->default_length);
-
-    v->inchord = 0;
-    v->chordcount = 0;
-    marknoteend();
-    if (tuplecount > 0) --tuplecount;
-  };
-}
-
-
-void event_finger(p)
-/* a 1, 2, 3, 4 or 5 has been found in a guitar chord field */
-char *p;
-{
-  /* does nothing */
-}
-
-static int pitchof(note, accidental, mult, octave, propogate_accs)
-/* finds MIDI pitch value for note */
-/* if propogate_accs is 1, apply any accidental to all instances of  */
-/* that note in the bar. If propogate_accs is 0, accidental does not */
-/* apply to other notes */
-char note, accidental;
-int mult, octave;
-int propogate_accs;
-{
-  int p;
-  char acc;
-  int mul, noteno;
-  static int scale[7] = {0, 2, 4, 5, 7, 9, 11};
-  char *anoctave = "cdefgab";
-
-  p = (int) ((long) strchr(anoctave, note) - (long) anoctave);
-  p = scale[p];
-  acc = accidental;
-  mul = mult;
-  noteno = (int)note - 'a';
-  if (acc == ' ') {
-    acc = v->workmap[noteno];
-    mul = v->workmul[noteno];
-  } else {
-    if ((retain_accidentals) && (propogate_accs)) {
-      v->workmap[noteno] = acc;
-      v->workmul[noteno] = mul;
-    };
-  };
-  if (acc == '^') p = p + mul;
-  if (acc == '_') p = p - mul;
-  return p + 12*octave + middle_c;
-}
-
-
-
-static void hornp(num, denom)
-/* If we have used R:hornpipe, this routine modifies the rhythm by */
-/* applying appropriate broken rhythm                              */
-int num, denom;
-{
-  if ((hornpipe) && (notes > 0) && (feature[notes-1] != GT)) {
-    if ((num*last_denom == last_num*denom) && (num == 1) &&
-        (denom*time_num == 32)) {
-      if (((time_num == 4) && (bar_denom == 8)) ||
-          ((time_num == 2) && (bar_denom == 16))) {
-           /* addfeature(GT, 1, 0, 0); */
-           v->brokentype = GT;
-           v->brokenmult = 1;
-           v->brokenpending = 0;
-      };
-    };
-    last_num = num;
-    last_denom = denom;
-  };
-}
-
-
-void event_note(decorators, accidental, mult, note, xoctave, n, m)
-/* handles a note in the abc */
-int decorators[DECSIZE];
-int mult;
-char accidental, note;
-int xoctave, n, m;
-{
-  int pitch;
-  int pitch_noacc;
-  int num, denom;
-  int octave;
-
-  if (v == NULL) {
-    event_fatal_error("Internal error - no voice allocated");
-  };
-  octave = xoctave + v->octaveshift;
-  num = n;
-  denom = m;
-  if (v->inchord) v->chordcount = v->chordcount + 1;
-  if (tuplecount > 0) {
-    num = num * tfact_num;
-    denom = denom * tfact_denom;
-    if (tnote_num == 0) {
-      tnote_num = num;
-      tnote_denom = denom;
-    } else {
-      if (tnote_num * denom != num * tnote_denom) {
-        if (!specialtuple) {
-          event_warning("Different length notes in tuple");
-        };
-      };
-    };
-    if ((!gracenotes) &&
-        ((!v->inchord) || ((v->inchord) && (v->chordcount == 1)))) {
-      tuplecount = tuplecount - 1;
-    };
-  };
-  if ((!v->ingrace) && (!v->inchord)) {
-    hornp(num, denom*(v->default_length));
-  } else {
-    last_num = 3; /* hornpiping (>) cannot follow chord or grace notes */
-  };
-  if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) {
-    addunits(num, denom*(v->default_length));
-  };
-  pitch = pitchof(note, accidental, mult, octave, 1);
-  pitch_noacc = pitchof(note,0,0,octave,0);
-  if (decorators[FERMATA]) {
-    num = num*2;
-  };
-  if (v->chordcount == 1) {
-    v->chord_num = num*4;
-    v->chord_denom = denom*(v->default_length);
-  };
-
-   pitchline[notes] = pitch_noacc;
-   addfeature(NOTE, pitch, num*4, denom*(v->default_length));
-   marknote();
-}
-
-void event_microtone(int dir, int a, int b)
-{
-}
-
-void event_normal_tone()
-{
-}
-
-
-
-char *get_accidental(place, accidental)
-/* read in accidental - used by event_handle_gchord() */
-char *place; /* place in string being parsed */
-char *accidental; /* pointer to char variable */
-{
-  char *p;
-
-  p = place;
-  *accidental = '=';
-  if (*p == '#') {
-    *accidental = '^';
-    p = p + 1;
-  };
-  if (*p == 'b') {
-    *accidental = '_';
-    p = p + 1;
-  };
-  return(p);
-}
-
-void event_handle_gchord(s)
-/* handler for the guitar chords */
-char* s;
-{
-}
-
-void event_handle_instruction(s)
-/* handler for ! ! instructions */
-/* does ppp pp p mp mf f ff fff */
-/* also does !drum! and !nodrum! */
-char* s;
-{
-}
-
-static void setmap(sf, map, mult)
-/* work out accidentals to be applied to each note */
-int sf; /* number of sharps in key signature -7 to +7 */
-char map[7];
-int mult[7];
-{
-  int j;
-
-  for (j=0; j<7; j++) {
-    map[j] = '=';
-    mult[j] = 1;
-  };
-  if (sf >= 1) map['f'-'a'] = '^';
-  if (sf >= 2) map['c'-'a'] = '^';
-  if (sf >= 3) map['g'-'a'] = '^';
-  if (sf >= 4) map['d'-'a'] = '^';
-  if (sf >= 5) map['a'-'a'] = '^';
-  if (sf >= 6) map['e'-'a'] = '^';
-  if (sf >= 7) map['b'-'a'] = '^';
-  if (sf <= -1) map['b'-'a'] = '_';
-  if (sf <= -2) map['e'-'a'] = '_';
-  if (sf <= -3) map['a'-'a'] = '_';
-  if (sf <= -4) map['d'-'a'] = '_';
-  if (sf <= -5) map['g'-'a'] = '_';
-  if (sf <= -6) map['c'-'a'] = '_';
-  if (sf <= -7) map['f'-'a'] = '_';
-}
-
-static void altermap(v, modmap, modmul)
-/* apply modifiers to a set of accidentals */
-struct voicecontext* v;
-char modmap[7];
-int modmul[7];
-{
-  int i;
-
-  for (i=0; i<7; i++) {
-    if (modmap[i] != ' ') {
-      v->basemap[i] = modmap[i];
-      v->basemul[i] = modmul[i];
-    };
-  };
-}
-
-static void copymap(v)
-/* sets up working map at the start of each bar */
-struct voicecontext* v;
-{
-  int j;
-
-  for (j=0; j<7; j++) {
-    v->workmap[j] = v->basemap[j];
-    v->workmul[j] = v->basemul[j];
-  };
-}
-
-/* workaround for problems with PCC compiler */
-/* data may be written to an internal buffer */
-
-int myputc(c)
-char c;
-{
-  return (putc(c,fp));
-}
-
-static void addfract(xnum, xdenom, a, b)
-/* add a/b to the count of units in the bar */
-int *xnum;
-int *xdenom;
-int a, b;
-{
-  *xnum = (*xnum)*b + a*(*xdenom);
-  *xdenom = (*xdenom) * b;
-  reduce(xnum, xdenom);
-}
-
-
-static void dotie(j, xinchord,voiceno)
-/* called in preprocessing stage to handle ties */
-/* we need the voiceno in case a tie is broken by a */
-/* voice switch.                                    */
-int j, xinchord,voiceno;
-{
-  int tienote, place;
-  int tietodo, done;
-  int lastnote, lasttie;
-  int inchord;
-  int tied_num, tied_denom;
-  int localvoiceno;
-  int samechord;
-
-  /* find note to be tied */
-  samechord = 0;
-  if (xinchord) samechord = 1;
-  tienote = j;
-  localvoiceno = voiceno;
-  while ((tienote > 0) && (feature[tienote] != NOTE) &&
-         (feature[tienote] != REST)) {
-    tienote = tienote - 1;
-  };
-  if (feature[tienote] != NOTE) {
-    event_error("Cannot find note before tie");
-  } else {
-    inchord = xinchord;
-    /* change NOTE + TIE to TNOTE + REST */
-    feature[tienote] = TNOTE;
-    feature[j] = REST;
-    num[j] = num[tienote];
-    denom[j] = denom[tienote];
-    place = j;
-    tietodo = 1;
-    lasttie = j;
-    tied_num = num[tienote];
-    tied_denom = denom[tienote];
-    lastnote = -1;
-    done = 0;
-    while ((place < notes) && (tied_num >=0) && (done == 0)) {
-     /* printf("%d %s   %d %d/%d ",place,featname[feature[place]],pitch[place],num[place],denom[place]); */
-      switch (feature[place]) {
-        case NOTE:
-          if(localvoiceno != voiceno) break;
-          lastnote = place;
-          if ((tied_num == 0) && (tietodo == 0)) {
-            done = 1;
-          };
-          if ((pitchline[place] == pitchline[tienote])
-             && (tietodo == 1) && (samechord == 0)) {
-            /* tie in note */
-            if (tied_num != 0) {
-              event_error("Time mismatch at tie");
-            };
-            tietodo = 0;
-	    pitch[place] = pitch[tienote]; /* in case accidentals did not
-					      propagate                   */
-            /* add time to tied time */
-            addfract(&tied_num, &tied_denom, num[place], denom[place]);
-            /* add time to tied note */
-            addfract(&num[tienote], &denom[tienote], num[place], denom[place]);
-            /* change note to a rest */
-            feature[place] = REST;
-            /* get rid of tie */
-            if (lasttie != j) {
-              feature[lasttie] = OLDTIE;
-            };
-          };
-          if (inchord == 0) {
-            /* subtract time from tied time */
-            addfract(&tied_num, &tied_denom, -num[place], denom[place]);
-          };
-          break;
-        case REST:
-          if(localvoiceno != voiceno) break;
-          if ((tied_num == 0) && (tietodo == 0)) {
-            done = 1;
-          };
-          if (inchord == 0) {
-            /* subtract time from tied time */
-            addfract(&tied_num, &tied_denom, -num[place], denom[place]);
-          };
-          break;
-        case TIE:
-          if(localvoiceno != voiceno) break;
-          if (lastnote == -1) {
-            event_error("Bad tie: possibly two ties in a row");
-          } else {
-            if (pitch[lastnote] == pitch[tienote] && samechord == 0) {
-              lasttie = place;
-              tietodo = 1;
-              if (inchord) samechord = 1;
-            };
-          };
-          break;
-        case CHORDON:
-          if(localvoiceno != voiceno) break;
-          inchord = 1;
-          break;
-        case CHORDOFF:
-        case CHORDOFFEX:
-          samechord = 0;
-          if(localvoiceno != voiceno) break;
-          inchord = 0;
-          /* subtract time from tied time */
-          addfract(&tied_num, &tied_denom, -num[place], denom[place]);
-          break;
-        case VOICE:
-          localvoiceno = pitch[place];
-        default:
-          break;
-      };
-      /*printf("tied_num = %d done = %d inchord = %d\n",tied_num, done, inchord); */
-      place = place + 1;
-    };
-    if (tietodo == 1) {
-      event_error("Could not find note to be tied");
-    };
-  };
-/* printf("dotie finished\n"); */
-}
-
-static void tiefix()
-/* connect up tied notes and cleans up the */
-/* note lengths in the chords (eg [ace]3 ) */
-{
-  int j;
-  int inchord;
-  int chord_num, chord_denom;
-  int chord_start,chord_end;
-  int voiceno;
-
-  j = 0;
-  inchord = 0;
-  voiceno = 1;
-  while (j<notes) {
-    switch (feature[j]) {
-    case CHORDON:
-      inchord = 1;
-      chord_num = -1;
-      chord_start = j;
-      j = j + 1;
-      break;
-    case CHORDOFFEX:
-      inchord = 0;
-      chord_end=j;
-      j = j + 1;
-      break;
-    case CHORDOFF:
-      if (!((!inchord) || (chord_num == -1))) {
-        num[j] = chord_num; 
-        denom[j] = chord_denom; 
-      };
-      inchord = 0;
-      chord_end=j;
-      j = j + 1;
-      break;
-    case NOTE:
-      if ((inchord) && (chord_num == -1)) {
-        chord_num = num[j];
-        chord_denom = denom[j];
-        /* use note length in num,denom as chord length */
-        /* if chord length is not set outside []        */
-      };
-      j = j + 1;
-      break;
-    case REST:
-      if ((inchord) && (chord_num == -1)) {
-        chord_num = num[j];
-        chord_denom = denom[j];
-      };
-      j = j + 1;
-      break;
-    case TIE:
-      dotie(j, inchord,voiceno);
-      j = j + 1;
-      break;
-    case LINENUM:
-      lineno = pitch[j];
-      j = j + 1;
-      break;
-    case VOICE:
-      voiceno = pitch[j];
-    default:
-      j = j + 1;
-      break;
-    };
-  };
-}
-
-
-static void zerobar()
-/* start a new count of beats in the bar */
-{
-  bar_num = 0;
-  bar_denom = 1;
-}
-
-void event_bar(type, replist)
-/* handles bar lines of various types in the abc */
-int type;
-char* replist;
-{
-  int newtype;
-#ifdef DEBUG
-  printf("bar line\n");
-#endif
-  newtype = type;
-  if ((type == THIN_THICK) || (type == THICK_THIN)) {
-    newtype = DOUBLE_BAR;
-  };
-  if (type == BAR1) {
-    newtype = SINGLE_BAR;
-  };
-  if (type == REP_BAR2) {
-    newtype = REP_BAR;
-  };
-  addfeature(newtype, 0, 0, 0);
-  copymap(v);
-  zerobar();
-  if (strlen(replist) > 0) {
-    event_playonrep(replist);
-  };
-/*
-  if (type == BAR1) {
-    addfeature(PLAY_ON_REP, 0, 0, 1);
-  };
-  if (type == REP_BAR2) {
-    addfeature(PLAY_ON_REP, 0, 0, 2);
-  };
-*/
-}
-
-
-
-
-void startfile()
-/* called at the beginning of an abc tune by event_refno */
-/* This sets up all the default values */
-{
-  int j;
-
-  if (verbose) {
-    printf("scanning tune\n");
-  };
-  /* set up defaults */
-  sf = 0;
-  mi = 0;
-  setmap(0, global.basemap, global.basemul);
-  copymap(&global);
-  global.octaveshift = 0;
-  voicecount = 0;
-  head = NULL;
-  v = NULL;
-  time_num = 4;
-  time_denom = 4;
-  timesigset = 0;
-  barchecking = 1;
-  global.default_length = -1;
-  event_tempo(120, 1, 4, 0,NULL, NULL);
-  notes = 0;
-  ntexts = 0;
-  gfact_num = 1;
-  gfact_denom = 3;
-  global_transpose = 0;
-  hornpipe = 0;
-  karaoke = 0;
-  retain_accidentals = 1;
-  ratio_a = 2;
-  ratio_b = 4;
-  wcount = 0;
-  parts = -1;
-  middle_c = 60;
-  for (j=0; j<26; j++) {
-    part_start[j] = -1;
-  };
-  headerpartlabel = 0;
-  additive = 1;
-  initvstring(&part);
- }
-
-
-static void headerprocess()
-/* called after the K: field has been reached, signifying the end of */
-/* the header and the start of the tune */
-{
-  int t_num, t_denom;
-
-  if (headerpartlabel == 1) {
-    part_start[(int)part.st[0] - (int)'A'] = notes;
-    addfeature(PART, part.st[0], 0, 0);
-  };
-  addfeature(DOUBLE_BAR, 0, 0, 0);
-  pastheader = 1;
-
-  gracenotes = 0; /* not in a grace notes section */
-  if (!timesigset) {
-    event_warning("No M: in header, using default");
-  };
-  /* calculate time for a default length note */
-  if (global.default_length == -1) {
-    if (((float) time_num)/time_denom < 0.75) {
-      global.default_length = 16;
-    } else {
-      global.default_length = 8;
-    };
-  };
-  bar_num = 0;
-  bar_denom = 1;
-  set_meter(time_num, time_denom); 
-  if (hornpipe) {
-    if ((time_denom != 4) || ((time_num != 2) && (time_num != 4))) {
-      event_error("Hornpipe must be in 2/4 or 4/4 time");
-      hornpipe = 0;
-    };
-  };
-
-  tempounits(&t_num, &t_denom);
-  /* make tempo in terms of 1/4 notes */
-/*  tempo = (long) 60*1000000*t_denom/(Qtempo*4*t_num); */
-/*  div_factor = division; */
-  voicesused = 0;
-}
-
-void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname,
-          octave, transpose, gotoctave, gottranspose)
-/* handles a K: field */
-int sharps; /* sharps is number of sharps in key signature */
-int modeindex; /* 0 major, 1,2,3 minor, 4 locrian, etc.  */
-char *s; /* original string following K: */
-char modmap[7]; /* array of accidentals to be applied */
-int  modmul[7]; /* array giving multiplicity of each accent (1 or 2) */
-int gotkey, gotclef;
-int octave, transpose, gotoctave, gottranspose;
-char* clefname;
-{
-  int minor;
-  if (modeindex >0 && modeindex <4) minor = 1;
-  if ((dotune) && gotkey) {
-    if (pastheader) {
-      setmap(sharps, v->basemap, v->basemul);
-      altermap(v, modmap, modmul);
-      copymap(v);
-      addfeature(KEY, sharps, 0, minor);
-      if (gottranspose) {
-        addfeature(TRANSPOSE, transpose, 0, 0);
-      };
-    } else {
-      if (gottranspose) {
-        global_transpose = transpose;
-      };
-      setmap(sharps, global.basemap, global.basemul);
-      altermap(&global, modmap, modmul);
-      copymap(&global);
-      sf = sharps;
-      mi = minor;
-      headerprocess();
-      v = newvoice(1);
-      head = v;
-    };
-    if (gotoctave) {
-      event_octave(octave,0);
-    };
-  };
-}
-
-
-
-void print_feature_list ()
-{
-int i,length;
-float fract;
-printf("feature list \n");
-for (i=0;i<notes;i++) {
-  printf("%d %d %s %d %d %d",i,feature[i],featname[feature[i]],pitch[i],num[i],denom[i]);
-  if (feature[i] == NOTE || feature[i] == TNOTE || feature[i] == REST) {
-    fract = (float) num[i]/ (float) denom[i];
-    length = (int) (fract * 12.0 +0.1);
-    printf(" %d",length);
-    }
-  printf("\n");
-  }
-}
-
-static void finishfile()
-/* end of tune has been reached - write out MIDI file */
-{
-  extern int nullputc();
-  int i;
-
-
-  clearvoicecontexts();
-  if (!pastheader) {
-    event_error("No valid K: field found at start of tune");
-  } else {
-
-
-    if (parts > -1) {
-      addfeature(PART, ' ', 0, 0);
-    };
-    if (headerpartlabel == 1) {
-      event_error("P: field in header should go after K: field");
-    };
-
-    tiefix();
-
-
-    };
-    for (i=0; i<ntexts; i++) {
-      free(atext[i]);
-    };
-    for (i=0; i<wcount; i++) {
-      free(words[i]);
-    };
-    freevstring(&part);
-}
-
-
-
-void event_blankline()
-/* blank line found in abc signifies the end of a tune */
-{
-  if (dotune) {
-    intune = 0;
-    finishfile();
-    parseroff();
-    dotune = 0;
-  };
-}
-
-void event_refno(n)
-/* handles an X: field (which indicates the start of a tune) */
-int n;
-{
-  if (dotune) {
-    finishfile();
-    parseroff();
-    dotune = 0;
-  };
-  if (verbose) {
-    printf("Reference X: %d\n", n);
-  };
-  if ((n == xmatch) || (xmatch == 0) || (xmatch == -1)) {
-    if (xmatch == -1) {
-      xmatch = -2;
-    };
-    parseron();
-    dotune = 1;
-    pastheader = 0;
-    xrefno = n;
-    startfile();
-  };
-}
-
-void event_eof()
-/* end of abc file encountered */
-{
-  if (dotune) {
-    dotune = 0;
-    parseroff();
-    finishfile();
-  };
-  if (verbose) {
-    printf("End of File reached\n");
-  };
-}
-
-
-void free_feature_representation ()
-{
-  free(pitch);
-  free(pitchline);
-  free(num);
-  free(denom);
-  free(feature);
-  free(words);
-}
+/*
+  matchsup.c  (abcmatch support functions)
+  Seymour Shlien
+
+  
+
+
+ * originally store.c
+ * abc2midi - program to convert abc files to MIDI files.
+ * Copyright (C) 1999 James Allwright
+ * e-mail: J.R.Allwright@westminster.ac.uk
+
+store.c was adapted for the purpose of analyzing the contents
+of abc tunes. The code is much the same except many functions
+related to the generation of midi files has been trimmed off.
+In particular: links to the code in genmidi.c and queue.c are gone.
+All the gchord stuff is removed. There are options to suppress
+all warning and error messages. Certain variables are no longer
+extern's (parts, partno, bar_num, global_transpose etc.).
+Output file generation stuff is gone. A new variable xrefno is
+added to pass the reference number to abcmatch. Event_init has
+been moved to the main program abcmatch.c and maxnotes has
+been raised to 3000 since there seems to be a problem with
+the autoextend procedure.  Some DEBUG statements were
+added to addfeature - (they can probably be removed). Support
+for text features and comments are gone. All the karaoke stuff
+is gone. Tempo stuff, slurs, grace notes, decorations, hornpipe
+indications  are all ignored. Event_note was changed to ignore
+trills and rolls.  When a [chord] is included, only the highest
+note is extracted from the chord. For debugging, a new function
+print_feature_list was introduced.etc.
+
+Essentially for comparing abc files, we want to ignore repeats,
+grace notes, staccato indications and midi indications. We are
+only interested in comparing the tunes. The main output 
+which is used is the feature[],pitch,num[],denom[] list which
+is used by abcmatch to create a new representation of the abc
+file.
+
+Some abc files with interleaved voices will not be treated
+propertly with this program. In general parts, repeats and
+voice indications are ignored.
+ 
+
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+#define XTEN1 1
+
+#include "abc.h"
+#include "parseabc.h"
+#include "parser2.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __MWERKS__
+#define __MACINTOSH__ 1
+#endif /* __MWERKS__ */
+
+#ifdef __MACINTOSH__
+int setOutFileCreator(char *fileName,unsigned long theType,
+                      unsigned long theCreator);
+#endif /* __MACINTOSH__ */
+/* define USE_INDEX if your C libraries have index() instead of strchr() */
+#ifdef USE_INDEX
+#define strchr index
+#endif
+
+#ifdef ANSILIBS
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#else
+extern char* strchr();
+extern void reduce();
+#endif
+
+#define MAXLINE 500
+#define INITTEXTS 20
+#define INITWORDS 20
+#define MAXCHANS 16
+
+/*#define DEBUG*/
+
+
+/* global variables grouped roughly by function */
+
+FILE *fp;
+
+programname fileprogram = ABCMATCH;
+
+
+/* parsing stage */
+int tuplecount, tfact_num, tfact_denom, tnote_num, tnote_denom;
+int specialtuple;
+int gracenotes;
+int headerpartlabel;
+int dotune, pastheader;
+int hornpipe, last_num, last_denom;
+int timesigset;
+int retain_accidentals;
+int ratio_a, ratio_b;
+
+struct voicecontext {
+  /* maps of accidentals for each stave line */
+  char basemap[7], workmap[7];
+  int  basemul[7], workmul[7];
+  int default_length;
+  int voiceno;
+  int indexno;
+  int hasgchords;
+  int haswords;
+  int inslur;
+  int ingrace;
+  int octaveshift;
+  /* chord handling */
+  int inchord, chordcount;
+  int chord_num, chord_denom;
+  /* details of last 2 notes/chords to apply length-modifiers to */
+  int laststart, lastend, thisstart, thisend;
+  /* broken rythm handling */
+  int brokentype, brokenmult, brokenpending;
+  int broken_stack[7];
+  struct voicecontext* next;
+};
+struct voicecontext global;
+struct voicecontext* v;
+struct voicecontext* head;
+int voicecount;
+
+/* storage structure for strings */
+int maxtexts = INITTEXTS;
+char** atext;
+int ntexts = 0;
+
+int note_unit_length=8;
+
+/* general purpose storage structure */
+int maxnotes;
+int *pitch, *num, *denom;
+featuretype *feature;
+int *pitchline;
+int notes;
+
+int verbose = 0;
+int nowarn=1;
+int noerror=1;
+int xmatch;
+int sf, mi;
+
+/* Part handling */
+struct vstring part;
+int parts, partno, partlabel;
+int part_start[26], part_count[26];
+
+int voicesused;
+
+/* Tempo handling (Q: field) */
+int time_num, time_denom;
+long tempo;
+int tempo_num, tempo_denom;
+int relative_tempo, Qtempo;
+extern int division;
+extern int div_factor;
+
+/* output file generation */
+int check;
+int ntracks;
+
+/* bar length checking */
+int bar_num, bar_denom;
+int barchecking;
+int beat;
+
+/* generating MIDI output */
+int middle_c;
+extern int channels[MAXCHANS + 3];
+
+int global_transpose;
+
+int additive;
+int gfact_num, gfact_denom;
+
+/* karaoke handling */
+int karaoke, wcount;
+char** words;
+int maxwords = INITWORDS;
+int xrefno;
+
+extern int intune; /* signals to parsetune that tune is finished */
+
+/* Many of these functions have been retained in order to link with parseabc.
+As I have been forced to also modifiy parseabc, now called abcparse, these
+functions can also be removed eventually.
+ */
+
+char *featname[] = {
+"SINGLE_BAR", "DOUBLE_BAR", "BAR_REP", "REP_BAR",
+"PLAY_ON_REP", "REP1", "REP2", "BAR1",
+"REP_BAR2", "DOUBLE_REP", "THICK_THIN", "THIN_THICK",
+"PART", "TEMPO", "TIME", "KEY",
+"REST", "TUPLE", "NOTE", "NONOTE",
+"OLDTIE", "TEXT", "SLUR_ON", "SLUR_OFF",
+"TIE", "CLOSE_TIE", "TITLE", "CHANNEL",
+"TRANSPOSE", "RTRANSPOSE", "GTRANSPOSE", "GRACEON",
+"GRACEOFF", "SETGRACE", "SETC", "SETTRIM", "GCHORD",
+"GCHORDON", "GCHORDOFF", "VOICE", "CHORDON",
+"CHORDOFF", "CHORDOFFEX", "DRUMON", "DRUMOFF",
+"DRONEON", "DRONEOFF", "SLUR_TIE", "TNOTE",
+"LT", "GT", "DYNAMIC", "LINENUM",
+"MUSICLINE", "MUSICSTOP", "WORDLINE", "WORDSTOP",
+"INSTRUCTION", "NOBEAM", "CHORDNOTE", "CLEF",
+"PRINTLINE", "NEWPAGE", "LEFT_TEXT", "CENTRE_TEXT",
+"VSKIP", "COPYRIGHT", "COMPOSER", "ARPEGGIO",
+"SPLITVOICE"
+};
+
+
+
+void event_info (place)
+char * place;
+{
+}
+
+void event_gchord (chord)
+char * chord;
+{
+}
+
+void event_slur (t)
+int t;
+{
+}
+
+
+void event_instruction (s)
+char *s;
+{
+}
+
+
+void event_reserved (p)
+char p;
+{
+}
+
+int bar_num, bar_denom, barno, barsize;
+int b_num,b_denom;
+
+void reduce(a, b)
+/* elimate common factors in fraction a/b */
+int *a, *b;
+{
+  int sign;
+  int t, n, m;
+
+  if (*a < 0) {
+    sign = -1;
+    *a = -*a;
+  } else {
+    sign = 1;
+  };
+  /* find HCF using Euclid's algorithm */
+  if (*a > *b) {
+    n = *a;
+    m = *b;
+  } else {
+    n = *b;
+    m = *a;
+  };
+  while (m != 0) {
+    t = n % m;
+    n = m;
+    m = t;
+  };
+  *a = (*a/n)*sign;
+  *b = *b/n;
+}
+
+void addunits(a, b)
+/* add a/b to the count of units in the bar */
+int a, b;
+{
+  bar_num = bar_num*(b*b_denom) + (a*b_num)*bar_denom;
+  bar_denom = bar_denom * (b*b_denom);
+  reduce(&bar_num, &bar_denom);
+}
+
+
+void set_meter(n, m)
+/* set up variables associated with meter */
+int n, m;
+{
+  /* set up barsize */
+  barsize = n;
+  if (barsize % 3 == 0) {
+    beat = 3;
+  } else {
+    if (barsize % 2 == 0) {
+      beat = 2;
+    } else {
+      beat = barsize;
+    };
+  };
+  /* correction factor to make sure we count in the right units */
+  if (m > 4) {
+    b_num = m/4;
+    b_denom = 1;
+  } else {
+   b_num = 1;
+   b_denom = 4/m;
+  };
+}
+
+int dummydecorator[DECSIZE]; /* used in event_chord */
+
+
+static struct voicecontext* newvoice(n)
+/* allocate and initialize the data for a new voice */
+int n;
+{
+  struct voicecontext *s;
+  int i;
+
+  s = (struct voicecontext*) checkmalloc(sizeof(struct voicecontext));
+  voicecount = voicecount + 1;
+  s->voiceno = n;
+  s->indexno = voicecount;
+  s->default_length = global.default_length;
+  s->hasgchords = 0;
+  s->haswords = 0;
+  s->inslur = 0;
+  s->ingrace = 0;
+  s->inchord = 0;
+  s->chordcount = 0;
+  s->laststart = -1;
+  s->lastend = -1;
+  s->thisstart = -1;
+  s->thisend = -1;
+  s->brokenpending = -1;
+  s->next = NULL;
+  for (i=0; i<7; i++) {
+    s->basemap[i] = global.basemap[i];
+    s->basemul[i] = global.basemul[i];
+    s->workmap[i] = global.workmap[i];
+    s->workmul[i] = global.workmul[i];
+  };
+  s->octaveshift = global.octaveshift;
+  return(s);
+}
+
+static struct voicecontext* getvoicecontext(n)
+/* find the data structure for a given voice number */
+int n;
+{
+  struct voicecontext *p;
+  struct voicecontext *q;
+
+  p = head;
+  q = NULL;
+  while ((p != NULL) && (p->voiceno != n)) {
+    q = p;
+    p = p->next;
+  };
+  if (p == NULL) {
+    p = newvoice(n);
+    if (q != NULL) {
+      q->next = p;
+    };
+  };
+  if (head == NULL) {
+    head = p;
+  };
+  return(p);
+}
+
+static void clearvoicecontexts()
+/* free up all the memory allocated to voices */
+{
+  struct voicecontext *p;
+  struct voicecontext *q;
+
+  p = head;
+  while (p != NULL) {
+    q = p->next;
+    free(p);
+    p = q;
+  };
+  head = NULL;
+}
+
+
+
+
+void event_text(s)
+/* text found in abc file */
+char *s;
+{
+}
+
+
+void event_specific (package, s)
+char *package, *s;
+{
+}
+
+
+void event_x_reserved(p)
+/* reserved character H-Z found in abc file */
+char p;
+{
+}
+
+void event_abbreviation(symbol, string, container)
+/* abbreviation encountered - this is handled within the parser */
+char symbol;
+char *string;
+char container;
+{
+}
+
+
+void event_acciaccatura()
+{
+/* does nothing here but outputs a / in abc2abc */
+return;
+}
+
+void event_split_voice()
+{
+}
+
+
+
+void event_tex(s)
+/* TeX command found - ignore it */
+char *s;
+{
+}
+
+void event_fatal_error(s)
+/* print error message and halt */
+char *s;
+{
+  event_error(s);
+  exit(1);
+}
+
+void event_error(s)
+/* generic error handler */
+char *s;
+{
+if (noerror) return;
+#ifdef NOFTELL
+  extern int nullpass;
+
+  if (nullpass != 1) {
+    printf("Error in line %d : %s\n", lineno, s);
+  };
+#else
+  printf("Error in line %d : %s\n", lineno, s);
+#endif
+}
+
+void event_warning(s)
+/* generic warning handler - for flagging possible errors */
+char *s;
+{
+if (nowarn) return;
+#ifdef NOFTELL
+  extern int nullpass;
+
+  if (nullpass != 1) {
+    printf("Warning in line %d : %s\n", lineno, s);
+  };
+#else
+  printf("Warning in line %d : %s\n", lineno, s);
+#endif
+}
+
+static int autoextend(maxnotes)
+/* increase the number of abc elements the program can cope with */
+int maxnotes;
+{
+  int newlimit;
+  int *ptr;
+  featuretype *fptr;
+  int i;
+
+  if (verbose) {
+    event_warning("Extending note capacity");
+  };
+  newlimit = maxnotes*2;
+  fptr = (featuretype*) checkmalloc(newlimit*sizeof(featuretype));
+  for(i=0;i<maxnotes;i++){
+    fptr[i] = feature[i];
+  };
+  free(feature);
+  feature = fptr;
+  ptr = checkmalloc(newlimit*sizeof(int));
+  for(i=0;i<maxnotes;i++){
+    ptr[i] = pitch[i];
+  };
+  free(pitch);
+  pitch = ptr;
+  ptr = checkmalloc(newlimit*sizeof(int));
+  for(i=0;i<maxnotes;i++){
+    ptr[i] = pitchline[i];
+  };
+  free(pitchline);
+  pitchline = ptr;
+  ptr = checkmalloc(newlimit*sizeof(int));
+  for(i=0;i<maxnotes;i++){
+    ptr[i] = num[i];
+  };
+  free(num);
+  num = ptr;
+  ptr = checkmalloc(newlimit*sizeof(int));
+  for(i=0;i<maxnotes;i++){
+    ptr[i] = denom[i];
+  };
+  free(denom);
+  denom = ptr;
+  return(newlimit);
+}
+
+
+static void addfeature(f, p, n, d)
+/* place feature in internal table */
+int f, p, n, d;
+{
+  feature[notes] = f;
+  pitch[notes] = p;
+  num[notes] = n;
+  denom[notes] = d;
+  if ((f == NOTE) || (f == REST) || (f == CHORDOFF)) {
+    reduce(&num[notes], &denom[notes]);
+  };
+#ifdef DEBUG
+  if ((f == NOTE) || (f == REST)) {
+    fract = (float) num[notes]/ (float) denom[notes];
+    length = fract * 12.0 +0.1;
+    printf("%2d %2d %2d %2d\n",pitch[notes],num[notes],denom[notes],length);
+    }
+  if (f == TIME) printf("time signature = %d/%d\n",n,d);
+#endif 
+  notes = notes + 1;
+  if (notes >= maxnotes) {
+    maxnotes = autoextend(maxnotes);
+  };
+}
+
+void event_linebreak()
+/* reached end of line in abc */
+{
+  addfeature(LINENUM, lineno, 0, 0);
+}
+
+void event_startmusicline()
+/* starting to parse line of abc music */
+{
+  addfeature(MUSICLINE, 0, 0, 0);
+}
+
+void event_endmusicline(endchar)
+/* finished parsing line of abc music */
+char endchar;
+{
+  addfeature(MUSICSTOP, 0, 0, 0);
+}
+
+static void textfeature(type, s)
+/* called while parsing abc - stores an item which requires an */
+/* associared string */
+int type;
+char* s;
+{
+}
+
+void event_comment(s)
+/* comment found in abc */
+char *s;
+{
+}
+
+
+void event_startinline()
+/* start of in-line field in abc music line */
+{
+}
+
+void event_closeinline()
+/* end of in-line field in abc music line */
+{
+}
+
+void event_field(k, f)
+/* Handles R: T: and any other field not handled elsewhere */
+char k;
+char *f;
+{
+  if (dotune) {
+    switch (k) {
+    case 'R':
+      {
+        char* p;
+
+        p = f;
+        skipspace(&p);
+/******** if ((strncmp(p, "Hornpipe", 8) == 0) ||
+            (strncmp(p, "hornpipe", 8) == 0)) {
+          hornpipe = 1;
+        };
+********/
+      };
+      break;
+    default:
+      {
+      };
+    };
+  };
+}
+
+void event_words(p, continuation)
+/* handles a w: field in the abc */
+char* p;
+int continuation;
+{
+}
+
+
+static void checkbreak()
+/* check that we are in not in chord, grace notes or tuple */
+/* called at voice change */
+{
+  if (tuplecount != 0) {
+    event_error("Previous voice has an unfinished tuple");
+    tuplecount = 0;
+  };
+  if (v->inchord != 0) {
+    event_error("Previous voice has incomplete chord");
+    event_chordoff(1,1);
+  };
+  if (v->ingrace != 0) {
+    event_error("Previous voice has unfinished grace notes");
+    v->ingrace = 0;
+  };
+}
+
+
+static void read_spec(spec, part)
+/* converts a P: field to a list of part labels */
+/* e.g. P:A(AB)3(CD)2 becomes P:AABABABCDCD */
+/* A '+' indicates 'additive' behaviour (a part may include repeats).  */
+/* A '-' indicates 'non-additive' behaviour (repeat marks in the music */
+/* are ignored and only repeats implied by the part order statement    */
+/* are played).  */
+char spec[];
+struct vstring* part;
+{
+}
+
+void event_part(s)
+/* handles a P: field in the abc */
+char* s;
+{
+  char* p;
+
+  if (dotune) {
+    p = s;
+    skipspace(&p);
+    if (pastheader) {
+      if (((int)*p < 'A') || ((int)*p > 'Z')) {
+        event_error("Part must be one of A-Z");
+        return;
+      };
+      if ((headerpartlabel == 1) && (part.st[0] == *p)) {
+        /* P: field in header is not a label */
+        headerpartlabel = 0;
+        /* remove speculative part label */
+        feature[part_start[(int)*p - (int)'A']] = NONOTE;
+      } else {
+        if (part_start[(int)*p - (int)'A'] != -1) {
+          event_error("Part defined more than once");
+        };
+      };
+      part_start[(int)*p - (int)'A'] = notes;
+      addfeature(PART, (int)*p, 0, 0);
+      checkbreak();
+      v = getvoicecontext(1);
+    } else {
+      parts = 0;
+      read_spec(p, &part);
+      if (parts == 1) {
+        /* might be a label not a specificaton */
+        headerpartlabel = 1;
+      };
+    };
+  };
+}
+
+void event_voice(n, s, vp)
+/* handles a V: field in the abc */
+int n;
+char *s;
+struct voice_params *vp;
+{
+  if (pastheader || XTEN1) {
+    voicesused = 1;
+    if (pastheader)  checkbreak();
+    v = getvoicecontext(n);
+    addfeature(VOICE, v->indexno, 0, 0);
+    if (vp->gotoctave) {
+      event_octave(vp->octave,1);
+    };
+    if (vp->gottranspose) {
+      addfeature(TRANSPOSE, vp->transpose, 0, 0);
+    };
+  } else {
+    event_warning("V: in header ignored");
+  };
+}
+
+
+void event_length(n)
+/* handles an L: field in the abc */
+int n;
+{
+  note_unit_length = 8;
+  if (pastheader) {
+    v->default_length = n;
+  } else {
+    global.default_length = n;
+  };
+}
+
+static void tempounits(t_num, t_denom)
+/* interprets Q: once default length is known */
+int *t_num, *t_denom;
+{
+}
+
+void event_tempo(n, a, b, rel, pre, post)
+/* handles a Q: field e.g. Q: a/b = n  or  Q: Ca/b = n */
+/* strings before and after are ignored */
+int n;
+int a, b, rel;
+char *pre;
+char *post;
+{
+}
+
+
+void event_timesig(n, m, dochecking)
+/* handles an M: field  M:n/m */
+int n, m, dochecking;
+{
+  if (dotune) {
+    if (pastheader) {
+      addfeature(TIME, dochecking, n, m);
+   } else { 
+      time_num = n;
+      time_denom = m;
+      timesigset = 1;
+      barchecking = dochecking;
+    };
+  };
+}
+
+void event_octave(num, local)
+/* used internally by other routines when octave=N is encountered */
+/* in I: or K: fields */
+int num;
+{
+  if (dotune) {
+    if (pastheader || local) {
+      v->octaveshift = num;
+    } else {
+      global.octaveshift = num;
+    };
+  };
+}
+
+void event_info_key(key, value)
+char* key;
+char* value;
+{
+  int num;
+
+  if (strcmp(key, "octave")==0) {
+    num = readsnumf(value);
+    event_octave(num,0);
+  };
+}
+
+static void stack_broken(v)
+struct voicecontext* v;
+{
+  v->broken_stack[0] = v->laststart;
+  v->broken_stack[1] = v->lastend;
+  v->broken_stack[2] = v->thisstart;
+  v->broken_stack[3] = v->thisend;
+  v->broken_stack[4] = v->brokentype;
+  v->broken_stack[5] = v->brokenmult;
+  v->broken_stack[6] = v->brokenpending;
+  v->laststart = -1;
+  v->lastend = -1;
+  v->thisstart = -1;
+  v->thisend = -1;
+  v->brokenpending = -1;
+}
+
+static void restore_broken(v)
+struct voicecontext* v;
+{
+  if (v->brokenpending != -1) {
+    event_error("Unresolved broken rhythm in grace notes");
+  };
+  v->laststart = v->broken_stack[0];
+  v->lastend = v->broken_stack[1];
+  v->thisstart = v->broken_stack[2];
+  v->thisend = v->broken_stack[3];
+  v->brokentype = v->broken_stack[4];
+  v->brokenmult = v->broken_stack[5];
+  v->brokenpending = v->broken_stack[6];
+}
+
+void event_graceon()
+/* a { in the abc */
+{
+  if (gracenotes) {
+    event_error("Nested grace notes not allowed");
+  } else {
+    if (v->inchord) {
+      event_error("Grace notes not allowed in chord");
+    } else {
+      gracenotes = 1;
+      addfeature(GRACEON, 0, 0, 0);
+      v->ingrace = 1;
+      stack_broken(v);
+    };
+  };
+}
+
+void event_graceoff()
+/* a } in the abc */
+{
+  if (!gracenotes) {
+    event_error("} without matching {");
+  } else {
+    gracenotes = 0;
+    addfeature(GRACEOFF, 0, 0, 0);
+    v->ingrace = 0;
+    restore_broken(v);
+  };
+}
+
+void event_rep1()
+/* [1 in the abc */
+{
+  addfeature(PLAY_ON_REP, 0, 0, 1);
+/*
+  if ((notes == 0) || (feature[notes-1] != SINGLE_BAR)) {
+    event_error("[1 must follow a single bar");
+  } else {
+    feature[notes-1] = BAR1;
+  };
+*/
+}
+
+void event_rep2()
+/* [2 in the abc */
+{
+  addfeature(PLAY_ON_REP, 0, 0, 2);
+/*
+  if ((notes == 0) || (feature[notes-1] != REP_BAR)) {
+    event_error("[2 must follow a :| ");
+  } else {
+    feature[notes-1] = REP_BAR2;
+  };
+*/
+}
+
+void event_playonrep(s)
+char* s;
+/* [X in the abc, where X is a list of numbers */
+{
+  int num, converted;
+  char seps[2];
+
+  converted = sscanf(s, "%d%1[,-]", &num, seps);
+  if (converted == 0) {
+    event_error("corrupted variant ending");
+  } else {
+    if ((converted == 1) && (num != 0)) {
+      addfeature(PLAY_ON_REP, 0, 0, num);
+    } else {
+      textfeature(PLAY_ON_REP, s);
+    };
+  };
+}
+
+static void slurtotie()
+/* converts a pair of identical slurred notes to tied notes */
+{
+}
+
+void event_sluron(t)
+/* called when ( is encountered in the abc */
+int t;
+{
+  if (t == 1) {
+    addfeature(SLUR_ON, 0, 0, 0);
+    v->inslur = 1;
+  };
+}
+
+void event_sluroff(t)
+/* called when ) is encountered */
+int t;
+{
+  if (t == 0) {
+    slurtotie();
+    addfeature(SLUR_OFF, 0, 0, 0);
+    v->inslur = 0;
+  };
+}
+
+void event_tie()
+/* a tie - has been encountered in the abc */
+{
+  addfeature(TIE, 0, 0, 0);
+}
+
+void event_space()
+/* space character in the abc is ignored by abc2midi */
+{
+  /* ignore */
+  /* printf("Space event\n"); */
+}
+
+void event_lineend(ch, n)
+/* called when \ or ! or * or ** is encountered at the end of a line */
+char ch;
+int n;
+{
+  /* ignore */
+}
+
+void event_broken(type, mult)
+/* handles > >> >>> < << <<< in the abc */
+int type, mult;
+{
+  if (v->inchord) {
+    event_error("Broken rhythm not allowed in chord");
+  } else {
+    if (v->ingrace) {
+      event_error("Broken rhythm not allowed in grace notes");
+    } else {
+      v->brokentype = type;
+      v->brokenmult = mult;
+      v->brokenpending = 0;
+    };
+  };
+}
+
+void event_tuple(n, q, r)
+/* handles triplets (3 and general tuplets (n:q:r in the abc */
+int n, q, r;
+{
+  if (tuplecount > 0) {
+    event_error("nested tuples");
+  } else {
+    if (r == 0) {
+      specialtuple = 0;
+      tuplecount = n;
+    } else {
+      specialtuple = 1;
+      tuplecount = r;
+    };
+    if (q != 0) {
+      tfact_num = q;
+      tfact_denom = n;
+    } else {
+      if ((n < 2) || (n > 9)) {
+        event_error("Only tuples (2 - (9 allowed");
+        tfact_num = 1;
+        tfact_denom = 1;
+        tuplecount = 0;
+      } else {
+        /* deduce tfact_num using standard abc rules */
+        if ((n == 2) || (n == 4) || (n == 8)) tfact_num = 3;
+        if ((n == 3) || (n == 6)) tfact_num = 2;
+        if ((n == 5) || (n == 7) || (n == 9)) {
+          if ((time_num % 3) == 0) {
+            tfact_num = 3;
+          } else {
+            tfact_num = 2;
+          };
+        };
+        tfact_denom = n;
+      };
+    };
+    tnote_num = 0;
+    tnote_denom = 0;
+  };
+}
+
+void event_chord()
+/* a + has been encountered in the abc */
+{
+  if (v->inchord) {
+    event_chordoff(1,1);
+  } else {
+    event_chordon(dummydecorator);
+  };
+}
+
+static void lenmul(n, a, b)
+/* multiply note length by a/b */
+int n, a, b;
+{
+  if ((feature[n] == NOTE) || (feature[n] == REST) || 
+      (feature[n] == CHORDOFF)) {
+    num[n] = num[n] * a;
+    denom[n] = denom[n] * b;
+    reduce(&num[n], &denom[n]);
+  };
+}
+
+
+static void brokenadjust()
+/* adjust lengths of broken notes */
+{
+  int num1, num2, denom12;
+  int j;
+  int failed;
+
+  switch(v->brokenmult) {
+    default:
+      event_error("unsupported type of broken rhythm");
+    case 1:
+      num1 = ratio_b;
+      num2 = ratio_a;
+      break;
+    case 2:
+      num1 = 7;
+      num2 = 1;
+      break;
+    case 3:
+      num1 = 15;
+      num2 = 1;
+      break;
+  };
+  denom12 = (num1 + num2)/2;
+  if (v->brokentype == LT) {
+    j = num1;
+    num1 = num2;
+    num2 = j;
+  };
+  failed = 0;
+  if ((v->laststart == -1) || (v->lastend == -1) || 
+      (v->thisstart == -1) || (v->thisend == -1)) {
+    failed = 1;
+  } else {
+    /* check for same length notes */
+    if ((num[v->laststart]*denom[v->thisstart]) != 
+             (num[v->thisstart]*denom[v->laststart])) {
+      failed = 1;
+    };
+  };
+  if (failed) {
+    event_error("Cannot apply broken rhythm");
+  } else {
+/*
+    printf("Adjusting %d to %d and %d to %d\n",
+           v->laststart, v->lastend, v->thisstart, v->thisend);
+*/
+    for (j=v->laststart; j<=v->lastend; j++) {
+      lenmul(j, num1, denom12);
+    };
+    for (j=v->thisstart; j<=v->thisend; j++) {
+      lenmul(j, num2, denom12);
+    };
+  };
+}
+
+static void marknotestart()
+/* voice data structure keeps a record of last few notes encountered */
+/* in order to process broken rhythm. This is called at the start of */
+/* a note or chord */
+{
+  v->laststart = v->thisstart;
+  v->lastend = v->thisend;
+  v->thisstart = notes-1;
+}
+
+static void marknoteend()
+/* voice data structure keeps a record of last few notes encountered */
+/* in order to process broken rhythm. This is called at the end of */
+/* a note or chord */
+{
+  v->thisend = notes-1;
+  if (v->brokenpending != -1) {
+    v->brokenpending = v->brokenpending + 1;
+    if (v->brokenpending == 1) {
+      brokenadjust();
+      v->brokenpending = -1;
+    };
+  };
+}
+
+static void marknote()
+/* when handling a single note, not a chord, marknotestart() and */
+/* marknoteend() can be called together */
+{
+  marknotestart();
+  marknoteend();
+}
+
+/* just a stub to ignore 'y' */
+void event_spacing(n, m)
+int n,m;
+{
+}
+
+void event_rest(decorators,n,m,type)
+/* rest of n/m in the abc */
+int n, m,type;
+int decorators[DECSIZE];
+{
+  int num, denom;
+
+  num = n;
+  denom = m;
+  if (v == NULL) {
+    event_fatal_error("Internal error : no voice allocated");
+  };
+  if (v->inchord) v->chordcount = v->chordcount + 1;
+  if (tuplecount > 0) {
+    num = num * tfact_num;
+    denom = denom * tfact_denom;
+    if (tnote_num == 0) {
+      tnote_num = num;
+      tnote_denom = denom;
+    } else {
+      if (tnote_num * denom != num * tnote_denom) {
+        if (!specialtuple) {
+          event_warning("Different length notes in tuple");
+        };
+      };
+    };
+    if ((!gracenotes) && (!v->inchord)) {
+      tuplecount = tuplecount - 1;
+    };
+  };
+  if (v->chordcount == 1) {
+    v->chord_num = num*4;
+    v->chord_denom = denom*(v->default_length);
+  };
+  if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) {
+    addunits(num, denom*(v->default_length));
+  };
+  last_num = 3; /* hornpiping (>) cannot follow rest */
+  addfeature(REST, 0, num*4, denom*(v->default_length));
+  if (!v->inchord ) {
+    marknote();
+  };
+}
+
+void event_mrest(n,m)
+/* multiple bar rest of n/m in the abc */
+/* we check for m == 1 in the parser */
+int n, m;
+{
+  int i;
+  int decorators[DECSIZE];
+  decorators[FERMATA]=0;
+/* it is not legal to pass a fermata to a multirest */
+
+  for (i=0; i<n; i++) {
+    event_rest(decorators,time_num*(v->default_length), time_denom,0);
+    if (i != n-1) {
+      event_bar(SINGLE_BAR, "");
+    };
+  };
+}
+
+
+
+void event_chordon(int chorddecorators[])
+/* handles a chord start [ in the abc */
+/* the array chorddecorators is needed in toabc.c and yapstree.c */
+/* but is not relevant here.                                    */
+
+{
+  if (v->inchord) {
+    event_error("Attempt to nest chords");
+  } else {
+    addfeature(CHORDON, 0, 0, 0);
+    v->inchord = 1;
+    v->chordcount = 0;
+    v->chord_num = 0;
+    v->chord_denom = 1;
+    marknotestart();
+  };
+}
+
+void event_chordoff(int chord_n, int chord_m)
+/* handles a chord close ] in the abc */
+{
+  if (!v->inchord) {
+    event_error("Chord already finished");
+  } else {
+
+    if(chord_m == 1 && chord_n == 1) /* chord length not set outside [] */
+      addfeature(CHORDOFF, 0, v->chord_num, v->chord_denom);
+    else
+      addfeature(CHORDOFFEX, 0, chord_n*4, chord_m*v->default_length);
+
+    v->inchord = 0;
+    v->chordcount = 0;
+    marknoteend();
+    if (tuplecount > 0) --tuplecount;
+  };
+}
+
+
+void event_finger(p)
+/* a 1, 2, 3, 4 or 5 has been found in a guitar chord field */
+char *p;
+{
+  /* does nothing */
+}
+
+static int pitchof(note, accidental, mult, octave, propogate_accs)
+/* finds MIDI pitch value for note */
+/* if propogate_accs is 1, apply any accidental to all instances of  */
+/* that note in the bar. If propogate_accs is 0, accidental does not */
+/* apply to other notes */
+char note, accidental;
+int mult, octave;
+int propogate_accs;
+{
+  int p;
+  char acc;
+  int mul, noteno;
+  static int scale[7] = {0, 2, 4, 5, 7, 9, 11};
+  char *anoctave = "cdefgab";
+
+  p = (int) ((long) strchr(anoctave, note) - (long) anoctave);
+  p = scale[p];
+  acc = accidental;
+  mul = mult;
+  noteno = (int)note - 'a';
+  if (acc == ' ') {
+    acc = v->workmap[noteno];
+    mul = v->workmul[noteno];
+  } else {
+    if ((retain_accidentals) && (propogate_accs)) {
+      v->workmap[noteno] = acc;
+      v->workmul[noteno] = mul;
+    };
+  };
+  if (acc == '^') p = p + mul;
+  if (acc == '_') p = p - mul;
+  return p + 12*octave + middle_c;
+}
+
+
+
+static void hornp(num, denom)
+/* If we have used R:hornpipe, this routine modifies the rhythm by */
+/* applying appropriate broken rhythm                              */
+int num, denom;
+{
+  if ((hornpipe) && (notes > 0) && (feature[notes-1] != GT)) {
+    if ((num*last_denom == last_num*denom) && (num == 1) &&
+        (denom*time_num == 32)) {
+      if (((time_num == 4) && (bar_denom == 8)) ||
+          ((time_num == 2) && (bar_denom == 16))) {
+           /* addfeature(GT, 1, 0, 0); */
+           v->brokentype = GT;
+           v->brokenmult = 1;
+           v->brokenpending = 0;
+      };
+    };
+    last_num = num;
+    last_denom = denom;
+  };
+}
+
+
+void event_note(decorators, accidental, mult, note, xoctave, n, m)
+/* handles a note in the abc */
+int decorators[DECSIZE];
+int mult;
+char accidental, note;
+int xoctave, n, m;
+{
+  int pitch;
+  int pitch_noacc;
+  int num, denom;
+  int octave;
+
+  if (v == NULL) {
+    event_fatal_error("Internal error - no voice allocated");
+  };
+  octave = xoctave + v->octaveshift;
+  num = n;
+  denom = m;
+  if (v->inchord) v->chordcount = v->chordcount + 1;
+  if (tuplecount > 0) {
+    num = num * tfact_num;
+    denom = denom * tfact_denom;
+    if (tnote_num == 0) {
+      tnote_num = num;
+      tnote_denom = denom;
+    } else {
+      if (tnote_num * denom != num * tnote_denom) {
+        if (!specialtuple) {
+          event_warning("Different length notes in tuple");
+        };
+      };
+    };
+    if ((!gracenotes) &&
+        ((!v->inchord) || ((v->inchord) && (v->chordcount == 1)))) {
+      tuplecount = tuplecount - 1;
+    };
+  };
+  if ((!v->ingrace) && (!v->inchord)) {
+    hornp(num, denom*(v->default_length));
+  } else {
+    last_num = 3; /* hornpiping (>) cannot follow chord or grace notes */
+  };
+  if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) {
+    addunits(num, denom*(v->default_length));
+  };
+  pitch = pitchof(note, accidental, mult, octave, 1);
+  pitch_noacc = pitchof(note,0,0,octave,0);
+  if (decorators[FERMATA]) {
+    num = num*2;
+  };
+  if (v->chordcount == 1) {
+    v->chord_num = num*4;
+    v->chord_denom = denom*(v->default_length);
+  };
+
+   pitchline[notes] = pitch_noacc;
+   addfeature(NOTE, pitch, num*4, denom*(v->default_length));
+   marknote();
+}
+
+void event_microtone(int dir, int a, int b)
+{
+}
+
+void event_normal_tone()
+{
+}
+
+
+
+char *get_accidental(place, accidental)
+/* read in accidental - used by event_handle_gchord() */
+char *place; /* place in string being parsed */
+char *accidental; /* pointer to char variable */
+{
+  char *p;
+
+  p = place;
+  *accidental = '=';
+  if (*p == '#') {
+    *accidental = '^';
+    p = p + 1;
+  };
+  if (*p == 'b') {
+    *accidental = '_';
+    p = p + 1;
+  };
+  return(p);
+}
+
+void event_handle_gchord(s)
+/* handler for the guitar chords */
+char* s;
+{
+}
+
+void event_handle_instruction(s)
+/* handler for ! ! instructions */
+/* does ppp pp p mp mf f ff fff */
+/* also does !drum! and !nodrum! */
+char* s;
+{
+}
+
+static void setmap(sf, map, mult)
+/* work out accidentals to be applied to each note */
+int sf; /* number of sharps in key signature -7 to +7 */
+char map[7];
+int mult[7];
+{
+  int j;
+
+  for (j=0; j<7; j++) {
+    map[j] = '=';
+    mult[j] = 1;
+  };
+  if (sf >= 1) map['f'-'a'] = '^';
+  if (sf >= 2) map['c'-'a'] = '^';
+  if (sf >= 3) map['g'-'a'] = '^';
+  if (sf >= 4) map['d'-'a'] = '^';
+  if (sf >= 5) map['a'-'a'] = '^';
+  if (sf >= 6) map['e'-'a'] = '^';
+  if (sf >= 7) map['b'-'a'] = '^';
+  if (sf <= -1) map['b'-'a'] = '_';
+  if (sf <= -2) map['e'-'a'] = '_';
+  if (sf <= -3) map['a'-'a'] = '_';
+  if (sf <= -4) map['d'-'a'] = '_';
+  if (sf <= -5) map['g'-'a'] = '_';
+  if (sf <= -6) map['c'-'a'] = '_';
+  if (sf <= -7) map['f'-'a'] = '_';
+}
+
+static void altermap(v, modmap, modmul)
+/* apply modifiers to a set of accidentals */
+struct voicecontext* v;
+char modmap[7];
+int modmul[7];
+{
+  int i;
+
+  for (i=0; i<7; i++) {
+    if (modmap[i] != ' ') {
+      v->basemap[i] = modmap[i];
+      v->basemul[i] = modmul[i];
+    };
+  };
+}
+
+static void copymap(v)
+/* sets up working map at the start of each bar */
+struct voicecontext* v;
+{
+  int j;
+
+  for (j=0; j<7; j++) {
+    v->workmap[j] = v->basemap[j];
+    v->workmul[j] = v->basemul[j];
+  };
+}
+
+/* workaround for problems with PCC compiler */
+/* data may be written to an internal buffer */
+
+int myputc(c)
+char c;
+{
+  return (putc(c,fp));
+}
+
+static void addfract(xnum, xdenom, a, b)
+/* add a/b to the count of units in the bar */
+int *xnum;
+int *xdenom;
+int a, b;
+{
+  *xnum = (*xnum)*b + a*(*xdenom);
+  *xdenom = (*xdenom) * b;
+  reduce(xnum, xdenom);
+}
+
+
+static void dotie(j, xinchord,voiceno)
+/* called in preprocessing stage to handle ties */
+/* we need the voiceno in case a tie is broken by a */
+/* voice switch.                                    */
+int j, xinchord,voiceno;
+{
+  int tienote, place;
+  int tietodo, done;
+  int lastnote, lasttie;
+  int inchord;
+  int tied_num, tied_denom;
+  int localvoiceno;
+  int samechord;
+
+  /* find note to be tied */
+  samechord = 0;
+  if (xinchord) samechord = 1;
+  tienote = j;
+  localvoiceno = voiceno;
+  while ((tienote > 0) && (feature[tienote] != NOTE) &&
+         (feature[tienote] != REST)) {
+    tienote = tienote - 1;
+  };
+  if (feature[tienote] != NOTE) {
+    event_error("Cannot find note before tie");
+  } else {
+    inchord = xinchord;
+    /* change NOTE + TIE to TNOTE + REST */
+    feature[tienote] = TNOTE;
+    feature[j] = REST;
+    num[j] = num[tienote];
+    denom[j] = denom[tienote];
+    place = j;
+    tietodo = 1;
+    lasttie = j;
+    tied_num = num[tienote];
+    tied_denom = denom[tienote];
+    lastnote = -1;
+    done = 0;
+    while ((place < notes) && (tied_num >=0) && (done == 0)) {
+     /* printf("%d %s   %d %d/%d ",place,featname[feature[place]],pitch[place],num[place],denom[place]); */
+      switch (feature[place]) {
+        case NOTE:
+          if(localvoiceno != voiceno) break;
+          lastnote = place;
+          if ((tied_num == 0) && (tietodo == 0)) {
+            done = 1;
+          };
+          if ((pitchline[place] == pitchline[tienote])
+             && (tietodo == 1) && (samechord == 0)) {
+            /* tie in note */
+            if (tied_num != 0) {
+              event_error("Time mismatch at tie");
+            };
+            tietodo = 0;
+	    pitch[place] = pitch[tienote]; /* in case accidentals did not
+					      propagate                   */
+            /* add time to tied time */
+            addfract(&tied_num, &tied_denom, num[place], denom[place]);
+            /* add time to tied note */
+            addfract(&num[tienote], &denom[tienote], num[place], denom[place]);
+            /* change note to a rest */
+            feature[place] = REST;
+            /* get rid of tie */
+            if (lasttie != j) {
+              feature[lasttie] = OLDTIE;
+            };
+          };
+          if (inchord == 0) {
+            /* subtract time from tied time */
+            addfract(&tied_num, &tied_denom, -num[place], denom[place]);
+          };
+          break;
+        case REST:
+          if(localvoiceno != voiceno) break;
+          if ((tied_num == 0) && (tietodo == 0)) {
+            done = 1;
+          };
+          if (inchord == 0) {
+            /* subtract time from tied time */
+            addfract(&tied_num, &tied_denom, -num[place], denom[place]);
+          };
+          break;
+        case TIE:
+          if(localvoiceno != voiceno) break;
+          if (lastnote == -1) {
+            event_error("Bad tie: possibly two ties in a row");
+          } else {
+            if (pitch[lastnote] == pitch[tienote] && samechord == 0) {
+              lasttie = place;
+              tietodo = 1;
+              if (inchord) samechord = 1;
+            };
+          };
+          break;
+        case CHORDON:
+          if(localvoiceno != voiceno) break;
+          inchord = 1;
+          break;
+        case CHORDOFF:
+        case CHORDOFFEX:
+          samechord = 0;
+          if(localvoiceno != voiceno) break;
+          inchord = 0;
+          /* subtract time from tied time */
+          addfract(&tied_num, &tied_denom, -num[place], denom[place]);
+          break;
+        case VOICE:
+          localvoiceno = pitch[place];
+        default:
+          break;
+      };
+      /*printf("tied_num = %d done = %d inchord = %d\n",tied_num, done, inchord); */
+      place = place + 1;
+    };
+    if (tietodo == 1) {
+      event_error("Could not find note to be tied");
+    };
+  };
+/* printf("dotie finished\n"); */
+}
+
+static void tiefix()
+/* connect up tied notes and cleans up the */
+/* note lengths in the chords (eg [ace]3 ) */
+{
+  int j;
+  int inchord;
+  int chord_num = 0, chord_denom = 0;
+  int chord_start,chord_end;
+  int voiceno;
+
+  j = 0;
+  inchord = 0;
+  voiceno = 1;
+  while (j<notes) {
+    switch (feature[j]) {
+    case CHORDON:
+      inchord = 1;
+      chord_num = -1;
+      chord_start = j;
+      j = j + 1;
+      break;
+    case CHORDOFFEX:
+      inchord = 0;
+      chord_end=j;
+      j = j + 1;
+      break;
+    case CHORDOFF:
+      if (!((!inchord) || (chord_num == -1))) {
+        num[j] = chord_num; 
+        denom[j] = chord_denom; 
+      };
+      inchord = 0;
+      chord_end=j;
+      j = j + 1;
+      break;
+    case NOTE:
+      if ((inchord) && (chord_num == -1)) {
+        chord_num = num[j];
+        chord_denom = denom[j];
+        /* use note length in num,denom as chord length */
+        /* if chord length is not set outside []        */
+      };
+      j = j + 1;
+      break;
+    case REST:
+      if ((inchord) && (chord_num == -1)) {
+        chord_num = num[j];
+        chord_denom = denom[j];
+      };
+      j = j + 1;
+      break;
+    case TIE:
+      dotie(j, inchord,voiceno);
+      j = j + 1;
+      break;
+    case LINENUM:
+      lineno = pitch[j];
+      j = j + 1;
+      break;
+    case VOICE:
+      voiceno = pitch[j];
+    default:
+      j = j + 1;
+      break;
+    };
+  };
+}
+
+
+static void zerobar()
+/* start a new count of beats in the bar */
+{
+  bar_num = 0;
+  bar_denom = 1;
+}
+
+void event_bar(type, replist)
+/* handles bar lines of various types in the abc */
+int type;
+char* replist;
+{
+  int newtype;
+#ifdef DEBUG
+  printf("bar line\n");
+#endif
+  newtype = type;
+  if ((type == THIN_THICK) || (type == THICK_THIN)) {
+    newtype = DOUBLE_BAR;
+  };
+  if (type == BAR1) {
+    newtype = SINGLE_BAR;
+  };
+  if (type == REP_BAR2) {
+    newtype = REP_BAR;
+  };
+  addfeature(newtype, 0, 0, 0);
+  copymap(v);
+  zerobar();
+  if (strlen(replist) > 0) {
+    event_playonrep(replist);
+  };
+/*
+  if (type == BAR1) {
+    addfeature(PLAY_ON_REP, 0, 0, 1);
+  };
+  if (type == REP_BAR2) {
+    addfeature(PLAY_ON_REP, 0, 0, 2);
+  };
+*/
+}
+
+
+
+
+void startfile()
+/* called at the beginning of an abc tune by event_refno */
+/* This sets up all the default values */
+{
+  int j;
+
+  if (verbose) {
+    printf("scanning tune\n");
+  };
+  /* set up defaults */
+  sf = 0;
+  mi = 0;
+  setmap(0, global.basemap, global.basemul);
+  copymap(&global);
+  global.octaveshift = 0;
+  voicecount = 0;
+  head = NULL;
+  v = NULL;
+  time_num = 4;
+  time_denom = 4;
+  timesigset = 0;
+  barchecking = 1;
+  global.default_length = -1;
+  event_tempo(120, 1, 4, 0,NULL, NULL);
+  notes = 0;
+  ntexts = 0;
+  gfact_num = 1;
+  gfact_denom = 3;
+  global_transpose = 0;
+  hornpipe = 0;
+  karaoke = 0;
+  retain_accidentals = 1;
+  ratio_a = 2;
+  ratio_b = 4;
+  wcount = 0;
+  parts = -1;
+  middle_c = 60;
+  for (j=0; j<26; j++) {
+    part_start[j] = -1;
+  };
+  headerpartlabel = 0;
+  additive = 1;
+  initvstring(&part);
+ }
+
+
+static void headerprocess()
+/* called after the K: field has been reached, signifying the end of */
+/* the header and the start of the tune */
+{
+  int t_num, t_denom;
+
+  if (headerpartlabel == 1) {
+    part_start[(int)part.st[0] - (int)'A'] = notes;
+    addfeature(PART, part.st[0], 0, 0);
+  };
+  addfeature(DOUBLE_BAR, 0, 0, 0);
+  pastheader = 1;
+
+  gracenotes = 0; /* not in a grace notes section */
+  if (!timesigset) {
+    event_warning("No M: in header, using default");
+  };
+  /* calculate time for a default length note */
+  if (global.default_length == -1) {
+    if (((float) time_num)/time_denom < 0.75) {
+      global.default_length = 16;
+    } else {
+      global.default_length = 8;
+    };
+  };
+  bar_num = 0;
+  bar_denom = 1;
+  set_meter(time_num, time_denom); 
+  if (hornpipe) {
+    if ((time_denom != 4) || ((time_num != 2) && (time_num != 4))) {
+      event_error("Hornpipe must be in 2/4 or 4/4 time");
+      hornpipe = 0;
+    };
+  };
+
+  tempounits(&t_num, &t_denom);
+  /* make tempo in terms of 1/4 notes */
+/*  tempo = (long) 60*1000000*t_denom/(Qtempo*4*t_num); */
+/*  div_factor = division; */
+  voicesused = 0;
+}
+
+void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname,
+          octave, transpose, gotoctave, gottranspose)
+/* handles a K: field */
+int sharps; /* sharps is number of sharps in key signature */
+int modeindex; /* 0 major, 1,2,3 minor, 4 locrian, etc.  */
+char *s; /* original string following K: */
+char modmap[7]; /* array of accidentals to be applied */
+int  modmul[7]; /* array giving multiplicity of each accent (1 or 2) */
+int gotkey, gotclef;
+int octave, transpose, gotoctave, gottranspose;
+char* clefname;
+{
+  int minor;
+  if (modeindex >0 && modeindex <4) minor = 1;
+  if ((dotune) && gotkey) {
+    if (pastheader) {
+      setmap(sharps, v->basemap, v->basemul);
+      altermap(v, modmap, modmul);
+      copymap(v);
+      addfeature(KEY, sharps, 0, minor);
+      if (gottranspose) {
+        addfeature(TRANSPOSE, transpose, 0, 0);
+      };
+    } else {
+      if (gottranspose) {
+        global_transpose = transpose;
+      };
+      setmap(sharps, global.basemap, global.basemul);
+      altermap(&global, modmap, modmul);
+      copymap(&global);
+      sf = sharps;
+      mi = minor;
+      headerprocess();
+      v = newvoice(1);
+      head = v;
+    };
+    if (gotoctave) {
+      event_octave(octave,0);
+    };
+  };
+}
+
+
+
+void print_feature_list ()
+{
+int i,length;
+float fract;
+printf("feature list \n");
+for (i=0;i<notes;i++) {
+  printf("%d %d %s %d %d %d",i,feature[i],featname[feature[i]],pitch[i],num[i],denom[i]);
+  if (feature[i] == NOTE || feature[i] == TNOTE || feature[i] == REST) {
+    fract = (float) num[i]/ (float) denom[i];
+    length = (int) (fract * 12.0 +0.1);
+    printf(" %d",length);
+    }
+  printf("\n");
+  }
+}
+
+static void finishfile()
+/* end of tune has been reached - write out MIDI file */
+{
+  extern int nullputc();
+  int i;
+
+
+  clearvoicecontexts();
+  if (!pastheader) {
+    event_error("No valid K: field found at start of tune");
+  } else {
+
+
+    if (parts > -1) {
+      addfeature(PART, ' ', 0, 0);
+    };
+    if (headerpartlabel == 1) {
+      event_error("P: field in header should go after K: field");
+    };
+
+    tiefix();
+
+
+    };
+    for (i=0; i<ntexts; i++) {
+      free(atext[i]);
+    };
+    for (i=0; i<wcount; i++) {
+      free(words[i]);
+    };
+    freevstring(&part);
+}
+
+
+
+void event_blankline()
+/* blank line found in abc signifies the end of a tune */
+{
+  if (dotune) {
+    intune = 0;
+    finishfile();
+    parseroff();
+    dotune = 0;
+  };
+}
+
+void event_refno(n)
+/* handles an X: field (which indicates the start of a tune) */
+int n;
+{
+  if (dotune) {
+    finishfile();
+    parseroff();
+    dotune = 0;
+  };
+  if (verbose) {
+    printf("Reference X: %d\n", n);
+  };
+  if ((n == xmatch) || (xmatch == 0) || (xmatch == -1)) {
+    if (xmatch == -1) {
+      xmatch = -2;
+    };
+    parseron();
+    dotune = 1;
+    pastheader = 0;
+    xrefno = n;
+    startfile();
+  };
+}
+
+void event_eof()
+/* end of abc file encountered */
+{
+  if (dotune) {
+    dotune = 0;
+    parseroff();
+    finishfile();
+  };
+  if (verbose) {
+    printf("End of File reached\n");
+  };
+}
+
+
+void free_feature_representation ()
+{
+  free(pitch);
+  free(pitchline);
+  free(num);
+  free(denom);
+  free(feature);
+  free(words);
+}
--- abcmidi-20070318.orig/drawtune.c
+++ abcmidi-20070318/drawtune.c
@@ -29,7 +29,7 @@
 #endif
 
 #include <stdio.h>
-#ifdef ANSILIBS
+#if defined(ANSILIBS) || defined(__STDC__)
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
@@ -329,6 +329,8 @@
   return(i);
 }
 
+/* This routine is never actually used anywhere. */
+#if 0
 static void ISOdecode(char s[], char out[])
 /* convert coded characters to straight 8-bit ascii */
 {
@@ -345,6 +347,7 @@
   };
   out[j] = '\0';
 }
+#endif
 
 static void ISOfprintf(char s[])
 /* interpret special characters and print to file */
@@ -492,7 +495,7 @@
   double x;
   char units[40];
 
-  count = sscanf(s, "%lf%s", &x, units);
+  count = sscanf(s, "%lf%39s", &x, units);
   if (count > 0) {
     if ((count >= 2) && (strncmp(units, "cm", 2) == 0)) {
       x = x*28.3;
@@ -689,6 +692,8 @@
   int note;
   
   switch (clef->type) {
+  default:
+    event_error("unknown clef type in draw_keysig (shouldn't happen)");
   case treble:
     offset = 0;
     break;
@@ -1024,7 +1029,7 @@
   struct feature* place;
   struct note* anote;
   int thisy, lasty, lastflip;
-  int stemdir;
+  int stemdir = 0;
   int doneflip;
   int ygap[10];
   int accplace;
@@ -1149,7 +1154,7 @@
 {
   int i, d;
   int donenotes;
-  int start, stop;
+  int start, stop = 0;
   double x0, x1, y0, y1, offset;
   struct note* n;
   int stemup, beamdir;
@@ -1244,9 +1249,9 @@
   struct note* lastnote;
   struct chord* thischord;
   struct feature* chordplace;
-  struct tuple* thistuple;
-  enum tail_type chordbeaming;
-  int intuple, tuplecount;
+  struct tuple* thistuple = NULL;
+  enum tail_type chordbeaming = nostem;
+  int intuple, tuplecount = 0;
   struct feature* tuplefeature;
 
   ingrace = 0;
@@ -1525,6 +1530,8 @@
         ft->xright = BASS_RIGHT;
         ft->xleft = BASS_LEFT;
         break;
+      default:
+        event_error("noclef in sizevoice switch (shouldn't happen)");
       };
       if (theclef->octave > 0) {
         ft->yup = ft->yup + CLEFNUM_HT;
@@ -1821,6 +1828,9 @@
       exit(1);
     };
     break;
+  default:
+    event_error("handlegracebeam for nostem (shouldn't happen)");
+    break;
   };
 }
 
@@ -1950,7 +1960,7 @@
   char fontname[80];
   int fontsize, params;
    
-  params = sscanf(s, "%s %d", fontname, &fontsize);
+  params = sscanf(s, "%79s %d", fontname, &fontsize);
   if (params >= 1) {
     if (strcmp(fontname, "-") != 0) {
       if (thefont->name != NULL) {
@@ -1974,7 +1984,7 @@
   int result;
 
   p[0] = '\0';
-  sscanf(s, " %10s", p);
+  sscanf(s, " %9s", p);
   result = 1;
   if ((strcmp(p, "0") == 0) || (strcmp(p, "no") == 0) || 
       (strcmp(p, "false") == 0)) {
@@ -2109,6 +2119,9 @@
 /* notes beamed together */
 {
   switch (n->beaming) {
+  case nostem:
+    event_error("handlebeam for nostem (shouldn't happen)");
+    break;
   case single:
     beamctr = -1;
     break;
@@ -2363,7 +2376,7 @@
   struct feature* gracebeamnote[64];
   struct chord* gracechording[64];
   struct chord* gracelastchord;
-  int i, j;
+  int i = 0, j = 0;
   int ingrace;
 
   p = ft;
@@ -2779,7 +2792,7 @@
 {
   double x0, y0, x1, y1;
   struct feature* ft;
-  struct note* n;
+  struct note* n = NULL;
   struct rest* r;
 
   ft = s->begin;
@@ -2839,7 +2852,7 @@
 {
   double x0, y0, x1, y1;
   struct feature* ft;
-  struct note* n;
+  struct note* n = NULL;
   struct rest* r;
 
   if ((s == NULL) || (s->crossline == 0)) {
@@ -2922,10 +2935,10 @@
   int sharps;
   struct chord* thischord;
   int chordcount;
-  double xchord;
+  double xchord = 0.0;
   struct aclef* theclef;
   int printedline;
-  double xend;
+  double xend = 0.0;
   int inend;
   char endstr[80];
   int ingrace;
@@ -3282,7 +3295,7 @@
 {
   struct feature* ft;
   double height, descender;
-  double yend, yinstruct, ygchord, ywords;
+  double yend = 0.0, yinstruct = 0.0, ygchord = 0.0, ywords = 0.0;
   struct vertspacing* avertspacing;
 
   /* skip over line number so we can check for end of tune */
@@ -3445,7 +3458,7 @@
   int titleno;
   struct voice* thisvoice;
   int doneline;
-  double firstvline, lastvline;
+  double firstvline = 0, lastvline;
   struct voice* firstvoice;
   char xtitle[200];
   struct bbox boundingbox;
--- abcmidi-20070318.orig/midicopy.c
+++ abcmidi-20070318/midicopy.c
@@ -50,8 +50,12 @@
 
 #include <stdio.h>
 
+#if defined(ANSILIBS) || defined(__STDC__)
+#include <string.h>
+#include <stdlib.h>
+#else
 char *strcpy(), *strcat();
-
+#endif
 
 /* Functions to be called while processing the MIDI file. */
 int (*Mf_arbitrary) () = NULLFUNC;
@@ -411,7 +415,7 @@
 {
     int n = 0;
     char *p = s;
-    int c;
+    int c = EOF;
 
     while (n++ < 4 && (c = getc(F_in)) != EOF) {
 	if (c != *p++) {
@@ -1393,7 +1397,7 @@
 
 int seconds_to_tick (float seconds)
 {
-int i, ind;
+int i, ind = 0;
 float tick,fraction;
 for (i = 0;i<temposize;i++) 
    {
@@ -1418,7 +1422,7 @@
 
 float tick_to_seconds (int tick)
 {
-int i,ind;
+int i,ind = 0;
 float seconds;
 float delta;
 for (i = 0; i < temposize; i++) {
--- abcmidi-20070318.orig/pslib.c
+++ abcmidi-20070318/pslib.c
@@ -1,1081 +1,1081 @@
-
-/*
- * This file is Copyright (C) 1999 Michael Methfessel
- * with modifications by James Allwright
- * e-mail: J.R.Allwright@westminster.ac.uk
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-/* pslib.c */
-/* part of yaps - abc to PostScript converter */
-/* This file contains a single C routine which prints a library of */
-/* PostScript routines to a file */
-
-/*  Extra routines added :                                            */
-/*  /slurup, /slurdown  - simpler interface than original functions   */
-/*  /endy1, /endy2      - re-positionable versions of end1, end2      */
-/*  /setx, /sety        - set /x and /y with no other effects         */
-/*  /boxshow            - show text string in a box                   */
-/*  /segno              - draw segno symbol                           */
-/*  /coda               - draw coda symbol                            */
-/*  /setISOfont         - create ISO variant of font                  */
-/*  /BHD                - draw breve                                  */
-/*  /r0                 - breve rest                                  */
-/*  /mrest              - multiple bar rest (taken from abcm2ps)      */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-/*  #define ANSILIBS is just used to access time functions for */
-/*  %%CreationDate . This can safely be removed if it causes   */
-/*  compilation problems */
-#ifdef ANSILIBS
-#include <time.h>
-#endif
-#include "drawtune.h"
-
-/* output library of PostScript routines for drawing music symbols */
-
-static void ps_header(f, filename, boundingbox)
-/* create header section of PostScript file */
-FILE* f;
-char* filename;
-struct bbox* boundingbox;
-{
-
-  if (eps_out) {
-    fprintf(f,"%%!PS-Adobe-3.0 EPSF-3.0\n");
-  } else {
-    fprintf(f,"%%!PS-Adobe-3.0\n");
-  };
-  if (boundingbox != NULL) {
-    fprintf(f,"%%%%BoundingBox: %d %d %d %d\n", boundingbox->llx, 
-              boundingbox->lly, boundingbox->urx, boundingbox->ury);
-  };
-  fprintf(f,"%%%%Title: %s\n", filename);
-  fprintf(f,"%%%%Creator: yaps (abc to PostScript converter)\n");
-#ifdef ANSILIBS
-  {
-    char timebuff[40];
-    time_t now;
-
-    fprintf(f,"%%%%CreationDate: ");
-    now = time(NULL);
-    /* define ASCTIME if your system does not have strftime() */
-#ifdef ASCTIME
-    fprintf(f, asctime(localtime(&now)));
-#else
-    strftime(timebuff, (size_t)40, "%a %d %b %Y at %H:%M\n", localtime(&now));
-    fprintf(f, timebuff);
-#endif
-  };
-#endif
-  fprintf(f,"%%%%LanguageLevel: 2\n");
-  fprintf(f,"%%%%EndComments\n");
-  fprintf(f,"\n");
-  fprintf(f,"%%\n");
-  fprintf(f,"%%  This is the abc2ps PostScript Music Library,\n");
-  fprintf(f,"%%  containing Postscript for generating musical symbols.\n");
-  fprintf(f,"%%  Original Copyright (c) 1999 Michael Methfessel.\n");
-  fprintf(f,"%%  This Library may be re-distributed under the\n");
-  fprintf(f,"%%  terms of the GNU General Public License.\n");
-  fprintf(f,"%%  This form of the library created by James\n");
-  fprintf(f,"%%  Allwright, July 1999.\n");
-  fprintf(f,"%%\n");
-  fprintf(f,"\n");
-  fprintf(f,"%%%%BeginSetup\n");
-  fprintf(f,"\n");
-}
-
-static void section1(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 1 - Fonts and String Manipulation\n");
-  fprintf(f,"\n");
-  fprintf(f,"/Times-Roman findfont\n");
-  fprintf(f,"dup length dict begin\n");
-  fprintf(f,"   {1 index /FID ne {def} {pop pop} ifelse} forall\n");
-  fprintf(f,"   /Encoding ISOLatin1Encoding def\n");
-  fprintf(f,"   currentdict\n");
-  fprintf(f,"end\n");
-  fprintf(f,"/Times-Roman-ISO exch definefont pop\n");
-  fprintf(f,"/F0 { /Times-Roman-ISO exch selectfont } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/Times-Italic findfont\n");
-  fprintf(f,"dup length dict begin\n");
-  fprintf(f,"   {1 index /FID ne {def} {pop pop} ifelse} forall\n");
-  fprintf(f,"   /Encoding ISOLatin1Encoding def\n");
-  fprintf(f,"   currentdict\n");
-  fprintf(f,"end\n");
-  fprintf(f,"/Times-Italic-ISO exch definefont pop\n");
-  fprintf(f,"/F1 { /Times-Italic-ISO exch selectfont } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/Times-Bold findfont\n");
-  fprintf(f,"dup length dict begin\n");
-  fprintf(f,"   {1 index /FID ne {def} {pop pop} ifelse} forall\n");
-  fprintf(f,"   /Encoding ISOLatin1Encoding def\n");
-  fprintf(f,"   currentdict\n");
-  fprintf(f,"end\n");
-  fprintf(f,"/Times-Bold-ISO exch definefont pop\n");
-  fprintf(f,"/F2 { /Times-Bold-ISO exch selectfont } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/Helvetica findfont\n");
-  fprintf(f,"dup length dict begin\n");
-  fprintf(f,"   {1 index /FID ne {def} {pop pop} ifelse} forall\n");
-  fprintf(f,"   /Encoding ISOLatin1Encoding def\n");
-  fprintf(f,"   currentdict\n");
-  fprintf(f,"end\n");
-  fprintf(f,"/Helvetica-ISO exch definefont pop\n");
-  fprintf(f,"/F3 { /Helvetica-ISO exch selectfont } bind def\n");
-  fprintf(f,"\n");
-
-  fprintf(f,"/setISOfont { %% usage /Name-ISO /Name setISOfont\n");
-  fprintf(f,"              %% define ISO encoding variant of font\n");
-  fprintf(f,"  findfont\n");
-  fprintf(f,"  dup length dict begin\n");
-  fprintf(f,"     {1 index /FID ne {def} {pop pop} ifelse} forall\n");
-  fprintf(f,"     /Encoding ISOLatin1Encoding def\n");
-  fprintf(f,"     currentdict\n");
-  fprintf(f,"  end\n");
-  fprintf(f,"  definefont pop\n");
-  fprintf(f,"} def\n");
-  fprintf(f,"\n");
-
-  fprintf(f,"/cshow { %% usage: string cshow  - center at current pt\n");
-  fprintf(f,"   dup stringwidth pop 2 div neg 0 rmoveto\n");
-  fprintf(f,"   currentpoint pop dup 0 lt {neg 0 rmoveto} {pop} ifelse\n");
-  fprintf(f,"   show\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/lshow { %% usage: string lshow - show left-aligned\n");
-  fprintf(f,"   dup stringwidth pop neg 0 rmoveto show\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f, "/boxshow {  %% usage: x y h string boxshow - text in a box\n");
-  fprintf(f, "  3 index 2 add 3 index 2 add moveto\n");
-  fprintf(f, "  dup show\n");
-  fprintf(f, "  3 index 3 index moveto\n");
-  fprintf(f, "  stringwidth pop 4 add exch dup 0 exch rlineto\n");
-  fprintf(f, "  exch 0 rlineto\n");
-  fprintf(f, "  neg 0 exch rlineto\n");
-  fprintf(f, "  closepath stroke\n");
-  fprintf(f, "} bind def\n");
-  fprintf(f, "\n");
-  fprintf(f,"/wd { moveto show } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/wln {\n");
-  fprintf(f,"dup 3 1 roll moveto gsave 0.6 setlinewidth lineto stroke grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/whf {moveto gsave 0.5 1.2 scale (-) show grestore} bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section2(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 2 - Clefs\n");
-  fprintf(f,"\n");
-  fprintf(f,"/tclef {  %% usage:  x tclef  - treble clef \n");
-  fprintf(f,"  0 moveto\n");
-  fprintf(f,"  -2.22 5.91 rmoveto\n");
-  fprintf(f,"  -0.74 -1.11 rlineto\n");
-  fprintf(f,"  -2.22 2.22 -0.74 8.12 3.69 8.12 rcurveto\n");
-  fprintf(f,"  2.22 0.74 7.02 -1.85 7.02 -6.65 rcurveto\n");
-  fprintf(f,"  0.00 -4.43 -4.06 -6.65 -7.75 -6.65 rcurveto\n");
-  fprintf(f,"  -4.43 0.00 -8.49 2.22 -8.49 8.49 rcurveto\n");
-  fprintf(f,"  0.00 2.58 0.37 5.54 5.91 9.97 rcurveto\n");
-  fprintf(f,"  6.28 4.43 6.28 7.02 6.28 8.86 rcurveto\n");
-  fprintf(f,"  0.00 1.85 -0.37 3.32 -1.11 3.32 rcurveto\n");
-  fprintf(f,"  -1.85 -1.48 -3.32 -5.17 -3.32 -7.38 rcurveto\n");
-  fprintf(f,"  0.00 -13.66 4.43 -16.25 4.80 -25.85 rcurveto\n");
-  fprintf(f,"  0.00 -3.69 -2.22 -5.54 -5.54 -5.54 rcurveto\n");
-  fprintf(f,"  -2.22 0.00 -4.06 1.85 -4.06 3.69 rcurveto\n");
-  fprintf(f,"  0.00 1.85 1.11 3.32 2.95 3.32 rcurveto\n");
-  fprintf(f,"  3.69 0.00 3.69 -5.91 0.37 -4.80 rcurveto\n");
-  fprintf(f,"  0.37 -2.22 5.54 -1.11 5.54 2.95 rcurveto\n");
-  fprintf(f,"  -0.74 12.18 -5.17 14.40 -5.17 28.06 rcurveto\n");
-  fprintf(f,"  0.00 4.06 1.11 7.38 4.43 8.86 rcurveto\n");
-  fprintf(f,"  2.22 -1.48 4.06 -4.06 3.69 -6.65 rcurveto\n");
-  fprintf(f,"  0.00 -4.06 -2.58 -7.02 -5.91 -10.34 rcurveto\n");
-  fprintf(f,"  -2.22 -2.58 -5.91 -4.43 -5.91 -9.60 rcurveto\n");
-  fprintf(f,"  0.00 -4.43 2.58 -6.65 5.54 -6.65 rcurveto\n");
-  fprintf(f,"  2.95 0.00 5.54 1.85 5.54 4.80 rcurveto\n");
-  fprintf(f,"  0.00 3.32 -2.95 4.43 -4.80 4.43 rcurveto\n");
-  fprintf(f,"  -2.58 0.00 -4.06 -1.85 -2.95 -3.69 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/stclef {\n");
-  fprintf(f,"  0.85 div gsave 0.85 0.85 scale tclef grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/bclef {  %% usage:  x bclef  - bass clef \n");
-  fprintf(f,"  0 moveto\n");
-  fprintf(f,"  -9.80 2.50 rmoveto\n");
-  fprintf(f,"  8.30 4.00 12.80 9.00 12.80 13.00 rcurveto\n");
-  fprintf(f,"  0.00 4.50 -2.00 7.50 -4.30 7.30 rcurveto\n");
-  fprintf(f,"  -1.00 0.20 -4.20 0.20 -5.70 -3.80 rcurveto\n");
-  fprintf(f,"  1.50 0.50 3.50 0.00 3.50 -1.50 rcurveto\n");
-  fprintf(f,"  0.00 -1.00 -0.50 -2.00 -2.00 -2.00 rcurveto\n");
-  fprintf(f,"  -1.00 0.00 -2.00 0.90 -2.00 2.50 rcurveto\n");
-  fprintf(f,"  0.00 2.50 2.10 5.50 6.00 5.50 rcurveto\n");
-  fprintf(f,"  4.00 0.00 7.50 -2.50 7.50 -7.50 rcurveto\n");
-  fprintf(f,"  0.00 -5.50 -6.50 -11.00 -15.50 -13.70 rcurveto\n");
-  fprintf(f,"  8.30 4.00 12.80 9.00 12.80 13.00 rcurveto\n");
-  fprintf(f,"  0.00 4.50 -2.00 7.50 -4.30 7.30 rcurveto\n");
-  fprintf(f,"  -1.00 0.20 -4.20 0.20 -5.70 -3.80 rcurveto\n");
-  fprintf(f,"  1.50 0.50 3.50 0.00 3.50 -1.50 rcurveto\n");
-  fprintf(f,"  0.00 -1.00 -0.50 -2.00 -2.00 -2.00 rcurveto\n");
-  fprintf(f,"  -1.00 0.00 -2.00 0.90 -2.00 2.50 rcurveto\n");
-  fprintf(f,"  0.00 2.50 2.10 5.50 6.00 5.50 rcurveto\n");
-  fprintf(f,"  4.00 0.00 7.50 -2.50 7.50 -7.50 rcurveto\n");
-  fprintf(f,"  0.00 -5.50 -6.50 -11.00 -15.50 -13.70 rcurveto\n");
-  fprintf(f,"  16.90 18.20 rmoveto\n");
-  fprintf(f,"  0.00 1.50 2.00 1.50 2.00 0.00 rcurveto\n");
-  fprintf(f,"  0.00 -1.50 -2.00 -1.50 -2.00 0.00 rcurveto\n");
-  fprintf(f,"  0.00 -5.50 rmoveto\n");
-  fprintf(f,"  0.00 1.50 2.00 1.50 2.00 0.00 rcurveto\n");
-  fprintf(f,"  0.00 -1.50 -2.00 -1.50 -2.00 0.00 rcurveto\n");
-  fprintf(f,"fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/sbclef {\n");
-  fprintf(f,"  0.85 div gsave 0.85 0.85 scale 0 4 translate bclef grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/cchalf {\n");
-  fprintf(f,"  0 moveto\n");
-  fprintf(f,"  0.00 12.00 rmoveto\n");
-  fprintf(f,"  1.20 2.75 rlineto\n");
-  fprintf(f,"  4.20 -0.50 6.00 2.25 6.00 5.00 rcurveto\n");
-  fprintf(f,"  0.00 2.00 -0.60 3.90 -3.30 4.00 rcurveto\n");
-  fprintf(f,"  -0.78 0.00 -2.70 0.00 -3.60 -2.00 rcurveto\n");
-  fprintf(f,"  0.90 0.25 2.10 0.00 2.10 -0.75 rcurveto\n");
-  fprintf(f,"  0.00 -0.50 -0.30 -1.00 -1.20 -1.00 rcurveto\n");
-  fprintf(f,"  -0.60 0.00 -1.20 0.45 -1.20 1.25 rcurveto\n");
-  fprintf(f,"  0.00 1.25 1.26 2.75 3.60 2.75 rcurveto\n");
-  fprintf(f,"  3.60 0.00 5.40 -1.25 5.40 -3.75 rcurveto\n");
-  fprintf(f,"  0.00 -3.25 -3.00 -6.00 -6.60 -5.75 rcurveto\n");
-  fprintf(f,"  -0.60 -2.50 rlineto\n");
-  fprintf(f,"fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/cclef {   %% usage: x cclef\n");
-  fprintf(f,"   dup dup dup\n");
-  fprintf(f,"   cchalf gsave 0 24 translate 1 -1 scale cchalf\n");
-  fprintf(f,"   6.5 sub 0 moveto 0 24 rlineto 3 0 rlineto 0 -24 rlineto fill\n");
-  fprintf(f,"   1.8 sub 0 moveto 0 24 rlineto 0.8 setlinewidth stroke grestore \n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/scclef { cclef } bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section3(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 3 - Note Heads, Stems and Beams\n");
-  fprintf(f,"\n");
-  fprintf(f,"/hd {  %% usage: x y hd  - full head\n");
-  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
-  fprintf(f,"  3.30 2.26 rmoveto\n");
-  fprintf(f,"  -2.26 3.30 -8.86 -1.22 -6.60 -4.52 rcurveto\n");
-  fprintf(f,"  2.26 -3.30 8.86 1.22 6.60 4.52 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/Hd {  %% usage: x y Hd  - open head for half\n");
-  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
-  fprintf(f,"  3.51 1.92 rmoveto\n");
-  fprintf(f,"  -2.04 3.73 -9.06 -0.10 -7.02 -3.83 rcurveto\n");
-  fprintf(f,"  2.04 -3.73 9.06 0.10 7.02 3.83 rcurveto\n");
-  fprintf(f,"  -0.44 -0.24 rmoveto\n");
-  fprintf(f,"  0.96 -1.76 -5.19 -5.11 -6.15 -3.35 rcurveto\n");
-  fprintf(f,"  -0.96 1.76 5.19 5.11 6.15 3.35 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/HD { %% usage: x y HD  - open head for whole\n");
-  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
-  fprintf(f,"  5.96 0.00 rmoveto\n");
-  fprintf(f,"  0.00 1.08 -2.71 3.52 -5.96 3.52 rcurveto\n");
-  fprintf(f,"  -3.25 0.00 -5.96 -2.44 -5.96 -3.52 rcurveto\n");
-  fprintf(f,"  0.00 -1.08 2.71 -3.52 5.96 -3.52 rcurveto\n");
-  fprintf(f,"  3.25 0.00 5.96 2.44 5.96 3.52 rcurveto\n");
-  fprintf(f,"  -8.13 1.62 rmoveto\n");
-  fprintf(f,"  1.62 2.17 5.96 -1.07 4.34 -3.24 rcurveto\n");
-  fprintf(f,"  -1.62 -2.17 -5.96 1.07 -4.34 3.24 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/BHD { %% usage x y BHD - breve\n");
-  fprintf(f,"  HD\n");
-  fprintf(f,"  x 6.0 sub y 3.5 sub moveto 0 7.0 rlineto stroke\n");
-  fprintf(f,"  x 8.0 sub y 3.5 sub moveto 0 7.0 rlineto stroke\n");
-  fprintf(f,"  x 6.0 add y 3.5 sub moveto 0 7.0 rlineto stroke\n");
-  fprintf(f,"  x 8.0 add y 3.5 sub moveto 0 7.0 rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/setx { %% usage: x setx - set x value\n");
-  fprintf(f,"  /x exch store\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/sety { %% usage: y sety - set y value\n");
-  fprintf(f,"  /y exch store\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/su {  %% usage: len su   - up stem\n");
-  fprintf(f,"  x y moveto 3.5 1.0 rmoveto 1.0 sub 0 exch rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/sd {  %% usage: len td   - down stem\n");
-  fprintf(f,"  x y moveto -3.5 -1.0 rmoveto neg 1.0 add 0 exch rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/bm {  %% usage: x1 y1 x2 y2 t bm  - beam, depth t\n");
-  fprintf(f,"  3 1 roll moveto dup 0 exch neg rlineto\n");
-  fprintf(f,"  dup 4 1 roll sub lineto 0 exch rlineto fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/bnum {  %% usage: x y (str) bnum  - number on beam\n");
-  fprintf(f,"  3 1 roll moveto gsave /Times-Italic 12 selectfont\n");
-  fprintf(f,"  cshow grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/hbr {  %% usage: x1 y1 x2 y2 hbr  - half bracket\n");
-  fprintf(f,"  moveto lineto 0 -3 rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/SL {  %% usage: pp2x pp1x p1 pp1 pp2 p2 p1 sl\n");
-  fprintf(f,"  moveto curveto rlineto curveto fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f, "\n");
-  fprintf(f, "%% New slurs with simple interface \n");
-  fprintf(f, "/slurdown { %% Slur - usage x1 y1 x2 y2 slurdown\n");
-  fprintf(f, "  /ys2 exch def\n");
-  fprintf(f, "  /xs2 exch def\n");
-  fprintf(f, "  /ys1 exch def\n");
-  fprintf(f, "  /xs1 exch def\n");
-  fprintf(f, "  /ddy xs2 xs1 sub abs 2 div dup 12 gt {pop 12} if def\n");
-  fprintf(f, "  xs1 4 add ys1 4 sub moveto\n");
-  fprintf(f, "  xs1 2 mul xs2 add 3 div ys1 2 mul ys2 add 3 div ddy sub\n");
-  fprintf(f, "  xs1 xs2 2 mul add 3 div ys1 ys2 2 mul add 3 div ddy sub\n");
-  fprintf(f, "  xs2 4 sub ys2 4 sub\n");
-  fprintf(f, "  curveto\n");
-  fprintf(f, "  xs1 xs2 2 mul add 3 div ys1 ys2 2 mul add 3 div ddy sub 2 sub\n");
-  fprintf(f, "  xs1 2 mul xs2 add 3 div ys1 2 mul ys2 add 3 div ddy sub 2 sub\n");
-  fprintf(f, "  xs1 4 add ys1 4 sub\n");
-  fprintf(f, "  curveto fill\n");
-  fprintf(f, "} def\n");
-  fprintf(f, "/slurup { %% Slur - usage x1 y1 x2 y2 slurup\n");
-  fprintf(f, "  /ys2 exch def\n");
-  fprintf(f, "  /xs2 exch def\n");
-  fprintf(f, "  /ys1 exch def\n");
-  fprintf(f, "  /xs1 exch def\n");
-  fprintf(f, "  /ddy xs2 xs1 sub abs 2 div dup 12 gt {pop 12} if def\n");
-  fprintf(f, "  xs1 4 add ys1 4 add moveto\n");
-  fprintf(f, "  xs1 2 mul xs2 add 3 div ys1 2 mul ys2 add 3 div ddy add\n");
-  fprintf(f, "  xs1 xs2 2 mul add 3 div ys1 ys2 2 mul add 3 div ddy add\n");
-  fprintf(f, "  xs2 4 sub ys2 4 add\n");
-  fprintf(f, "  curveto\n");
-  fprintf(f, "  xs1 xs2 2 mul add 3 div ys1 ys2 2 mul add 3 div ddy add 2 sub\n");
-  fprintf(f, "  xs1 2 mul xs2 add 3 div ys1 2 mul ys2 add 3 div ddy add 2 sub\n");
-  fprintf(f, "  xs1 4 add ys1 4 add\n");
-  fprintf(f, "  curveto fill\n");
-  fprintf(f, "} def\n");
-  fprintf(f,"\n");
-}
-
-static void section4(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 4 - Note Ornaments (Staccato, Roll, Trill etc.)\n");
-  fprintf(f,"\n");
-  fprintf(f,"/dt {  %% usage: dx dy dt  - dot shifted by dx,dy\n");
-  fprintf(f,"  y add exch x add exch 1.2 0 360 arc fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/grm {  %% usage:  y grm  - gracing mark\n");
-  fprintf(f,"  x exch moveto\n");
-  fprintf(f,"  -5.00 -1.00 rmoveto\n");
-  fprintf(f,"  5.00 8.50 5.50 -4.50 10.00 2.00 rcurveto\n");
-  fprintf(f,"  -5.00 -8.50 -5.50 4.50 -10.00 -2.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/stc {  %% usage:  y stc  - staccato mark\n");
-  fprintf(f,"  x exch 1.2 0 360 arc fill } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/cpu {  %% usage:  y cpu  - roll sign above head\n");
-  fprintf(f,"  x exch moveto\n");
-  fprintf(f,"  -5.85 0.00 rmoveto\n");
-  fprintf(f,"  0.45 7.29 11.25 7.29 11.70 0.00 rcurveto\n");
-  fprintf(f,"  -1.35 5.99 -10.35 5.99 -11.70 0.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/cpd {  %% usage:  y cpd  - roll sign below head\n");
-  fprintf(f,"  x exch moveto\n");
-  fprintf(f,"  -5.85 0.00 rmoveto\n");
-  fprintf(f,"  0.45 -7.29 11.25 -7.29 11.70 0.00 rcurveto\n");
-  fprintf(f,"  -1.35 -5.99 -10.35 -5.99 -11.70 0.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/sld {  %% usage:  y dx sld  - slide\n");
-  fprintf(f,"  x exch sub exch moveto\n");
-  fprintf(f,"  -7.20 -4.80 rmoveto\n");
-  fprintf(f,"  1.80 -0.70 4.50 0.20 7.20 4.80 rcurveto\n");
-  fprintf(f,"  -2.07 -5.00 -5.40 -6.80 -7.65 -6.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/emb {  %% usage:  y emb  - empahsis bar\n");
-  fprintf(f,"  gsave 1.2 setlinewidth 1 setlinecap x exch moveto \n");
-  fprintf(f," -2.5 0 rmoveto 5 0 rlineto stroke grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/trl {  %% usage:  y trl  - trill sign\n");
-  fprintf(f,"  gsave /Times-BoldItalic 14 selectfont\n");
-  fprintf(f,"  x 4 sub exch moveto (tr) show grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/hld {  %% usage:  y hld  - hold sign\n");
-  fprintf(f,"  x exch 2 copy 1.5 add 1.3 0 360 arc moveto\n");
-  fprintf(f,"  -7.50 0.00 rmoveto\n");
-  fprintf(f,"  0.00 11.50 15.00 11.50 15.00 0.00 rcurveto\n");
-  fprintf(f,"  -0.25 0.00 rlineto\n");
-  fprintf(f,"  -1.25 9.00 -13.25 9.00 -14.50 0.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/dnb {  %% usage:  y dnb  - down bow\n");
-  fprintf(f,"  x exch moveto\n");
-  fprintf(f,"  -3.20 0.00 rmoveto\n");
-  fprintf(f,"  0.00 7.20 rlineto\n");
-  fprintf(f,"  6.40 0.00 rlineto\n");
-  fprintf(f,"  0.00 -7.20 rlineto\n");
-  fprintf(f,"   currentpoint stroke moveto\n");
-  fprintf(f,"  -6.40 4.80 rmoveto\n");
-  fprintf(f,"  0.00 2.40 rlineto\n");
-  fprintf(f,"  6.40 0.00 rlineto\n");
-  fprintf(f,"  0.00 -2.40 rlineto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/upb {  %% usage:  y upb  - up bow\n");
-  fprintf(f,"  x exch moveto\n");
-  fprintf(f,"  -2.56 8.80 rmoveto\n");
-  fprintf(f,"  2.56 -8.80 rlineto\n");
-  fprintf(f,"  2.56 8.80 rlineto\n");
-  fprintf(f,"   stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section5(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 5 - helper lines\n");
-  fprintf(f,"\n");
-  fprintf(f,"/hl {  %% usage: y hl  - helper line at height y\n");
-  fprintf(f,"   gsave 1 setlinewidth x exch moveto \n");
-  fprintf(f,"   -5.5 0 rmoveto 11 0 rlineto stroke grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/hl1 {  %% usage: y hl1  - longer helper line\n");
-  fprintf(f,"   gsave 1 setlinewidth x exch moveto \n");
-  fprintf(f,"   -7 0 rmoveto 14 0 rlineto stroke grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section6(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 6 - Note tails \n");
-  fprintf(f,"\n");
-  fprintf(f,"/f1u {  %% usage:  len f1u  - single flag up\n");
-  fprintf(f,"  y add x 3.5 add exch moveto\n");
-  fprintf(f,"  0.00 0.00 rmoveto\n");
-  fprintf(f,"  1.00 -2.00 0.67 -1.67 2.67 -4.00 rcurveto\n");
-  fprintf(f,"  3.33 -2.67 3.33 -6.67 2.67 -9.33 rcurveto\n");
-  fprintf(f,"  -0.67 -2.67 -2.67 -4.00 -1.00 -1.00 rcurveto\n");
-  fprintf(f,"  1.67 4.33 -1.67 8.33 -4.33 9.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/f1d {  %% usage:  len f1d  - single flag down\n");
-  fprintf(f,"  neg y add x 3.5 sub exch moveto\n");
-  fprintf(f,"  0.00 0.00 rmoveto\n");
-  fprintf(f,"  1.20 2.00 0.80 1.67 3.20 4.00 rcurveto\n");
-  fprintf(f,"  4.00 2.67 4.00 6.67 3.20 9.33 rcurveto\n");
-  fprintf(f,"  -0.80 2.67 -3.20 4.00 -1.20 1.00 rcurveto\n");
-  fprintf(f,"  2.00 -4.33 -2.00 -8.33 -5.20 -9.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/f2u {  %% usage:  len f2u  - double flag up\n");
-  fprintf(f,"  y add x 3.5 add exch moveto\n");
-  fprintf(f,"  0.00 0.00 rmoveto\n");
-  fprintf(f,"  1.33 -3.33 6.00 -4.00 5.00 -12.00 rcurveto\n");
-  fprintf(f,"  0.00 6.00 -4.00 7.67 -5.00 7.67 rcurveto\n");
-  fprintf(f,"  1.33 -5.00 6.00 -5.00 5.00 -13.00 rcurveto\n");
-  fprintf(f,"  0.00 6.00 -4.00 7.67 -5.00 8.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/f2d {  %% usage:  len f2d  - double flag down\n");
-  fprintf(f,"  neg y add x 3.5 sub exch moveto\n");
-  fprintf(f,"  0.00 0.00 rmoveto\n");
-  fprintf(f,"  1.60 3.33 7.20 4.00 6.00 12.00 rcurveto\n");
-  fprintf(f,"  0.00 -6.00 -4.80 -7.67 -6.00 -7.67 rcurveto\n");
-  fprintf(f,"  1.60 5.00 7.20 5.00 6.00 13.00 rcurveto\n");
-  fprintf(f,"  0.00 -6.00 -4.80 -7.67 -6.00 -8.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/xfu {  %% usage:  len xfu  - extra flag up\n");
-  fprintf(f,"  y add x 3.5 add exch moveto\n");
-  fprintf(f,"  0.00 0.00 rmoveto\n");
-  fprintf(f,"  1.33 -5.00 6.00 -5.00 5.00 -13.00 rcurveto\n");
-  fprintf(f,"  0.00 6.00 -4.00 7.67 -5.00 8.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/xfd {  %% usage:  len xfd  - extra flag down\n");
-  fprintf(f,"  neg y add x 3.5 sub exch moveto\n");
-  fprintf(f,"  0.00 0.00 rmoveto\n");
-  fprintf(f,"  1.60 5.00 7.20 5.00 6.00 13.00 rcurveto\n");
-  fprintf(f,"  0.00 -6.00 -4.80 -7.67 -6.00 -8.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/f3d {dup f2d 9.5 sub xfd} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/f4d {dup dup f2d 9.5 sub xfd 14.7 sub xfd} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/f3u {dup f2u 9.5 sub xfu} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/f4u {dup dup f2u 9.5 sub xfu 14.7 sub xfu} bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section7(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 7 - Flats, Sharps and Naturals.\n");
-  fprintf(f,"\n");
-  fprintf(f,"/ft0 { %% usage:  x y ft0  - flat sign\n");
-  fprintf(f,"  moveto\n");
-  fprintf(f,"  -1.60 2.67 rmoveto\n");
-  fprintf(f,"  6.40 3.11 6.40 -3.56 0.00 -6.67 rcurveto\n");
-  fprintf(f,"  4.80 4.00 4.80 7.56 0.00 5.78 rcurveto\n");
-  fprintf(f,"  currentpoint fill moveto\n");
-  fprintf(f,"  0.00 7.11 rmoveto\n");
-  fprintf(f,"  0.00 -12.44 rlineto\n");
-  fprintf(f,"  stroke\n");
-  fprintf(f," } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/ft { %% usage: dx ft  - flat relative to head\n");
-  fprintf(f," neg x add y ft0 } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/ftx { %% usage:  x y ftx  - narrow flat sign\n");
-  fprintf(f,"  moveto\n");
-  fprintf(f,"  -1.42 2.67 rmoveto\n");
-  fprintf(f,"  5.69 3.11 5.69 -3.56 0.00 -6.67 rcurveto\n");
-  fprintf(f,"  4.27 4.00 4.27 7.56 0.00 5.78 rcurveto\n");
-  fprintf(f,"  currentpoint fill moveto\n");
-  fprintf(f,"  0.00 7.11 rmoveto\n");
-  fprintf(f,"  0.00 -12.44 rlineto\n");
-  fprintf(f,"  stroke\n");
-  fprintf(f," } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/dft0 { %% usage: x y dft0 ft  - double flat sign\n");
-  fprintf(f,"  2 copy exch 2.5 sub exch ftx exch 1.5 add exch ftx } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/dft { %% usage: dx dft  - double flat relative to head\n");
-  fprintf(f,"  neg x add y dft0 } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/sh0 {  %% usage:  x y sh0  - sharp sign\n");
-  fprintf(f,"  moveto\n");
-  fprintf(f,"  2.60 2.89 rmoveto\n");
-  fprintf(f,"  0.00 2.17 rlineto\n");
-  fprintf(f,"  -5.20 -1.44 rlineto\n");
-  fprintf(f,"  0.00 -2.17 rlineto\n");
-  fprintf(f,"  5.20 1.44 rlineto\n");
-  fprintf(f,"  0.00 -6.50 rmoveto\n");
-  fprintf(f,"  0.00 2.17 rlineto\n");
-  fprintf(f,"  -5.20 -1.44 rlineto\n");
-  fprintf(f,"  0.00 -2.17 rlineto\n");
-  fprintf(f,"  5.20 1.44 rlineto\n");
-  fprintf(f,"  currentpoint fill moveto\n");
-  fprintf(f,"  -1.30 -3.61 rmoveto\n");
-  fprintf(f,"  0.00 15.53 rlineto\n");
-  fprintf(f,"  currentpoint stroke moveto\n");
-  fprintf(f,"  -2.60 -16.61 rmoveto\n");
-  fprintf(f,"  0.00 15.53 rlineto\n");
-  fprintf(f,"  stroke\n");
-  fprintf(f," } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/sh { %% usage: dx sh  - sharp relative to head\n");
-  fprintf(f," neg x add y sh0 } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/nt0 {  %% usage:  x y nt0  - natural sign\n");
-  fprintf(f,"  moveto\n");
-  fprintf(f,"  -1.62 -4.33 rmoveto\n");
-  fprintf(f,"  3.25 0.72 rlineto\n");
-  fprintf(f,"  0.00 2.17 rlineto\n");
-  fprintf(f,"  -3.25 -0.72 rlineto\n");
-  fprintf(f,"  0.00 6.50 rlineto\n");
-  fprintf(f,"  0.00 -2.89 rmoveto\n");
-  fprintf(f,"  3.25 0.72 rlineto\n");
-  fprintf(f,"  0.00 2.17 rlineto\n");
-  fprintf(f,"  -3.25 -0.72 rlineto\n");
-  fprintf(f,"  0.00 -2.17 rlineto\n");
-  fprintf(f,"  currentpoint fill moveto\n");
-  fprintf(f,"  0.00 6.50 rmoveto\n");
-  fprintf(f,"  0.00 -11.92 rlineto\n");
-  fprintf(f,"  currentpoint stroke moveto\n");
-  fprintf(f,"  3.25 7.94 rmoveto\n");
-  fprintf(f,"  0.00 -11.92 rlineto\n");
-  fprintf(f,"  stroke\n");
-  fprintf(f," } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/nt { %% usage: dx nt  - natural relative to head\n");
-  fprintf(f," neg x add y nt0 } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/dsh0 {  %% usage:  x y dsh0  - double sharp \n");
-  fprintf(f,"  moveto\n");
-  fprintf(f,"  0.39 0.00 rmoveto\n");
-  fprintf(f,"  1.78 1.67 rlineto\n");
-  fprintf(f,"  1.17 0.00 rlineto\n");
-  fprintf(f,"  0.11 1.78 rlineto\n");
-  fprintf(f,"  -1.78 -0.11 rlineto\n");
-  fprintf(f,"  0.00 -1.17 rlineto\n");
-  fprintf(f,"  -1.67 -1.78 rlineto\n");
-  fprintf(f,"  -1.67 1.78 rlineto\n");
-  fprintf(f,"  0.00 1.17 rlineto\n");
-  fprintf(f,"  -1.78 0.11 rlineto\n");
-  fprintf(f,"  0.11 -1.78 rlineto\n");
-  fprintf(f,"  1.17 0.00 rlineto\n");
-  fprintf(f,"  1.78 -1.67 rlineto\n");
-  fprintf(f,"  -1.78 -1.67 rlineto\n");
-  fprintf(f,"  -1.17 0.00 rlineto\n");
-  fprintf(f,"  -0.11 -1.78 rlineto\n");
-  fprintf(f,"  1.78 0.11 rlineto\n");
-  fprintf(f,"  0.00 1.17 rlineto\n");
-  fprintf(f,"  1.67 1.78 rlineto\n");
-  fprintf(f,"  1.67 -1.78 rlineto\n");
-  fprintf(f,"  0.00 -1.17 rlineto\n");
-  fprintf(f,"  1.78 -0.11 rlineto\n");
-  fprintf(f,"  -0.11 1.78 rlineto\n");
-  fprintf(f,"  -1.17 0.00 rlineto\n");
-  fprintf(f,"  -1.78 1.67 rlineto\n");
-  fprintf(f,"  fill\n");
-  fprintf(f," } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/dsh { %% usage: dx dsh  - double sharp relative to head\n");
-  fprintf(f," neg x add y dsh0 } bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section8(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 8 - Guitar Chords\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gc { %% usage: x y (str) gc  -- draw guitar chord string\n");
-  fprintf(f,"  3 1 roll moveto show\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section9(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 9 - Rests\n");
-  fprintf(f,"\n");
-  fprintf(f,"/r4 {  %% usage:  x y r4  -  quarter rest\n");
-  fprintf(f,"   dup /y exch def exch dup /x exch def exch moveto\n");
-  fprintf(f,"  -0.52 8.87 rmoveto\n");
-  fprintf(f,"  8.35 -6.78 -2.61 -4.70 3.91 -11.48 rcurveto\n");
-  fprintf(f,"  -4.43 1.57 -6.00 -3.13 -2.87 -5.22 rcurveto\n");
-  fprintf(f,"  -5.22 2.09 -3.65 7.83 0.00 7.30 rcurveto\n");
-  fprintf(f,"  -5.22 4.17 3.13 3.13 -1.04 9.39 rcurveto\n");
-  fprintf(f,"  fill\n");
-  fprintf(f," } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/r8 {  %% usage:  x y r8  -  eighth rest\n");
-  fprintf(f,"   dup /y exch def exch dup /x exch def exch moveto\n");
-  fprintf(f,"  3.11 5.44 rmoveto\n");
-  fprintf(f,"  -1.17 -1.94 -1.94 -3.50 -3.69 -3.89 rcurveto\n");
-  fprintf(f,"  2.14 2.72 -2.92 3.89 -2.92 1.17 rcurveto\n");
-  fprintf(f,"  0.00 -1.17 1.17 -1.94 2.33 -1.94 rcurveto\n");
-  fprintf(f,"  2.72 0.00 3.11 1.94 3.89 3.50 rcurveto\n");
-  fprintf(f,"  -3.42 -12.06 rlineto\n");
-  fprintf(f,"  0.51 0.00 rlineto\n");
-  fprintf(f,"  3.50 13.22 rlineto\n");
-  fprintf(f,"  fill\n");
-  fprintf(f," } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/r16 {  %% usage:  x y r16  -  16th rest\n");
-  fprintf(f,"   dup /y exch def exch dup /x exch def exch moveto\n");
-  fprintf(f,"  3.11 5.44 rmoveto\n");
-  fprintf(f,"  -1.17 -1.94 -1.94 -3.50 -3.69 -3.89 rcurveto\n");
-  fprintf(f,"  2.14 2.72 -2.92 3.89 -2.92 1.17 rcurveto\n");
-  fprintf(f,"  0.00 -1.17 1.17 -1.94 2.33 -1.94 rcurveto\n");
-  fprintf(f,"  2.72 0.00 3.11 1.94 3.89 3.50 rcurveto\n");
-  fprintf(f,"  -1.24 -4.28 rlineto\n");
-  fprintf(f,"  -1.17 -1.94 -1.94 -3.50 -3.69 -3.89 rcurveto\n");
-  fprintf(f,"  2.14 2.72 -2.92 3.89 -2.92 1.17 rcurveto\n");
-  fprintf(f,"  0.00 -1.17 1.17 -1.94 2.33 -1.94 rcurveto\n");
-  fprintf(f,"  2.72 0.00 3.11 1.94 4.01 3.50 rcurveto\n");
-  fprintf(f,"  -1.91 -7.00 rlineto\n");
-  fprintf(f,"  0.51 0.00 rlineto\n");
-  fprintf(f,"  3.50 13.61 rlineto\n");
-  fprintf(f,"  fill\n");
-  fprintf(f," } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/r0 {  %% usage:  x y r0  -  breve rest\n");
-  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
-  fprintf(f,"  -3 0 rmoveto 0 6 rlineto 6 0 rlineto 0 -6 rlineto fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f, "\n");
-  fprintf(f,"/r1 {  %% usage:  x y r1  -  whole rest\n");
-  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
-  fprintf(f,"  -3 0 rmoveto 0 -3 rlineto 6 0 rlineto 0 3 rlineto fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/r2 {  %% usage:  x y r2  -  half rest\n");
-  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
-  fprintf(f,"  -3 0 rmoveto 0 3 rlineto 6 0 rlineto 0 -3 rlineto fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/r32 {\n");
-  fprintf(f,"  2 copy r16 5.5 add exch 1.6 add exch r8\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/r64 {\n");
-  fprintf(f,"  2 copy 5.5 add exch 1.6 add exch r16\n");
-  fprintf(f,"  5.5 sub exch 1.5 sub exch r16\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/mrest {  %%usage: nb_measures x y mrest\n");
-  fprintf(f,"  gsave 1 setlinewidth\n");
-  fprintf(f,"  2 copy -6 add moveto 0 12 rlineto stroke\n");
-  fprintf(f,"  2 copy exch 40 add exch -6 add moveto 0 12 rlineto stroke\n");
-  fprintf(f,"  2 copy moveto 5 setlinewidth 40 0 rlineto stroke\n");
-  fprintf(f,"  /Times-Bold 15 selectfont exch 20 add exch 16 add moveto cshow\n");
-  fprintf(f,"  grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section10(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 10 - Bar signs\n");
-  fprintf(f,"\n");
-  fprintf(f,"/bar {  %% usage: x bar  - single bar\n");
-  fprintf(f,"  0 moveto  0 24 rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/dbar {  %% usage: x dbar  - thin double bar\n");
-  fprintf(f,"   0 moveto 0 24 rlineto -3 -24 rmoveto\n");
-  fprintf(f,"   0 24 rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/fbar1 {  %% usage: x fbar1  - fat double bar at start\n");
-  fprintf(f,"  0 moveto  0 24 rlineto 3 0 rlineto 0 -24 rlineto \n");
-  fprintf(f,"  currentpoint fill moveto\n");
-  fprintf(f,"  3 0 rmoveto 0 24 rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/fbar2 {  %% usage: x fbar2  - fat double bar at end\n");
-  fprintf(f,"  0 moveto  0 24 rlineto -3 0 rlineto 0 -24 rlineto \n");
-  fprintf(f,"  currentpoint fill moveto\n");
-  fprintf(f,"  -3 0 rmoveto 0 24 rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/rdots {  %% usage: x rdots  - repeat dots \n");
-  fprintf(f,"  0 moveto 0 9 rmoveto currentpoint 2 copy 1.2 0 360 arc \n");
-  fprintf(f,"  moveto 0 6 rmoveto  currentpoint 1.2 0 360 arc fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/end1 {  %% usage: x1 x2 (str) end1  - mark first ending\n");
-  fprintf(f,"  3 1 roll 44 moveto 0 6 rlineto dup 50 lineto 0 -6 rlineto stroke\n");
-  fprintf(f,"  4 add 40 moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n");
-  fprintf(f,"  show grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/end2 {  %% usage: x1 x2 (str) end2  - mark second ending\n");
-  fprintf(f,"  3 1 roll 50 moveto dup 50 lineto 0 -6 rlineto stroke\n");
-  fprintf(f,"  4 add 40 moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n");
-  fprintf(f,"  show grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"\n %% following 2 routines added by J. Allwright\n");
-  fprintf(f,"/endy1 {  %% usage: y x1 x2 (str) endy1  - mark first ending\n");
-  fprintf(f,"  4 -1 roll /yval exch def\n");
-  fprintf(f,"  3 1 roll yval 4 add moveto 0 6 rlineto\n");
-  fprintf(f,"  dup yval 10 add lineto 0 -6 rlineto stroke\n");
-  fprintf(f,"  4 add yval moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n");
-  fprintf(f,"  show grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/endy2 {  %% usage: y x1 x2 (str) endy2  - mark second ending\n");
-  fprintf(f,"  4 -1 roll /yval exch def\n");
-  fprintf(f,"  3 1 roll yval 10 add moveto\n");
-  fprintf(f,"  dup yval 10 add lineto 0 -6 rlineto stroke\n");
-  fprintf(f,"  4 add yval moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n");
-  fprintf(f,"  show grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section11(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 11 - Grace Notes\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gn {  %% usage: x y gn  - grace note head only\n");
-  fprintf(f,"  moveto\n");
-  fprintf(f,"  -1.29 1.53 rmoveto\n");
-  fprintf(f,"  2.45 2.06 5.02 -1.00 2.58 -3.06 rcurveto\n");
-  fprintf(f,"  -2.45 -2.06 -5.02 1.00 -2.58 3.06 rcurveto\n");
-  fprintf(f,"  fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gn1 {  %% usage: x y l gnt  - grace note with tail\n");
-  fprintf(f,"  3 1 roll 2 copy moveto\n");
-  fprintf(f,"  -1.29 1.53 rmoveto\n");
-  fprintf(f,"  2.45 2.06 5.02 -1.00 2.58 -3.06 rcurveto\n");
-  fprintf(f,"  -2.45 -2.06 -5.02 1.00 -2.58 3.06 rcurveto\n");
-  fprintf(f,"  fill moveto 2.00 0 rmoveto 0 exch rlineto\n");
-  fprintf(f,"3 -4 4 -5 2 -8 rcurveto -5 2 rmoveto 7 4 rlineto   \n");
-  fprintf(f,"stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gnt {  %% usage: x y l gnt  - grace note\n");
-  fprintf(f,"  3 1 roll 2 copy moveto\n");
-  fprintf(f,"  -1.29 1.53 rmoveto\n");
-  fprintf(f,"  2.45 2.06 5.02 -1.00 2.58 -3.06 rcurveto\n");
-  fprintf(f,"  -2.45 -2.06 -5.02 1.00 -2.58 3.06 rcurveto\n");
-  fprintf(f,"  fill moveto 2.00 0 rmoveto 0 exch rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gbm2 {  %% usage: x1 y1 x2 y2 gbm2  - double note beam\n");
-  fprintf(f,"  gsave 1.4 setlinewidth\n");
-  fprintf(f,"  4 copy 0.5 sub moveto 0.5 sub lineto stroke\n");
-  fprintf(f,"  3.4 sub moveto 3.4 sub lineto stroke grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gbm3 {  %% usage: x1 y1 x2 y2 gbm3  - triple gnote beam\n");
-  fprintf(f,"  gsave 1.2 setlinewidth\n");
-  fprintf(f,"  4 copy 0.3 sub moveto 0.3 sub lineto stroke\n");
-  fprintf(f,"  4 copy 2.5 sub moveto 2.5 sub lineto stroke\n");
-  fprintf(f,"  4.7 sub moveto 4.7 sub lineto stroke grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/ghl {  %% usage: x y ghl  - grace note helper line\n");
-  fprintf(f,"   gsave 0.7 setlinewidth moveto \n");
-  fprintf(f,"   -3 0 rmoveto 6 0 rlineto stroke grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gsl {  %% usage: x1 y2 x2 y2 x3 y3 x0 y0 gsl\n");
-  fprintf(f,"  moveto curveto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gsh0 {  %% usage: x y gsh0\n");
-  fprintf(f,"gsave translate 0.7 0.7 scale 0 0 sh0 grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gft0 {  %% usage: x y gft0\n");
-  fprintf(f,"gsave translate 0.7 0.7 scale 0 0 ft0 grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gnt0 {  %% usage: x y gnt0\n");
-  fprintf(f,"gsave translate 0.7 0.7 scale 0 0 nt0 grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gdf0 {  %% usage: x y gdf0\n");
-  fprintf(f,"gsave translate 0.7 0.6 scale 0 0 dft0 grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/gds0 {  %% usage: x y gds0\n");
-  fprintf(f,"gsave translate 0.7 0.7 scale 0 0 dsh0 grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section12(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 12 - Time Signatures\n");
-  fprintf(f,"\n");
-  fprintf(f,"/csig {  %% usage:  x csig  - C timesig \n");
-  fprintf(f,"  0 moveto\n");
-  fprintf(f,"  1.00 17.25 rmoveto\n");
-  fprintf(f,"  1.00 0.00 2.75 -0.75 2.75 -3.00 rcurveto\n");
-  fprintf(f,"  0.00 1.50 -1.50 1.25 -1.50 0.00 rcurveto\n");
-  fprintf(f,"  0.00 -1.25 1.75 -1.25 1.75 0.25 rcurveto\n");
-  fprintf(f,"  0.00 2.50 -1.50 3.25 -3.00 3.25 rcurveto\n");
-  fprintf(f,"  -3.75 0.00 -6.25 -2.75 -6.25 -6.50 rcurveto\n");
-  fprintf(f,"  0.00 -3.00 3.75 -7.50 9.00 -2.50 rcurveto\n");
-  fprintf(f,"  -4.25 -3.00 -7.25 -0.75 -7.25 2.50 rcurveto\n");
-  fprintf(f,"  0.00 3.00 1.00 6.00 4.50 6.00 rcurveto\n");
-  fprintf(f,"   fill\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/ctsig {  %% usage:  x ctsig  - C| timesig \n");
-  fprintf(f,"  dup csig 4 moveto 0 16 rlineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/sep0 { %% usage: x1 x2 sep0  - hline separator \n");
-  fprintf(f,"   0 moveto 0 lineto stroke\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/tsig { %% usage: x (top) (bot) tsig -- draw time signature\n");
-  fprintf(f,"   3 -1 roll 0 moveto\n");
-  fprintf(f,"   gsave /Times-Bold 16 selectfont 1.2 1 scale\n");
-  fprintf(f,"   0 1.0 rmoveto currentpoint 3 -1 roll cshow\n");
-  fprintf(f,"   moveto 0 12 rmoveto cshow grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-}
-
-static void section13(f)
-FILE* f;
-{
-  fprintf(f,"%% Section 13 - Staff And Other things\n");
-  fprintf(f,"\n");
-  fprintf(f,"/staff {  %% usage: l staff  - draw staff\n");
-  fprintf(f,"  gsave 0.5 setlinewidth 0 0 moveto\n");
-  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
-  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
-  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
-  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
-  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
-  fprintf(f,"  pop stroke grestore\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f, "/segno { %% segno symbol usage: x y segno\n");
-  fprintf(f, "  gsave translate\n");
-  fprintf(f, "  5.82 0.84 moveto\n");
-  fprintf(f, "  4.62 1.15   5.04 3.20   4.6 3.64 curveto\n");
-  fprintf(f, "  4.17 4.08   3.19 2.75   3.9 1.51 curveto\n");
-  fprintf(f, "  4.62 0.27   7.45 0.0    8.03 1.82 curveto\n");
-  fprintf(f, "  8.61 3.64   5.06 7.81   3.38 9.67 curveto\n");
-  fprintf(f, "  1.69 11.53  1.59 14.46  2.79 14.16 curveto\n");
-  fprintf(f, "  3.99 13.85  3.55 11.80  4.00 11.36 curveto\n");
-  fprintf(f, "  4.44 10.92  5.33 12.25  4.66 13.49 curveto\n");
-  fprintf(f, "  3.99 14.73  1.15 15.0   0.57 13.18 curveto\n");
-  fprintf(f, "  0.0  11.36  3.50 7.19   5.21 5.32  curveto\n");
-  fprintf(f, "  6.92 3.46   7.01 0.53   5.82 0.84 curveto\n");
-  fprintf(f, "  closepath fill\n");
-  fprintf(f, "  -0.43 2.93 moveto\n");
-  fprintf(f, "  8.79 12.25 lineto 9.32 11.72 lineto -0.09 2.40 lineto\n");
-  fprintf(f, "  closepath fill\n");
-  fprintf(f, "  0.71 7.50 1.0 0 360 arc\n");
-  fprintf(f, "  closepath fill\n");
-  fprintf(f, "  7.85 7.50 1.0 0 360 arc\n");
-  fprintf(f, "  closepath fill\n");
-  fprintf(f, "  grestore\n");
-  fprintf(f, "} bind def\n");
-  fprintf(f, "\n");
-  fprintf(f, "/coda { %% coda : usage x y coda\n");
-  fprintf(f, "  gsave\n");
-  fprintf(f, "  translate\n");
-  fprintf(f, "  1.0 setlinewidth\n");
-  fprintf(f, "  0.0 7.5 moveto 15.0 7.5 lineto stroke\n");
-  fprintf(f, "  7.5 0.0 moveto 7.5 15.0 lineto stroke\n");
-  fprintf(f, "  7.5 7.5 5.0 0 360 arc stroke\n");
-  fprintf(f, "  grestore\n");
-  fprintf(f, "} bind def\n");
-  fprintf(f, "\n");
-  fprintf(f,"/WS {   %%usage:  w nspaces str WS\n");
-  fprintf(f,"   dup stringwidth pop 4 -1 roll\n");
-  fprintf(f,"   sub neg 3 -1 roll div 0 8#040 4 -1 roll\n");
-  fprintf(f,"   widthshow\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/W1 { show pop pop } bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/str 50 string def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/W0 {\n");
-  fprintf(f,"   dup stringwidth pop str cvs exch show (  ) show show pop pop\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/WC { counttomark 1 sub dup 0 eq { 0 }\n");
-  fprintf(f,"  {  ( ) stringwidth pop neg 0 3 -1 roll\n");
-  fprintf(f,"  {  dup 3 add index stringwidth pop ( ) stringwidth pop add\n");
-  fprintf(f,"  dup 3 index add 4 index lt 2 index 1 lt or\n");
-  fprintf(f,"  {3 -1 roll add exch 1 add} {pop exit} ifelse\n");
-  fprintf(f,"  } repeat } ifelse\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/P1 {\n");
-  fprintf(f,"  {  WC dup 0 le {exit} if\n");
-  fprintf(f,"      exch pop gsave { exch show ( ) show } repeat grestore LF\n");
-  fprintf(f,"   } loop pop pop pop pop\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"/P2 {\n");
-  fprintf(f,"   {  WC dup 0 le {exit} if\n");
-  fprintf(f,"      dup 1 sub dup 0 eq\n");
-  fprintf(f,"      { pop exch pop 0.0 }\n");
-  fprintf(f,"      { 3 2 roll 3 index exch sub exch div } ifelse\n");
-  fprintf(f,"      counttomark 3 sub 2 index eq { pop 0 } if exch gsave\n");
-  fprintf(f,"      {  3 2 roll show ( ) show dup 0 rmoveto } repeat\n");
-  fprintf(f,"      grestore LF pop\n");
-  fprintf(f,"   } loop pop pop pop pop\n");
-  fprintf(f,"} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"0 setlinecap 0 setlinejoin 0.8 setlinewidth\n");
-  fprintf(f,"\n");
-  fprintf(f,"/T {translate} bind def\n");
-  fprintf(f,"/M {moveto} bind def\n");
-  fprintf(f,"/L {lineto stroke} bind def\n");
-  fprintf(f,"\n");
-  fprintf(f,"%% End of abc2ps Postscript Library\n");
-  fprintf(f,"%%%%EndSetup\n");
-  fprintf(f,"\n");
-}
-
-void printlib(f, filename, boundingbox)
-FILE*f;
-char* filename;
-struct bbox* boundingbox;
-{
-  ps_header(f, filename, boundingbox);
-  section1(f);
-  section2(f);
-  section3(f);
-  section4(f);
-  section5(f);
-  section6(f);
-  section7(f);
-  section8(f);
-  section9(f);
-  section10(f);
-  section11(f);
-  section12(f);
-  section13(f);
-}
+
+/*
+ * This file is Copyright (C) 1999 Michael Methfessel
+ * with modifications by James Allwright
+ * e-mail: J.R.Allwright@westminster.ac.uk
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/* pslib.c */
+/* part of yaps - abc to PostScript converter */
+/* This file contains a single C routine which prints a library of */
+/* PostScript routines to a file */
+
+/*  Extra routines added :                                            */
+/*  /slurup, /slurdown  - simpler interface than original functions   */
+/*  /endy1, /endy2      - re-positionable versions of end1, end2      */
+/*  /setx, /sety        - set /x and /y with no other effects         */
+/*  /boxshow            - show text string in a box                   */
+/*  /segno              - draw segno symbol                           */
+/*  /coda               - draw coda symbol                            */
+/*  /setISOfont         - create ISO variant of font                  */
+/*  /BHD                - draw breve                                  */
+/*  /r0                 - breve rest                                  */
+/*  /mrest              - multiple bar rest (taken from abcm2ps)      */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/*  #define ANSILIBS is just used to access time functions for */
+/*  %%CreationDate . This can safely be removed if it causes   */
+/*  compilation problems */
+#if defined(ANSILIBS) || defined(__STDC__)
+#include <time.h>
+#endif
+#include "drawtune.h"
+
+/* output library of PostScript routines for drawing music symbols */
+
+static void ps_header(f, filename, boundingbox)
+/* create header section of PostScript file */
+FILE* f;
+char* filename;
+struct bbox* boundingbox;
+{
+
+  if (eps_out) {
+    fprintf(f,"%%!PS-Adobe-3.0 EPSF-3.0\n");
+  } else {
+    fprintf(f,"%%!PS-Adobe-3.0\n");
+  };
+  if (boundingbox != NULL) {
+    fprintf(f,"%%%%BoundingBox: %d %d %d %d\n", boundingbox->llx, 
+              boundingbox->lly, boundingbox->urx, boundingbox->ury);
+  };
+  fprintf(f,"%%%%Title: %s\n", filename);
+  fprintf(f,"%%%%Creator: yaps (abc to PostScript converter)\n");
+#ifdef ANSILIBS
+  {
+    char timebuff[40];
+    time_t now;
+
+    fputs("%%CreationDate: ", f);
+    now = time(NULL);
+    /* define ASCTIME if your system does not have strftime() */
+#ifdef ASCTIME
+    fprintf(f, asctime(localtime(&now)));
+#else
+    strftime(timebuff, (size_t)40, "%a %d %b %Y at %H:%M\n", localtime(&now));
+    fputs(timebuff, f);
+#endif
+  };
+#endif
+  fprintf(f,"%%%%LanguageLevel: 2\n");
+  fprintf(f,"%%%%EndComments\n");
+  fprintf(f,"\n");
+  fprintf(f,"%%\n");
+  fprintf(f,"%%  This is the abc2ps PostScript Music Library,\n");
+  fprintf(f,"%%  containing Postscript for generating musical symbols.\n");
+  fprintf(f,"%%  Original Copyright (c) 1999 Michael Methfessel.\n");
+  fprintf(f,"%%  This Library may be re-distributed under the\n");
+  fprintf(f,"%%  terms of the GNU General Public License.\n");
+  fprintf(f,"%%  This form of the library created by James\n");
+  fprintf(f,"%%  Allwright, July 1999.\n");
+  fprintf(f,"%%\n");
+  fprintf(f,"\n");
+  fprintf(f,"%%%%BeginSetup\n");
+  fprintf(f,"\n");
+}
+
+static void section1(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 1 - Fonts and String Manipulation\n");
+  fprintf(f,"\n");
+  fprintf(f,"/Times-Roman findfont\n");
+  fprintf(f,"dup length dict begin\n");
+  fprintf(f,"   {1 index /FID ne {def} {pop pop} ifelse} forall\n");
+  fprintf(f,"   /Encoding ISOLatin1Encoding def\n");
+  fprintf(f,"   currentdict\n");
+  fprintf(f,"end\n");
+  fprintf(f,"/Times-Roman-ISO exch definefont pop\n");
+  fprintf(f,"/F0 { /Times-Roman-ISO exch selectfont } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/Times-Italic findfont\n");
+  fprintf(f,"dup length dict begin\n");
+  fprintf(f,"   {1 index /FID ne {def} {pop pop} ifelse} forall\n");
+  fprintf(f,"   /Encoding ISOLatin1Encoding def\n");
+  fprintf(f,"   currentdict\n");
+  fprintf(f,"end\n");
+  fprintf(f,"/Times-Italic-ISO exch definefont pop\n");
+  fprintf(f,"/F1 { /Times-Italic-ISO exch selectfont } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/Times-Bold findfont\n");
+  fprintf(f,"dup length dict begin\n");
+  fprintf(f,"   {1 index /FID ne {def} {pop pop} ifelse} forall\n");
+  fprintf(f,"   /Encoding ISOLatin1Encoding def\n");
+  fprintf(f,"   currentdict\n");
+  fprintf(f,"end\n");
+  fprintf(f,"/Times-Bold-ISO exch definefont pop\n");
+  fprintf(f,"/F2 { /Times-Bold-ISO exch selectfont } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/Helvetica findfont\n");
+  fprintf(f,"dup length dict begin\n");
+  fprintf(f,"   {1 index /FID ne {def} {pop pop} ifelse} forall\n");
+  fprintf(f,"   /Encoding ISOLatin1Encoding def\n");
+  fprintf(f,"   currentdict\n");
+  fprintf(f,"end\n");
+  fprintf(f,"/Helvetica-ISO exch definefont pop\n");
+  fprintf(f,"/F3 { /Helvetica-ISO exch selectfont } bind def\n");
+  fprintf(f,"\n");
+
+  fprintf(f,"/setISOfont { %% usage /Name-ISO /Name setISOfont\n");
+  fprintf(f,"              %% define ISO encoding variant of font\n");
+  fprintf(f,"  findfont\n");
+  fprintf(f,"  dup length dict begin\n");
+  fprintf(f,"     {1 index /FID ne {def} {pop pop} ifelse} forall\n");
+  fprintf(f,"     /Encoding ISOLatin1Encoding def\n");
+  fprintf(f,"     currentdict\n");
+  fprintf(f,"  end\n");
+  fprintf(f,"  definefont pop\n");
+  fprintf(f,"} def\n");
+  fprintf(f,"\n");
+
+  fprintf(f,"/cshow { %% usage: string cshow  - center at current pt\n");
+  fprintf(f,"   dup stringwidth pop 2 div neg 0 rmoveto\n");
+  fprintf(f,"   currentpoint pop dup 0 lt {neg 0 rmoveto} {pop} ifelse\n");
+  fprintf(f,"   show\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/lshow { %% usage: string lshow - show left-aligned\n");
+  fprintf(f,"   dup stringwidth pop neg 0 rmoveto show\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f, "/boxshow {  %% usage: x y h string boxshow - text in a box\n");
+  fprintf(f, "  3 index 2 add 3 index 2 add moveto\n");
+  fprintf(f, "  dup show\n");
+  fprintf(f, "  3 index 3 index moveto\n");
+  fprintf(f, "  stringwidth pop 4 add exch dup 0 exch rlineto\n");
+  fprintf(f, "  exch 0 rlineto\n");
+  fprintf(f, "  neg 0 exch rlineto\n");
+  fprintf(f, "  closepath stroke\n");
+  fprintf(f, "} bind def\n");
+  fprintf(f, "\n");
+  fprintf(f,"/wd { moveto show } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/wln {\n");
+  fprintf(f,"dup 3 1 roll moveto gsave 0.6 setlinewidth lineto stroke grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/whf {moveto gsave 0.5 1.2 scale (-) show grestore} bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section2(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 2 - Clefs\n");
+  fprintf(f,"\n");
+  fprintf(f,"/tclef {  %% usage:  x tclef  - treble clef \n");
+  fprintf(f,"  0 moveto\n");
+  fprintf(f,"  -2.22 5.91 rmoveto\n");
+  fprintf(f,"  -0.74 -1.11 rlineto\n");
+  fprintf(f,"  -2.22 2.22 -0.74 8.12 3.69 8.12 rcurveto\n");
+  fprintf(f,"  2.22 0.74 7.02 -1.85 7.02 -6.65 rcurveto\n");
+  fprintf(f,"  0.00 -4.43 -4.06 -6.65 -7.75 -6.65 rcurveto\n");
+  fprintf(f,"  -4.43 0.00 -8.49 2.22 -8.49 8.49 rcurveto\n");
+  fprintf(f,"  0.00 2.58 0.37 5.54 5.91 9.97 rcurveto\n");
+  fprintf(f,"  6.28 4.43 6.28 7.02 6.28 8.86 rcurveto\n");
+  fprintf(f,"  0.00 1.85 -0.37 3.32 -1.11 3.32 rcurveto\n");
+  fprintf(f,"  -1.85 -1.48 -3.32 -5.17 -3.32 -7.38 rcurveto\n");
+  fprintf(f,"  0.00 -13.66 4.43 -16.25 4.80 -25.85 rcurveto\n");
+  fprintf(f,"  0.00 -3.69 -2.22 -5.54 -5.54 -5.54 rcurveto\n");
+  fprintf(f,"  -2.22 0.00 -4.06 1.85 -4.06 3.69 rcurveto\n");
+  fprintf(f,"  0.00 1.85 1.11 3.32 2.95 3.32 rcurveto\n");
+  fprintf(f,"  3.69 0.00 3.69 -5.91 0.37 -4.80 rcurveto\n");
+  fprintf(f,"  0.37 -2.22 5.54 -1.11 5.54 2.95 rcurveto\n");
+  fprintf(f,"  -0.74 12.18 -5.17 14.40 -5.17 28.06 rcurveto\n");
+  fprintf(f,"  0.00 4.06 1.11 7.38 4.43 8.86 rcurveto\n");
+  fprintf(f,"  2.22 -1.48 4.06 -4.06 3.69 -6.65 rcurveto\n");
+  fprintf(f,"  0.00 -4.06 -2.58 -7.02 -5.91 -10.34 rcurveto\n");
+  fprintf(f,"  -2.22 -2.58 -5.91 -4.43 -5.91 -9.60 rcurveto\n");
+  fprintf(f,"  0.00 -4.43 2.58 -6.65 5.54 -6.65 rcurveto\n");
+  fprintf(f,"  2.95 0.00 5.54 1.85 5.54 4.80 rcurveto\n");
+  fprintf(f,"  0.00 3.32 -2.95 4.43 -4.80 4.43 rcurveto\n");
+  fprintf(f,"  -2.58 0.00 -4.06 -1.85 -2.95 -3.69 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/stclef {\n");
+  fprintf(f,"  0.85 div gsave 0.85 0.85 scale tclef grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/bclef {  %% usage:  x bclef  - bass clef \n");
+  fprintf(f,"  0 moveto\n");
+  fprintf(f,"  -9.80 2.50 rmoveto\n");
+  fprintf(f,"  8.30 4.00 12.80 9.00 12.80 13.00 rcurveto\n");
+  fprintf(f,"  0.00 4.50 -2.00 7.50 -4.30 7.30 rcurveto\n");
+  fprintf(f,"  -1.00 0.20 -4.20 0.20 -5.70 -3.80 rcurveto\n");
+  fprintf(f,"  1.50 0.50 3.50 0.00 3.50 -1.50 rcurveto\n");
+  fprintf(f,"  0.00 -1.00 -0.50 -2.00 -2.00 -2.00 rcurveto\n");
+  fprintf(f,"  -1.00 0.00 -2.00 0.90 -2.00 2.50 rcurveto\n");
+  fprintf(f,"  0.00 2.50 2.10 5.50 6.00 5.50 rcurveto\n");
+  fprintf(f,"  4.00 0.00 7.50 -2.50 7.50 -7.50 rcurveto\n");
+  fprintf(f,"  0.00 -5.50 -6.50 -11.00 -15.50 -13.70 rcurveto\n");
+  fprintf(f,"  8.30 4.00 12.80 9.00 12.80 13.00 rcurveto\n");
+  fprintf(f,"  0.00 4.50 -2.00 7.50 -4.30 7.30 rcurveto\n");
+  fprintf(f,"  -1.00 0.20 -4.20 0.20 -5.70 -3.80 rcurveto\n");
+  fprintf(f,"  1.50 0.50 3.50 0.00 3.50 -1.50 rcurveto\n");
+  fprintf(f,"  0.00 -1.00 -0.50 -2.00 -2.00 -2.00 rcurveto\n");
+  fprintf(f,"  -1.00 0.00 -2.00 0.90 -2.00 2.50 rcurveto\n");
+  fprintf(f,"  0.00 2.50 2.10 5.50 6.00 5.50 rcurveto\n");
+  fprintf(f,"  4.00 0.00 7.50 -2.50 7.50 -7.50 rcurveto\n");
+  fprintf(f,"  0.00 -5.50 -6.50 -11.00 -15.50 -13.70 rcurveto\n");
+  fprintf(f,"  16.90 18.20 rmoveto\n");
+  fprintf(f,"  0.00 1.50 2.00 1.50 2.00 0.00 rcurveto\n");
+  fprintf(f,"  0.00 -1.50 -2.00 -1.50 -2.00 0.00 rcurveto\n");
+  fprintf(f,"  0.00 -5.50 rmoveto\n");
+  fprintf(f,"  0.00 1.50 2.00 1.50 2.00 0.00 rcurveto\n");
+  fprintf(f,"  0.00 -1.50 -2.00 -1.50 -2.00 0.00 rcurveto\n");
+  fprintf(f,"fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/sbclef {\n");
+  fprintf(f,"  0.85 div gsave 0.85 0.85 scale 0 4 translate bclef grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/cchalf {\n");
+  fprintf(f,"  0 moveto\n");
+  fprintf(f,"  0.00 12.00 rmoveto\n");
+  fprintf(f,"  1.20 2.75 rlineto\n");
+  fprintf(f,"  4.20 -0.50 6.00 2.25 6.00 5.00 rcurveto\n");
+  fprintf(f,"  0.00 2.00 -0.60 3.90 -3.30 4.00 rcurveto\n");
+  fprintf(f,"  -0.78 0.00 -2.70 0.00 -3.60 -2.00 rcurveto\n");
+  fprintf(f,"  0.90 0.25 2.10 0.00 2.10 -0.75 rcurveto\n");
+  fprintf(f,"  0.00 -0.50 -0.30 -1.00 -1.20 -1.00 rcurveto\n");
+  fprintf(f,"  -0.60 0.00 -1.20 0.45 -1.20 1.25 rcurveto\n");
+  fprintf(f,"  0.00 1.25 1.26 2.75 3.60 2.75 rcurveto\n");
+  fprintf(f,"  3.60 0.00 5.40 -1.25 5.40 -3.75 rcurveto\n");
+  fprintf(f,"  0.00 -3.25 -3.00 -6.00 -6.60 -5.75 rcurveto\n");
+  fprintf(f,"  -0.60 -2.50 rlineto\n");
+  fprintf(f,"fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/cclef {   %% usage: x cclef\n");
+  fprintf(f,"   dup dup dup\n");
+  fprintf(f,"   cchalf gsave 0 24 translate 1 -1 scale cchalf\n");
+  fprintf(f,"   6.5 sub 0 moveto 0 24 rlineto 3 0 rlineto 0 -24 rlineto fill\n");
+  fprintf(f,"   1.8 sub 0 moveto 0 24 rlineto 0.8 setlinewidth stroke grestore \n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/scclef { cclef } bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section3(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 3 - Note Heads, Stems and Beams\n");
+  fprintf(f,"\n");
+  fprintf(f,"/hd {  %% usage: x y hd  - full head\n");
+  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
+  fprintf(f,"  3.30 2.26 rmoveto\n");
+  fprintf(f,"  -2.26 3.30 -8.86 -1.22 -6.60 -4.52 rcurveto\n");
+  fprintf(f,"  2.26 -3.30 8.86 1.22 6.60 4.52 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/Hd {  %% usage: x y Hd  - open head for half\n");
+  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
+  fprintf(f,"  3.51 1.92 rmoveto\n");
+  fprintf(f,"  -2.04 3.73 -9.06 -0.10 -7.02 -3.83 rcurveto\n");
+  fprintf(f,"  2.04 -3.73 9.06 0.10 7.02 3.83 rcurveto\n");
+  fprintf(f,"  -0.44 -0.24 rmoveto\n");
+  fprintf(f,"  0.96 -1.76 -5.19 -5.11 -6.15 -3.35 rcurveto\n");
+  fprintf(f,"  -0.96 1.76 5.19 5.11 6.15 3.35 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/HD { %% usage: x y HD  - open head for whole\n");
+  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
+  fprintf(f,"  5.96 0.00 rmoveto\n");
+  fprintf(f,"  0.00 1.08 -2.71 3.52 -5.96 3.52 rcurveto\n");
+  fprintf(f,"  -3.25 0.00 -5.96 -2.44 -5.96 -3.52 rcurveto\n");
+  fprintf(f,"  0.00 -1.08 2.71 -3.52 5.96 -3.52 rcurveto\n");
+  fprintf(f,"  3.25 0.00 5.96 2.44 5.96 3.52 rcurveto\n");
+  fprintf(f,"  -8.13 1.62 rmoveto\n");
+  fprintf(f,"  1.62 2.17 5.96 -1.07 4.34 -3.24 rcurveto\n");
+  fprintf(f,"  -1.62 -2.17 -5.96 1.07 -4.34 3.24 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/BHD { %% usage x y BHD - breve\n");
+  fprintf(f,"  HD\n");
+  fprintf(f,"  x 6.0 sub y 3.5 sub moveto 0 7.0 rlineto stroke\n");
+  fprintf(f,"  x 8.0 sub y 3.5 sub moveto 0 7.0 rlineto stroke\n");
+  fprintf(f,"  x 6.0 add y 3.5 sub moveto 0 7.0 rlineto stroke\n");
+  fprintf(f,"  x 8.0 add y 3.5 sub moveto 0 7.0 rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/setx { %% usage: x setx - set x value\n");
+  fprintf(f,"  /x exch store\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/sety { %% usage: y sety - set y value\n");
+  fprintf(f,"  /y exch store\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/su {  %% usage: len su   - up stem\n");
+  fprintf(f,"  x y moveto 3.5 1.0 rmoveto 1.0 sub 0 exch rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/sd {  %% usage: len td   - down stem\n");
+  fprintf(f,"  x y moveto -3.5 -1.0 rmoveto neg 1.0 add 0 exch rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/bm {  %% usage: x1 y1 x2 y2 t bm  - beam, depth t\n");
+  fprintf(f,"  3 1 roll moveto dup 0 exch neg rlineto\n");
+  fprintf(f,"  dup 4 1 roll sub lineto 0 exch rlineto fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/bnum {  %% usage: x y (str) bnum  - number on beam\n");
+  fprintf(f,"  3 1 roll moveto gsave /Times-Italic 12 selectfont\n");
+  fprintf(f,"  cshow grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/hbr {  %% usage: x1 y1 x2 y2 hbr  - half bracket\n");
+  fprintf(f,"  moveto lineto 0 -3 rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/SL {  %% usage: pp2x pp1x p1 pp1 pp2 p2 p1 sl\n");
+  fprintf(f,"  moveto curveto rlineto curveto fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f, "\n");
+  fprintf(f, "%% New slurs with simple interface \n");
+  fprintf(f, "/slurdown { %% Slur - usage x1 y1 x2 y2 slurdown\n");
+  fprintf(f, "  /ys2 exch def\n");
+  fprintf(f, "  /xs2 exch def\n");
+  fprintf(f, "  /ys1 exch def\n");
+  fprintf(f, "  /xs1 exch def\n");
+  fprintf(f, "  /ddy xs2 xs1 sub abs 2 div dup 12 gt {pop 12} if def\n");
+  fprintf(f, "  xs1 4 add ys1 4 sub moveto\n");
+  fprintf(f, "  xs1 2 mul xs2 add 3 div ys1 2 mul ys2 add 3 div ddy sub\n");
+  fprintf(f, "  xs1 xs2 2 mul add 3 div ys1 ys2 2 mul add 3 div ddy sub\n");
+  fprintf(f, "  xs2 4 sub ys2 4 sub\n");
+  fprintf(f, "  curveto\n");
+  fprintf(f, "  xs1 xs2 2 mul add 3 div ys1 ys2 2 mul add 3 div ddy sub 2 sub\n");
+  fprintf(f, "  xs1 2 mul xs2 add 3 div ys1 2 mul ys2 add 3 div ddy sub 2 sub\n");
+  fprintf(f, "  xs1 4 add ys1 4 sub\n");
+  fprintf(f, "  curveto fill\n");
+  fprintf(f, "} def\n");
+  fprintf(f, "/slurup { %% Slur - usage x1 y1 x2 y2 slurup\n");
+  fprintf(f, "  /ys2 exch def\n");
+  fprintf(f, "  /xs2 exch def\n");
+  fprintf(f, "  /ys1 exch def\n");
+  fprintf(f, "  /xs1 exch def\n");
+  fprintf(f, "  /ddy xs2 xs1 sub abs 2 div dup 12 gt {pop 12} if def\n");
+  fprintf(f, "  xs1 4 add ys1 4 add moveto\n");
+  fprintf(f, "  xs1 2 mul xs2 add 3 div ys1 2 mul ys2 add 3 div ddy add\n");
+  fprintf(f, "  xs1 xs2 2 mul add 3 div ys1 ys2 2 mul add 3 div ddy add\n");
+  fprintf(f, "  xs2 4 sub ys2 4 add\n");
+  fprintf(f, "  curveto\n");
+  fprintf(f, "  xs1 xs2 2 mul add 3 div ys1 ys2 2 mul add 3 div ddy add 2 sub\n");
+  fprintf(f, "  xs1 2 mul xs2 add 3 div ys1 2 mul ys2 add 3 div ddy add 2 sub\n");
+  fprintf(f, "  xs1 4 add ys1 4 add\n");
+  fprintf(f, "  curveto fill\n");
+  fprintf(f, "} def\n");
+  fprintf(f,"\n");
+}
+
+static void section4(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 4 - Note Ornaments (Staccato, Roll, Trill etc.)\n");
+  fprintf(f,"\n");
+  fprintf(f,"/dt {  %% usage: dx dy dt  - dot shifted by dx,dy\n");
+  fprintf(f,"  y add exch x add exch 1.2 0 360 arc fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/grm {  %% usage:  y grm  - gracing mark\n");
+  fprintf(f,"  x exch moveto\n");
+  fprintf(f,"  -5.00 -1.00 rmoveto\n");
+  fprintf(f,"  5.00 8.50 5.50 -4.50 10.00 2.00 rcurveto\n");
+  fprintf(f,"  -5.00 -8.50 -5.50 4.50 -10.00 -2.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/stc {  %% usage:  y stc  - staccato mark\n");
+  fprintf(f,"  x exch 1.2 0 360 arc fill } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/cpu {  %% usage:  y cpu  - roll sign above head\n");
+  fprintf(f,"  x exch moveto\n");
+  fprintf(f,"  -5.85 0.00 rmoveto\n");
+  fprintf(f,"  0.45 7.29 11.25 7.29 11.70 0.00 rcurveto\n");
+  fprintf(f,"  -1.35 5.99 -10.35 5.99 -11.70 0.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/cpd {  %% usage:  y cpd  - roll sign below head\n");
+  fprintf(f,"  x exch moveto\n");
+  fprintf(f,"  -5.85 0.00 rmoveto\n");
+  fprintf(f,"  0.45 -7.29 11.25 -7.29 11.70 0.00 rcurveto\n");
+  fprintf(f,"  -1.35 -5.99 -10.35 -5.99 -11.70 0.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/sld {  %% usage:  y dx sld  - slide\n");
+  fprintf(f,"  x exch sub exch moveto\n");
+  fprintf(f,"  -7.20 -4.80 rmoveto\n");
+  fprintf(f,"  1.80 -0.70 4.50 0.20 7.20 4.80 rcurveto\n");
+  fprintf(f,"  -2.07 -5.00 -5.40 -6.80 -7.65 -6.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/emb {  %% usage:  y emb  - empahsis bar\n");
+  fprintf(f,"  gsave 1.2 setlinewidth 1 setlinecap x exch moveto \n");
+  fprintf(f," -2.5 0 rmoveto 5 0 rlineto stroke grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/trl {  %% usage:  y trl  - trill sign\n");
+  fprintf(f,"  gsave /Times-BoldItalic 14 selectfont\n");
+  fprintf(f,"  x 4 sub exch moveto (tr) show grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/hld {  %% usage:  y hld  - hold sign\n");
+  fprintf(f,"  x exch 2 copy 1.5 add 1.3 0 360 arc moveto\n");
+  fprintf(f,"  -7.50 0.00 rmoveto\n");
+  fprintf(f,"  0.00 11.50 15.00 11.50 15.00 0.00 rcurveto\n");
+  fprintf(f,"  -0.25 0.00 rlineto\n");
+  fprintf(f,"  -1.25 9.00 -13.25 9.00 -14.50 0.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/dnb {  %% usage:  y dnb  - down bow\n");
+  fprintf(f,"  x exch moveto\n");
+  fprintf(f,"  -3.20 0.00 rmoveto\n");
+  fprintf(f,"  0.00 7.20 rlineto\n");
+  fprintf(f,"  6.40 0.00 rlineto\n");
+  fprintf(f,"  0.00 -7.20 rlineto\n");
+  fprintf(f,"   currentpoint stroke moveto\n");
+  fprintf(f,"  -6.40 4.80 rmoveto\n");
+  fprintf(f,"  0.00 2.40 rlineto\n");
+  fprintf(f,"  6.40 0.00 rlineto\n");
+  fprintf(f,"  0.00 -2.40 rlineto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/upb {  %% usage:  y upb  - up bow\n");
+  fprintf(f,"  x exch moveto\n");
+  fprintf(f,"  -2.56 8.80 rmoveto\n");
+  fprintf(f,"  2.56 -8.80 rlineto\n");
+  fprintf(f,"  2.56 8.80 rlineto\n");
+  fprintf(f,"   stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section5(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 5 - helper lines\n");
+  fprintf(f,"\n");
+  fprintf(f,"/hl {  %% usage: y hl  - helper line at height y\n");
+  fprintf(f,"   gsave 1 setlinewidth x exch moveto \n");
+  fprintf(f,"   -5.5 0 rmoveto 11 0 rlineto stroke grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/hl1 {  %% usage: y hl1  - longer helper line\n");
+  fprintf(f,"   gsave 1 setlinewidth x exch moveto \n");
+  fprintf(f,"   -7 0 rmoveto 14 0 rlineto stroke grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section6(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 6 - Note tails \n");
+  fprintf(f,"\n");
+  fprintf(f,"/f1u {  %% usage:  len f1u  - single flag up\n");
+  fprintf(f,"  y add x 3.5 add exch moveto\n");
+  fprintf(f,"  0.00 0.00 rmoveto\n");
+  fprintf(f,"  1.00 -2.00 0.67 -1.67 2.67 -4.00 rcurveto\n");
+  fprintf(f,"  3.33 -2.67 3.33 -6.67 2.67 -9.33 rcurveto\n");
+  fprintf(f,"  -0.67 -2.67 -2.67 -4.00 -1.00 -1.00 rcurveto\n");
+  fprintf(f,"  1.67 4.33 -1.67 8.33 -4.33 9.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/f1d {  %% usage:  len f1d  - single flag down\n");
+  fprintf(f,"  neg y add x 3.5 sub exch moveto\n");
+  fprintf(f,"  0.00 0.00 rmoveto\n");
+  fprintf(f,"  1.20 2.00 0.80 1.67 3.20 4.00 rcurveto\n");
+  fprintf(f,"  4.00 2.67 4.00 6.67 3.20 9.33 rcurveto\n");
+  fprintf(f,"  -0.80 2.67 -3.20 4.00 -1.20 1.00 rcurveto\n");
+  fprintf(f,"  2.00 -4.33 -2.00 -8.33 -5.20 -9.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/f2u {  %% usage:  len f2u  - double flag up\n");
+  fprintf(f,"  y add x 3.5 add exch moveto\n");
+  fprintf(f,"  0.00 0.00 rmoveto\n");
+  fprintf(f,"  1.33 -3.33 6.00 -4.00 5.00 -12.00 rcurveto\n");
+  fprintf(f,"  0.00 6.00 -4.00 7.67 -5.00 7.67 rcurveto\n");
+  fprintf(f,"  1.33 -5.00 6.00 -5.00 5.00 -13.00 rcurveto\n");
+  fprintf(f,"  0.00 6.00 -4.00 7.67 -5.00 8.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/f2d {  %% usage:  len f2d  - double flag down\n");
+  fprintf(f,"  neg y add x 3.5 sub exch moveto\n");
+  fprintf(f,"  0.00 0.00 rmoveto\n");
+  fprintf(f,"  1.60 3.33 7.20 4.00 6.00 12.00 rcurveto\n");
+  fprintf(f,"  0.00 -6.00 -4.80 -7.67 -6.00 -7.67 rcurveto\n");
+  fprintf(f,"  1.60 5.00 7.20 5.00 6.00 13.00 rcurveto\n");
+  fprintf(f,"  0.00 -6.00 -4.80 -7.67 -6.00 -8.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/xfu {  %% usage:  len xfu  - extra flag up\n");
+  fprintf(f,"  y add x 3.5 add exch moveto\n");
+  fprintf(f,"  0.00 0.00 rmoveto\n");
+  fprintf(f,"  1.33 -5.00 6.00 -5.00 5.00 -13.00 rcurveto\n");
+  fprintf(f,"  0.00 6.00 -4.00 7.67 -5.00 8.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/xfd {  %% usage:  len xfd  - extra flag down\n");
+  fprintf(f,"  neg y add x 3.5 sub exch moveto\n");
+  fprintf(f,"  0.00 0.00 rmoveto\n");
+  fprintf(f,"  1.60 5.00 7.20 5.00 6.00 13.00 rcurveto\n");
+  fprintf(f,"  0.00 -6.00 -4.80 -7.67 -6.00 -8.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/f3d {dup f2d 9.5 sub xfd} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/f4d {dup dup f2d 9.5 sub xfd 14.7 sub xfd} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/f3u {dup f2u 9.5 sub xfu} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/f4u {dup dup f2u 9.5 sub xfu 14.7 sub xfu} bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section7(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 7 - Flats, Sharps and Naturals.\n");
+  fprintf(f,"\n");
+  fprintf(f,"/ft0 { %% usage:  x y ft0  - flat sign\n");
+  fprintf(f,"  moveto\n");
+  fprintf(f,"  -1.60 2.67 rmoveto\n");
+  fprintf(f,"  6.40 3.11 6.40 -3.56 0.00 -6.67 rcurveto\n");
+  fprintf(f,"  4.80 4.00 4.80 7.56 0.00 5.78 rcurveto\n");
+  fprintf(f,"  currentpoint fill moveto\n");
+  fprintf(f,"  0.00 7.11 rmoveto\n");
+  fprintf(f,"  0.00 -12.44 rlineto\n");
+  fprintf(f,"  stroke\n");
+  fprintf(f," } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/ft { %% usage: dx ft  - flat relative to head\n");
+  fprintf(f," neg x add y ft0 } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/ftx { %% usage:  x y ftx  - narrow flat sign\n");
+  fprintf(f,"  moveto\n");
+  fprintf(f,"  -1.42 2.67 rmoveto\n");
+  fprintf(f,"  5.69 3.11 5.69 -3.56 0.00 -6.67 rcurveto\n");
+  fprintf(f,"  4.27 4.00 4.27 7.56 0.00 5.78 rcurveto\n");
+  fprintf(f,"  currentpoint fill moveto\n");
+  fprintf(f,"  0.00 7.11 rmoveto\n");
+  fprintf(f,"  0.00 -12.44 rlineto\n");
+  fprintf(f,"  stroke\n");
+  fprintf(f," } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/dft0 { %% usage: x y dft0 ft  - double flat sign\n");
+  fprintf(f,"  2 copy exch 2.5 sub exch ftx exch 1.5 add exch ftx } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/dft { %% usage: dx dft  - double flat relative to head\n");
+  fprintf(f,"  neg x add y dft0 } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/sh0 {  %% usage:  x y sh0  - sharp sign\n");
+  fprintf(f,"  moveto\n");
+  fprintf(f,"  2.60 2.89 rmoveto\n");
+  fprintf(f,"  0.00 2.17 rlineto\n");
+  fprintf(f,"  -5.20 -1.44 rlineto\n");
+  fprintf(f,"  0.00 -2.17 rlineto\n");
+  fprintf(f,"  5.20 1.44 rlineto\n");
+  fprintf(f,"  0.00 -6.50 rmoveto\n");
+  fprintf(f,"  0.00 2.17 rlineto\n");
+  fprintf(f,"  -5.20 -1.44 rlineto\n");
+  fprintf(f,"  0.00 -2.17 rlineto\n");
+  fprintf(f,"  5.20 1.44 rlineto\n");
+  fprintf(f,"  currentpoint fill moveto\n");
+  fprintf(f,"  -1.30 -3.61 rmoveto\n");
+  fprintf(f,"  0.00 15.53 rlineto\n");
+  fprintf(f,"  currentpoint stroke moveto\n");
+  fprintf(f,"  -2.60 -16.61 rmoveto\n");
+  fprintf(f,"  0.00 15.53 rlineto\n");
+  fprintf(f,"  stroke\n");
+  fprintf(f," } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/sh { %% usage: dx sh  - sharp relative to head\n");
+  fprintf(f," neg x add y sh0 } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/nt0 {  %% usage:  x y nt0  - natural sign\n");
+  fprintf(f,"  moveto\n");
+  fprintf(f,"  -1.62 -4.33 rmoveto\n");
+  fprintf(f,"  3.25 0.72 rlineto\n");
+  fprintf(f,"  0.00 2.17 rlineto\n");
+  fprintf(f,"  -3.25 -0.72 rlineto\n");
+  fprintf(f,"  0.00 6.50 rlineto\n");
+  fprintf(f,"  0.00 -2.89 rmoveto\n");
+  fprintf(f,"  3.25 0.72 rlineto\n");
+  fprintf(f,"  0.00 2.17 rlineto\n");
+  fprintf(f,"  -3.25 -0.72 rlineto\n");
+  fprintf(f,"  0.00 -2.17 rlineto\n");
+  fprintf(f,"  currentpoint fill moveto\n");
+  fprintf(f,"  0.00 6.50 rmoveto\n");
+  fprintf(f,"  0.00 -11.92 rlineto\n");
+  fprintf(f,"  currentpoint stroke moveto\n");
+  fprintf(f,"  3.25 7.94 rmoveto\n");
+  fprintf(f,"  0.00 -11.92 rlineto\n");
+  fprintf(f,"  stroke\n");
+  fprintf(f," } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/nt { %% usage: dx nt  - natural relative to head\n");
+  fprintf(f," neg x add y nt0 } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/dsh0 {  %% usage:  x y dsh0  - double sharp \n");
+  fprintf(f,"  moveto\n");
+  fprintf(f,"  0.39 0.00 rmoveto\n");
+  fprintf(f,"  1.78 1.67 rlineto\n");
+  fprintf(f,"  1.17 0.00 rlineto\n");
+  fprintf(f,"  0.11 1.78 rlineto\n");
+  fprintf(f,"  -1.78 -0.11 rlineto\n");
+  fprintf(f,"  0.00 -1.17 rlineto\n");
+  fprintf(f,"  -1.67 -1.78 rlineto\n");
+  fprintf(f,"  -1.67 1.78 rlineto\n");
+  fprintf(f,"  0.00 1.17 rlineto\n");
+  fprintf(f,"  -1.78 0.11 rlineto\n");
+  fprintf(f,"  0.11 -1.78 rlineto\n");
+  fprintf(f,"  1.17 0.00 rlineto\n");
+  fprintf(f,"  1.78 -1.67 rlineto\n");
+  fprintf(f,"  -1.78 -1.67 rlineto\n");
+  fprintf(f,"  -1.17 0.00 rlineto\n");
+  fprintf(f,"  -0.11 -1.78 rlineto\n");
+  fprintf(f,"  1.78 0.11 rlineto\n");
+  fprintf(f,"  0.00 1.17 rlineto\n");
+  fprintf(f,"  1.67 1.78 rlineto\n");
+  fprintf(f,"  1.67 -1.78 rlineto\n");
+  fprintf(f,"  0.00 -1.17 rlineto\n");
+  fprintf(f,"  1.78 -0.11 rlineto\n");
+  fprintf(f,"  -0.11 1.78 rlineto\n");
+  fprintf(f,"  -1.17 0.00 rlineto\n");
+  fprintf(f,"  -1.78 1.67 rlineto\n");
+  fprintf(f,"  fill\n");
+  fprintf(f," } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/dsh { %% usage: dx dsh  - double sharp relative to head\n");
+  fprintf(f," neg x add y dsh0 } bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section8(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 8 - Guitar Chords\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gc { %% usage: x y (str) gc  -- draw guitar chord string\n");
+  fprintf(f,"  3 1 roll moveto show\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section9(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 9 - Rests\n");
+  fprintf(f,"\n");
+  fprintf(f,"/r4 {  %% usage:  x y r4  -  quarter rest\n");
+  fprintf(f,"   dup /y exch def exch dup /x exch def exch moveto\n");
+  fprintf(f,"  -0.52 8.87 rmoveto\n");
+  fprintf(f,"  8.35 -6.78 -2.61 -4.70 3.91 -11.48 rcurveto\n");
+  fprintf(f,"  -4.43 1.57 -6.00 -3.13 -2.87 -5.22 rcurveto\n");
+  fprintf(f,"  -5.22 2.09 -3.65 7.83 0.00 7.30 rcurveto\n");
+  fprintf(f,"  -5.22 4.17 3.13 3.13 -1.04 9.39 rcurveto\n");
+  fprintf(f,"  fill\n");
+  fprintf(f," } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/r8 {  %% usage:  x y r8  -  eighth rest\n");
+  fprintf(f,"   dup /y exch def exch dup /x exch def exch moveto\n");
+  fprintf(f,"  3.11 5.44 rmoveto\n");
+  fprintf(f,"  -1.17 -1.94 -1.94 -3.50 -3.69 -3.89 rcurveto\n");
+  fprintf(f,"  2.14 2.72 -2.92 3.89 -2.92 1.17 rcurveto\n");
+  fprintf(f,"  0.00 -1.17 1.17 -1.94 2.33 -1.94 rcurveto\n");
+  fprintf(f,"  2.72 0.00 3.11 1.94 3.89 3.50 rcurveto\n");
+  fprintf(f,"  -3.42 -12.06 rlineto\n");
+  fprintf(f,"  0.51 0.00 rlineto\n");
+  fprintf(f,"  3.50 13.22 rlineto\n");
+  fprintf(f,"  fill\n");
+  fprintf(f," } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/r16 {  %% usage:  x y r16  -  16th rest\n");
+  fprintf(f,"   dup /y exch def exch dup /x exch def exch moveto\n");
+  fprintf(f,"  3.11 5.44 rmoveto\n");
+  fprintf(f,"  -1.17 -1.94 -1.94 -3.50 -3.69 -3.89 rcurveto\n");
+  fprintf(f,"  2.14 2.72 -2.92 3.89 -2.92 1.17 rcurveto\n");
+  fprintf(f,"  0.00 -1.17 1.17 -1.94 2.33 -1.94 rcurveto\n");
+  fprintf(f,"  2.72 0.00 3.11 1.94 3.89 3.50 rcurveto\n");
+  fprintf(f,"  -1.24 -4.28 rlineto\n");
+  fprintf(f,"  -1.17 -1.94 -1.94 -3.50 -3.69 -3.89 rcurveto\n");
+  fprintf(f,"  2.14 2.72 -2.92 3.89 -2.92 1.17 rcurveto\n");
+  fprintf(f,"  0.00 -1.17 1.17 -1.94 2.33 -1.94 rcurveto\n");
+  fprintf(f,"  2.72 0.00 3.11 1.94 4.01 3.50 rcurveto\n");
+  fprintf(f,"  -1.91 -7.00 rlineto\n");
+  fprintf(f,"  0.51 0.00 rlineto\n");
+  fprintf(f,"  3.50 13.61 rlineto\n");
+  fprintf(f,"  fill\n");
+  fprintf(f," } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/r0 {  %% usage:  x y r0  -  breve rest\n");
+  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
+  fprintf(f,"  -3 0 rmoveto 0 6 rlineto 6 0 rlineto 0 -6 rlineto fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f, "\n");
+  fprintf(f,"/r1 {  %% usage:  x y r1  -  whole rest\n");
+  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
+  fprintf(f,"  -3 0 rmoveto 0 -3 rlineto 6 0 rlineto 0 3 rlineto fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/r2 {  %% usage:  x y r2  -  half rest\n");
+  fprintf(f,"  dup /y exch def exch dup /x exch def exch moveto\n");
+  fprintf(f,"  -3 0 rmoveto 0 3 rlineto 6 0 rlineto 0 -3 rlineto fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/r32 {\n");
+  fprintf(f,"  2 copy r16 5.5 add exch 1.6 add exch r8\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/r64 {\n");
+  fprintf(f,"  2 copy 5.5 add exch 1.6 add exch r16\n");
+  fprintf(f,"  5.5 sub exch 1.5 sub exch r16\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/mrest {  %%usage: nb_measures x y mrest\n");
+  fprintf(f,"  gsave 1 setlinewidth\n");
+  fprintf(f,"  2 copy -6 add moveto 0 12 rlineto stroke\n");
+  fprintf(f,"  2 copy exch 40 add exch -6 add moveto 0 12 rlineto stroke\n");
+  fprintf(f,"  2 copy moveto 5 setlinewidth 40 0 rlineto stroke\n");
+  fprintf(f,"  /Times-Bold 15 selectfont exch 20 add exch 16 add moveto cshow\n");
+  fprintf(f,"  grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section10(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 10 - Bar signs\n");
+  fprintf(f,"\n");
+  fprintf(f,"/bar {  %% usage: x bar  - single bar\n");
+  fprintf(f,"  0 moveto  0 24 rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/dbar {  %% usage: x dbar  - thin double bar\n");
+  fprintf(f,"   0 moveto 0 24 rlineto -3 -24 rmoveto\n");
+  fprintf(f,"   0 24 rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/fbar1 {  %% usage: x fbar1  - fat double bar at start\n");
+  fprintf(f,"  0 moveto  0 24 rlineto 3 0 rlineto 0 -24 rlineto \n");
+  fprintf(f,"  currentpoint fill moveto\n");
+  fprintf(f,"  3 0 rmoveto 0 24 rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/fbar2 {  %% usage: x fbar2  - fat double bar at end\n");
+  fprintf(f,"  0 moveto  0 24 rlineto -3 0 rlineto 0 -24 rlineto \n");
+  fprintf(f,"  currentpoint fill moveto\n");
+  fprintf(f,"  -3 0 rmoveto 0 24 rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/rdots {  %% usage: x rdots  - repeat dots \n");
+  fprintf(f,"  0 moveto 0 9 rmoveto currentpoint 2 copy 1.2 0 360 arc \n");
+  fprintf(f,"  moveto 0 6 rmoveto  currentpoint 1.2 0 360 arc fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/end1 {  %% usage: x1 x2 (str) end1  - mark first ending\n");
+  fprintf(f,"  3 1 roll 44 moveto 0 6 rlineto dup 50 lineto 0 -6 rlineto stroke\n");
+  fprintf(f,"  4 add 40 moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n");
+  fprintf(f,"  show grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/end2 {  %% usage: x1 x2 (str) end2  - mark second ending\n");
+  fprintf(f,"  3 1 roll 50 moveto dup 50 lineto 0 -6 rlineto stroke\n");
+  fprintf(f,"  4 add 40 moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n");
+  fprintf(f,"  show grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"\n %% following 2 routines added by J. Allwright\n");
+  fprintf(f,"/endy1 {  %% usage: y x1 x2 (str) endy1  - mark first ending\n");
+  fprintf(f,"  4 -1 roll /yval exch def\n");
+  fprintf(f,"  3 1 roll yval 4 add moveto 0 6 rlineto\n");
+  fprintf(f,"  dup yval 10 add lineto 0 -6 rlineto stroke\n");
+  fprintf(f,"  4 add yval moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n");
+  fprintf(f,"  show grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/endy2 {  %% usage: y x1 x2 (str) endy2  - mark second ending\n");
+  fprintf(f,"  4 -1 roll /yval exch def\n");
+  fprintf(f,"  3 1 roll yval 10 add moveto\n");
+  fprintf(f,"  dup yval 10 add lineto 0 -6 rlineto stroke\n");
+  fprintf(f,"  4 add yval moveto gsave /Times-Roman 13 selectfont 1.2 0.95 scale\n");
+  fprintf(f,"  show grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section11(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 11 - Grace Notes\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gn {  %% usage: x y gn  - grace note head only\n");
+  fprintf(f,"  moveto\n");
+  fprintf(f,"  -1.29 1.53 rmoveto\n");
+  fprintf(f,"  2.45 2.06 5.02 -1.00 2.58 -3.06 rcurveto\n");
+  fprintf(f,"  -2.45 -2.06 -5.02 1.00 -2.58 3.06 rcurveto\n");
+  fprintf(f,"  fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gn1 {  %% usage: x y l gnt  - grace note with tail\n");
+  fprintf(f,"  3 1 roll 2 copy moveto\n");
+  fprintf(f,"  -1.29 1.53 rmoveto\n");
+  fprintf(f,"  2.45 2.06 5.02 -1.00 2.58 -3.06 rcurveto\n");
+  fprintf(f,"  -2.45 -2.06 -5.02 1.00 -2.58 3.06 rcurveto\n");
+  fprintf(f,"  fill moveto 2.00 0 rmoveto 0 exch rlineto\n");
+  fprintf(f,"3 -4 4 -5 2 -8 rcurveto -5 2 rmoveto 7 4 rlineto   \n");
+  fprintf(f,"stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gnt {  %% usage: x y l gnt  - grace note\n");
+  fprintf(f,"  3 1 roll 2 copy moveto\n");
+  fprintf(f,"  -1.29 1.53 rmoveto\n");
+  fprintf(f,"  2.45 2.06 5.02 -1.00 2.58 -3.06 rcurveto\n");
+  fprintf(f,"  -2.45 -2.06 -5.02 1.00 -2.58 3.06 rcurveto\n");
+  fprintf(f,"  fill moveto 2.00 0 rmoveto 0 exch rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gbm2 {  %% usage: x1 y1 x2 y2 gbm2  - double note beam\n");
+  fprintf(f,"  gsave 1.4 setlinewidth\n");
+  fprintf(f,"  4 copy 0.5 sub moveto 0.5 sub lineto stroke\n");
+  fprintf(f,"  3.4 sub moveto 3.4 sub lineto stroke grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gbm3 {  %% usage: x1 y1 x2 y2 gbm3  - triple gnote beam\n");
+  fprintf(f,"  gsave 1.2 setlinewidth\n");
+  fprintf(f,"  4 copy 0.3 sub moveto 0.3 sub lineto stroke\n");
+  fprintf(f,"  4 copy 2.5 sub moveto 2.5 sub lineto stroke\n");
+  fprintf(f,"  4.7 sub moveto 4.7 sub lineto stroke grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/ghl {  %% usage: x y ghl  - grace note helper line\n");
+  fprintf(f,"   gsave 0.7 setlinewidth moveto \n");
+  fprintf(f,"   -3 0 rmoveto 6 0 rlineto stroke grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gsl {  %% usage: x1 y2 x2 y2 x3 y3 x0 y0 gsl\n");
+  fprintf(f,"  moveto curveto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gsh0 {  %% usage: x y gsh0\n");
+  fprintf(f,"gsave translate 0.7 0.7 scale 0 0 sh0 grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gft0 {  %% usage: x y gft0\n");
+  fprintf(f,"gsave translate 0.7 0.7 scale 0 0 ft0 grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gnt0 {  %% usage: x y gnt0\n");
+  fprintf(f,"gsave translate 0.7 0.7 scale 0 0 nt0 grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gdf0 {  %% usage: x y gdf0\n");
+  fprintf(f,"gsave translate 0.7 0.6 scale 0 0 dft0 grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/gds0 {  %% usage: x y gds0\n");
+  fprintf(f,"gsave translate 0.7 0.7 scale 0 0 dsh0 grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section12(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 12 - Time Signatures\n");
+  fprintf(f,"\n");
+  fprintf(f,"/csig {  %% usage:  x csig  - C timesig \n");
+  fprintf(f,"  0 moveto\n");
+  fprintf(f,"  1.00 17.25 rmoveto\n");
+  fprintf(f,"  1.00 0.00 2.75 -0.75 2.75 -3.00 rcurveto\n");
+  fprintf(f,"  0.00 1.50 -1.50 1.25 -1.50 0.00 rcurveto\n");
+  fprintf(f,"  0.00 -1.25 1.75 -1.25 1.75 0.25 rcurveto\n");
+  fprintf(f,"  0.00 2.50 -1.50 3.25 -3.00 3.25 rcurveto\n");
+  fprintf(f,"  -3.75 0.00 -6.25 -2.75 -6.25 -6.50 rcurveto\n");
+  fprintf(f,"  0.00 -3.00 3.75 -7.50 9.00 -2.50 rcurveto\n");
+  fprintf(f,"  -4.25 -3.00 -7.25 -0.75 -7.25 2.50 rcurveto\n");
+  fprintf(f,"  0.00 3.00 1.00 6.00 4.50 6.00 rcurveto\n");
+  fprintf(f,"   fill\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/ctsig {  %% usage:  x ctsig  - C| timesig \n");
+  fprintf(f,"  dup csig 4 moveto 0 16 rlineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/sep0 { %% usage: x1 x2 sep0  - hline separator \n");
+  fprintf(f,"   0 moveto 0 lineto stroke\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/tsig { %% usage: x (top) (bot) tsig -- draw time signature\n");
+  fprintf(f,"   3 -1 roll 0 moveto\n");
+  fprintf(f,"   gsave /Times-Bold 16 selectfont 1.2 1 scale\n");
+  fprintf(f,"   0 1.0 rmoveto currentpoint 3 -1 roll cshow\n");
+  fprintf(f,"   moveto 0 12 rmoveto cshow grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+}
+
+static void section13(f)
+FILE* f;
+{
+  fprintf(f,"%% Section 13 - Staff And Other things\n");
+  fprintf(f,"\n");
+  fprintf(f,"/staff {  %% usage: l staff  - draw staff\n");
+  fprintf(f,"  gsave 0.5 setlinewidth 0 0 moveto\n");
+  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
+  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
+  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
+  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
+  fprintf(f,"  dup 0 rlineto dup neg 6 rmoveto\n");
+  fprintf(f,"  pop stroke grestore\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f, "/segno { %% segno symbol usage: x y segno\n");
+  fprintf(f, "  gsave translate\n");
+  fprintf(f, "  5.82 0.84 moveto\n");
+  fprintf(f, "  4.62 1.15   5.04 3.20   4.6 3.64 curveto\n");
+  fprintf(f, "  4.17 4.08   3.19 2.75   3.9 1.51 curveto\n");
+  fprintf(f, "  4.62 0.27   7.45 0.0    8.03 1.82 curveto\n");
+  fprintf(f, "  8.61 3.64   5.06 7.81   3.38 9.67 curveto\n");
+  fprintf(f, "  1.69 11.53  1.59 14.46  2.79 14.16 curveto\n");
+  fprintf(f, "  3.99 13.85  3.55 11.80  4.00 11.36 curveto\n");
+  fprintf(f, "  4.44 10.92  5.33 12.25  4.66 13.49 curveto\n");
+  fprintf(f, "  3.99 14.73  1.15 15.0   0.57 13.18 curveto\n");
+  fprintf(f, "  0.0  11.36  3.50 7.19   5.21 5.32  curveto\n");
+  fprintf(f, "  6.92 3.46   7.01 0.53   5.82 0.84 curveto\n");
+  fprintf(f, "  closepath fill\n");
+  fprintf(f, "  -0.43 2.93 moveto\n");
+  fprintf(f, "  8.79 12.25 lineto 9.32 11.72 lineto -0.09 2.40 lineto\n");
+  fprintf(f, "  closepath fill\n");
+  fprintf(f, "  0.71 7.50 1.0 0 360 arc\n");
+  fprintf(f, "  closepath fill\n");
+  fprintf(f, "  7.85 7.50 1.0 0 360 arc\n");
+  fprintf(f, "  closepath fill\n");
+  fprintf(f, "  grestore\n");
+  fprintf(f, "} bind def\n");
+  fprintf(f, "\n");
+  fprintf(f, "/coda { %% coda : usage x y coda\n");
+  fprintf(f, "  gsave\n");
+  fprintf(f, "  translate\n");
+  fprintf(f, "  1.0 setlinewidth\n");
+  fprintf(f, "  0.0 7.5 moveto 15.0 7.5 lineto stroke\n");
+  fprintf(f, "  7.5 0.0 moveto 7.5 15.0 lineto stroke\n");
+  fprintf(f, "  7.5 7.5 5.0 0 360 arc stroke\n");
+  fprintf(f, "  grestore\n");
+  fprintf(f, "} bind def\n");
+  fprintf(f, "\n");
+  fprintf(f,"/WS {   %%usage:  w nspaces str WS\n");
+  fprintf(f,"   dup stringwidth pop 4 -1 roll\n");
+  fprintf(f,"   sub neg 3 -1 roll div 0 8#040 4 -1 roll\n");
+  fprintf(f,"   widthshow\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/W1 { show pop pop } bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/str 50 string def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/W0 {\n");
+  fprintf(f,"   dup stringwidth pop str cvs exch show (  ) show show pop pop\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/WC { counttomark 1 sub dup 0 eq { 0 }\n");
+  fprintf(f,"  {  ( ) stringwidth pop neg 0 3 -1 roll\n");
+  fprintf(f,"  {  dup 3 add index stringwidth pop ( ) stringwidth pop add\n");
+  fprintf(f,"  dup 3 index add 4 index lt 2 index 1 lt or\n");
+  fprintf(f,"  {3 -1 roll add exch 1 add} {pop exit} ifelse\n");
+  fprintf(f,"  } repeat } ifelse\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/P1 {\n");
+  fprintf(f,"  {  WC dup 0 le {exit} if\n");
+  fprintf(f,"      exch pop gsave { exch show ( ) show } repeat grestore LF\n");
+  fprintf(f,"   } loop pop pop pop pop\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"/P2 {\n");
+  fprintf(f,"   {  WC dup 0 le {exit} if\n");
+  fprintf(f,"      dup 1 sub dup 0 eq\n");
+  fprintf(f,"      { pop exch pop 0.0 }\n");
+  fprintf(f,"      { 3 2 roll 3 index exch sub exch div } ifelse\n");
+  fprintf(f,"      counttomark 3 sub 2 index eq { pop 0 } if exch gsave\n");
+  fprintf(f,"      {  3 2 roll show ( ) show dup 0 rmoveto } repeat\n");
+  fprintf(f,"      grestore LF pop\n");
+  fprintf(f,"   } loop pop pop pop pop\n");
+  fprintf(f,"} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"0 setlinecap 0 setlinejoin 0.8 setlinewidth\n");
+  fprintf(f,"\n");
+  fprintf(f,"/T {translate} bind def\n");
+  fprintf(f,"/M {moveto} bind def\n");
+  fprintf(f,"/L {lineto stroke} bind def\n");
+  fprintf(f,"\n");
+  fprintf(f,"%% End of abc2ps Postscript Library\n");
+  fprintf(f,"%%%%EndSetup\n");
+  fprintf(f,"\n");
+}
+
+void printlib(f, filename, boundingbox)
+FILE*f;
+char* filename;
+struct bbox* boundingbox;
+{
+  ps_header(f, filename, boundingbox);
+  section1(f);
+  section2(f);
+  section3(f);
+  section4(f);
+  section5(f);
+  section6(f);
+  section7(f);
+  section8(f);
+  section9(f);
+  section10(f);
+  section11(f);
+  section12(f);
+  section13(f);
+}
--- abcmidi-20070318.orig/crack.c
+++ abcmidi-20070318/crack.c
@@ -64,6 +64,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 /* define USE_INDEX if your C libraries have index() instead of strchr() */
 #ifdef USE_INDEX
@@ -77,7 +78,7 @@
 char* crack(argc, argv, flags, ign)
     int argc; char **argv; char *flags; int ign;
 {
-    char *pv, *flgp, *strchr();
+    char *pv, *flgp;
     while ((arg_index) < argc)
 	{
 	if (pvcon != NULL)
--- abcmidi-20070318.orig/parseabc.c
+++ abcmidi-20070318/parseabc.c
@@ -59,7 +59,7 @@
 #define strchr index
 #endif
 
-#ifdef ANSILIBS
+#if defined(ANSILIBS) || defined(__STDC__)
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
--- abcmidi-20070318.orig/genmidi.c
+++ abcmidi-20070318/genmidi.c
@@ -39,15 +39,15 @@
 #include "genmidi.h"
 #include "midifile.h"
 #include <stdio.h>
-#ifdef ANSILIBS
+#if defined(ANSILIBS) || defined(__STDC__)
 #include <string.h>
 #include <ctype.h>
+#include <stdlib.h>
 #endif
 /* define USE_INDEX if your C libraries have index() instead of strchr() */
 #ifdef USE_INDEX
 #define strchr index
 #endif
-#include <stdlib.h>
 
 void   single_note_tuning_change(int midikey, float midipitch);
 void addfract(int *xnum, int *xdenom, int a, int b);
--- abcmidi-20070318.orig/doc/abcmatch.1
+++ abcmidi-20070318/doc/abcmatch.1
@@ -0,0 +1,177 @@
+.TH ABCMATCH 1 "24 August 2007"
+.SH NAME
+abcmatch \- search sequences of notes in an ABC file
+.SH SYNOPSIS
+\fBabcmatch\fP \fIdata-file\fP [\fInumber\fR] [-a] [-br \fId\fP] [-c] [-con] [-ign] [-length_hist] [-pitch_hist] [-qnt] [-r \fIn\fP] [-v] [-ver]
+.SH "DESCRIPTION"
+.PP
+.B abcmatch
+searches an ABC file containing (potentially) many tunes for specific
+sequences of notes. For example, if you know a few bars of a tune, you
+can use this program to find the tune having this sequence and perhaps
+identify the tune.
+.PP
+At a minimum, abcmatch requires two files. A \fItemplate file\fP called
+\fBmatch.abc\fP which contains the bars that you are searching for and
+a large file consisting of a hundred or more ABC tunes.
+The program automatically loads up the match.abc file and
+then scans every tune in the large file.
+.PP
+Though the program can be run stand-alone, it is really meant to be
+run with a GUI such as runabc.tcl (which is not yet part of
+Debian). Most of its output is rather cryptic.
+.SH "THE MATCHING PROCESS"
+.PP
+The \fItemplate file\fR must be a well-formed ABC file containing the
+basic \fBX:\fP, \fBM:\fP, \fBL:\fP, and \fBK:\fP headers as well as
+the bars to be matched. (Normally, this file is created by
+runabc.tcl.) It is important to finish each bar in the match file with
+a vertical line.
+.PP
+.B abcmatch
+uses the key signature to figure out the relative position of the
+notes in the scale, and to determine all the assumed sharps and
+flats. Therefore the program can find matching bars in a tune that has
+been transposed to another key, as long as the key difference is not
+too large. Matches are output in a list format looking like
+.P
+29 30 4
+.br
+30 31 4
+
+.PP
+Each line indicates a particular match found by the program. The first
+number on each line gives the relative position of the tune in the
+\fIdata-file\fP, while the next number gives the \fBX:\fP number of
+that tune. The last number is the bar number of the matching tune. Bar
+numbers are counted sequentially from the start of the tune, and all
+\fBV:\fP and \fBP:\fP indications are ignored. That is, the bar number
+returned by \fBabcmatch\fP may not match bar numbers printed by one of
+the PostScript-producing ABC processors such as \fBabcm2ps\fP or
+\fBabcmidi-yaps\fP.
+.PP
+For the purposes of matching, \fBabcmatch\fP ignores all guitar
+chords, lyrics, note decorations (e.g., staccato markings), grace
+notes, etc. In chords such as \fB[G2c2]\fP, only the highest note is
+considered. Any warnings or error messages from the ABC parser are
+suppressed unless the \fB-c\fP option is given.
+
+.SH OPTIONS
+.TP
+.B \-a
+Report any matching bars. By default, if the template file contains a
+sequence of several bars, the program will try to find places in the
+data file where the whole sequence matches. With this option, it
+returns all places in the data file where \fIany\fP of the bars in the
+template file match.
+.TP
+.BI \-br " d"
+`Brief mode' is designed to identify groups of tunes sharing common
+bars. In this mode, the program determines the number of all bars in each
+tune from the data file which are also present in the template
+file. If the number of common bars is greater than or equal to the
+value of the \fId\fP parameter, the program reports the tune and the
+number of common bars. Currently there is no user control of the
+matching criterion; the rhythm must match exactly, and the notes are
+transposed to suit the key signature.
+.TP
+.B \-c
+Display error and warning messages from the ABC parser (which are
+suppressed by default).
+.TP
+.B \-con
+Do a pitch contour match. In this case, the program uses the key
+signature only to indicate accidentals. The pitch contour is computed
+from the pitch difference (interval) between adjacent notes. That is,
+\fBC2 DE\fP, \fBc2 de\fP, and \fBG2 AB\fP all have the same pitch
+contour.
+.TP
+.B \-ign
+Ignore simple bars.
+.TP
+.B \-length_hist
+This does no matching at all but returns a histogram of the
+distribution of note lengths in the data file. The output looks like
+
+.RS
+length histogram
+.br
+12 100
+.br
+24 20
+.br
+36 6
+.br
+48 2
+.br
+72 4
+.RE
+
+.RS
+where a quarter note is 24 units, an eight note 12 units, a dotted
+half note 72 units etc.
+.RE
+.TP
+.B \-pitch_hist
+This does no matching at all but returns a histogram of the
+distribution of pitches in the data file. The output looks like
+
+.RS
+pitch histogram
+.br
+64 2
+.br
+66 9
+.br
+67 11
+...
+.RE
+
+.RS
+where the first number on each line is a MIDI note number and the
+second is a count of the number of times that note occurred.
+.RE
+.TP
+.B \-qnt
+Do a quantized pitch contour match. This works as described above for
+the \fB-con\fP option, but will also quantize the intervals as
+follows: Unison and semitone intervals are assigned value 0, major
+2nds to major 3rds value 1, and a perfect 4th or greater value
+2. Negative numbers are used for descending intervals.
+.TP
+.BI \-r " n"
+Resolution for matching. If the \fIn\fP parameter is zero, a perfect
+match must be found, meaning that the lengths of each note in a bar
+must match exactly in order to be reported. The larger the value of
+\fIn\fP, the looser the match will be. Note lengths are converted into
+temporal units where a quarter note is normally assigned a value of 24
+(therefore an eighth note has a value of 12, a sixteenth a value of 6,
+a half note a value of 48 etc.) If you specify a temporal resolution
+of 12, then the pitch values of the notes only need to match at the
+time units that are multiples of an eight note. This means that the
+program would match the two bars \fBC2 D2\fP and \fBC C D D\fP, as
+well as \fBC2 D2\fP and \fBC/D/C/D/D2\fP. By selecting a suitable
+value for \fIn\fP, you can search for matches only at the beginning of
+a measure or at the beginning of each beat.
+.TP
+.B \-v
+Run verbosely.
+.TP
+.B \-ver
+Display the program's version number.
+.SH LIMITATIONS
+.PP
+The program has some limitations. For example, the data file must
+contain bar lines, and tied notes cannot be longer than the equivalent
+of 8 quarter notes. A resolution (\fB-r\fP option) that is too small
+may cause some buffers to be exceeded. When there are differences of
+key signatures of more than 5 semitones, the program may transpose the
+notes in the wrong direction. Also, tunes with more than one key
+signature or time signature may not be processed correctly.
+.SH "SEE ALSO"
+.IR abc2midi "(1), " midi2abc "(1), " mftext "(1)"
+.SH AUTHOR
+This manual page was written by Anselm Lingnau <lingnau@debian.org>
+for the GNU/Linux system.
+.SH VERSION
+This manual page describes abcmatch version 1.42 as of 21 December 2006.
--- abcmidi-20070318.orig/debian/abcmidi-yaps.README.Debian
+++ abcmidi-20070318/debian/abcmidi-yaps.README.Debian
@@ -0,0 +1,20 @@
+abcmidi-yaps for Debian
+-----------------------
+
+This package contains yaps 1.1 from abcMIDI 8 (which is available as a
+Debian package `abcmidi'). It has been packaged separately for the
+convenience of those who already use another ABC-to-PostScript
+converter such as abc2ps.
+
+There is another software package called `yaps', which is a program
+for talking to pagers (as in things that go beep in your pocket), and
+while this apparently hasn't been packaged for Debian yet, I am using
+the qualified name `abcmidi-yaps' to avoid confusion. The executable
+is also called `abcmidi-yaps'. (Make(1) is your friend, and ln(1)
+too.)
+
+There is a manual page which was contributed by Colin Watson
+<cjwatson@debian.org>, and another, more detailed explanatory file
+in /usr/share/doc/abcmidi-yaps/yaps.txt.
+
+ -- Anselm Lingnau <lingnau@debian.org>, Tue, 20 Feb 2001 15:42:36 +0100
--- abcmidi-20070318.orig/debian/abcmidi-yaps.dirs
+++ abcmidi-20070318/debian/abcmidi-yaps.dirs
@@ -0,0 +1,3 @@
+usr/bin
+usr/share/doc/abcmidi-yaps
+usr/share/man/man1
--- abcmidi-20070318.orig/debian/dirs
+++ abcmidi-20070318/debian/dirs
@@ -0,0 +1,3 @@
+usr/bin
+usr/share/doc/abcmidi
+usr/share/man/man1
--- abcmidi-20070318.orig/debian/copyright
+++ abcmidi-20070318/debian/copyright
@@ -0,0 +1,28 @@
+This package was debianized by Anselm Lingnau <lingnau@debian.org> on
+Tue, 27 May 2003.
+
+It was downloaded from http://ifdo.pugmarks.com/~seymour/runabc/top.html
+
+Upstream Authors: James Allwright <J.R.Allwright@westminster.ac.uk>
+		  Seymour Shlien <seymour.shlien@crc.ca>
+
+Copyright:
+
+This is free software. You may copy and re-distribute it under the terms of
+the GNU General Public License version 2 or later. You should have received
+a copy of the GNU General Public License on Debian systems as
+/usr/share/common-licenses/GPL; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+This package is to be found on the web at
+ 
+http://ifdo.pugmarks.com/~seymour/runabc/top.html
+ 
+These programs make use of the 'midifilelib' public domain MIDI file utilities,
+available from
+ 
+http://www.harmony-central.com/MIDI/midifilelib.tar.gz
+ 
+If you have the source distribution and intend to re-compile the code,
+read the file coding.txt.
+
--- abcmidi-20070318.orig/debian/changelog
+++ abcmidi-20070318/debian/changelog
@@ -0,0 +1,125 @@
+abcmidi (20070318-2.4.201403111059) ucs4-0-0-0; urgency=low
+
+  * UCS auto build. No patches were applied to the original source package
+
+ -- Univention builddaemon <buildd@univention.de>  Tue, 11 Mar 2014 10:59:08 +0100
+
+abcmidi (20070318-2) unstable; urgency=low
+
+  * Bring forward the fixes from 20060422-1 :^(
+
+ -- Anselm Lingnau <lingnau@debian.org>  Fri, 24 Aug 2007 13:48:32 +0200
+
+abcmidi (20070318-1) unstable; urgency=low
+
+  * New upstream release
+  * Now includes "abcmatch" program and documentation
+  * Various small policy fixes
+  
+ -- Anselm Lingnau <lingnau@debian.org>  Fri, 24 Aug 2007 11:19:10 +0200
+
+abcmidi (20060422-1) unstable; urgency=high
+
+  * New upstream release
+  * Incorporate fixes by the Security Team for unchecked sscanf() calls
+    [drawtune.c, yapstree.c, CVE-2006-1514]
+  * Fix most warnings to do with uninitialised variables
+  * Incorporate those bits of Roger Leigh's NMU that still make sense
+    (closes: #288770)
+
+ -- Anselm Lingnau <lingnau@debian.org>  Thu, 11 May 2006 00:50:52 +0200
+
+abcmidi (20051010-1) unstable; urgency=low
+
+  * New upstream release (closes: #304111)
+
+ -- Anselm Lingnau <lingnau@debian.org>  Tue, 18 Oct 2005 03:13:57 +0200
+
+abcmidi (20050101-2) unstable; urgency=low
+
+  * Remove the "-Wformat-non-literal" gcc option which was introduced for
+    the last version, and which is not supported on all gcc
+    versions. Thanks to Andreas Jochens (closes: #288770).
+
+ -- Anselm Lingnau <lingnau@debian.org>  Wed,  5 Jan 2005 20:46:27 +0100
+
+abcmidi (20050101-1) unstable; urgency=low
+
+  * New upstream release
+  * In particular, the DJB security bugs are now fixed (closes: #287050).
+  * Fixed another (very similar) security bug five lines above the other
+    ones.
+  
+ -- Anselm Lingnau <lingnau@debian.org>  Tue,  4 Jan 2005 08:37:05 +0100
+
+abcmidi (20040821-1) unstable; urgency=low
+
+  * New upstream release.
+  * Changed Suggests to include pmidi and abcm2ps, remove awe-midi.
+  * Adapted to policy 3.6.1.
+
+ -- Anselm Lingnau <lingnau@debian.org>  Wed, 25 Aug 2004 01:34:41 +0200
+
+abcmidi (20030521-1) unstable; urgency=low
+
+  * New upstream release (upstream maintainer changed, too).
+  * Adapted to policy 3.5.9.
+  
+ -- Anselm Lingnau <anselm@strathspey.org>  Tue, 27 May 2003 00:09:13 +0200
+
+abcmidi (17-1) unstable; urgency=low
+
+  * New upstream version
+
+ -- Anselm Lingnau <lingnau@debian.org>  Wed, 18 Jul 2001 10:48:33 +0200
+
+abcmidi (15-1) unstable; urgency=low
+
+  * New upstream version (closes: #77524, #100874).
+  * Changed `Suggests:' to suggest various alternatives for MIDI playback
+    instead of just timidity. (Suggested by Michael Karcher.)
+    Closes: #98420
+
+ -- Anselm Lingnau <lingnau@debian.org>  Thu, 28 Jun 2001 13:25:17 +0200
+
+abcmidi (8-2) unstable; urgency=low
+
+  * Streamlined the package some more (again thanks to Colin Watson
+    <cjwatson@debian.org>).
+    Closes: #80873
+
+ -- Anselm Lingnau <lingnau@debian.org>  Wed, 21 Feb 2001 10:14:43 +0100
+
+abcmidi (8-1) unstable; urgency=low
+
+  * New upstream version.
+  * Moved `yaps' into separate binary package abcmidi-yaps
+    (note that there is another software package called `yaps').
+  * Adapted to policy version 3.5.2.
+  
+ -- Anselm Lingnau <lingnau@debian.org>  Tue, 20 Feb 2001 15:42:36 +0100
+
+abcmidi (1.7.3-1) unstable; urgency=low
+ 
+  * New upstream version.
+  * Converted build process to debhelper. This fixes bug#33577 where
+    the binaries would be installed in the wrong directory.
+ 
+ -- Anselm Lingnau <lingnau@debian.org>  Fri, 19 Feb 1999 11:09:23 +0100
+ 
+abcmidi (1.5.7-1) unstable; urgency=low
+ 
+  * New upstream version.
+  * Miscellaneous formatting fixes to manpage.
+ 
+ -- Anselm Lingnau <lingnau@debian.org>  Mon, 31 Aug 1998 14:47:12 +0200
+ 
+abcmidi (1.5.1-1) unstable; urgency=low
+ 
+  * Initial Release.
+ 
+ -- Anselm Lingnau <lingnau@debian.org>  Thu, 27 Nov 1997 11:26:15 +0100
+
+Local variables:
+add-log-mailing-address "lingnau@debian.org"
+End:
--- abcmidi-20070318.orig/debian/compat
+++ abcmidi-20070318/debian/compat
@@ -0,0 +1 @@
+4
--- abcmidi-20070318.orig/debian/rules
+++ abcmidi-20070318/debian/rules
@@ -0,0 +1,75 @@
+#!/usr/bin/make -f
+# Sample debian/rules that uses debhelper. 
+# GNU copyright 1997 by Joey Hess.
+#
+# Uncomment this to turn on verbose mode. 
+#export DH_VERBOSE=1
+
+# This has to be exported to make some magic below work.
+export DH_OPTIONS
+
+# This is K&R C, so don't worry about a couple of classes of warnings.
+ifeq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
+CFLAGS="-DANSILIBS -O2 -Wall -Wno-implicit -Wno-return-type -Wformat-nonliteral -c"
+else
+CFLAGS="-DANSILIBS -O2 -g -Wall -Wno-implicit -Wno-return-type -Wformat-nonliteral -c"
+endif
+
+build: build-stamp
+build-stamp:
+	dh_testdir
+
+	$(MAKE) -f makefiles/unix.mak CFLAGS=$(CFLAGS)
+
+	touch build-stamp
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp
+
+	$(MAKE) -f makefiles/unix.mak clean
+
+	dh_clean
+
+install: DH_OPTIONS=
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k
+	dh_installdirs
+
+	set -e; \
+	for i in abc2abc abcmatch abc2midi mftext midi2abc midicopy; do \
+		install -m 755 $$i $(CURDIR)/debian/abcmidi/usr/bin/`basename $$i .exe`; \
+	done
+	install -m 755 yaps $(CURDIR)/debian/abcmidi-yaps/usr/bin/abcmidi-yaps
+	cd doc; install -m 644 abc2abc.1 abcmatch.1 abc2midi.1 mftext.1 midi2abc.1 midicopy.1 \
+		$(CURDIR)/debian/abcmidi/usr/share/man/man1
+	cd doc; install -m 644 yaps.1 $(CURDIR)/debian/abcmidi-yaps/usr/share/man/man1/abcmidi-yaps.1
+
+# Build architecture-independent files here.
+# Pass -i to all debhelper commands in this target to reduce clutter.
+binary-indep: DH_OPTIONS=-i
+binary-indep: build install
+
+# Build architecture-dependent files here.
+# Pass -a to all debhelper commands in this target to reduce clutter.
+binary-arch: DH_OPTIONS=-a
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_installdocs
+	dh_installmenu
+	dh_installchangelogs
+	dh_strip
+	dh_compress
+	dh_fixperms
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
--- abcmidi-20070318.orig/debian/abcmidi-yaps.docs
+++ abcmidi-20070318/debian/abcmidi-yaps.docs
@@ -0,0 +1,3 @@
+doc/readme.txt
+doc/yapshelp.txt
+doc/programming/yaps.txt
--- abcmidi-20070318.orig/debian/control
+++ abcmidi-20070318/debian/control
@@ -0,0 +1,40 @@
+Source: abcmidi
+Section: sound
+Priority: optional
+Maintainer: Anselm Lingnau <lingnau@debian.org>
+Build-Depends: debhelper (>> 3.0.0)
+Standards-Version: 3.7.2
+
+Package: abcmidi
+Architecture: any
+Depends: ${shlibs:Depends}
+Suggests: abcmidi-yaps | abcm2ps, timidity | pmidi | playmidi
+Description: converter from ABC to MIDI format and back
+ This package contains the programs `abc2midi' and `midi2abc',  which
+ convert from the abc musical notation format to standard MIDI format
+ and vice-versa. They can generate accompaniment from guitar chords
+ in the abc file, as well as insert various MIDI events; the
+ MIDI-to-abc translation tries to figure out bars, triplets and
+ accidentals on its own.
+ .
+ The package also contains `abc2abc' (an abc prettyprinter/transposer),
+ `mftext' (a program that dumps a MIDI file as text), and `midicopy'
+ (a program that extracts specific tracks, channels or time intervals
+ from a MIDI file).
+ .
+ The programs in this package are based on the `midifilelib'
+ distribution available from http://www.harmony-central.com/MIDI/.
+
+Package: abcmidi-yaps
+Architecture: any
+Depends: ${shlibs:Depends}
+Suggests: postscript-viewer, abcmidi
+Description: yet another ABC to PostScript converter
+ This program translates tunes written in the ABC format to PostScript,
+ which can then be viewed on screen or printed. It is essentially a
+ (non-exclusive) alternative to abc2ps, being based on the abc2ps
+ PostScript code together with the ABC parser from the abcmidi package.
+ .
+ People interested in this kind of software should also check out the
+ abcm2ps package, which contains a similar program that has lots of
+ additional features.
--- abcmidi-20070318.orig/debian/README.Debian
+++ abcmidi-20070318/debian/README.Debian
@@ -0,0 +1,17 @@
+abcmidi for Debian
+----------------------
+
+This version of the abcmidi package contains the following tools:
+
+     midi2abc version 2.5
+     abc2midi version 1.30
+     abc2abc  version 1.22
+
+The upstream abcMIDI package also contains an ABC-to-PostScript
+converter called yaps. This can be found in the `abcmidi-yaps'
+package. There is another software package called `yaps', which is
+a program for talking to pagers (as in things that go beep in your
+pocket), and while this apparently hasn't been packaged for Debian
+yet, I am using the qualified name to avoid confusion.
+
+ -- Anselm Lingnau <lingnau@debian.org>, Tue, 20 Feb 2001 15:42:36 +0100
--- abcmidi-20070318.orig/debian/docs
+++ abcmidi-20070318/debian/docs
@@ -0,0 +1,7 @@
+doc/AUTHORS
+doc/abcguide.txt
+doc/history.txt
+doc/readme.txt
+doc/programming/abc2midi.txt
+doc/programming/coding.txt
+doc/programming/midi2abc.txt
--- abcmidi-20070318.orig/debian/watch
+++ abcmidi-20070318/debian/watch
@@ -0,0 +1,6 @@
+# Example watch control file for uscan
+# Rename this file to "watch" and then you can run the "uscan" command
+# to check for upstream updates and more.
+# Site		Directory		Pattern			Version	Script
+version=2
+http://ifdo.pugmarks.com/~seymour/runabc/abcMIDI-(.*)\.zip	debian	uupdate
--- abcmidi-20070318.orig/makefiles/unix.mak
+++ abcmidi-20070318/makefiles/unix.mak
@@ -111,7 +111,7 @@
 matchsup.o : matchsup.c abc.h parseabc.h parser2.h
 
 clean :
-	rm *.o ${binaries}
+	rm -f *.o ${binaries}
 
 install: abc2midi midi2abc abc2abc mftext midicopy yaps abcmatch
 	$(INSTALL) -m 755 ${binaries} ${prefix}/${bindir}
