/*
    TuneToMidi.c
    Version 1.2.0
    Tune Language 1.1
    Copyright (C) 2003, 2004, 2005 J. David Sexton
    Some rights NOT reserved!
    e-mail: da5id65536@yahoo.com
    This revision of TuneToMidi.c was created on May 6, 2005.
    This C source code should compile with any C compiler that
    meets the ISO 9899:1990 (C89) standard. If GTK 2.0 is available,
    it can also be compiled with a graphical user interface.

    The purpose of the computer program created by compiling this
    document is to create MIDI files by compiling Tune files
    (files written in the Tune Language). Such Tune files and MIDI
    files are not subject to the license below.

    DISCLAIMER

    Because I have not been paid by anyone to create this document,
    and because I am allowing it to be distributed gratis (under the
    terms of the license below), I do not feel obliged to guarantee
    it to be free of errors. However, I have prepared it with care,
    and I am not aware of any errors. Any errors discovered may be
    reported to the e-mail address above.

    In legal jargon, there is no warranty for this document or an
    executable computer program created by compiling it. I do not
    guarantee that this document is free of errors, nor do I
    guarantee that a computer program created by compiling this
    document will perform as stated or implied in this document.
    This document is distributed "as is." Should a computer program
    created by compiling this document prove to be defective (whether
    because of errors in this document, errors in the libraries to
    which it is linked, errors in the compiler used to compile it,
    or for any other reason), any damage resulting from the use of
    that defective computer program shall be the sole responsibility
    of its user or users.

    LICENSE

    Everyone is hereby licensed:

    1. to compile this document into an executable computer program
    2. to use the computer program created by compiling this document
       to create MIDI files by compiling Tune files (files written
       in the Tune Language)
    3. to give unaltered copies of this document to others,
       provided that no payment is received in return
    4. to give copies of a computer program created by compiling
       this document to others, provided that:
       a. the computer program contains no library code (included
          by the compiler) which is distributed under a license
          that is incompatible with this license
       b. the computer program contains no code not created by
          compiling this document, other than library code included
          by the compiler during compilation (e.g., the program may
          not be used to distribute viruses)
       c. an unaltered copy of this document is included with
          every copy of the computer program
       d. no payment is received in return

    No one is hereby licensed:

    * to distribute copies of this document which have been
      altered in any way
    * to distribute works based on this document or derived from
      this document, except as allowed by item 4 above
    * to sell this document, either alone or as part of a
      collection which includes other items
    * to sell a computer program created by compiling this
      document, either alone or as part of a collection which
      includes other items

    This license applies only to this document and to any
    computer program created by compiling it.

    Licenses which grant rights in addition to those granted by
    this license may be negotiable. Contact the author at the
    e-mail address above.

    If the compiler (perhaps with an optional argument on its
    command line) defines TUNE_GTK_INTERFACE as 1, TuneToMidi
    will be compiled with a GTK 2.0 interface (assuming the
    necessary headers and libraries are available). If your
    system supports it, invoking the BuildTuneToMidi shell
    script is the easiest way to compile TuneToMidi.

    If TuneToMidi is compiled with the GTK interface, the macro
    TUNE_MIDI_PLAYER should be defined as the path name of the
    MIDI file player followed by necessary command-line options
    in a quoted, comma-separated list. For example:
    "/usr/bin/timidity", "-A", "100"
    This specifies TiMidity++ at full volume. By the way, this
    is the default definition of TUNE_MIDI_PLAYER. The last
    command-line argument passed to the MIDI file player will
    be the name of the MIDI file to be played. MIDI file players
    that can't accept command-line arguments won't work with
    TuneToMidi. TUNE_MIDI_PLAYER is best defined by the compiler.
    Remember, altered copies of this file may not be distributed.
    If TUNE_PLAY_SYNCH is defined as 1, playing will be
    synchronous and stdout and stderr fron the MIDI file player
    will be piped to TuneToMidi's window. If TUNE_PLAY_SYNCH is
    defined as 0, stdout and stderr from the MIDI file player
    will go to the same devices as TuneToMidi, and playing will
    be asynchronous. Another alternative is to run the MIDI
    player from a terminal like Konsole (from KDE).
    "/usr/bin/konsole", "-e", "/usr/bin/timidity", "-A", "100"
    In this case, TUNE_PLAY_SYNCH should be defined as 0.
    This makes TiMidity++, in effect, a GUI program.
    With GUI MIDI players, TUNE_PLAY_SYNCH should probably
    always be set to 0.

    Similarly, the macro TUNE_FILE_PRINTER should be defined
    as the path name of the file printer followed by necessary
    command-line options in a quoted, comma-separated list.
    For example:
    "/usr/bin/a2ps", "--margin", "-T", "4"
    specifies the Linux utility a2ps, which does an excellent
    job. Another alternative is
    "/usr/bin/lp"
    The lp (line printer) utility does an adequate job and is
    more widely available. The last command-line argument passed
    to the file printer will be the name of the Tune file to be
    printed. File printers that can't accept command-line
    arguments won't work with TuneToMidi. If TUNE_PRINT_SYNCH
    is defined as 1, printing will be synchronous and stdout and
    stderr fron the Tune file printer will be piped to
    TuneToMidi's window. If TUNE_PRINT_SYNCH is defined as 0,
    stdout and stderr from the Tune file printer will go to the
    same devices as TuneToMidi, and printing will be asynchronous.
    Because printing in a POSIX system is handled by a daemon,
    the Tune file printer will probably return almost immediately
    (after outputting text to stderr and stdout) even if
    TUNE_PRINT_SYNCH is defined as 1.

    If TuneToMidi isn't compiled with the GTK interface, and the
    POSIX function stat is available (i.e., the header files
    <sys/stat.h> and <unistd.h> are available), the macro
    GOT_STAT should be defined.
*/

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>

/*  The default is not GTK. */
#ifndef TUNE_GTK_INTERFACE
#define TUNE_GTK_INTERFACE 0
#endif
#if (TUNE_GTK_INTERFACE != 0 && TUNE_GTK_INTERFACE != 1)
#error "TUNE_GTK_INTERFACE must equal 0 or 1."
#endif

#if TUNE_GTK_INTERFACE
/*  If we're using GTK, check macros for playing and printing.  */
#ifndef TUNE_PLAY_SYNCH
#define TUNE_PLAY_SYNCH 1
#endif
#if (TUNE_PLAY_SYNCH != 0 && TUNE_PLAY_SYNCH != 1)
#error "TUNE_PLAY_SYNCH must equal 0 or 1."
#endif
#ifndef TUNE_PRINT_SYNCH
#define TUNE_PRINT_SYNCH 1
#endif
#if (TUNE_PRINT_SYNCH != 0 && TUNE_PRINT_SYNCH != 1)
#error "TUNE_PRINT_SYNCH must equal 0 or 1."
#endif
#ifndef TUNE_MIDI_PLAYER
/*  path name of the MIDI player, with necessary options    */
#define TUNE_MIDI_PLAYER "/usr/bin/timidity", "-A", "100"
#endif
#ifndef TUNE_FILE_PRINTER
/*  path name of the file printer, with necessary options   */
#define TUNE_FILE_PRINTER "/usr/bin/a2ps", "--margin", "-T", "4"
#endif
/*  There's just the one include for the whole GUI. */
#include <gtk/gtk.h>
#elif defined (GOT_STAT)
/*  These are the includes for the POSIX stat function. */
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif

        int     main (int argc, char **argv);
#if TUNE_GTK_INTERFACE
        int     TunePrintGTK (const char *theString, ...) G_GNUC_PRINTF (1, 2);
    gboolean    TuneCheckClip (gpointer theData);
    gboolean    TuneFixEditScroll (gpointer theData);
    gboolean    TuneFixCompScroll (gpointer theData);
    gboolean    TuneStatusBar (gpointer theData);
        void    TuneOverToggle (GtkTextView *theTextView, gpointer theData);
        void    TuneMainSensitive (gboolean makeSensitive);
        void    TuneToolOpen (GtkWidget *theWidget, gpointer theData);
        void    TuneOpenTune (GtkWidget *theWidget, gpointer theData);
    gboolean    TuneFileValidate (const void *theBlock, size_t blockSize);
        void    TuneToolClose (GtkWidget *theWidget, gpointer theData);
        void    TuneToolRevert (GtkWidget *theWidget, gpointer theData);
        void    TuneToolSave (GtkWidget *theWidget, gpointer theData);
        void    TuneToolSaveAs (GtkWidget *theWidget, gpointer theData);
        void    TuneSaveAs (GtkWidget *theWidget, gpointer theData);
        int     TuneSaveTune (GtkTextBuffer *theTextBuf,
                            const gchar *newFileName);
        void    TuneToolCompile (GtkWidget *theWidget, gpointer theData);
        void    TuneToolPlay (GtkWidget *theWidget, gpointer theData);
        void    TuneToolPrint (GtkWidget *theWidget, gpointer theData);
        void    TuneToolUndo (GtkWidget *theWidget, gpointer theData);
        void    TuneToolCut (GtkWidget *theWidget, gpointer theData);
        void    TuneToolCopy (GtkWidget *theWidget, gpointer theData);
        void    TuneToolPaste (GtkWidget *theWidget, gpointer theData);
        void    TuneToolFind (GtkWidget *theWidget, gpointer theData);
        void    TuneReplMark (GtkTextBuffer *theTextBuf, const GtkTextIter *theIter,
                            GtkTextMark *theMark, gpointer theData);
        void    TuneRTextChanged (GtkTextBuffer *theTextBuf, gpointer theData);
        void    TuneFindMark (GtkTextBuffer *theTextBuf, const GtkTextIter *theIter,
                            GtkTextMark *theMark, gpointer theData);
        void    TuneFTextChanged (GtkTextBuffer *theTextBuf, gpointer theData);
        void    TuneFixReplBtns (void);
        void    TuneWordCaseBtns (GtkToggleButton *theButton);
        void    TuneFindBtn (GtkWidget *theWidget, gpointer theData);
        void    TuneReplFindBtn (GtkWidget *theWidget, gpointer theData);
        void    TuneReplaceBtn (GtkWidget *theWidget, gpointer theData);
        void    TuneReplAllBtn (GtkWidget *theWidget, gpointer theData);
        void    TuneFind (void);
    gboolean    TuneFindForward (GtkTextIter *searchStart,
                            GtkTextIter *theStart, GtkTextIter *theEnd);
    gboolean    TuneCaseInsensFindFwd (GtkTextIter *searchStart,
                            GtkTextIter *theStart, GtkTextIter *theEnd);
    gboolean    TuneIsWholeWord (const GtkTextIter *theStart,
                            const GtkTextIter *theEnd);
        int     TuneCIStringsEqual (const char *stringA, const char *stringB);
        void    TuneReplace (void);
        void    TuneToolGoTo (GtkWidget *theWidget, gpointer theData);
        void    TuneGoToLine (GtkWidget *theWidget, gpointer theData);
        void    TuneScrollInsOnscreen (void);
        void    TuneHighlight (GtkTextBuffer *theTextBuf,
                            const GtkTextIter *startIter,
                            const GtkTextIter *endIter);
    gboolean    TuneCharPredicate (gunichar theChar, gpointer theData);
    gboolean    TuneStringIsNote (const gchar *theString);
        void    TuneEditChanged (GtkTextBuffer *theTextBuf, gpointer theData);
        void    TuneMarkSet (GtkTextBuffer *theTextBuf, const GtkTextIter *theIter,
                            GtkTextMark *theMark, gpointer theData);
        void    TuneTextDel (GtkTextBuffer *theTextBuf, GtkTextIter *theStart,
                            GtkTextIter *theEnd, gpointer theData);
        void    TuneTextIns (GtkTextBuffer *theTextBuf, GtkTextIter *theIter,
                            const gchar *theText, gint theLength,
                            gpointer theData);
        void    TuneBtnCompile (GtkWidget *theWidget, gpointer theData);
        void    TuneCompileSelections (GtkWidget *theWidget, gpointer theData);
        void    TuneCloseModal (GtkWidget *theWidget, gpointer theData);
        void    TuneModalDestroyed (GtkWidget *theWidget, gpointer theData);
    gboolean    TuneWindowDelete (GtkWidget *theWidget, GdkEventAny *theEvent,
                            gpointer theData);
        void    TuneQuit (GtkWidget *theWidget, gpointer theData);
        void    TuneZapUndos (void);
        int     StdInterface (int argc, char **argv);
#else
#define StdInterface main
#define TunePrint printf
#define TuneBeep StdBeep
#endif
        void    StdBeep (void);
        void    PrintHelp (void);
        void    PrintVersion (void);
#if TUNE_GTK_INTERFACE || defined (GOT_STAT)
        int     IsADirectory (const char *pathName, const char *fileOp);
#endif
        int     StringsEqual (const char *stringA, const char *stringB);
        int     TuneCompile (int firstArgIdx, int argc, char **argv);
        int     CheckDupChordNote (void);
        int     CheckSelfRef (void);
        void    SkipTextCommands (FILE *tuneFile, const char *theString);
unsigned long   NoteToNum (char *theString, unsigned long theOct, int theAuto);
        int     GetNoteValue (FILE *tuneFile, unsigned long *theNum);
        int     StringToNumber (const char *theString, unsigned long *theNum);
        int     GetSignedNumber (FILE *tuneFile, int *theNum);
        int     GetNumber (FILE *tuneFile, unsigned long *theNum);
        int     GetString (FILE *tuneFile, char *theString);
        int     WriteBigEndianLength (FILE *midiFile, unsigned long theLength);
        int     WriteByte (FILE *midiFile, unsigned char theChar);
        int     ReadByte (FILE *midiFile, unsigned char *theChar);
        int     WriteVariableLen (FILE *midiFile, unsigned long theLength);
        int     WriteString (FILE *midiFile, const char *theString);
        int     ReadTextStringN (FILE *tuneFile, char *theString,
                            unsigned long lengthToRead);
        int     ReadTextString (FILE *tuneFile, char *theString);
        int     WindToEndOfLine (FILE *tuneFile);
unsigned long   GetLineNumber (FILE *tuneFile, long theOffset);
        int     StringToInstNum (char *theString, unsigned long *theNum);
unsigned char   StringToKitNote (const char *theString);
        int     StringToStress (const char *theString, unsigned long *theNum);

/*  We use our own isalnum to avoid library calls and locale issues.    */
#define ISALPHNUM(c) (((c) >= 'a' && (c) <= 'z') || \
                    ((c) >= 'A' && (c) <= 'Z') || \
                    ((c) >= '0' && (c) <= '9'))
#define MAX_INCLUDE_DEPTH 1024
#define MAX_DEF_DEPTH 1024
#define MAX_REP_DEPTH 1024

/*  These are the error types   */

enum    {kErrorWritingFile = 1, kBadArgString, kBadArgNum, kArgNotNum,
        kNoArgs, kBadPlace, kBigTrans, kLastCommandNotO, kTooFewTracks,
        kTuneUnreadable, kReportedError};

unsigned long   gIncludeDepth;
FILE            *gIncludeStack [MAX_INCLUDE_DEPTH];
char            *gIncludeNameStack [MAX_INCLUDE_DEPTH];
char            *gTuneFileName;
char            *gMidiFileName;
unsigned char   gXNote;
unsigned char   gNumOfNotes, gNotes [128];
unsigned long   gDefDepth;
char            gDefName [256];
long            gDefRetStack [MAX_DEF_DEPTH];
long            gDefStartStack [MAX_DEF_DEPTH];
unsigned long   gRepeatDepth;
unsigned long   gRepeatIndex;
unsigned long   gRepIndexStack [MAX_REP_DEPTH];
long            gRepStartStack [MAX_REP_DEPTH];

#if TUNE_GTK_INTERFACE

guint8  gTuneIcon [] =
    {"GdkP"
    "\0\0\20\30"
    "\1\1\0\2"
    "\0\0\0\200"
    "\0\0\0\40"
    "\0\0\0\40"
    "\334\334\334\0\0q\0\377\0q\0\377\0q\0\377\0q\0\377\0q\0\377\0q\0\377"
    "\0q\0\377\0q\0\377\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0"
    "\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\334"
    "\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334"
    "\0\0q\0\377\334\334\334\0\0q\0\377\0q\0\377\0q\0\377\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\0q\0\377\0q\0\377\0q"
    "\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334"
    "\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\0q\0\377\334\334\334\0\334\334\334\0\0q\0\377\0q\0\377\334"
    "\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334"
    "\334\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334\0\334\334"
    "\334\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\0q\0\377\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334"
    "\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0"
    "q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0"
    "q\0\377\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334\0\0"
    "q\0\377\0q\0\377\0q\0\377\0q\0\377\0q\0\377\0q\0\377\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0"
    "q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334"
    "\334\334\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\0q\0\377\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0"
    "q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334"
    "\0\334\334\334\0\334\334\334\0\0q\0\377\0q\0\377\334\334\334\0\334\334"
    "\334\0\0q\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\0q\0\377\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\0q\0\377\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\0q\0\377"
    "\0q\0\377\334\334\334\0\0q\0\377\334\334\334\0\334\334\334\0\0q\0\377"
    "\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\334"
    "\334\334\0\334\334\334\0\334\334\334\0\0q\0\377\0q\0\377\0q\0\377\0q"
    "\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\233\0\0\377\233\0\0\377\233\0\0\377\233\0\0\377"
    "\233\0\0\377\233\0\0\377\233\0\0\377\233\0\0\377\233\0\0\377\233\0\0"
    "\377\233\0\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\233\0\0\377\233\0\0\377"
    "\233\0\0\377\233\0\0\377\233\0\0\377\233\0\0\377\233\0\0\377\233\0\0"
    "\377\233\0\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\233\0\0\377\233\0\0\377\233\0\0\377\233\0\0\377\233\0\0\377\233\0"
    "\0\377\233\0\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\233\0\0\377\233\0\0\377\233\0\0\377"
    "\233\0\0\377\233\0\0\377\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\233"
    "\0\0\377\233\0\0\377\233\0\0\377\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\233\0\0\377\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\0\0\211"
    "\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\0\0\211\377\0\0\211\377\334\334\334\0\334\334\334\0\0\0\211\377"
    "\0\0\211\377\0\0\211\377\0\0\211\377\0\0\211\377\334\334\334\0\334\334"
    "\334\0\0\0\211\377\0\0\211\377\0\0\211\377\0\0\211\377\0\0\211\377\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\0\0"
    "\211\377\0\0\211\377\0\0\211\377\0\0\211\377\0\0\211\377\334\334\334"
    "\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377"
    "\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0"
    "\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0"
    "\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0"
    "\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0"
    "\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0"
    "\0\0\211\377\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\0"
    "\0\211\377\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334"
    "\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334"
    "\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334"
    "\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0\0\0"
    "\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0"
    "\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0"
    "\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334"
    "\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\0\0\211\377\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334"
    "\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211"
    "\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211"
    "\377\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\0\0\211\377"
    "\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334"
    "\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377"
    "\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377"
    "\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377"
    "\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\0\0\211\377\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0"
    "\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334\0\334\334\334"
    "\0\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\0\0\211\377\334\334\334"
    "\0\334\334\334\0\0\0\211\377\0\0\211\377\0\0\211\377\0\0\211\377\0\0"
    "\211\377\334\334\334\0\334\334\334\0\0\0\211\377\0\0\211\377\0\0\211"
    "\377\0\0\211\377\0\0\211\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\0\0\211\377\0\0\211\377\0\0\211\377\0\0\211\377\0\0"
    "\211\377"};
guint8  gTunePlayIcon [] =
    {"GdkP"
    "\0\0\4\30"
    "\1\1\0\2"
    "\0\0\0@"
    "\0\0\0\20"
    "\0\0\0\20"
    "\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0""000\377000\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0""000\377000\377000\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0""000\377000\377000\377000\377\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0""000\377"
    "000\377000\377000\377000\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0""000\377000\377000\3770"
    "00\377000\377000\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0""000\377000\377000\377000\377000\377000\377000\377"
    "\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0""000\3770"
    "00\377000\377000\377000\377000\377000\377000\377\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0""000\377000\377000\377000\377000\377000\377000\377"
    "000\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0""000\377000\377000\377"
    "000\377000\377000\377000\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0""000\377000\377000\377000\377000\377000\377\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0""000\377"
    "000\377000\377000\377000\377\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0""000\377000\377000\3770"
    "00\377\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0""000\377000\377000\377\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334"
    "\0\334\334\334\0\334\334\334\0""000\377000\377\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334"
    "\334\0\334\334\334\0\334\334\334\0\334\334\334\0\334\334\334\0"};
GtkStockItem    gTuneStock [] =
    {{"TuneCompileB", "_Compile Tune Files", 0, 0, NULL},
    {"TuneQuitB", "_Quit TuneToMidi", 0, 0, NULL},
    {"TuneReplFindB", "_Replace then Find", 0, 0, NULL},
    {"TuneReplaceB", "Replace", 0, 0, NULL},
    {"TuneReplAllB", "Replace _All", 0, 0, NULL},
    {"TuneOpen", "Open", 0, 0, NULL},
    {"TuneClose", "Close", 0, 0, NULL},
    {"TuneRevert", "Revert", 0, 0, NULL},
    {"TuneSave", "Save", 0, 0, NULL},
    {"TuneSaveAs", "Save As", 0, 0, NULL},
    {"TuneCompile", "Compile", 0, 0, NULL},
    {"TunePlay", "Play", 0, 0, NULL},
    {"TunePrint", "Print", 0, 0, NULL},
    {"TuneUndo", "Undo", 0, 0, NULL},
    {"TuneCut", "Cut", 0, 0, NULL},
    {"TuneCopy", "Copy", 0, 0, NULL},
    {"TunePaste", "Paste", 0, 0, NULL},
    {"TuneFind", "Find", 0, 0, NULL},
    {"TuneGoTo", "Go to", 0, 0, NULL}};
enum    {kTuneLeftMargin = 4, kTuneRightMargin = 4, kTuneTabSpaces = 4};
gint            gCharWidth;
GtkWidget       *gWindow;
GtkWidget       *gMainFocus;
GtkWidget       *gEditTextView;
GtkWidget       *gCompTextView;
GtkWidget       *gOpenTool;
GtkWidget       *gCloseTool;
GtkWidget       *gRevertTool;
GtkWidget       *gCompileTool;
GtkWidget       *gSaveTool;
GtkWidget       *gSaveAsTool;
GtkWidget       *gPlayTool;
GtkWidget       *gPrintTool;
GtkWidget       *gUndoTool;
GtkWidget       *gCutTool;
GtkWidget       *gCopyTool;
GtkWidget       *gFindTool;
GtkWidget       *gGoToTool;
gchar           *gFindText, *gReplText;
GtkTextBuffer   *gFindTextBuf, *gReplTextBuf;
GtkWidget       *gWordBtn, *gCaseBtn, *gFindBtn, *gReplaceBtn;
GtkWidget       *gReplFindBtn, *gReplaceAllBtn;
gboolean        gFoundOne, gWholeWord, gCaseIns;
GtkSpinButton   *gSpinBtn;
gboolean        gUpdateStatusBar;
gboolean        gNeedHighlighting;
gint            gHighlightStart, gHighlightEnd;
enum    {kTuneUndoMax = 1024};
gboolean        gUndoing;
int             gUndoIdx, gNumUndos;
gchar           *gDelString [kTuneUndoMax];
gint            gEditStart [kTuneUndoMax], gEditEnd [kTuneUndoMax];
gboolean        gCursAtStart [kTuneUndoMax];
gchar           *gOpenTuneName;

const   gchar   *gTunePlayLine [] = {TUNE_MIDI_PLAYER, NULL, NULL};
const   gchar   *gTunePrintLine [] = {TUNE_FILE_PRINTER, NULL, NULL};

typedef void    (*TuneBeepFunc) (void);
typedef int     (*TunePrintFunc) (const char *theString, ...);
TuneBeepFunc    TuneBeep;
TunePrintFunc   TunePrint;

        int     main (int argc, char **argv)

            {GtkWidget              *eBox, *vBox, *hBox;
            GtkWidget               *theStatusBar, *theVPaned;
            GtkWidget               *editFrame, *compFrame;
            GtkWidget               *editScrollWin, *compScrollWin;
            GtkWidget               *quitButton, *compileButton;
            GtkWidget               *theToolbar, *pasteTool;
            GtkAccelGroup           *theAccel;
            GtkTextBuffer           *theTextBuf;
            GtkTextIter             theIter;
            GtkIconSet              *theIconSet;
            GtkIconFactory          *theFactory;
            GtkTooltips             *btnTips;
            GdkPixbuf               *thePixBuf;
            GdkRectangle            theRect;
            PangoFontDescription    *theFont;
            PangoTabArray           *theTabs;

            TuneBeep = StdBeep;
            TunePrint = printf;
            if (!gtk_init_check (&argc, &argv))
                return (StdInterface (argc, argv));
            if (argc > 1)
                return (StdInterface (argc, argv));
            TuneBeep = gdk_beep;
            TunePrint = TunePrintGTK;
            gOpenTuneName = gFindText = gReplText = (gchar *) 0;
            gUndoing = gWholeWord = gCaseIns = FALSE;
            gUpdateStatusBar = TRUE;
            gUndoIdx = gNumUndos = 0;
            gMainFocus = (GtkWidget *) 0;
            gtk_stock_add_static (gTuneStock,
                sizeof (gTuneStock) / sizeof (GtkStockItem));
            theFactory = gtk_icon_factory_new ();
            thePixBuf = gdk_pixbuf_new_from_inline (sizeof (gTuneIcon),
                gTuneIcon, FALSE, NULL);
            theIconSet = gtk_icon_set_new_from_pixbuf (thePixBuf);
            gtk_icon_factory_add (theFactory, "TuneCompileB", theIconSet);
            gtk_icon_factory_add (theFactory, "TuneCompile", theIconSet);
            gtk_icon_set_unref (theIconSet);
            g_object_unref (G_OBJECT (thePixBuf));
            thePixBuf = gdk_pixbuf_new_from_inline (sizeof (gTunePlayIcon),
                gTunePlayIcon, FALSE, NULL);
            theIconSet = gtk_icon_set_new_from_pixbuf (thePixBuf);
            gtk_icon_factory_add (theFactory, "TunePlay", theIconSet);
            gtk_icon_set_unref (theIconSet);
            g_object_unref (G_OBJECT (thePixBuf));
            gtk_icon_factory_add (theFactory, "TuneQuitB",
                gtk_icon_factory_lookup_default (GTK_STOCK_QUIT));
            gtk_icon_factory_add (theFactory, "TuneReplFindB",
                gtk_icon_factory_lookup_default (GTK_STOCK_FIND_AND_REPLACE));
            gtk_icon_factory_add (theFactory, "TuneReplaceB",
                gtk_icon_factory_lookup_default (GTK_STOCK_FIND_AND_REPLACE));
            gtk_icon_factory_add (theFactory, "TuneReplAllB",
                gtk_icon_factory_lookup_default (GTK_STOCK_FIND_AND_REPLACE));
            gtk_icon_factory_add (theFactory, "TuneOpen",
                gtk_icon_factory_lookup_default (GTK_STOCK_OPEN));
            gtk_icon_factory_add (theFactory, "TuneClose",
                gtk_icon_factory_lookup_default (GTK_STOCK_CLOSE));
            gtk_icon_factory_add (theFactory, "TuneRevert",
                gtk_icon_factory_lookup_default (GTK_STOCK_REVERT_TO_SAVED));
            gtk_icon_factory_add (theFactory, "TuneSave",
                gtk_icon_factory_lookup_default (GTK_STOCK_SAVE));
            gtk_icon_factory_add (theFactory, "TuneSaveAs",
                gtk_icon_factory_lookup_default (GTK_STOCK_SAVE_AS));
            gtk_icon_factory_add (theFactory, "TunePrint",
                gtk_icon_factory_lookup_default (GTK_STOCK_PRINT));
            gtk_icon_factory_add (theFactory, "TuneUndo",
                gtk_icon_factory_lookup_default (GTK_STOCK_UNDO));
            gtk_icon_factory_add (theFactory, "TuneCut",
                gtk_icon_factory_lookup_default (GTK_STOCK_CUT));
            gtk_icon_factory_add (theFactory, "TuneCopy",
                gtk_icon_factory_lookup_default (GTK_STOCK_COPY));
            gtk_icon_factory_add (theFactory, "TunePaste",
                gtk_icon_factory_lookup_default (GTK_STOCK_PASTE));
            gtk_icon_factory_add (theFactory, "TuneFind",
                gtk_icon_factory_lookup_default (GTK_STOCK_FIND_AND_REPLACE));
            gtk_icon_factory_add (theFactory, "TuneGoTo",
                gtk_icon_factory_lookup_default (GTK_STOCK_JUMP_TO));
            gtk_icon_factory_add_default (theFactory);
            g_object_unref (G_OBJECT (theFactory));
            gWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
            thePixBuf = gdk_pixbuf_new_from_inline (sizeof (gTuneIcon),
                gTuneIcon, FALSE, NULL);
            gtk_window_set_icon (GTK_WINDOW (gWindow), thePixBuf);
            g_object_unref (G_OBJECT (thePixBuf));
            gtk_window_set_default_size (GTK_WINDOW (gWindow), 800, 800);
            gtk_window_set_title (GTK_WINDOW (gWindow), "TuneToMidi");
            gtk_container_set_border_width (GTK_CONTAINER (gWindow), 8);
            theAccel = gtk_accel_group_new ();
            gtk_window_add_accel_group (GTK_WINDOW (gWindow), theAccel);
            theVPaned = gtk_vpaned_new ();
            eBox = gtk_vbox_new (FALSE, 0);
            vBox = gtk_vbox_new (FALSE, 8);
            hBox = gtk_hbox_new (FALSE, 8);
            editFrame = gtk_frame_new (NULL);
            compFrame = gtk_frame_new (NULL);
            editScrollWin = gtk_scrolled_window_new (NULL, NULL);
            gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (editScrollWin),
                GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
            gtk_timeout_add (500, TuneFixEditScroll, (gpointer) editScrollWin);
            compScrollWin = gtk_scrolled_window_new (NULL, NULL);
            gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (compScrollWin),
                GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
            gtk_timeout_add (500, TuneFixCompScroll, (gpointer) compScrollWin);
            theStatusBar = gtk_statusbar_new ();
            gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (theStatusBar),
                FALSE);
            gtk_statusbar_push (GTK_STATUSBAR (theStatusBar), 0, " ");
            gtk_timeout_add (50, TuneStatusBar, (gpointer) theStatusBar);
            gEditTextView = gtk_text_view_new ();
            gtk_text_view_set_editable (GTK_TEXT_VIEW (gEditTextView), TRUE);
            gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (gEditTextView),
                GTK_WRAP_NONE);
            gtk_text_view_set_left_margin (GTK_TEXT_VIEW (gEditTextView),
                kTuneLeftMargin);
            gtk_text_view_set_right_margin (GTK_TEXT_VIEW (gEditTextView),
                kTuneRightMargin);
            gCompTextView = gtk_text_view_new ();
            gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (gCompTextView),
                FALSE);
            gtk_text_view_set_editable (GTK_TEXT_VIEW (gCompTextView), FALSE);
            gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (gCompTextView),
                GTK_WRAP_WORD);
            gtk_text_view_set_left_margin (GTK_TEXT_VIEW (gCompTextView),
                kTuneLeftMargin);
            gtk_text_view_set_right_margin (GTK_TEXT_VIEW (gCompTextView),
                kTuneRightMargin);
            theFont = pango_font_description_from_string ("Monospace");
            gtk_widget_modify_font (gEditTextView, theFont);
            gtk_widget_modify_font (gCompTextView, theFont);
            pango_font_description_free (theFont);
            theTextBuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gEditTextView));
            gtk_text_buffer_create_tag (theTextBuf, "tunecommand", "foreground",
                "blue", NULL);
            gtk_text_buffer_create_tag (theTextBuf, "tunenote", "foreground",
                "dark green", NULL);
            g_signal_connect_object (G_OBJECT (gEditTextView), "toggle_overwrite",
                G_CALLBACK (TuneOverToggle), NULL, 0);
            g_signal_connect_object (G_OBJECT (gWindow), "delete-event",
                G_CALLBACK (TuneWindowDelete), (gpointer) theTextBuf, 0);
            g_signal_connect_object (G_OBJECT (theTextBuf), "mark_set",
                G_CALLBACK (TuneMarkSet), NULL, 0);
            g_signal_connect_object (G_OBJECT (theTextBuf), "modified_changed",
                G_CALLBACK (TuneEditChanged), NULL, 0);
            g_signal_connect_object (G_OBJECT (theTextBuf), "changed",
                G_CALLBACK (TuneEditChanged), NULL, 0);
            g_signal_connect_object (G_OBJECT (theTextBuf), "delete_range",
                G_CALLBACK (TuneTextDel), NULL, 0);
            g_signal_connect_object (G_OBJECT (theTextBuf), "insert_text",
                G_CALLBACK (TuneTextIns), NULL, 0);
            theToolbar = gtk_toolbar_new ();
            gOpenTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneOpen",
                "Opens a Tune file to edit;\n<Ctrl>O clicks this tool.",
                "Opens a Tune file to edit;\n<Ctrl>O clicks this tool.",
                G_CALLBACK (TuneToolOpen), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gOpenTool, "clicked", theAccel,
                'o', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gCloseTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneClose",
                "Closes the open Tune file;\n<Ctrl>W clicks this tool.",
                "Closes the open Tune file;\n<Ctrl>W clicks this tool.",
                G_CALLBACK (TuneToolClose), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gCloseTool, "clicked", theAccel,
                'w', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gCloseTool, FALSE);
            gRevertTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneRevert",
                "Reverts to the saved file, loosing all the changes;"
                "\n<Ctrl>R clicks this tool.",
                "Reverts to the saved file, loosing all the changes;"
                "\n<Ctrl>R clicks this tool.",
                G_CALLBACK (TuneToolRevert), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gRevertTool, "clicked", theAccel,
                'r', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gRevertTool, FALSE);
            gSaveTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneSave",
                "Saves the open Tune file;\n<Ctrl>S clicks this tool.",
                "Saves the open Tune file;\n<Ctrl>S clicks this tool.",
                G_CALLBACK (TuneToolSave), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gSaveTool, "clicked", theAccel,
                's', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gSaveTool, FALSE);
            gSaveAsTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneSaveAs",
                "Saves the open Tune file to a new file;"
                "\n<Ctrl><Shift>S clicks this tool.",
                "Saves the open Tune file to a new file;"
                "\n<Ctrl><Shift>S clicks this tool.",
                G_CALLBACK (TuneToolSaveAs), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gSaveAsTool, "clicked", theAccel,
                's', GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gSaveAsTool, FALSE);
            gtk_toolbar_append_space (GTK_TOOLBAR (theToolbar));
            gCompileTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneCompile",
                "Compiles the open Tune file into a MIDI file;"
                "\n<Ctrl>M clicks this tool.",
                "Compiles the open Tune file into a MIDI file;"
                "\n<Ctrl>M clicks this tool.",
                G_CALLBACK (TuneToolCompile), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gCompileTool, "clicked", theAccel,
                'm', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gCompileTool, FALSE);
            if (g_file_test (gTunePlayLine [0], G_FILE_TEST_IS_EXECUTABLE))
                {gPlayTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                    "TunePlay",
                    "Compiles the open Tune file into a MIDI file, then plays it;"
                    "\n<Ctrl>P clicks this tool.",
                    "Compiles the open Tune file into a MIDI file, then plays it;"
                    "\n<Ctrl>P clicks this tool.",
                    G_CALLBACK (TuneToolPlay), (gpointer) theTextBuf, -1);
                gtk_widget_add_accelerator (gPlayTool, "clicked", theAccel,
                    'p', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
                gtk_widget_set_sensitive (gPlayTool, FALSE);}
            else
                gPlayTool = (GtkWidget *) 0;
            if (g_file_test (gTunePrintLine [0], G_FILE_TEST_IS_EXECUTABLE))
                {gPrintTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                    "TunePrint",
                    "Prints the open Tune file."
                    "\n<Crtl><Shift>P clicks this tool.",
                    "Prints the open Tune file."
                    "\n<Crtl><Shift>P clicks this tool.",
                    G_CALLBACK (TuneToolPrint), (gpointer) theTextBuf, -1);
                gtk_widget_add_accelerator (gPrintTool, "clicked", theAccel,
                    'p', GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
                gtk_widget_set_sensitive (gPrintTool, FALSE);}
            else
                gPrintTool = (GtkWidget *) 0;
            gtk_toolbar_append_space (GTK_TOOLBAR (theToolbar));
            gUndoTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneUndo",
                "Undoes editing;\n<Ctrl>Z clicks this tool.",
                "Undoes editing;\n<Ctrl>Z clicks this tool.",
                G_CALLBACK (TuneToolUndo), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gUndoTool, "clicked", theAccel,
                'z', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gUndoTool, FALSE);
            gCutTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneCut",
                "Cuts the selected text to the clipboard;"
                "\n<Ctrl>X clicks this tool.",
                "Cuts the selected text to the clipboard;"
                "\n<Ctrl>X clicks this tool.",
                G_CALLBACK (TuneToolCut), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gCutTool, "clicked", theAccel,
                'x', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gCutTool, FALSE);
            gCopyTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneCopy",
                "Copies the selected text to the clipboard;"
                "\n<Ctrl>C clicks this tool.",
                "Copies the selected text to the clipboard;"
                "\n<Ctrl>C clicks this tool.",
                G_CALLBACK (TuneToolCopy), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gCopyTool, "clicked", theAccel,
                'c', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gCopyTool, FALSE);
            pasteTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TunePaste",
                "Pastes the clipboard text, replacing the selection;"
                "\n<Ctrl>V clicks this tool.",
                "Pastes the clipboard text, replacing the selection;"
                "\n<Ctrl>V clicks this tool.",
                G_CALLBACK (TuneToolPaste), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (pasteTool, "clicked", theAccel,
                'v', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (pasteTool, FALSE);
            gFindTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneFind",
                "Finds and replaces text in the Tune file;"
                "\n<Ctrl>F clicks this tool.",
                "Finds and replaces text in the Tune file;"
                "\n<Ctrl>F clicks this tool.",
                G_CALLBACK (TuneToolFind), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gFindTool, "clicked", theAccel,
                'f', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gFindTool, FALSE);
            gGoToTool = gtk_toolbar_insert_stock (GTK_TOOLBAR (theToolbar),
                "TuneGoTo",
                "Moves the cursor to the beginning of the specified line;"
                "\n<Ctrl>G clicks this tool.",
                "Moves the cursor to the beginning of the specified line;"
                "\n<Ctrl>G clicks this tool.",
                G_CALLBACK (TuneToolGoTo), (gpointer) theTextBuf, -1);
            gtk_widget_add_accelerator (gGoToTool, "clicked", theAccel,
                'g', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            gtk_widget_set_sensitive (gGoToTool, FALSE);
            gtk_timeout_add (500, TuneCheckClip, pasteTool);
            btnTips = gtk_tooltips_new ();
            compileButton = gtk_button_new_from_stock ("TuneCompileB");
            g_signal_connect (G_OBJECT (compileButton), "clicked",
                G_CALLBACK (TuneBtnCompile), NULL);
            gtk_tooltips_set_tip (btnTips, compileButton,
                "Compiles multiple specified Tune files;"
                "\n<Ctrl><Shift>M clicks this button.",
                "Compiles multiple specified Tune files;"
                "\n<Ctrl><Shift>M clicks this button.");
            gtk_widget_add_accelerator (compileButton, "activate", theAccel,
                'm', GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_ACCEL_VISIBLE);
            quitButton = gtk_button_new_from_stock ("TuneQuitB");
            g_signal_connect (G_OBJECT (quitButton), "clicked",
                G_CALLBACK (TuneQuit), (gpointer) theTextBuf);
            gtk_tooltips_set_tip (btnTips, quitButton,
                "Quits TuneToMidi;\n<Ctrl>Q clicks this button.",
                "Quits TuneToMidi;\n<Ctrl>Q clicks this button.");
            gtk_widget_add_accelerator (quitButton, "activate", theAccel,
                'q', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            theTextBuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gCompTextView));
            gtk_text_buffer_insert_at_cursor (theTextBuf,
                "TuneToMidi, version 1.2.0\n", -1);
            gtk_text_buffer_insert_at_cursor (theTextBuf,
                "Tune Language, version 1.1\n", -1);
            gtk_text_buffer_insert_at_cursor (theTextBuf,
                "Copyright (C) 2003, 2004, 2005 J. David Sexton\n", -1);
            gtk_text_buffer_insert_at_cursor (theTextBuf,
                "Some rights NOT reserved!\n", -1);
            gtk_text_buffer_insert_at_cursor (theTextBuf,
                "See the disclaimer and license in TuneToMidi.c.\n\n", -1);
            gtk_text_buffer_insert_at_cursor (theTextBuf,
                "TuneToMidi also accepts command-line arguments.\n", -1);
            gtk_text_buffer_insert_at_cursor (theTextBuf,
                "Type \"TuneToMidi -h\" at the command-line prompt\n", -1);
            gtk_text_buffer_insert_at_cursor (theTextBuf,
                "for options and examples.\n", -1);
            gtk_text_buffer_get_start_iter (theTextBuf, &theIter);
            gtk_text_view_get_iter_location (GTK_TEXT_VIEW (gCompTextView),
                &theIter, &theRect);
            gCharWidth = theRect.width;
            theTabs = pango_tab_array_new_with_positions (1, TRUE,
                PANGO_TAB_LEFT, gCharWidth * kTuneTabSpaces);
            gtk_text_view_set_tabs (GTK_TEXT_VIEW (gEditTextView), theTabs);
            gtk_text_view_set_tabs (GTK_TEXT_VIEW (gCompTextView), theTabs);
            pango_tab_array_free (theTabs);
            gtk_container_add (GTK_CONTAINER (editScrollWin), gEditTextView);
            gtk_container_add (GTK_CONTAINER (compScrollWin), gCompTextView);
            gtk_box_pack_start (GTK_BOX (eBox), theToolbar, FALSE, FALSE, 0);
            gtk_container_add (GTK_CONTAINER (eBox), editScrollWin);
            gtk_box_pack_end (GTK_BOX (eBox), theStatusBar, FALSE, FALSE, 0);
            gtk_container_add (GTK_CONTAINER (editFrame), eBox);
            gtk_container_add (GTK_CONTAINER (compFrame), compScrollWin);
            gtk_paned_add1 (GTK_PANED (theVPaned), editFrame);
            gtk_paned_add2 (GTK_PANED (theVPaned), compFrame);
            gtk_box_pack_start (GTK_BOX (hBox), quitButton, FALSE, FALSE, 0);
            gtk_box_pack_end (GTK_BOX (hBox), compileButton, FALSE, FALSE, 0);
            gtk_container_add (GTK_CONTAINER (vBox), theVPaned);
            gtk_box_pack_end (GTK_BOX (vBox), hBox, FALSE, FALSE, 0);
            gtk_container_add (GTK_CONTAINER (gWindow), vBox);
            gtk_widget_show_all (gWindow);
            gtk_window_set_focus (GTK_WINDOW (gWindow), gEditTextView);
            gtk_main ();
            return (EXIT_SUCCESS);}

/*
    TunePrintGTK must have the same prototype as printf, so we go to the
    trouble of returning the number of bytes printed, even though
    we ignore it. The little event loops force GTK to update the display
    after each print call, rather than wait for the signal handler
    to return. Continuous visual feedback is better human interface.
    Notice that gWindow, our main window, is desensitized whenever
    this function is called. TuneCompile can't be safely reentered,
    and it is impolite to have controls appear to be clickable when
    clicking them doesn't immediately produce a response.
*/

        int     TunePrintGTK (const char *theString, ...)

            {int            charsPrinted, errnoTemp;
            va_list         theVAList;
            GtkTextBuffer   *theTextBuf;
            GtkTextIter     theEnd;
            gchar           *theGString;

            errnoTemp = errno;
            va_start (theVAList, theString);
            theGString = g_strdup_vprintf (theString, theVAList);
            va_end (theVAList);
            charsPrinted = strlen ((char *) theGString);
            theTextBuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (gCompTextView));
            gtk_text_buffer_get_end_iter (theTextBuf, &theEnd);
            gtk_text_buffer_place_cursor (theTextBuf, &theEnd);
            gtk_text_buffer_insert (theTextBuf, &theEnd, theGString, -1);
            g_free (theGString);
            while (gtk_events_pending ())
                gtk_main_iteration ();
            if (gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (gCompTextView),
                    &theEnd, 0.0, FALSE, 0.0, 0.0))
                {while (gtk_events_pending ())
                    gtk_main_iteration ();}
            errno = errnoTemp;
            return (charsPrinted);}

/*  There should be a better way to do this!    */

    gboolean    TuneCheckClip (gpointer theData)

            {gchar  *clipText;

            clipText = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_NONE));
            if (clipText)
                {if (!GTK_WIDGET_SENSITIVE (GTK_WIDGET (theData)))
                    gtk_widget_set_sensitive (GTK_WIDGET (theData), TRUE);
                g_free (clipText);}
            else if (GTK_WIDGET_SENSITIVE (GTK_WIDGET (theData)))
                gtk_widget_set_sensitive (GTK_WIDGET (theData), FALSE);
            return (TRUE);}

/*
    Every line in our text views is the same height, but GTK doesn't know
    this; so we force the vertical scroll adjustments to work the way they
    should. GTK updates the adjustments at idle time, so we have to do our
    work at idle time too. Once the adjustments are right, these functions
    become very fast.
*/

    gboolean    TuneFixEditScroll (gpointer theData)

            {gint               totLines, linesPerPage;
            gdouble             newStepInc, newPageInc;
            gdouble             theRange;
            GtkTextBuffer       *theTextBuf;
            GtkScrolledWindow   *theSW;
            GtkAdjustment       *theAdj;

            theTextBuf =
                gtk_text_view_get_buffer (GTK_TEXT_VIEW (gEditTextView));
            totLines = gtk_text_buffer_get_line_count (theTextBuf);
            if (totLines > 1)
                {theSW = GTK_SCROLLED_WINDOW (theData);
                theAdj = gtk_scrolled_window_get_vadjustment (theSW);
                theRange = theAdj->upper - theAdj->lower;
                if (theRange > theAdj->page_size)
                    {newStepInc = theRange / totLines;
                    linesPerPage = theAdj->page_size / newStepInc;
                    newPageInc = --linesPerPage * newStepInc;
                    if (newPageInc < newStepInc)
                        newPageInc = newStepInc;
                    if (theAdj->step_increment != newStepInc ||
                            theAdj->page_increment != newPageInc)
                        {theAdj->step_increment = newStepInc;
                        theAdj->page_increment = newPageInc;
                        gtk_adjustment_changed (theAdj);}}}
            return (TRUE);}

    gboolean    TuneFixCompScroll (gpointer theData)

            {gint               totLines, linesPerPage;
            gdouble             newStepInc, newPageInc;
            gdouble             theRange;
            GtkTextBuffer       *theTextBuf;
            GtkScrolledWindow   *theSW;
            GtkAdjustment       *theAdj;

            theTextBuf =
                gtk_text_view_get_buffer (GTK_TEXT_VIEW (gCompTextView));
            totLines = gtk_text_buffer_get_line_count (theTextBuf);
            if (totLines > 1)
                {theSW = GTK_SCROLLED_WINDOW (theData);
                theAdj = gtk_scrolled_window_get_vadjustment (theSW);
                theRange = theAdj->upper - theAdj->lower;
                if (theRange > theAdj->page_size)
                    {newStepInc = theRange / totLines;
                    linesPerPage = theAdj->page_size / newStepInc;
                    newPageInc = --linesPerPage * newStepInc;
                    if (newPageInc < newStepInc)
                        newPageInc = newStepInc;
                    if (theAdj->step_increment != newStepInc ||
                            theAdj->page_increment != newPageInc)
                        {theAdj->step_increment = newStepInc;
                        theAdj->page_increment = newPageInc;
                        gtk_adjustment_changed (theAdj);}}}
            return (TRUE);}

/*
    We have to do this at idle time to make sure the overwrite_mode
    field in text view is updated. Another advantage of updating
    our status bar at idle time is reducing processor load. We
    update a fixed number of times per second rather than every
    time the text buffer is changed. We also return immediately
    if no update needs to be done.
*/

    gboolean    TuneStatusBar (gpointer theData)

            {int                theChar, totChars, theLine, totLines;
            int                 theCol, totCols;
    const   char                *insOvrStr;
    const   char                insStr [] = "insert";
    const   char                ovrStr [] = "overstrike";
    const   char                *modUnmodStr;
    const   char                modStr [] = "changed";
    const   char                unmodStr [] = "unchanged";
            gchar               *theString;
            GdkRectangle        theRect;
            GtkTextBuffer       *theTextBuf;
            GtkTextIter         theIter;

            if (gUpdateStatusBar)
                {theTextBuf =
                    gtk_text_view_get_buffer (GTK_TEXT_VIEW (gEditTextView));
                gtk_text_buffer_get_iter_at_mark (theTextBuf,
                    &theIter, gtk_text_buffer_get_insert (theTextBuf));
                theLine = 1 + gtk_text_iter_get_line (&theIter);
                totLines = gtk_text_buffer_get_line_count (theTextBuf);
                gtk_text_view_get_iter_location (GTK_TEXT_VIEW (gEditTextView),
                    &theIter, &theRect);
                theCol = (theRect.x - kTuneLeftMargin) / gCharWidth;
                totCols = (GTK_TEXT_VIEW (gEditTextView)->width -
                    kTuneLeftMargin - kTuneRightMargin) / gCharWidth;
                theChar = gtk_text_iter_get_offset (&theIter);
                totChars = gtk_text_buffer_get_char_count (theTextBuf);
                if (GTK_TEXT_VIEW (gEditTextView)->overwrite_mode)
                    insOvrStr = ovrStr;
                else
                    insOvrStr = insStr;
                if (gtk_text_buffer_get_modified (theTextBuf))
                    modUnmodStr = modStr;
                else
                    modUnmodStr = unmodStr;
                if (gOpenTuneName)
                    theString = g_strdup_printf ("line %d of %d | col. %d of %d | "
                        "char. %d of %d | %s | %s | \"%s\"", theLine,
                        totLines, theCol, totCols, theChar, totChars, insOvrStr,
                        modUnmodStr, gOpenTuneName);
                else
                    theString = g_strdup_printf ("line %d of %d | col. %d of %d | "
                        "char. %d of %d | %s | %s | \"\"", theLine,
                        totLines, theCol, totCols, theChar, totChars, insOvrStr,
                        modUnmodStr);
                gtk_statusbar_pop (GTK_STATUSBAR (theData), 0);
                gtk_statusbar_push (GTK_STATUSBAR (theData), 0, theString);
                g_free (theString);
                /*  If we can't be sure that the width is updated,  */
                /*  we'll have to do this again.                    */
                if (!GTK_TEXT_VIEW (gEditTextView)->first_validate_idle &&
                        !GTK_TEXT_VIEW (gEditTextView)->incremental_validate_idle)
                    gUpdateStatusBar = FALSE;}
            return (TRUE);}

        void    TuneOverToggle (GtkTextView *theTextView, gpointer theData)

            {gUpdateStatusBar = TRUE;
            return;}

/*
    It's bad human interface to have controls appear to be clickable when
    clicking them produces no immediate response. Modal dialogs should
    disable parent windows automatically, but they don't. We also need to
    disable the controls when we're in the middle of an operation that
    can't be interrupted.
*/

        void    TuneMainSensitive (gboolean makeSensitive)

            {GtkTextBuffer  *theBuffer;
            GtkTextIter     theIns, theBound;

            if (GTK_WIDGET_SENSITIVE (gWindow) != makeSensitive)
                {theBuffer = (GtkTextBuffer *) 0;
                if (!makeSensitive)
                    gMainFocus = gtk_window_get_focus (GTK_WINDOW (gWindow));
                else if (gMainFocus == gEditTextView ||
                        gMainFocus == gCompTextView)
                    {theBuffer =
                        gtk_text_view_get_buffer (GTK_TEXT_VIEW (gMainFocus));
                    gtk_text_buffer_get_iter_at_mark (theBuffer, &theIns,
                        gtk_text_buffer_get_insert (theBuffer));
                    gtk_text_buffer_get_iter_at_mark (theBuffer, &theBound,
                        gtk_text_buffer_get_selection_bound (theBuffer));
                    gtk_text_view_place_cursor_onscreen (GTK_TEXT_VIEW (gMainFocus));}
                gtk_widget_set_sensitive (gWindow, makeSensitive);
                if (makeSensitive && gMainFocus)
                    gtk_window_set_focus (GTK_WINDOW (gWindow), gMainFocus);
                if (theBuffer)
                    {gtk_text_buffer_move_mark (theBuffer,
                        gtk_text_buffer_get_insert (theBuffer), &theIns);
                    gtk_text_buffer_move_mark (theBuffer,
                        gtk_text_buffer_get_selection_bound (theBuffer),
                        &theBound);}}
            return;}

        void    TuneToolOpen (GtkWidget *theWidget, gpointer theData)

            {GtkWidget  *fileSel;

            fileSel = gtk_file_selection_new ("Select a Tune file to Open");
            gtk_window_set_transient_for (GTK_WINDOW (fileSel), GTK_WINDOW (gWindow));
            gtk_window_set_modal (GTK_WINDOW (fileSel), TRUE);
            g_signal_connect (G_OBJECT (fileSel), "destroy",
                G_CALLBACK (TuneModalDestroyed), NULL);
            g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileSel)->ok_button),
                "clicked", G_CALLBACK (TuneOpenTune), (gpointer) fileSel);
            g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileSel)->cancel_button),
                "clicked", G_CALLBACK (TuneCloseModal), (gpointer) fileSel);
            TuneMainSensitive (FALSE);
            gtk_widget_show (fileSel);
            return;}

        void    TuneOpenTune (GtkWidget *theWidget, gpointer theData)

            {void           *theBlock;
            char            gotErr, sArrray [64];
            size_t          blockSize, theLen;
            FILE            *theFile;
    const   gchar           *theFN;
            GtkTextBuffer   *theTextBuf;
            GtkTextIter     theStart;

            theFN =
                gtk_file_selection_get_filename (GTK_FILE_SELECTION (theData));
            if (theFN)
                {gtk_widget_hide (GTK_WIDGET (theData));
                while (gtk_events_pending ())
                    gtk_main_iteration ();
                gotErr = 1;
                if (g_file_test (theFN, G_FILE_TEST_IS_DIR))
                    errno = EISDIR;
                else if ((theFile = fopen (theFN, "rb")))
                    {blockSize = 0;
                    while ((theLen = fread (sArrray, 1, sizeof (sArrray),
                            theFile)))
                        blockSize += theLen;
                    if (blockSize)
                        {rewind (theFile);
                        if ((theBlock = malloc (blockSize)))
                            {if (fread (theBlock, 1, blockSize,
                                    theFile) == blockSize)
                                {if (TuneFileValidate (theBlock, blockSize))
                                    {theTextBuf = gtk_text_view_get_buffer (
                                        GTK_TEXT_VIEW (gEditTextView));
                                    gUndoing = TRUE;
                                    gtk_text_buffer_set_text (theTextBuf,
                                        theBlock, blockSize);
                                    gUndoing = FALSE;
                                    gtk_text_buffer_get_start_iter (theTextBuf,
                                        &theStart);
                                    gtk_text_buffer_place_cursor (theTextBuf,
                                        &theStart);
                                    gtk_text_buffer_set_modified (theTextBuf,
                                        FALSE);
                                    gotErr = 0;}}
                            free (theBlock);}}
                    else
                        gotErr = 0;
                    fclose (theFile);}
                if (gotErr)
                    {TunePrint ("\n==============\n");
                    TunePrint ("\"%s\" couldn't be opened.\n", theFN);
                    if (!errno)
                        TunePrint ("It contains illegal characters.\n");
                    else
                        TunePrint ("System: \"%s\"\n", strerror (errno));
                    errno = 0;
                    TuneBeep ();
                    TunePrint ("==============\n");}
                else
                    {gOpenTuneName = g_strdup (theFN);
                    TuneScrollInsOnscreen ();
                    while (gtk_events_pending ())
                        gtk_main_iteration ();
                    gMainFocus = gEditTextView;}}
            gtk_widget_destroy (GTK_WIDGET (theData));
            return;}

    gboolean    TuneFileValidate (const void *theBlock, size_t blockSize)

            {char   theChar;
    const   char    *charPtr;
            size_t  theIndex;

            charPtr = theBlock;
            theIndex = blockSize;
            while (theIndex)
                {theChar = *(charPtr++);
                if (theChar != 0x09 && theChar != 0x0A && theChar != 0x0C &&
                        theChar != 0x0D && theChar < 0x20)
                    return (FALSE);
                --theIndex;}
            return (TRUE);}

        void    TuneToolClose (GtkWidget *theWidget, gpointer theData)

            {gint       theResp;
            GtkTextIter theStart, theEnd;
            GtkWidget   *theDialog;

            if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                {TuneMainSensitive (FALSE);
                if (gOpenTuneName)
                    theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_YES_NO,
                        "\"%s\" has been changed since it was opened. "
                        "Save the changes before closing it?",
                        gOpenTuneName);
                else
                    theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_YES_NO,
                        "Save this new Tune file before closing it?");
                gtk_dialog_add_button (GTK_DIALOG (theDialog), GTK_STOCK_CANCEL,
                    GTK_RESPONSE_CANCEL);
                gtk_dialog_set_default_response (GTK_DIALOG (theDialog),
                    GTK_RESPONSE_CANCEL);
                theResp = gtk_dialog_run (GTK_DIALOG (theDialog));
                TuneMainSensitive (TRUE);
                gtk_widget_destroy (theDialog);
                if (theResp == GTK_RESPONSE_YES)
                    {TuneToolSave (gSaveTool, theData);
                    if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                        return;}    /*  because save was cancelled  */
                else if (theResp != GTK_RESPONSE_NO)
                    return;}
            if (gOpenTuneName)
                {g_free (gOpenTuneName);
                gOpenTuneName = (gchar *) 0;}
            TuneZapUndos ();
            gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (theData), &theStart,
                &theEnd);
            if (gtk_text_iter_equal (&theStart, &theEnd))
                /*  force call to TuneEditChanged   */
                gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (theData), TRUE);
            else
                {gUndoing = TRUE;
                gtk_text_buffer_delete (GTK_TEXT_BUFFER (theData), &theStart,
                    &theEnd);
                gUndoing = FALSE;}
            gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (theData), FALSE);
            gtk_window_set_focus (GTK_WINDOW (gWindow), gEditTextView);
            return;}

        void    TuneToolRevert (GtkWidget *theWidget, gpointer theData)

            {void       *theBlock;
            char        gotErr, sArrray [64];
            size_t      blockSize, theLen;
            FILE        *theFile;
            gint        theResp;
            GtkWidget   *theDialog;
            GtkTextIter theStart, theEnd;

            TuneMainSensitive (FALSE);
            theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                GTK_BUTTONS_OK_CANCEL,
                "Throw away all the changes to \"%s\"?",
                gOpenTuneName);
            gtk_dialog_set_default_response (GTK_DIALOG (theDialog),
                GTK_RESPONSE_CANCEL);
            theResp = gtk_dialog_run (GTK_DIALOG (theDialog));
            TuneMainSensitive (TRUE);
            gtk_widget_destroy (theDialog);
            if (theResp != GTK_RESPONSE_OK)
                return;
            TuneMainSensitive (FALSE);
            gotErr = 1;
            blockSize = 0;
            theBlock = (void *) 0;
            if ((theFile = fopen (gOpenTuneName, "rb")))
                {while ((theLen = fread (sArrray, 1, sizeof (sArrray),
                        theFile)))
                    blockSize += theLen;
                if (blockSize)
                    {rewind (theFile);
                    if ((theBlock = malloc (blockSize)))
                        {if (fread (theBlock, 1, blockSize,
                                theFile) == blockSize)
                            {if (TuneFileValidate (theBlock, blockSize))
                                gotErr = 0;}}
                        if (gotErr)
                            free (theBlock);}
                else
                    gotErr = 0;
                fclose (theFile);}
            if (!gotErr)
                {gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (theData), &theStart,
                    &theEnd);
                gUndoing = TRUE;
                if (!gtk_text_iter_equal (&theStart, &theEnd))
                    gtk_text_buffer_delete (GTK_TEXT_BUFFER (theData), &theStart,
                        &theEnd);
                if (theBlock)
                    {gtk_text_buffer_insert_at_cursor (GTK_TEXT_BUFFER (theData),
                        theBlock, blockSize);
                    free (theBlock);}
                gUndoing = FALSE;
                gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER (theData),
                    &theStart);
                gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (theData),
                    &theStart);
                TuneZapUndos ();
                gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (theData), FALSE);
                TuneScrollInsOnscreen ();
                while (gtk_events_pending ())
                    gtk_main_iteration ();
                gMainFocus = gEditTextView;}
            TuneMainSensitive (TRUE);
            if (gotErr)
                {TunePrint ("\n==============\n");
                TunePrint ("\"%s\" couldn't be reverted.\n", gOpenTuneName);
                if (!errno)
                    TunePrint ("It contains illegal characters.\n");
                else
                    TunePrint ("System: \"%s\"\n", strerror (errno));
                errno = 0;
                TuneBeep ();
                TunePrint ("==============\n");}
            return;}

        void    TuneToolSave (GtkWidget *theWidget, gpointer theData)

            {if (gOpenTuneName)
                {TuneMainSensitive (FALSE);
                TuneSaveTune (GTK_TEXT_BUFFER (theData), gOpenTuneName);
                TuneMainSensitive (TRUE);}
            else
                TuneToolSaveAs (gSaveAsTool, theData);
            return;}

        void    TuneToolSaveAs (GtkWidget *theWidget, gpointer theData)

            {GtkWidget  *fileSel;

            fileSel = gtk_file_selection_new ("Specifiy a Name for the New Tune File");
            gtk_file_selection_set_filename (GTK_FILE_SELECTION (fileSel),
                gOpenTuneName);
            gtk_window_set_transient_for (GTK_WINDOW (fileSel), GTK_WINDOW (gWindow));
            gtk_window_set_modal (GTK_WINDOW (fileSel), TRUE);
            g_signal_connect (G_OBJECT (fileSel), "destroy",
                G_CALLBACK (TuneModalDestroyed), NULL);
            g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileSel)->ok_button),
                "clicked", G_CALLBACK (TuneSaveAs), (gpointer) fileSel);
            g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileSel)->cancel_button),
                "clicked", G_CALLBACK (TuneCloseModal), (gpointer) fileSel);
            TuneMainSensitive (FALSE);
            gtk_widget_show (fileSel);
            /*  This signal handler is called by other signal handlers, */
            /*  so we can't return until the file is saved or the file  */
            /*  selection dialog is cancelled. This way we can test to  */
            /*  see if the save was cancelled by looking to see if the  */
            /*  text buffer still shows changed. If it does, then the   */
            /*  whole operation (Close, Compile, etc.) is cancelled.    */
            do
                {while (gtk_events_pending ())
                    gtk_main_iteration ();}
            while (!GTK_WIDGET_SENSITIVE (gWindow));
            return;}

        void    TuneSaveAs (GtkWidget *theWidget, gpointer theData)

            {int        okToWrite;
            FILE        *theFile;
    const   gchar       *theFN;
            GtkWidget   *theDialog;

            theFN =
                gtk_file_selection_get_filename (GTK_FILE_SELECTION (theData));
            if (theFN)
                {if (g_file_test (theFN, G_FILE_TEST_IS_DIR))
                    {errno = EISDIR;
                    TunePrint ("\n==============\n");
                    TunePrint ("\"%s\" couldn't be saved.\n", theFN);
                    TunePrint ("System: \"%s\"\n", strerror (errno));
                    errno = 0;
                    TuneBeep ();
                    TunePrint ("==============\n");}
                else
                    {okToWrite = 1;
                    if ((theFile = fopen (theFN, "rb")))
                        {fclose (theFile);
                        theDialog = gtk_message_dialog_new (GTK_WINDOW (theData),
                            GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                            GTK_BUTTONS_OK_CANCEL,
                            "A file named \"%s\" already exists. Replace it?",
                            theFN);
                        gtk_dialog_set_default_response (GTK_DIALOG (theDialog),
                            GTK_RESPONSE_CANCEL);
                        if (gtk_dialog_run (GTK_DIALOG (theDialog)) != GTK_RESPONSE_OK)
                            okToWrite = 0;
                        gtk_widget_destroy (theDialog);}
                    if (okToWrite)
                        {gtk_widget_hide (GTK_WIDGET (theData));
                        if (!TuneSaveTune (gtk_text_view_get_buffer (
                                GTK_TEXT_VIEW (gEditTextView)), theFN))
                            {if (gOpenTuneName)
                                g_free (gOpenTuneName);
                            gOpenTuneName = g_strdup (theFN);}}}}
            gtk_widget_destroy (GTK_WIDGET (theData));
            return;}

        int     TuneSaveTune (GtkTextBuffer *theTextBuf,
                            const gchar *newFileName)

            {int        gotErr;
            size_t      textLen;
            FILE        *theNewFile;
            gchar       *theText;
            GtkTextIter theStart, theEnd;

            gotErr = 1;
            gtk_text_buffer_get_bounds (theTextBuf, &theStart, &theEnd);
            if ((theText = gtk_text_iter_get_slice (&theStart, &theEnd)))
                {if ((theNewFile = fopen (newFileName, "wb")))
                    {if ((textLen = strlen ((char *) theText)))
                        {if (fwrite (theText, 1, textLen,
                                theNewFile) == textLen)
                            {if (!fflush (theNewFile))
                                gotErr = 0;}}
                    else
                        gotErr = 0;
                    fclose (theNewFile);}
                g_free (theText);}
            if (gotErr)
                {TunePrint ("\n==============\n");
                TunePrint ("\"%s\" couldn't be saved.\n", newFileName);
                TunePrint ("System: \"%s\"\n", strerror (errno));
                errno = 0;
                TuneBeep ();
                TunePrint ("==============\n");}
            else
                gtk_text_buffer_set_modified (theTextBuf, FALSE);
            return (gotErr);}

        void    TuneToolCompile (GtkWidget *theWidget, gpointer theData)

            {gint       theResp;
            GtkWidget   *theDialog;

            if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                {TuneMainSensitive (FALSE);
                if (gOpenTuneName)
                    {theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_YES_NO,
                        "When TuneToMidi compiles a Tune file, it reads "
                        "from the file saved on the disk. "
                        "\"%s\" has been changed since it was opened. "
                        "Save the changes before compiling it?",
                        gOpenTuneName);
                    gtk_dialog_add_button (GTK_DIALOG (theDialog),
                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);}
                else
                    theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_OK_CANCEL,
                        "When TuneToMidi compiles a Tune file, it reads "
                        "from the file saved on the disk. This new Tune can't "
                        "be compiled until it's saved to a disk. "
                        "Save this new Tune file and then compile it?");
                gtk_dialog_set_default_response (GTK_DIALOG (theDialog),
                    GTK_RESPONSE_CANCEL);
                theResp = gtk_dialog_run (GTK_DIALOG (theDialog));
                TuneMainSensitive (TRUE);
                gtk_widget_destroy (theDialog);
                if (theResp == GTK_RESPONSE_YES || theResp == GTK_RESPONSE_OK)
                    {TuneToolSave (gSaveTool, theData);
                    if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                        return;}    /*  because save was cancelled  */
                else if (theResp != GTK_RESPONSE_NO)
                    return;}
            /*  The 2 gtk_widget_set_sensitive calls work around an */
            /*  odd cosmetic bug in at least 1 version of GTK.  */
            gtk_widget_set_sensitive (theWidget, FALSE);
            TuneMainSensitive (FALSE);
            TunePrint ("\n");
            TuneCompile (0, 1, &gOpenTuneName);
            errno = 0;
            TuneMainSensitive (TRUE);
            gtk_widget_set_sensitive (theWidget, TRUE);
            return;}

        void    TuneToolPlay (GtkWidget *theWidget, gpointer theData)

            {size_t     theLen, midNameIdx;
            gchar       *midiName, *rootName, **theArgs;
            gint        theResp;
            GError      *theError;
            GtkWidget   *theDialog;
#if TUNE_PLAY_SYNCH
            char        theChars [201];
            gint        outStream, errStream;
#endif

            if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                {TuneMainSensitive (FALSE);
                if (gOpenTuneName)
                    {theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_YES_NO,
                        "When TuneToMidi compiles a Tune file, it reads "
                        "from the file saved on the disk. "
                        "\"%s\" has been changed since it was opened. "
                        "Save the changes before compiling and playing it?",
                        gOpenTuneName);
                    gtk_dialog_add_button (GTK_DIALOG (theDialog),
                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);}
                else
                    theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_OK_CANCEL,
                        "When TuneToMidi compiles a Tune file, it reads "
                        "from the file saved on the disk. This new Tune can't "
                        "be compiled until it's saved to a disk. "
                        "Save this new Tune file and then compile and play it?");
                gtk_dialog_set_default_response (GTK_DIALOG (theDialog),
                    GTK_RESPONSE_CANCEL);
                theResp = gtk_dialog_run (GTK_DIALOG (theDialog));
                TuneMainSensitive (TRUE);
                gtk_widget_destroy (theDialog);
                if (theResp == GTK_RESPONSE_YES || theResp == GTK_RESPONSE_OK)
                    {TuneToolSave (gSaveTool, theData);
                    if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                        return;}    /*  because save was cancelled  */
                else if (theResp != GTK_RESPONSE_NO)
                    return;}
            /*  The 2 gtk_widget_set_sensitive calls work around an */
            /*  odd cosmetic bug in at least 1 version of GTK.  */
            gtk_widget_set_sensitive (theWidget, FALSE);
            TuneMainSensitive (FALSE);
            TunePrint ("\n");
            if (TuneCompile (0, 1, &gOpenTuneName) == EXIT_SUCCESS)
                {theLen = strlen (gOpenTuneName);
                do
                    {--theLen;
                    if (!ISALPHNUM (gOpenTuneName [theLen]))
                        break;}
                while (theLen);
                if (gOpenTuneName [theLen] != '.')
                    theLen = strlen (gOpenTuneName);
                rootName = g_strndup (gOpenTuneName, theLen);
                midiName = g_strconcat (rootName, ".mid", NULL);
                g_free (rootName);
                TunePrint ("Playing \"%s\"\n", midiName);
                /*  We copy gTunePlayLine because it's (const gchar **),    */
                /*  but the argument in the prototype for g_spawn_async     */
                /*  isn't. Neither is the argument for g_strdupv, but       */
                /*  we'll trust it. */
                midNameIdx = (sizeof (gTunePlayLine) / sizeof (gchar *)) - 2;
                gTunePlayLine [midNameIdx] = midiName;
                theArgs = g_strdupv ((gchar **) gTunePlayLine);
                gTunePlayLine [midNameIdx] = NULL;
                theError = NULL;
#if TUNE_PLAY_SYNCH
                if (g_spawn_async_with_pipes (NULL, theArgs, NULL, 0, NULL, NULL,
                        NULL, NULL, &outStream, &errStream, &theError))
                    {while ((theLen = read (outStream, &theChars,
                            sizeof (theChars) - 1)))
                        {theChars [theLen] = '\0';
                        TunePrint ("%s", theChars);}
                    close (outStream);
                    while ((theLen = read (errStream, &theChars,
                            sizeof (theChars) - 1)))
                        {theChars [theLen] = '\0';
                        TunePrint ("%s", theChars);}
                    close (errStream);}
                else
#else
                if (!g_spawn_async (NULL, theArgs, NULL, 0, NULL, NULL,
                        NULL, &theError))
#endif
                    {TunePrint ("\n\"%s\" couldn't be played.\n", midiName);
                    TunePrint ("System: \"%s\"\n", theError->message);
                    g_error_free (theError);
                    TuneBeep ();}
                g_strfreev (theArgs);
                g_free (midiName);
                TunePrint ("==============\n");}
            else
                errno = 0;
            TuneMainSensitive (TRUE);
            gtk_widget_set_sensitive (theWidget, TRUE);
            return;}

        void    TuneToolPrint (GtkWidget *theWidget, gpointer theData)

            {size_t     ptrNameIdx;
            gchar       **theArgs;
            gint        theResp;
            GError      *theError;
            GtkWidget   *theDialog;
#if TUNE_PRINT_SYNCH
            size_t      theLen;
            char        theChars [201];
            gint        outStream, errStream;
#endif

            if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                {TuneMainSensitive (FALSE);
                if (gOpenTuneName)
                    {theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_YES_NO,
                        "When TuneToMidi prints a Tune file, it reads "
                        "from the file saved on the disk. "
                        "\"%s\" has been changed since it was opened. "
                        "Save the changes before printing it?",
                        gOpenTuneName);
                    gtk_dialog_add_button (GTK_DIALOG (theDialog),
                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);}
                else
                    theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_OK_CANCEL,
                        "When TuneToMidi prints a Tune file, it reads "
                        "from the file saved on the disk. This new Tune can't "
                        "be printed until it's saved to a disk. "
                        "Save this new Tune file and then print it?");
                gtk_dialog_set_default_response (GTK_DIALOG (theDialog),
                    GTK_RESPONSE_CANCEL);
                theResp = gtk_dialog_run (GTK_DIALOG (theDialog));
                TuneMainSensitive (TRUE);
                gtk_widget_destroy (theDialog);
                if (theResp == GTK_RESPONSE_YES || theResp == GTK_RESPONSE_OK)
                    {TuneToolSave (gSaveTool, theData);
                    if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                        return;}    /*  because save was cancelled  */
                else if (theResp != GTK_RESPONSE_NO)
                    return;}
            /*  The 2 gtk_widget_set_sensitive calls work around an */
            /*  odd cosmetic bug in at least 1 version of GTK.      */
            gtk_widget_set_sensitive (theWidget, FALSE);
            TuneMainSensitive (FALSE);
            TunePrint ("\n==============\n");
            TunePrint ("Printing \"%s\"\n", gOpenTuneName);
            /*  We copy gTunePrintLine because it's (const gchar **),   */
            /*  but the argument in the prototype for g_spawn_async     */
            /*  isn't. Neither is the argument for g_strdupv, but       */
            /*  we'll trust it. */
            ptrNameIdx = (sizeof (gTunePrintLine) / sizeof (gchar *)) - 2;
            gTunePrintLine [ptrNameIdx] = gOpenTuneName;
            theArgs = g_strdupv ((gchar **) gTunePrintLine);
            gTunePrintLine [ptrNameIdx] = NULL;
            theError = NULL;
#if TUNE_PRINT_SYNCH
            if (g_spawn_async_with_pipes (NULL, theArgs, NULL, 0, NULL, NULL,
                    NULL, NULL, &outStream, &errStream, &theError))
                {while ((theLen = read (outStream, &theChars,
                        sizeof (theChars) - 1)))
                    {theChars [theLen] = '\0';
                    TunePrint ("%s", theChars);}
                close (outStream);
                while ((theLen = read (errStream, &theChars,
                        sizeof (theChars) - 1)))
                    {theChars [theLen] = '\0';
                    TunePrint ("%s", theChars);}
                close (errStream);}
            else
#else
            if (!g_spawn_async (NULL, theArgs, NULL, 0, NULL, NULL,
                    NULL, &theError))
#endif
                {TunePrint ("\n\"%s\" couldn't be printed.\n", gOpenTuneName);
                TunePrint ("System: \"%s\"\n", theError->message);
                g_error_free (theError);
                TuneBeep ();}
            g_strfreev (theArgs);
            TunePrint ("==============\n");
            TuneMainSensitive (TRUE);
            gtk_widget_set_sensitive (theWidget, TRUE);
            return;}

        void    TuneToolUndo (GtkWidget *theWidget, gpointer theData)

            {GtkTextIter    theStart, theEnd;

            gUndoing = TRUE;
            --gNumUndos;
            gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (theData),
                &theStart, gEditStart [gUndoIdx]);
            gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (theData),
                &theStart);
            if (gEditStart [gUndoIdx] != gEditEnd [gUndoIdx])
                {gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (theData),
                    &theEnd, gEditEnd [gUndoIdx]);
                gtk_text_buffer_delete (GTK_TEXT_BUFFER (theData), &theStart,
                    &theEnd);}
            if (gDelString [gUndoIdx])
                {gtk_text_buffer_insert_at_cursor (GTK_TEXT_BUFFER (theData),
                    gDelString [gUndoIdx], -1);
                g_free (gDelString [gUndoIdx]);
                if (gCursAtStart [gUndoIdx])
                    {gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (theData),
                        &theStart, gEditStart [gUndoIdx]);
                    gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (theData),
                        &theStart);}}
            TuneScrollInsOnscreen ();
            if (!gUndoIdx)
                gUndoIdx = kTuneUndoMax - 1;
            else
                --gUndoIdx;
            gUndoing = FALSE;
            gtk_window_set_focus (GTK_WINDOW (gWindow), gEditTextView);
            return;}

        void    TuneToolCut (GtkWidget *theWidget, gpointer theData)

            {gtk_text_buffer_cut_clipboard (GTK_TEXT_BUFFER (theData),
                gtk_clipboard_get (GDK_NONE), TRUE);
            gtk_window_set_focus (GTK_WINDOW (gWindow), gEditTextView);
            return;}

        void    TuneToolCopy (GtkWidget *theWidget, gpointer theData)

            {gtk_text_buffer_copy_clipboard (GTK_TEXT_BUFFER (theData),
                gtk_clipboard_get (GDK_NONE));
            gtk_window_set_focus (GTK_WINDOW (gWindow), gEditTextView);
            return;}

        void    TuneToolPaste (GtkWidget *theWidget, gpointer theData)

            {gchar  *clipText;

            /*  This works around bugs in gtk_text_buffer_paste_clipboard.  */
            clipText = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_NONE));
            if (clipText)
                {gtk_text_buffer_delete_selection (GTK_TEXT_BUFFER (theData),
                    TRUE, TRUE);
                gtk_text_buffer_insert_at_cursor (GTK_TEXT_BUFFER (theData),
                    clipText, -1);
                g_free (clipText);
                TuneScrollInsOnscreen ();
                gtk_window_set_focus (GTK_WINDOW (gWindow), gEditTextView);}
            return;}

        void    TuneToolFind (GtkWidget *theWidget, gpointer theData)

            {GtkWidget              *theDialog, *vBox, *bBox, *hBox;
            GtkWidget               *fFrame, *rFrame, *fSW, *rSW;
            GtkWidget               *fText, *rText;
            GtkWidget               *closeBtn;
            GtkAccelGroup           *theAccel;
            GtkTextIter             theStart, theEnd;
            PangoFontDescription    *theFont;
            PangoTabArray           *theTabs;
            guint                   theKey;
            GdkModifierType         theMod;

            theDialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
            gtk_window_set_default_size (GTK_WINDOW (theDialog), 450, 200);
            gtk_window_set_title (GTK_WINDOW (theDialog),
                "Find and Replace");
            gtk_container_set_border_width (GTK_CONTAINER (theDialog), 8);
            gtk_window_set_transient_for (GTK_WINDOW (theDialog),
                GTK_WINDOW (gWindow));
            gtk_window_set_position (GTK_WINDOW (theDialog),
                GTK_WIN_POS_CENTER_ON_PARENT);
            gtk_window_set_modal (GTK_WINDOW (theDialog), TRUE);
            g_signal_connect (G_OBJECT (theDialog), "destroy",
                G_CALLBACK (TuneModalDestroyed), NULL);
            theAccel = gtk_accel_group_new ();
            gtk_window_add_accel_group (GTK_WINDOW (theDialog), theAccel);
            fFrame = gtk_frame_new ("Find Text");
            rFrame = gtk_frame_new ("Replace Text");
            fSW = gtk_scrolled_window_new (NULL, NULL);
            rSW = gtk_scrolled_window_new (NULL, NULL);
            gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (fSW),
                GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
            gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (rSW),
                GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
            fText = gtk_text_view_new ();
            rText = gtk_text_view_new ();
            gtk_text_view_set_editable (GTK_TEXT_VIEW (fText), TRUE);
            gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (fText),
                GTK_WRAP_NONE);
            gtk_text_view_set_editable (GTK_TEXT_VIEW (rText), TRUE);
            gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (rText),
                GTK_WRAP_NONE);
            theFont = pango_font_description_from_string ("Monospace");
            gtk_widget_modify_font (fText, theFont);
            gtk_widget_modify_font (rText, theFont);
            pango_font_description_free (theFont);
            theTabs = pango_tab_array_new_with_positions (1, TRUE,
                PANGO_TAB_LEFT, gCharWidth * kTuneTabSpaces);
            gtk_text_view_set_tabs (GTK_TEXT_VIEW (fText), theTabs);
            gtk_text_view_set_tabs (GTK_TEXT_VIEW (rText), theTabs);
            pango_tab_array_free (theTabs);
            gtk_text_view_set_left_margin (GTK_TEXT_VIEW (fText),
                kTuneLeftMargin);
            gtk_text_view_set_right_margin (GTK_TEXT_VIEW (fText),
                kTuneRightMargin);
            gtk_text_view_set_left_margin (GTK_TEXT_VIEW (rText),
                kTuneLeftMargin);
            gtk_text_view_set_right_margin (GTK_TEXT_VIEW (rText),
                kTuneRightMargin);
            gFindTextBuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (fText));
            gReplTextBuf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (rText));
            vBox = gtk_vbox_new (FALSE, 8);
            bBox = gtk_hbox_new (FALSE, 8);
            hBox = gtk_hbox_new (FALSE, 8);
            gWordBtn = gtk_check_button_new_with_label ("Whole Words Only");
            gCaseBtn = gtk_check_button_new_with_label ("Case Insensitive");
            closeBtn = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
            gtk_accelerator_parse ("Escape", &theKey, &theMod);
            gtk_widget_add_accelerator (closeBtn, "activate", theAccel,
                theKey, theMod, GTK_ACCEL_VISIBLE);
            g_signal_connect (GTK_OBJECT (closeBtn), "clicked",
                G_CALLBACK (TuneCloseModal), (gpointer) theDialog);
            gFindBtn = gtk_button_new_from_stock (GTK_STOCK_FIND);
            gtk_widget_add_accelerator (gFindBtn, "activate", theAccel,
                'f', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            g_signal_connect (GTK_OBJECT (gFindBtn), "clicked",
                G_CALLBACK (TuneFindBtn), NULL);
            gReplFindBtn = gtk_button_new_from_stock ("TuneReplFindB");
            gtk_widget_add_accelerator (gReplFindBtn, "activate", theAccel,
                'r', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            g_signal_connect (GTK_OBJECT (gReplFindBtn), "clicked",
                G_CALLBACK (TuneReplFindBtn), NULL);
            gReplaceBtn = gtk_button_new_from_stock ("TuneReplaceB");
            g_signal_connect (GTK_OBJECT (gReplaceBtn), "clicked",
                G_CALLBACK (TuneReplaceBtn), NULL);
            gReplaceAllBtn = gtk_button_new_from_stock ("TuneReplAllB");
            gtk_widget_add_accelerator (gReplaceAllBtn, "activate", theAccel,
                'a', GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
            g_signal_connect (GTK_OBJECT (gReplaceAllBtn), "clicked",
                G_CALLBACK (TuneReplAllBtn), NULL);
            if (gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (theData),
                    &theStart, &theEnd))
                {if (gFindText)
                    g_free (gFindText);
                gFindText = gtk_text_iter_get_slice (&theStart, &theEnd);
                gWholeWord = TuneIsWholeWord (&theStart, &theEnd);
                gCaseIns = FALSE;
                gFoundOne = TRUE;}
            else
                {gtk_widget_set_sensitive (gFindBtn, FALSE);
                gtk_widget_set_sensitive (gReplFindBtn, FALSE);
                gtk_widget_set_sensitive (gReplaceBtn, FALSE);
                gtk_widget_set_sensitive (gReplaceAllBtn, FALSE);
                gFoundOne = FALSE;}
            if (gFindText)
                {gtk_text_buffer_insert_at_cursor (gFindTextBuf, gFindText, -1);
                gtk_text_buffer_set_modified (gFindTextBuf, FALSE);}
            if (gReplText)
                {gtk_text_buffer_insert_at_cursor (gReplTextBuf, gReplText, -1);
                gtk_text_buffer_set_modified (gReplTextBuf, FALSE);}
            if (gWholeWord)
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gWordBtn),
                    TRUE);
            if (gCaseIns)
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gCaseBtn),
                    TRUE);
            g_signal_connect_object (G_OBJECT (gWordBtn), "toggled",
                G_CALLBACK (TuneWordCaseBtns), NULL, 0);
            g_signal_connect_object (G_OBJECT (gCaseBtn), "toggled",
                G_CALLBACK (TuneWordCaseBtns), NULL, 0);
            g_signal_connect_object (G_OBJECT (gFindTextBuf), "changed",
                G_CALLBACK (TuneFTextChanged), NULL, 0);
            g_signal_connect_object (G_OBJECT (gReplTextBuf), "changed",
                G_CALLBACK (TuneRTextChanged), NULL, 0);
            g_signal_connect_object (G_OBJECT (gFindTextBuf), "mark_set",
                G_CALLBACK (TuneFindMark), NULL, 0);
            g_signal_connect_object (G_OBJECT (gReplTextBuf), "mark_set",
                G_CALLBACK (TuneReplMark), NULL, 0);
            gtk_container_add (GTK_CONTAINER (fSW), fText);
            gtk_container_add (GTK_CONTAINER (rSW), rText);
            gtk_container_add (GTK_CONTAINER (fFrame), fSW);
            gtk_container_add (GTK_CONTAINER (rFrame), rSW);
            gtk_container_add (GTK_CONTAINER (hBox), gCaseBtn);
            gtk_container_add (GTK_CONTAINER (hBox), gWordBtn);
            gtk_box_pack_end (GTK_BOX (bBox), closeBtn, FALSE, FALSE, 0);
            gtk_box_pack_end (GTK_BOX (bBox), gFindBtn, FALSE, FALSE, 0);
            gtk_box_pack_end (GTK_BOX (bBox), gReplFindBtn, FALSE, FALSE, 0);
            gtk_box_pack_end (GTK_BOX (bBox), gReplaceBtn, FALSE, FALSE, 0);
            gtk_box_pack_end (GTK_BOX (bBox), gReplaceAllBtn, FALSE, FALSE, 0);
            gtk_container_add (GTK_CONTAINER (vBox), fFrame);
            gtk_container_add (GTK_CONTAINER (vBox), rFrame);
            gtk_box_pack_end (GTK_BOX (vBox), bBox, FALSE, FALSE, 0);
            gtk_box_pack_end (GTK_BOX (vBox), hBox, FALSE, FALSE, 0);
            gtk_container_add (GTK_CONTAINER (theDialog), vBox);
            TuneMainSensitive (FALSE);
            if (gFoundOne)
                gtk_window_set_focus (GTK_WINDOW (theDialog), rText);
            else
                gtk_window_set_focus (GTK_WINDOW (theDialog), fText);
            gtk_widget_show_all (theDialog);
            return;}

        void    TuneReplMark (GtkTextBuffer *theTextBuf, const GtkTextIter *theIter,
                            GtkTextMark *theMark, gpointer theData)

            {TuneFTextChanged (gFindTextBuf, theData);
            return;}

        void    TuneRTextChanged (GtkTextBuffer *theTextBuf, gpointer theData)

            {GtkTextIter    theStart, theEnd;

            gtk_text_buffer_get_bounds (gReplTextBuf, &theStart, &theEnd);
            if (gReplText)
                g_free (gReplText);
            if (gtk_text_iter_equal (&theStart, &theEnd))
                gReplText = (gchar *) 0;
            else
                gReplText = gtk_text_iter_get_slice (&theStart, &theEnd);
            TuneFTextChanged (gFindTextBuf, theData);
            return;}

        void    TuneFindMark (GtkTextBuffer *theTextBuf, const GtkTextIter *theIter,
                            GtkTextMark *theMark, gpointer theData)

            {TuneFTextChanged (theTextBuf, theData);
            return;}

        void    TuneFTextChanged (GtkTextBuffer *theTextBuf, gpointer theData)

            {GtkTextBuffer  *editTextBuf;
            GtkTextIter     theStart, theEnd;
            gchar           *foundText;
            int             theCmp;

            gFoundOne = FALSE;
            if (gFindText)
                g_free (gFindText);
            gtk_text_buffer_get_bounds (theTextBuf, &theStart, &theEnd);
            if (gtk_text_iter_equal (&theStart, &theEnd))
                {if (GTK_WIDGET_SENSITIVE (gFindBtn))
                    gtk_widget_set_sensitive (gFindBtn, FALSE);
                if (GTK_WIDGET_SENSITIVE (gReplaceAllBtn))
                    gtk_widget_set_sensitive (gReplaceAllBtn, FALSE);
                gFindText = (gchar *) 0;}
            else
                {if (!GTK_WIDGET_SENSITIVE (gFindBtn))
                    gtk_widget_set_sensitive (gFindBtn, TRUE);
                if (!GTK_WIDGET_SENSITIVE (gReplaceAllBtn))
                    gtk_widget_set_sensitive (gReplaceAllBtn, TRUE);
                gFindText = gtk_text_iter_get_slice (&theStart, &theEnd);
                editTextBuf =
                    gtk_text_view_get_buffer (GTK_TEXT_VIEW (gEditTextView));
                if (gtk_text_buffer_get_selection_bounds (editTextBuf, &theStart,
                        &theEnd))
                    {foundText = gtk_text_iter_get_slice (&theStart, &theEnd);
                    if (gCaseIns)
                        theCmp = TuneCIStringsEqual (gFindText, foundText);
                    else
                        theCmp = StringsEqual (gFindText, foundText);
                    if (theCmp)
                        {if (gWholeWord)
                            gFoundOne = TuneIsWholeWord (&theStart, &theEnd);
                        else
                            gFoundOne = TRUE;}
                    g_free (foundText);}}
            TuneFixReplBtns ();
            return;}

        void    TuneFixReplBtns (void)

            {if (GTK_WIDGET_SENSITIVE (gReplFindBtn) != gFoundOne)
                gtk_widget_set_sensitive (gReplFindBtn, gFoundOne);
            if (GTK_WIDGET_SENSITIVE (gReplaceBtn) != gFoundOne)
                gtk_widget_set_sensitive (gReplaceBtn, gFoundOne);
            return;}

        void    TuneWordCaseBtns (GtkToggleButton *theButton)

            {TuneFTextChanged (gFindTextBuf, NULL);
            gWholeWord =
                gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gWordBtn));
            gCaseIns =
                gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gCaseBtn));
            return;}

        void    TuneFindBtn (GtkWidget *theWidget, gpointer theData)

            {TuneFind ();
            if (gFoundOne)
                TuneScrollInsOnscreen ();
            TuneFixReplBtns ();
            return;}

        void    TuneReplFindBtn (GtkWidget *theWidget, gpointer theData)

            {TuneReplace ();
            TuneFind ();
            TuneScrollInsOnscreen ();
            TuneFixReplBtns ();
            return;}

        void    TuneReplaceBtn (GtkWidget *theWidget, gpointer theData)

            {TuneReplace ();
            TuneScrollInsOnscreen ();
            gFoundOne = FALSE;
            TuneFixReplBtns ();
            return;}

        void    TuneReplAllBtn (GtkWidget *theWidget, gpointer theData)

            {GtkTextBuffer  *theTextBuf;
            GtkTextIter     theStart, theEnd, markIter;
            GtkTextMark     *theMark;

            if (!gFoundOne)
                TuneFind ();
            theTextBuf =
                gtk_text_view_get_buffer (GTK_TEXT_VIEW (gEditTextView));
            gtk_text_buffer_get_selection_bounds (theTextBuf, &theStart,
                &theEnd);
            theMark = gtk_text_buffer_create_mark (theTextBuf, NULL,
                &theEnd, FALSE);
            while (gFoundOne)
                {TuneReplace ();
                TuneFind ();
                gtk_text_buffer_get_selection_bounds (theTextBuf,
                    &theStart, &theEnd);
                gtk_text_buffer_get_iter_at_mark (theTextBuf, &markIter,
                    theMark);
                if (gtk_text_iter_get_offset (&theEnd) ==
                        gtk_text_iter_get_offset (&markIter))
                    break;}
            gtk_text_buffer_delete_mark (theTextBuf, theMark);
            TuneScrollInsOnscreen ();
            TuneFixReplBtns ();
            return;}

        void    TuneFind (void)

            {GtkTextBuffer  *theTextBuf;
            GtkTextIter     searchStart, theStart, theEnd;

            gFoundOne = TRUE;
            theTextBuf =
                gtk_text_view_get_buffer (GTK_TEXT_VIEW (gEditTextView));
            gtk_text_buffer_get_selection_bounds (theTextBuf, &theStart,
                &searchStart);
            if (!TuneFindForward (&searchStart, &theStart, &theEnd))
                {gtk_text_buffer_get_bounds (theTextBuf, &searchStart,
                    &theEnd);
                if (!TuneFindForward (&searchStart, &theStart, &theEnd))
                    {gtk_widget_set_sensitive (gFindBtn, FALSE);
                    gtk_widget_set_sensitive (gReplaceAllBtn, FALSE);
                    gFoundOne = FALSE;}}
            if (gFoundOne)
                {gtk_text_buffer_move_mark (theTextBuf,
                    gtk_text_buffer_get_selection_bound (theTextBuf),
                    &theStart);
                gtk_text_buffer_move_mark (theTextBuf,
                    gtk_text_buffer_get_insert (theTextBuf), &theEnd);}
            return;}

    gboolean    TuneFindForward (GtkTextIter *searchStart,
                            GtkTextIter *theStart, GtkTextIter *theEnd)

            {gboolean   gotOne;

            for (;;)
                {if (gCaseIns)
                    gotOne = TuneCaseInsensFindFwd (searchStart, theStart,
                        theEnd);
                else
                    gotOne = gtk_text_iter_forward_search (searchStart,
                        gFindText, 0, theStart, theEnd, NULL);
                if (!gotOne || !gWholeWord)
                    break;
                if (TuneIsWholeWord (theStart, theEnd))
                    break;
                *searchStart = *theEnd;}
            return (gotOne);}

    gboolean    TuneCaseInsensFindFwd (GtkTextIter *searchStart,
                            GtkTextIter *theStart, GtkTextIter *theEnd)

            {char       *ptrA, *ptrB;
            size_t      charLen, textLen, theIndex;
            gchar       *foundText, *nextChar;
            glong       findChars;
            gboolean    gotOne;
            GtkTextIter iterA, iterB;

            findChars = g_utf8_strlen (gFindText, -1);
            iterA = iterB = *searchStart;
            if (!gtk_text_iter_forward_chars (&iterB, findChars))
                return (FALSE);
            foundText = gtk_text_iter_get_slice (&iterA, &iterB);
            textLen = strlen (foundText);
            for (;;)
                {if ((gotOne = TuneCIStringsEqual (gFindText, foundText)))
                    break;
                iterA = iterB;
                if (!gtk_text_iter_forward_char (&iterB))
                    break;
                nextChar = gtk_text_iter_get_slice (&iterA, &iterB);
                charLen = strlen (nextChar);
                ptrA = (char *) foundText;
                if ((theIndex = textLen - charLen))
                    {ptrB = ptrA + charLen;
                    do
                        *(ptrA++) = *(ptrB++);
                    while (--theIndex);}
                ptrB = (char *) nextChar;
                theIndex = charLen;
                do
                    *(ptrA++) = *(ptrB++);
                while (--theIndex);
                g_free (nextChar);}
            g_free (foundText);
            if (gotOne)
                {*theStart = *theEnd = iterB;
                gtk_text_iter_backward_chars (theStart, findChars);}
            return (gotOne);}

    gboolean    TuneIsWholeWord (const GtkTextIter *theStart,
                            const GtkTextIter *theEnd)

            {GtkTextIter    theIter;
            gchar           *theChar;
            gboolean        gotOne;

            /*  Our rule is that any contiguous string of alphanumeric  */
            /*  ASCII characters is a word. This is appropriate for     */
            /*  languages like C and the Tune Language.                 */
            /*  gtk_text_iter_starts_word and gtk_text_iter_ends_word   */
            /*  do not follow this rule.                                */
            gotOne = TRUE;
            if (ISALPHNUM (gFindText [0]))
                {theIter = *theStart;
                if (gtk_text_iter_backward_char (&theIter))
                    {theChar = gtk_text_iter_get_slice (&theIter,
                        theStart);
                    if (ISALPHNUM (theChar [0]))
                        gotOne = FALSE;
                    g_free (theChar);}}
            if (gotOne &&
                    ISALPHNUM (g_utf8_offset_to_pointer (gFindText,
                    g_utf8_strlen (gFindText, -1) - 1) [0]))
                {theIter = *theEnd;
                if (gtk_text_iter_forward_char (&theIter))
                    {theChar = gtk_text_iter_get_slice (theEnd,
                        &theIter);
                    if (ISALPHNUM (theChar [0]))
                        gotOne = FALSE;
                    g_free (theChar);}}
            return (gotOne);}

/*
    This function MAY be slightly more efficient than the G Library
    function. Note that this ignores the locale.
*/

        int     TuneCIStringsEqual (const char *stringA, const char *stringB)

            {char   byteA, byteB;
    const   char    *ptrA, *ptrB;

            ptrA = stringA;
            ptrB = stringB;
            do
                {if (!(byteA = *(ptrA++)))
                    return (!(*ptrB));
                if (!(byteB = *(ptrB++)))
                    break;
                if (byteA == byteB)
                    continue;
                if (byteA >= 'A')
                    {if (byteA <= 'Z')
                        byteA += 'a' - 'A';
                    else if (byteA >= 'a')
                        {if (byteA <= 'z')
                            byteA -= 'a' - 'A';
                        else
                            break;}
                    else
                        break;}
                else
                    break;}
            while (byteA == byteB);
            return (0);}

        void    TuneReplace (void)

            {GtkTextBuffer  *theTextBuf;

            theTextBuf =
                gtk_text_view_get_buffer (GTK_TEXT_VIEW (gEditTextView));
            gtk_text_buffer_delete_selection (theTextBuf, TRUE, TRUE);
            if (gReplText)
                gtk_text_buffer_insert_at_cursor (theTextBuf, gReplText, -1);
            return;}
            
        void    TuneToolGoTo (GtkWidget *theWidget, gpointer theData)

            {GtkWidget      *theDialog, *vBox, *bBoxA, *bBoxB;
            GtkWidget       *okBtn, *canBtn;
            GtkAccelGroup   *theAccel;
            guint           theKey;
            GtkTextIter     theIt;
            GdkModifierType theMod;

            theDialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
            gtk_widget_set_size_request (theDialog, 250, 100);
            gtk_window_set_title (GTK_WINDOW (theDialog),
                "Select the Line to Go to");
            gtk_container_set_border_width (GTK_CONTAINER (theDialog), 8);
            gtk_window_set_transient_for (GTK_WINDOW (theDialog),
                GTK_WINDOW (gWindow));
            gtk_window_set_position (GTK_WINDOW (theDialog),
                GTK_WIN_POS_CENTER_ON_PARENT);
            gtk_window_set_modal (GTK_WINDOW (theDialog), TRUE);
            g_signal_connect (G_OBJECT (theDialog), "destroy",
                G_CALLBACK (TuneModalDestroyed), NULL);
            theAccel = gtk_accel_group_new ();
            gtk_window_add_accel_group (GTK_WINDOW (theDialog), theAccel);
            vBox = gtk_vbox_new (FALSE, 8);
            bBoxA = gtk_hbutton_box_new ();
            gtk_button_box_set_layout (GTK_BUTTON_BOX (bBoxA),
                GTK_BUTTONBOX_SPREAD);
            gtk_box_set_spacing (GTK_BOX (bBoxA), 16);
            bBoxB = gtk_hbutton_box_new ();
            gtk_button_box_set_layout (GTK_BUTTON_BOX (bBoxB),
                GTK_BUTTONBOX_END);
            gtk_box_set_spacing (GTK_BOX (bBoxB), 16);
            okBtn = gtk_button_new_from_stock (GTK_STOCK_OK);
            gtk_accelerator_parse ("KP_Enter", &theKey, &theMod);
            gtk_widget_add_accelerator (okBtn, "activate", theAccel,
                theKey, theMod, GTK_ACCEL_VISIBLE);
            gtk_accelerator_parse ("Return", &theKey, &theMod);
            gtk_widget_add_accelerator (okBtn, "activate", theAccel,
                theKey, theMod, GTK_ACCEL_VISIBLE);
            g_signal_connect (GTK_OBJECT (okBtn), "clicked",
                G_CALLBACK (TuneGoToLine), (gpointer) theDialog);
            canBtn = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
            gtk_accelerator_parse ("Escape", &theKey, &theMod);
            gtk_widget_add_accelerator (canBtn, "activate", theAccel,
                theKey, theMod, GTK_ACCEL_VISIBLE);
            g_signal_connect (GTK_OBJECT (canBtn), "clicked",
                G_CALLBACK (TuneCloseModal), (gpointer) theDialog);
            gSpinBtn = GTK_SPIN_BUTTON (gtk_spin_button_new_with_range (1.0,
                gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (theData)),
                1.0));
            gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (theData), &theIt,
                gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (theData)));
            gtk_spin_button_set_value (gSpinBtn,
                1.0 + gtk_text_iter_get_line (&theIt));
            gtk_container_add (GTK_CONTAINER (bBoxB), canBtn);
            gtk_container_add (GTK_CONTAINER (bBoxB), okBtn);
            gtk_container_add (GTK_CONTAINER (bBoxA), GTK_WIDGET (gSpinBtn));
            gtk_container_add (GTK_CONTAINER (vBox), bBoxA);
            gtk_box_pack_end (GTK_BOX (vBox), bBoxB, FALSE, FALSE, 0);
            gtk_container_add (GTK_CONTAINER (theDialog), vBox);
            TuneMainSensitive (FALSE);
            gtk_widget_show_all (theDialog);
            return;}

        void    TuneGoToLine (GtkWidget *theWidget, gpointer theData)

            {GtkTextIter    lineStart;
            GtkTextBuffer   *theTextBuf;

            gtk_spin_button_update (gSpinBtn);
            theTextBuf =
                gtk_text_view_get_buffer (GTK_TEXT_VIEW (gEditTextView));
            gtk_text_buffer_get_iter_at_line (theTextBuf, &lineStart,
                gtk_spin_button_get_value_as_int (gSpinBtn) - 1);
            gtk_text_buffer_place_cursor (theTextBuf, &lineStart);
            TuneScrollInsOnscreen ();
            gtk_widget_set_sensitive (GTK_WIDGET (theData), FALSE);
            while (gtk_events_pending ())
                gtk_main_iteration ();
            gMainFocus = gEditTextView;
            gtk_widget_destroy (GTK_WIDGET (theData));
            return;}

        void    TuneScrollInsOnscreen (void)

            {GtkTextBuffer  *theTextBuf;
            GtkTextIter     theIter;
            GtkTextMark     *theMark;
            GdkRectangle    visibleRect, insRect;

            theTextBuf =
                gtk_text_view_get_buffer (GTK_TEXT_VIEW (gEditTextView));
            gtk_text_buffer_get_iter_at_mark (theTextBuf, &theIter,
                gtk_text_buffer_get_insert (theTextBuf));
            gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (gEditTextView),
                &visibleRect);
            gtk_text_view_get_iter_location (GTK_TEXT_VIEW (gEditTextView),
                &theIter, &insRect);
            if (insRect.y <= visibleRect.y)
                gtk_text_iter_backward_line (&theIter);
            else if (insRect.y + insRect.height >= visibleRect.y +
                    visibleRect.height)
                gtk_text_iter_forward_line (&theIter);
            theMark = gtk_text_buffer_create_mark (theTextBuf, NULL, &theIter,
                FALSE);
            gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (gEditTextView),
                theMark);
            gtk_text_buffer_delete_mark (theTextBuf, theMark);
            return;}

/*
    Notice that only two tags are used: one for notes, and another for
    all commands other than note commands. Notes are highlighted even
    when the notes are arguments. Rests and drum kit items are
    highlighted as notes.
*/

        void    TuneHighlight (GtkTextBuffer *theTextBuf,
                            const GtkTextIter *startIter,
                            const GtkTextIter *endIter)

            {GtkTextIter    wordStart, wordEnd, theEnd;
            gchar           *theWord;

            wordStart = *startIter;
            theEnd = *endIter;
            gtk_text_iter_backward_to_tag_toggle (&wordStart, NULL);
            if (gtk_text_iter_ends_tag (&wordStart, NULL))
                gtk_text_iter_backward_to_tag_toggle (&wordStart, NULL);
            gtk_text_iter_forward_to_tag_toggle (&theEnd, NULL);
            if (gtk_text_iter_ends_tag (&theEnd, NULL))
                gtk_text_iter_forward_to_tag_toggle (&theEnd, NULL);
            if (TuneCharPredicate (gtk_text_iter_get_char (&wordStart),
                    (gpointer) TRUE))
                gtk_text_iter_forward_find_char (&wordStart,
                    TuneCharPredicate, (gpointer) FALSE, &theEnd);
            if (gtk_text_iter_compare (&wordStart, &theEnd) >= 0)
                return;
            gtk_text_buffer_remove_all_tags (theTextBuf, &wordStart,
                &theEnd);
            do
                {wordEnd = wordStart;
                gtk_text_iter_forward_find_char (&wordEnd,
                    TuneCharPredicate, (gpointer) TRUE, &theEnd);
                theWord = gtk_text_iter_get_slice (&wordStart, &wordEnd);
                if (TuneCIStringsEqual (theWord, "include") ||
                        TuneCIStringsEqual (theWord, "inc") ||
                        TuneCIStringsEqual (theWord, "text") ||
                        TuneCIStringsEqual (theWord, "copr") ||
                        TuneCIStringsEqual (theWord, "copyright") ||
                        TuneCIStringsEqual (theWord, "seqtitle") ||
                        TuneCIStringsEqual (theWord, "sequencetitle") ||
                        TuneCIStringsEqual (theWord, "trackname") ||
                        TuneCIStringsEqual (theWord, "instname") ||
                        TuneCIStringsEqual (theWord, "instrumentname") ||
                        TuneCIStringsEqual (theWord, "in") ||
                        TuneCIStringsEqual (theWord, "lyric") ||
                        TuneCIStringsEqual (theWord, "l") ||
                        TuneCIStringsEqual (theWord, "mark") ||
                        TuneCIStringsEqual (theWord, "cue") ||
                        TuneCIStringsEqual (theWord, "rem") ||
                        TuneCIStringsEqual (theWord, "remark"))
                    {gtk_text_buffer_apply_tag_by_name (theTextBuf,
                        "tunecommand", &wordStart, &wordEnd);
                    wordStart = wordEnd;
                    if (!gtk_text_iter_ends_line (&wordEnd))
                        gtk_text_iter_forward_to_line_end (&wordEnd);
                    gtk_text_buffer_remove_all_tags (theTextBuf, &wordStart,
                        &wordEnd);}
                else if (TuneCIStringsEqual (theWord, "comment"))
                    {gtk_text_buffer_apply_tag_by_name (theTextBuf,
                        "tunecommand", &wordStart, &wordEnd);
                    wordStart = wordEnd;
                    gtk_text_iter_forward_to_end (&wordEnd);
                    gtk_text_buffer_remove_all_tags (theTextBuf, &wordStart,
                        &wordEnd);}
                else if (TuneCIStringsEqual (theWord, "usedef") ||
                        TuneCIStringsEqual (theWord, "define"))
                    {gtk_text_buffer_apply_tag_by_name (theTextBuf,
                        "tunecommand", &wordStart, &wordEnd);
                    wordStart = wordEnd;
                    gtk_text_iter_forward_find_char (&wordStart,
                        TuneCharPredicate, (gpointer) FALSE, &theEnd);
                    wordEnd = wordStart;
                    gtk_text_iter_forward_find_char (&wordEnd,
                        TuneCharPredicate, (gpointer) TRUE, &theEnd);
                    gtk_text_buffer_remove_all_tags (theTextBuf, &wordStart,
                        &wordEnd);}
                else if (TuneCIStringsEqual (theWord, "enddef") ||
                        TuneCIStringsEqual (theWord, "repeat") ||
                        TuneCIStringsEqual (theWord, "endrep") ||
                        TuneCIStringsEqual (theWord, "stress") ||
                        TuneCIStringsEqual (theWord, "s") ||
                        TuneCIStringsEqual (theWord, "pstress") ||
                        TuneCIStringsEqual (theWord, "ps") ||
                        TuneCIStringsEqual (theWord, "persistentstress") ||
                        TuneCIStringsEqual (theWord, "trans") ||
                        TuneCIStringsEqual (theWord, "tr") ||
                        TuneCIStringsEqual (theWord, "transpose") ||
                        TuneCIStringsEqual (theWord, "auto") ||
                        TuneCIStringsEqual (theWord, "seqnum") ||
                        TuneCIStringsEqual (theWord, "sequencenumber") ||
                        TuneCIStringsEqual (theWord, "o") ||
                        TuneCIStringsEqual (theWord, "owari") ||
                        TuneCIStringsEqual (theWord, "endtrack") ||
                        TuneCIStringsEqual (theWord, "bpm") ||
                        TuneCIStringsEqual (theWord, "beatsperminute") ||
                        TuneCIStringsEqual (theWord, "crotchetsperminute") ||
                        TuneCIStringsEqual (theWord, "quarternotesperminute") ||
                        TuneCIStringsEqual (theWord, "tempo") ||
                        TuneCIStringsEqual (theWord, "timesig") ||
                        TuneCIStringsEqual (theWord, "timesignature") ||
                        TuneCIStringsEqual (theWord, "keysig") ||
                        TuneCIStringsEqual (theWord, "keysignature") ||
                        TuneCIStringsEqual (theWord, "drum") ||
                        TuneCIStringsEqual (theWord, "dr") ||
                        TuneCIStringsEqual (theWord, "nodrum") ||
                        TuneCIStringsEqual (theWord, "nd") ||
                        TuneCIStringsEqual (theWord, "redrum") ||
                        TuneCIStringsEqual (theWord, "rd") ||
                        TuneCIStringsEqual (theWord, "i") ||
                        TuneCIStringsEqual (theWord, "instrument") ||
                        TuneCIStringsEqual (theWord, "vol") ||
                        TuneCIStringsEqual (theWord, "volume") ||
                        TuneCIStringsEqual (theWord, "pan") ||
                        TuneCIStringsEqual (theWord, "stereolocation") ||
                        TuneCIStringsEqual (theWord, "suson") ||
                        TuneCIStringsEqual (theWord, "sustainon") ||
                        TuneCIStringsEqual (theWord, "susoff") ||
                        TuneCIStringsEqual (theWord, "sustainoff") ||
                        TuneCIStringsEqual (theWord, "ch") ||
                        TuneCIStringsEqual (theWord, "chord") ||
                        TuneCIStringsEqual (theWord, "noteon") ||
                        TuneCIStringsEqual (theWord, "noteoff") ||
                        TuneCIStringsEqual (theWord, "x0") ||
                        TuneCIStringsEqual (theWord, "x1") ||
                        TuneCIStringsEqual (theWord, "x2") ||
                        TuneCIStringsEqual (theWord, "x3") ||
                        TuneCIStringsEqual (theWord, "x4") ||
                        TuneCIStringsEqual (theWord, "x5") ||
                        TuneCIStringsEqual (theWord, "x6") ||
                        TuneCIStringsEqual (theWord, "x7") ||
                        TuneCIStringsEqual (theWord, "x8") ||
                        TuneCIStringsEqual (theWord, "x9"))
                    gtk_text_buffer_apply_tag_by_name (theTextBuf,
                        "tunecommand", &wordStart, &wordEnd);
                else if (StringToKitNote (theWord) ||
                        TuneStringIsNote (theWord) ||
                        TuneCIStringsEqual (theWord, "x") ||
                        TuneCIStringsEqual (theWord, "r") ||
                        TuneCIStringsEqual (theWord, "rest") ||
                        TuneCIStringsEqual (theWord, "wait"))
                    gtk_text_buffer_apply_tag_by_name (theTextBuf,
                        "tunenote", &wordStart, &wordEnd);
                g_free (theWord);
                wordStart = wordEnd;
                gtk_text_iter_forward_find_char (&wordStart,
                    TuneCharPredicate, (gpointer) FALSE, &theEnd);}
            while (gtk_text_iter_compare (&wordStart, &theEnd) < 0);
            return;}

    gboolean    TuneCharPredicate (gunichar theChar, gpointer theData)

            {return ((gboolean) theData == g_unichar_isspace (theChar));}

    gboolean    TuneStringIsNote (const gchar *theString)

            {if ((theString [0] < 'a' || theString [0] > 'g') &&
                    (theString [0] < 'A' || theString [0] > 'G'))
                return (FALSE);
            if (theString [1] == '\0')
                return (TRUE);
            if (theString [1] >= '0' && theString [1] <= '9' &&
                    theString [2] == '\0')
                return (TRUE);
            if (theString [1] != 'f' && theString [1] != 's' &&
                    theString [1] != 'n' && theString [1] != 'F' &&
                    theString [1] != 'S' && theString [1] != 'N')
                return (FALSE);
            if (theString [2] == '\0')
                return (TRUE);
            if (theString [2] < '0' || theString [2] > '9')
                return (FALSE);
            if (theString [3] == '\0')
                return (TRUE);
            return (FALSE);}

        void    TuneEditChanged (GtkTextBuffer *theTextBuf, gpointer theData)

            {gboolean   isModified;
            GtkTextIter theStart, theEnd;

            gUpdateStatusBar = TRUE;
            isModified = gtk_text_buffer_get_modified (theTextBuf);
            if (gOpenTuneName && isModified)
                {if (!GTK_WIDGET_SENSITIVE (gRevertTool))
                    gtk_widget_set_sensitive (gRevertTool, TRUE);}
            else if (GTK_WIDGET_SENSITIVE (gRevertTool))
                gtk_widget_set_sensitive (gRevertTool, FALSE);
            if (gOpenTuneName || isModified)
                {if (GTK_WIDGET_SENSITIVE (gOpenTool))
                    gtk_widget_set_sensitive (gOpenTool, FALSE);
                if (!GTK_WIDGET_SENSITIVE (gCloseTool))
                    gtk_widget_set_sensitive (gCloseTool, TRUE);
                if (!GTK_WIDGET_SENSITIVE (gCompileTool))
                    gtk_widget_set_sensitive (gCompileTool, TRUE);
                if (gPlayTool)
                    {if (!GTK_WIDGET_SENSITIVE (gPlayTool))
                        gtk_widget_set_sensitive (gPlayTool, TRUE);}
                if (gPrintTool)
                    {if (!GTK_WIDGET_SENSITIVE (gPrintTool))
                        gtk_widget_set_sensitive (gPrintTool, TRUE);}}
            else
                {if (!GTK_WIDGET_SENSITIVE (gOpenTool))
                    gtk_widget_set_sensitive (gOpenTool, TRUE);
                if (GTK_WIDGET_SENSITIVE (gCloseTool))
                    gtk_widget_set_sensitive (gCloseTool, FALSE);
                if (GTK_WIDGET_SENSITIVE (gCompileTool))
                    gtk_widget_set_sensitive (gCompileTool, FALSE);
                if (gPlayTool)
                    {if (GTK_WIDGET_SENSITIVE (gPlayTool))
                        gtk_widget_set_sensitive (gPlayTool, FALSE);}
                if (gPrintTool)
                    {if (GTK_WIDGET_SENSITIVE (gPrintTool))
                        gtk_widget_set_sensitive (gPrintTool, FALSE);}}
            if (gOpenTuneName)
                {if (!GTK_WIDGET_SENSITIVE (gSaveAsTool))
                    gtk_widget_set_sensitive (gSaveAsTool, TRUE);}
            else if (GTK_WIDGET_SENSITIVE (gSaveAsTool))
                gtk_widget_set_sensitive (gSaveAsTool, FALSE);
            if (isModified)
                {if (!GTK_WIDGET_SENSITIVE (gSaveTool))
                    gtk_widget_set_sensitive (gSaveTool, TRUE);}
            else if (GTK_WIDGET_SENSITIVE (gSaveTool))
                gtk_widget_set_sensitive (gSaveTool, FALSE);
            if (gNumUndos)
                {if (!GTK_WIDGET_SENSITIVE (gUndoTool))
                    gtk_widget_set_sensitive (gUndoTool, TRUE);}
            else if (GTK_WIDGET_SENSITIVE (gUndoTool))
                gtk_widget_set_sensitive (gUndoTool, FALSE);
            if (gtk_text_buffer_get_selection_bounds (theTextBuf,
                    &theStart, &theEnd))
                {if (!GTK_WIDGET_SENSITIVE (gCutTool))
                    gtk_widget_set_sensitive (gCutTool, TRUE);
                if (!GTK_WIDGET_SENSITIVE (gCopyTool))
                    gtk_widget_set_sensitive (gCopyTool, TRUE);}
            else
                {if (GTK_WIDGET_SENSITIVE (gCutTool))
                    gtk_widget_set_sensitive (gCutTool, FALSE);
                if (GTK_WIDGET_SENSITIVE (gCopyTool))
                    gtk_widget_set_sensitive (gCopyTool, FALSE);}
            if (gtk_text_buffer_get_char_count (theTextBuf) > 0)
                {if (!GTK_WIDGET_SENSITIVE (gFindTool))
                    gtk_widget_set_sensitive (gFindTool, TRUE);}
            else if (GTK_WIDGET_SENSITIVE (gFindTool))
                gtk_widget_set_sensitive (gFindTool, FALSE);
            if (gtk_text_buffer_get_line_count (theTextBuf) > 1)
                {if (!GTK_WIDGET_SENSITIVE (gGoToTool))
                    gtk_widget_set_sensitive (gGoToTool, TRUE);}
            else if (GTK_WIDGET_SENSITIVE (gGoToTool))
                gtk_widget_set_sensitive (gGoToTool, FALSE);
            if (gNeedHighlighting)
                {gtk_text_buffer_get_iter_at_offset (theTextBuf,
                    &theStart, gHighlightStart);
                gtk_text_buffer_get_iter_at_offset (theTextBuf,
                    &theEnd, gHighlightEnd);
                TuneHighlight (theTextBuf, &theStart, &theEnd);
                gNeedHighlighting = FALSE;}
            return;}

        void    TuneMarkSet (GtkTextBuffer *theTextBuf, const GtkTextIter *theIter,
                            GtkTextMark *theMark, gpointer theData)

            {TuneEditChanged (theTextBuf, theData);
            return;}

        void    TuneTextDel (GtkTextBuffer *theTextBuf, GtkTextIter *theStart,
                            GtkTextIter *theEnd, gpointer theData)

            {GtkTextIter    theIter;

            gNeedHighlighting = TRUE;
            gHighlightStart = gHighlightEnd =
                gtk_text_iter_get_offset (theStart);
            if (!gUndoing)
                {if (++gUndoIdx >= kTuneUndoMax)
                    gUndoIdx = 0;
                if (++gNumUndos > kTuneUndoMax)
                    {gNumUndos = kTuneUndoMax;
                    if (gDelString [gUndoIdx])
                        g_free (gDelString [gUndoIdx]);}
                gDelString [gUndoIdx] = gtk_text_iter_get_slice (theStart,
                    theEnd);
                gEditEnd [gUndoIdx] = gEditStart [gUndoIdx] = gHighlightStart;
                gtk_text_buffer_get_iter_at_mark (theTextBuf, &theIter,
                    gtk_text_buffer_get_insert (theTextBuf));
                gCursAtStart [gUndoIdx] = gtk_text_iter_equal (theStart,
                    &theIter);}
            return;}

        void    TuneTextIns (GtkTextBuffer *theTextBuf, GtkTextIter *theIter,
                            const gchar *theText, gint theLength,
                            gpointer theData)

            {gNeedHighlighting = TRUE;
            gHighlightStart = gtk_text_iter_get_offset (theIter);
            gHighlightEnd = gHighlightStart +
                g_utf8_pointer_to_offset (theText,
                theText + (theLength / sizeof (gchar)));
            if (!gUndoing)
                {if (!gNumUndos || !gDelString [gUndoIdx] ||
                        gHighlightStart != gEditStart [gUndoIdx])
                    {if (++gUndoIdx >= kTuneUndoMax)
                        gUndoIdx = 0;
                    if (++gNumUndos > kTuneUndoMax)
                        {gNumUndos = kTuneUndoMax;
                        if (gDelString [gUndoIdx])
                            g_free (gDelString [gUndoIdx]);}
                    gDelString [gUndoIdx] = (gchar *) 0;}
                gEditStart [gUndoIdx] = gHighlightStart;
                gEditEnd [gUndoIdx] = gHighlightEnd;}
            return;}

        void    TuneBtnCompile (GtkWidget *theWidget, gpointer theData)

            {GtkWidget  *fileSel;

            fileSel = gtk_file_selection_new ("Select Tune files to Compile");
            gtk_file_selection_set_select_multiple (GTK_FILE_SELECTION (fileSel),
                TRUE);
            gtk_window_set_transient_for (GTK_WINDOW (fileSel),
                GTK_WINDOW (gWindow));
            gtk_window_set_modal (GTK_WINDOW (fileSel), TRUE);
            g_signal_connect (G_OBJECT (fileSel), "destroy",
                G_CALLBACK (TuneModalDestroyed), NULL);
            g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileSel)->ok_button),
                "clicked", G_CALLBACK (TuneCompileSelections), (gpointer) fileSel);
            g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (fileSel)->cancel_button),
                "clicked", G_CALLBACK (TuneCloseModal), (gpointer) fileSel);
            TuneMainSensitive (FALSE);
            gMainFocus = theWidget;
            gtk_widget_show (fileSel);
            return;}

        void    TuneCompileSelections (GtkWidget *theWidget, gpointer theData)

            {int    numOfSel;
            char    **argv;

            argv = (char **)
                gtk_file_selection_get_selections (GTK_FILE_SELECTION (theData));
            if (argv)
                {gtk_widget_hide (GTK_WIDGET (theData));
                numOfSel = 0;
                while (argv [numOfSel])
                    ++numOfSel;
                TunePrint ("\n");
                TuneCompile (0, numOfSel, argv);
                errno = 0;
                g_strfreev ((gchar **) argv);}
            gtk_widget_destroy (GTK_WIDGET (theData));
            return;}

        void    TuneCloseModal (GtkWidget *theWidget, gpointer theData)

            {gtk_widget_destroy (GTK_WIDGET (theData));
            return;}

        void    TuneModalDestroyed (GtkWidget *theWidget, gpointer theData)

            {TuneMainSensitive (TRUE);
            return;}

    gboolean    TuneWindowDelete (GtkWidget *theWidget, GdkEventAny *theEvent,
                            gpointer theData)

            {if (GTK_WIDGET_SENSITIVE (theWidget))
                TuneQuit (theWidget, theData);
            return (TRUE);}

        void    TuneQuit (GtkWidget *theWidget, gpointer theData)

            {gint       theResp;
            GtkWidget   *theDialog;

            if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                {TuneMainSensitive (FALSE);
                if (theWidget != gWindow)
                    gMainFocus = theWidget;
                if (gOpenTuneName)
                    theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_YES_NO,
                        "\"%s\" has been changed since it was opened. "
                        "Save the changes before quitting?",
                        gOpenTuneName);
                else
                    theDialog = gtk_message_dialog_new (GTK_WINDOW (gWindow),
                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                        GTK_BUTTONS_YES_NO,
                        "Save the new Tune file before quitting?");
                gtk_dialog_add_button (GTK_DIALOG (theDialog), GTK_STOCK_CANCEL,
                    GTK_RESPONSE_CANCEL);
                gtk_dialog_set_default_response (GTK_DIALOG (theDialog),
                    GTK_RESPONSE_CANCEL);
                theResp = gtk_dialog_run (GTK_DIALOG (theDialog));
                TuneMainSensitive (TRUE);
                gtk_widget_destroy (theDialog);
                if (theResp == GTK_RESPONSE_YES)
                    {TuneToolSave (gSaveTool, theData);
                    if (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (theData)))
                        return;}    /*  because save was cancelled  */
                else if (theResp != GTK_RESPONSE_NO)
                    return;}
            TuneZapUndos ();
            if (gOpenTuneName)
                g_free (gOpenTuneName);
            if (gFindText)
                g_free (gFindText);
            if (gReplText)
                g_free (gReplText);
            gtk_main_quit ();
            return;}

        void    TuneZapUndos (void)

            {while (gNumUndos)
                {if (gDelString [gUndoIdx])
                    g_free (gDelString [gUndoIdx]);
                if (!gUndoIdx)
                    gUndoIdx = kTuneUndoMax - 1;
                else
                    --gUndoIdx;
                --gNumUndos;}
            return;}

#endif

/*
    If TuneToMidi was compiled for the standard
    interface, StdInterface, TunePrint, and TuneBeep
    are macros:
    "StdInterface" is defined as "main"
    "TunePrint" is defined as "printf"
    "TuneBeep" is defined as "StdBeep"

    If TuneToMidi was compiled for the GTK
    interface, StdInterface is prototyped as
    a function (perhaps) called by main, and
    TunePrint and TuneBeep are global variables.
    If the GTK interface is used:
    TunePrint = TunePrintGTK
    TuneBeep = gdk_beep
    Otherwise, if TuneToMidi is called with
    command-line arguments or gtk_init_check
    fails:
    TunePrint = printf
    TuneBeep = StdBeep

    Be aware that StdInterface returns EXIT_SUCCESS if the
    last file in the list is successfully compiled--even
    if other files in the list were not compiled. If
    invoked from a script, TuneToMidi should be given one
    Tune file at a time to compile. That way the successful
    compilation of each MIDI file can be verified.
*/

        int     StdInterface (int argc, char **argv)

            {char   theString [256], *strPtr;
            int     returnValue, theIndex;
            size_t  stringLength;

            theIndex = 0;
            while (++theIndex < argc)
                {if (StringsEqual (argv [theIndex], "-h") ||
                        StringsEqual (argv [theIndex], "--help"))
                    {PrintHelp ();
                    printf ("\n");
                    return (EXIT_SUCCESS);}}
            theIndex = 0;
            while (++theIndex < argc)
                {if (StringsEqual (argv [theIndex], "--version"))
                    {PrintVersion ();
                    printf ("\n");
                    return (EXIT_SUCCESS);}}
            printf ("\nTuneToMidi, version 1.2.0");
            printf ("\nTune Language, version 1.1");
            printf ("\nCopyright (C) 2003, 2004, 2005 J. David Sexton");
            printf ("\nSome rights NOT reserved!");
            printf ("\nSee the disclaimer and license in TuneToMidi.c.\n");
            if (argc < 2)
                {printf ("\nTuneToMidi also accepts command-line arguments.");
                printf ("\nType \"TuneToMidi -h\" at the command-line prompt");
                printf ("\nfor options and examples.\n");
                printf ("\nEnter the name of the Tune file to be compiled: ");
                if (fgets (theString, 256, stdin))
                    {if ((stringLength = strlen (theString)))
                        {if (theString [--stringLength] < ' ')
                            theString [stringLength] = '\0';}}
                else
                    {printf ("\n\n==============\n");
                    printf ("Couldn't get the Tune file name.");
                    printf ("\n==============\n\n\a");
                    return (EXIT_FAILURE);}
                strPtr = theString;
                printf ("\n");
                returnValue = TuneCompile (0, 1, &strPtr);
                printf ("\n");
                return (returnValue);}
            printf ("\nTo review the command-line options, type\n");
            printf ("\"TuneToMidi -h\" at the command-line prompt.\n\n");
            returnValue = TuneCompile (1, argc, argv);
            printf ("\n");
            return (returnValue);}

        void    StdBeep (void)

            {printf ("\a");
            return;}

        void    PrintHelp (void)

            {printf ("\nTuneToMidi command-line arguments:\n\n");
            printf ("-h or --help     prints this help and exits;\n");
            printf ("                 should be the only argument\n");
            printf ("--version        prints the version and exits;\n");
            printf ("                 should be the only argument\n");
            printf ("<file name>      creates a MIDI file by compiling\n");
            printf ("                 <file name>; the MIDI file name\n");
            printf ("                 will end with \".mid\"\n");
            printf ("<file name list> the same as above, except that\n");
            printf ("                 every file in the list is compiled\n");
            printf ("-o or --output   used to specify the MIDI file name;\n");
            printf ("                 must follow a Tune file name and\n");
            printf ("                 be followed by a MIDI file name\n");
            printf ("Examples:\n\n");
#if !TUNE_GTK_INTERFACE
            printf ("TuneToMidi\n");
            printf ("               compiles a Tune file specified\n");
            printf ("               interactively; the MIDI file name\n");
            printf ("               will end with \".mid\"\n\n");
#endif
            printf ("TuneToMidi foo.txt\n\n");
            printf ("               compiles the Tune file \"foo.txt\"\n");
            printf ("               into the MIDI file \"foo.mid\"\n\n");
            printf ("TuneToMidi foo.txt bar.txt\n\n");
            printf ("               compiles the Tune files\n");
            printf ("               \"foo.txt\" and \"bar.txt\"\n");
            printf ("               into the MIDI files\n");
            printf ("               \"foo.mid\" and \"bar.mid\"\n\n");
            printf ("TuneToMidi foo.txt -o bar.mid\n\n");
            printf ("               compiles the Tune file \"foo.txt\"\n");
            printf ("               into the MIDI file \"bar.mid\"\n");
            return;}

        void    PrintVersion (void)

            {printf ("TuneToMidi 1.2.0\n");
            printf ("Tune Language 1.1\n");
            printf ("Copyright (C) 2003, 2004, 2005 J. David Sexton\n");
            printf ("Some rights NOT reserved!\n");
            printf ("See TuneToMidi.c for licensing details.\n");
            return;}

/*
    IsADirectory isn't absolutely necessary, but it does improve the
    quality of TuneToMidi's error messages.
*/


#if TUNE_GTK_INTERFACE

        int     IsADirectory (const char *pathName, const char *fileOp)

            {if (g_file_test (pathName, G_FILE_TEST_IS_DIR))
                {TunePrint ("\"%s\" couldn't be %s.\n", pathName, fileOp);
                TunePrint ("It's a directory.\n");
                TuneBeep ();
                return (1);}
            return (0);}

#elif defined (GOT_STAT)

        int     IsADirectory (const char *pathName, const char *fileOp)

            {struct stat    theStat;

            if (!stat (pathName, &theStat))
                {if (S_ISDIR (theStat.st_mode))
                    errno = EISDIR;}
            else if (errno == ENOENT)
                errno = 0;
            if (errno)
                {printf ("\"%s\" couldn't be %s.\n", pathName, fileOp);
                printf ("System: \"%s\"\n\a", strerror (errno));
                return (1);}
            return (0);}

#endif

/*
    This function MAY be slightly more efficient than strcmp.
    Note that this ignores the locale.
*/

        int     StringsEqual (const char *stringA, const char *stringB)

            {char   byteA;
    const   char    *ptrA, *ptrB;

            ptrA = stringA;
            ptrB = stringB;
            do
                {if (!(byteA = *(ptrA++)))
                    return (!(*ptrB));}
            while (byteA == *(ptrB++));
            return (0);}

/*
    argv is a pointer to a list of argc string pointers. These pointers
    point to the names of Tune files (or MIDI files when the -o or
    --output options are used). TuneCompile compiles Tune files starting
    with argv [firstArgIdx]. If firstArgIdx > 0, we assume we're
    processing the command line, so the command line options -o and
    --output are recognized; otherwise they're just treated as file
    names. TuneCompile returns EXIT_SUCCESS if the last Tune file in the
    list is sucessfully compiled, or EXIT_FAILURE otherwise.
*/

        int     TuneCompile (int firstArgIdx, int argc, char **argv)

            {char           theString [256], currCommand [256];
            int             returnValue, theTrans, theAuto, argIndex;
            long            errorLocationS, errorLocationE;
            unsigned char   timeSigN, timeSigD, clocksPerClick;
            unsigned char   theStress, pStress, altChannel, theChannel;
            unsigned char   theChar, instUsed, theStatus, outputSpec;
            unsigned long   theTime, lastTime, trackTime, lastTrackTime;
            unsigned long   theNum, numOfTracks, lastOctave, errorType;
            size_t          stringLength;
            FILE            *midiFile, *tuneFile, *tempFile;

            if (firstArgIdx < 0 || argc < 1 || firstArgIdx >= argc)
                return (EXIT_FAILURE);
            argIndex = firstArgIdx - 1;
            returnValue = 0;    /*  prevent bogus warning from gcc  */
            /*  Iterate through all the files named in the list.    */
            while (++argIndex < argc)
                {returnValue = 1;
                errno = 0;
                TunePrint ("==============\n");
                gTuneFileName = argv [argIndex];
                TunePrint ("Compiling Tune file \"%s\"\n\n", gTuneFileName);
                outputSpec = 0;
                if (firstArgIdx && argIndex + 1 < argc)
                    {if (StringsEqual (argv [argIndex + 1], "-o") ||
                            StringsEqual (argv [argIndex + 1], "--output"))
                        {if (argIndex + 2 < argc)
                            outputSpec = 1;
                        else
                            {TunePrint ("On the command line, \"%s\" must\n",
                                argv [argIndex + 1]);
                            TunePrint ("be preceded by a Tune file name and\n");
                            TunePrint ("followed by a MIDI file name.\n");
                            TuneBeep ();
                            break;}}}
                if (!(stringLength = strlen (gTuneFileName)))
                    {TunePrint ("A Tune file name can't be zero-length.\n");
                    TuneBeep ();
                    if (outputSpec)
                        argIndex += 2;
                    continue;}
#if TUNE_GTK_INTERFACE || defined (GOT_STAT)
                if (IsADirectory (gTuneFileName, "opened"))
                    {if (outputSpec)
                        argIndex += 2;
                    continue;}
#endif
                if (firstArgIdx && (StringsEqual (gTuneFileName, "-o") ||
                        StringsEqual (gTuneFileName, "--output")))
                    {TunePrint ("On the command line, \"%s\" must\n",
                        gTuneFileName);
                    TunePrint ("be preceded by a Tune file name and\n");
                    TunePrint ("followed by a MIDI file name.\n");
                    TuneBeep ();
                    if (outputSpec)
                        argIndex += 2;
                    continue;}
                if (!(tuneFile = fopen (gTuneFileName, "rb")))
                    {TunePrint ("\"%s\" couldn't be opened.\n",
                        gTuneFileName);
                    TunePrint ("System: \"%s\"\n", strerror (errno));
                    TuneBeep ();
                    if (outputSpec)
                        argIndex += 2;
                    continue;}
                if (outputSpec)
                    {argIndex += 2;
                    gMidiFileName = argv [argIndex];
                    TunePrint ("Compiling into MIDI file \"%s\"\n\n",
                        gMidiFileName);
                    if (!gMidiFileName [0])
                        {TunePrint ("A MIDI file name can't be zero-length.\n");
                        TuneBeep ();
                        fclose (tuneFile);
                        continue;}
#if TUNE_GTK_INTERFACE || defined (GOT_STAT)
                    if (IsADirectory (gMidiFileName, "saved"))
                        {fclose (tuneFile);
                        continue;}
#endif
                    if (firstArgIdx && (StringsEqual (gMidiFileName, "-o") ||
                            StringsEqual (gMidiFileName, "--output")))
                        {TunePrint ("On the command line, \"%s\" must\n",
                            gMidiFileName);
                        TunePrint ("be preceded by a Tune file name and\n");
                        TunePrint ("followed by a MIDI file name.\n");
                        TuneBeep ();
                        fclose (tuneFile);
                        continue;}}
                else
                    {do
                        {--stringLength;
                        if (!ISALPHNUM (gTuneFileName [stringLength]))
                            break;}
                    while (stringLength);
                    if (gTuneFileName [stringLength] != '.')
                        stringLength = strlen (gTuneFileName);
                    if (!(gMidiFileName = malloc (stringLength + 5)))
                        {TunePrint ("The MIDI file couldn't be saved.\n");
                        TunePrint ("System: \"%s\"\n", strerror (errno));
                        TuneBeep ();
                        fclose (tuneFile);
                        continue;}
                    strncpy (gMidiFileName, gTuneFileName, stringLength);
                    gMidiFileName [stringLength] = '.';
                    gMidiFileName [++stringLength] = 'm';
                    gMidiFileName [++stringLength] = 'i';
                    gMidiFileName [++stringLength] = 'd';
                    gMidiFileName [++stringLength] = '\0';
                    TunePrint ("Compiling into MIDI file \"%s\"\n\n",
                        gMidiFileName);}
                if (StringsEqual (gTuneFileName, gMidiFileName))
                    {TunePrint ("The Tune file and the MIDI file\n");
                    TunePrint ("can't have the same name.\n");
                    TuneBeep ();
                    fclose (tuneFile);
                    if (!outputSpec)
                        free (gMidiFileName);
                    continue;}
                if ((midiFile = fopen (gMidiFileName, "rb")))
                    {if (fread (theString, 1, 4, midiFile) == 4)
                        {if (theString [0] != 'M' ||
                                theString [1] != 'T' ||
                                theString [2] != 'h' ||
                                theString [3] != 'd')
                            {TunePrint ("\"%s\" already exists and",
                                gMidiFileName);
                            TunePrint (" is not a MIDI file.\n");
                            TuneBeep ();
                            fclose (tuneFile);
                            fclose (midiFile);
                            if (!outputSpec)
                                free (gMidiFileName);
                            continue;}}
                    fclose (midiFile);}
                if (!(tempFile = tmpfile ()))
                    {TunePrint ("The temporary file couldn't be opened.\n");
                    TunePrint ("System: \"%s\"\n", strerror (errno));
                    TuneBeep ();
                    fclose (tuneFile);
                    if (!outputSpec)
                        free (gMidiFileName);
                    continue;}
                if (!(midiFile = fopen (gMidiFileName, "wb")))
                    {TunePrint ("\"%s\" couldn't be saved.\n", gMidiFileName);
                    TunePrint ("System: \"%s\"\n", strerror (errno));
                    TuneBeep ();
                    fclose (tempFile);
                    fclose (tuneFile);
                    if (!outputSpec)
                        free (gMidiFileName);
                    continue;}
                gIncludeDepth = gDefDepth = gRepeatDepth = gRepeatIndex = 0UL;
                numOfTracks = lastTrackTime = 0UL;
                errorLocationS = 0L;
                theChannel = 0x00;
                /*  Iterate through all the tracks. */
                for (;;)
                    {theTime = trackTime = 0UL;
                    lastOctave = 4UL;
                    lastTime = 96;
                    theStress = pStress = 64;
                    theTrans = theAuto = 0;
                    instUsed = theStatus = 0;
                    altChannel = theChannel;
                    gXNote = 0;
                    errorType = kErrorWritingFile;
                    /*  Iterate through all the commands in the track.  */
                    for (;;)
                        {if (GetString (tuneFile, currCommand))
                            {if (!feof (tuneFile))
                                {returnValue = 1;
                                errorType = kTuneUnreadable;
                                break;}
                            if (gIncludeDepth)
                                {fclose (tuneFile);
                                tuneFile = gIncludeStack [--gIncludeDepth];
                                free (gIncludeNameStack [gIncludeDepth]);
                                continue;}
                            if (ftell (tempFile) > 0)
                                {if (gDefDepth)
                                    {fseek (tuneFile, gDefRetStack [--gDefDepth],
                                        SEEK_SET);
                                    /*  We're pretending that we saw the        */
                                    /*  missing "endrep." The "define" handler  */
                                    /*  will catch the mistake later and give   */
                                    /*  us a missing enddef error message;      */
                                    /*  otherwise, we'd get a missing end-of-   */
                                    /*  track.  */
                                    continue;}
                                returnValue = 1;
                                errorType = kLastCommandNotO;}
                            break;}
                        errorLocationS = ftell (tuneFile) - strlen (currCommand);
                        if (!feof (tuneFile))
                            --errorLocationS;
                        if (StringsEqual (currCommand, "include") ||
                                StringsEqual (currCommand, "inc"))
                            {if (gIncludeDepth >= MAX_INCLUDE_DEPTH)
                                {returnValue = 1;
                                TunePrint ("Include files are nested too deeply.\n");
                                errorType = kReportedError;
                                break;}
                            if ((returnValue = ReadTextString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
#if TUNE_GTK_INTERFACE || defined (GOT_STAT)
                            if (IsADirectory (theString, "opened"))
                                {returnValue = 1;
                                errorType = kReportedError;
                                break;}
#endif
                            if (!(gIncludeNameStack [gIncludeDepth] =
                                    malloc (strlen (theString) + 1)))
                                {returnValue = 1;
                                TunePrint ("\"%s\" couldn't be opened.\n", theString);
                                TunePrint ("System: \"%s\"\n", strerror (errno));
                                errorType = kReportedError;
                                break;}
                            strcpy (gIncludeNameStack [gIncludeDepth], theString);
                            gIncludeStack [gIncludeDepth++] = tuneFile;
                            if (!(tuneFile = fopen (theString, "rb")))
                                {tuneFile = gIncludeStack [--gIncludeDepth];
                                free (gIncludeNameStack [gIncludeDepth]);
                                returnValue = 1;
                                TunePrint ("\"%s\" couldn't be opened.\n", theString);
                                TunePrint ("System: \"%s\"\n", strerror (errno));
                                errorType = kReportedError;
                                break;}}
                        else if (StringsEqual (currCommand, "define"))
                            {if ((returnValue = GetString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            else
                                {while (!(returnValue = GetString (tuneFile, theString)))
                                    {if (StringsEqual (theString, "enddef"))
                                        break;
                                    if (StringsEqual (theString, "define"))
                                        {returnValue = 1;
                                        break;}
                                    SkipTextCommands (tuneFile, theString);}}
                            if (returnValue)
                                {TunePrint ("The \"enddef\" argument is missing.\n");
                                errorType = kReportedError;
                                break;}}
                        else if (StringsEqual (currCommand, "usedef") ||
                                (currCommand [0] == 'x' &&
                                currCommand [1] >= '0' &&
                                currCommand [1] <= '9' &&
                                !currCommand [2]))
                            {if (currCommand [0] == 'x')
                                strcpy (gDefName, currCommand);
                            else if ((returnValue = GetString (tuneFile, gDefName)))
                                {errorType = kNoArgs;
                                break;}
                            if (gDefDepth >= MAX_DEF_DEPTH)
                                {returnValue = 1;
                                TunePrint ("\"usedef\" commands are ");
                                TunePrint ("nested too deeply.\n");
                                errorType = kReportedError;
                                break;}
                            gDefRetStack [gDefDepth++] = ftell (tuneFile);
                            rewind (tuneFile);
                            while (!(returnValue = GetString (tuneFile, theString)))
                                {if (StringsEqual (theString, "define"))
                                    {if ((returnValue = GetString (tuneFile,
                                            theString)))
                                        break;
                                    if (StringsEqual (theString, gDefName))
                                        break;}
                                else
                                    SkipTextCommands (tuneFile, theString);}
                            if (returnValue)
                                {TunePrint ("The definition \"%s\" wasn't found.\n",
                                    gDefName);
                                errorType = kReportedError;}
                            else
                                {gDefStartStack [gDefDepth - 1] = ftell (tuneFile);
                                if ((returnValue = CheckSelfRef ()))
                                    {TunePrint ("\"%s\" references itself.\n",
                                        gDefName);
                                    errorType = kReportedError;}}
                            if (!returnValue)
                                {while (!(returnValue = GetString (tuneFile, theString)))
                                    {if (StringsEqual (theString, "define"))
                                        {if ((returnValue = GetString (tuneFile,
                                                theString)))
                                            break;
                                        if (StringsEqual (theString, gDefName))
                                            break;}
                                    else
                                        SkipTextCommands (tuneFile, theString);}
                                if ((returnValue = !returnValue))
                                    {TunePrint ("\"%s\" is defined more than once.\n",
                                        gDefName);
                                    errorType = kReportedError;}
                                else
                                    fseek (tuneFile, gDefStartStack [gDefDepth - 1],
                                        SEEK_SET);}
                            if (returnValue)
                                {fseek (tuneFile, gDefRetStack [--gDefDepth],
                                    SEEK_SET);
                                break;}}
                        else if (StringsEqual (currCommand, "enddef"))
                            {if (!gDefDepth)
                                {returnValue = 1;
                                TunePrint ("An \"enddef\" may only ");
                                TunePrint ("appear as the last\n");
                                TunePrint ("argument of a \"define\" command.\n");
                                errorType = kReportedError;
                                break;}
                            fseek (tuneFile, gDefRetStack [--gDefDepth], SEEK_SET);}
                        else if (StringsEqual (currCommand, "repeat"))
                            {if ((returnValue = GetNumber (tuneFile, &theNum)))
                                {errorType = kArgNotNum;
                                break;}
                            if (!theNum)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            if (gRepeatDepth >= MAX_REP_DEPTH)
                                {returnValue = 1;
                                TunePrint ("Repeats are nested too deeply.\n");
                                errorType = kReportedError;
                                break;}
                            gRepIndexStack [gRepeatDepth] = gRepeatIndex;
                            gRepeatIndex = theNum;
                            gRepStartStack [gRepeatDepth] = ftell (tuneFile);
                            theNum = 1UL;
                            do
                                {if ((returnValue = GetString (tuneFile, theString)))
                                    break;
                                if (StringsEqual (theString, "define") ||
                                        StringsEqual (theString, "enddef"))
                                    {returnValue = 1;
                                    break;}
                                else if (StringsEqual (theString, "endrep"))
                                    --theNum;
                                else if (StringsEqual (theString, "repeat"))
                                    ++theNum;
                                else
                                    SkipTextCommands (tuneFile, theString);}
                            while (theNum);
                            if (returnValue)
                                {TunePrint ("An \"endrep\" argument is missing.\n");
                                errorType = kReportedError;
                                break;}
                            fseek (tuneFile, gRepStartStack [gRepeatDepth++],
                                SEEK_SET);}
                        else if (StringsEqual (currCommand, "endrep"))
                            {if (!gRepeatDepth)
                                {returnValue = 1;
                                TunePrint ("An \"endrep\" may only ");
                                TunePrint ("appear as the last\n");
                                TunePrint ("argument of a \"repeat\" command.\n");
                                errorType = kReportedError;
                                break;}
                            if ((--gRepeatIndex))
                                fseek (tuneFile, gRepStartStack [gRepeatDepth - 1],
                                    SEEK_SET);
                            else
                                gRepeatIndex = gRepIndexStack [--gRepeatDepth];}
                        else if (StringsEqual (currCommand, "comment"))
                            {while (!feof (tuneFile))
                                {if ((returnValue = WindToEndOfLine (tuneFile)))
                                    break;}
                            if (returnValue)
                                {TunePrint ("A comment contains illegal characters.\n");
                                errorType = kReportedError;
                                break;}}
                        else if (StringsEqual (currCommand, "rem") ||
                                StringsEqual (currCommand, "remark"))
                            {if ((returnValue = WindToEndOfLine (tuneFile)))
                                {TunePrint ("A remark contains illegal characters.\n");
                                errorType = kReportedError;
                                break;}}
                        else if (StringsEqual (currCommand, "stress") ||
                                StringsEqual (currCommand, "s"))
                            {if (!numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if (GetNumber (tuneFile, &theNum))
                                {if ((returnValue = GetString (tuneFile, theString)))
                                    {errorType = kNoArgs;
                                    break;}
                                else if ((returnValue =
                                        StringToStress (theString, &theNum)))
                                    {errorType = kBadArgString;
                                    break;}}
                            if (!theNum || theNum > 127)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            theStress = theNum;}
                        else if (StringsEqual (currCommand, "pstress") ||
                                StringsEqual (currCommand, "ps") ||
                                StringsEqual (currCommand, "persistentstress"))
                            {if (!numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if (GetNumber (tuneFile, &theNum))
                                {if ((returnValue = GetString (tuneFile, theString)))
                                    {errorType = kNoArgs;
                                    break;}
                                else if ((returnValue =
                                        StringToStress (theString, &theNum)))
                                    {errorType = kBadArgString;
                                    break;}}
                            if (!theNum || theNum > 127)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            pStress = theStress = theNum;}
                        else if (StringsEqual (currCommand, "trans") ||
                                StringsEqual (currCommand, "tr") ||
                                StringsEqual (currCommand, "transpose"))
                            {if (!numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetSignedNumber (tuneFile, &theTrans)))
                                {errorType = kArgNotNum;
                                break;}
                            if (theTrans < -127 || theTrans > 115)
                                {returnValue = 1;
                                TunePrint ("\"%d\" is an inappropriate argument\n",
                                    theTrans);
                                TunePrint ("for the \"%s\" command.\n", currCommand);
                                errorType = kReportedError;
                                break;}}
                        else if (StringsEqual (currCommand, "auto"))
                            {if (!numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if (StringsEqual (theString, "cfmaj") ||
                                    StringsEqual (theString, "afmin") ||
                                    StringsEqual (theString, "7f"))
                                theAuto = -7;
                            else if (StringsEqual (theString, "gfmaj") ||
                                    StringsEqual (theString, "efmin") ||
                                    StringsEqual (theString, "6f"))
                                theAuto = -6;
                            else if (StringsEqual (theString, "dfmaj") ||
                                    StringsEqual (theString, "bfmin") ||
                                    StringsEqual (theString, "5f"))
                                theAuto = -5;
                            else if (StringsEqual (theString, "afmaj") ||
                                    StringsEqual (theString, "fmin") ||
                                    StringsEqual (theString, "4f"))
                                theAuto = -4;
                            else if (StringsEqual (theString, "efmaj") ||
                                    StringsEqual (theString, "cmin") ||
                                    StringsEqual (theString, "3f"))
                                theAuto = -3;
                            else if (StringsEqual (theString, "bfmaj") ||
                                    StringsEqual (theString, "gmin") ||
                                    StringsEqual (theString, "2f"))
                                theAuto = -2;
                            else if (StringsEqual (theString, "fmaj") ||
                                    StringsEqual (theString, "dmin") ||
                                    StringsEqual (theString, "1f"))
                                theAuto = -1;
                            else if (StringsEqual (theString, "cmaj") ||
                                    StringsEqual (theString, "amin") ||
                                    StringsEqual (theString, "0") ||
                                    StringsEqual (theString, "0f") ||
                                    StringsEqual (theString, "0s"))
                                theAuto = 0;
                            else if (StringsEqual (theString, "gmaj") ||
                                    StringsEqual (theString, "emin") ||
                                    StringsEqual (theString, "1s"))
                                theAuto = 1;
                            else if (StringsEqual (theString, "dmaj") ||
                                    StringsEqual (theString, "bmin") ||
                                    StringsEqual (theString, "2s"))
                                theAuto = 2;
                            else if (StringsEqual (theString, "amaj") ||
                                    StringsEqual (theString, "fsmin") ||
                                    StringsEqual (theString, "3s"))
                                theAuto = 3;
                            else if (StringsEqual (theString, "emaj") ||
                                    StringsEqual (theString, "csmin") ||
                                    StringsEqual (theString, "4s"))
                                theAuto = 4;
                            else if (StringsEqual (theString, "bmaj") ||
                                    StringsEqual (theString, "gsmin") ||
                                    StringsEqual (theString, "5s"))
                                theAuto = 5;
                            else if (StringsEqual (theString, "fsmaj") ||
                                    StringsEqual (theString, "dsmin") ||
                                    StringsEqual (theString, "6s"))
                                theAuto = 6;
                            else if (StringsEqual (theString, "csmaj") ||
                                    StringsEqual (theString, "asmin") ||
                                    StringsEqual (theString, "7s"))
                                theAuto = 7;
                            else
                                {returnValue = 1;
                                errorType = kBadArgString;
                                break;}}
                        else if (StringsEqual (currCommand, "r") ||
                                StringsEqual (currCommand, "rest") ||
                                StringsEqual (currCommand, "wait"))
                            {if (GetNoteValue (tuneFile, &theNum))
                                theNum = lastTime;
                            if (!theNum || theNum > 0x0FFFFFFF - theTime)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            lastTime = theNum;
                            theTime += theNum;
                            trackTime += theNum;}
                        else if (StringsEqual (currCommand, "seqnum") ||
                                StringsEqual (currCommand, "sequencenumber"))
                            {if (numOfTracks || theTime)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetNumber (tuneFile, &theNum)))
                                {errorType = kArgNotNum;
                                break;}
                            if (theNum > 0xFFFF)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, 0UL)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x00)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 2)))
                                break;
                            if ((returnValue = WriteByte (tempFile,
                                    (theNum >> 8) & 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theNum & 0xFF)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "text"))
                            {if ((returnValue = ReadTextString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x01)))
                                break;
                            if ((returnValue = WriteVariableLen (tempFile,
                                    strlen (theString))))
                                break;
                            if ((returnValue = WriteString (tempFile, theString)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "copr") ||
                                StringsEqual (currCommand, "copyright"))
                            {if (numOfTracks || theTime)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = ReadTextString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, 0UL)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x02)))
                                break;
                            if ((returnValue = WriteVariableLen (tempFile,
                                    strlen (theString))))
                                break;
                            if ((returnValue = WriteString (tempFile, theString)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "seqtitle") ||
                                StringsEqual (currCommand, "sequencetitle"))
                            {if (numOfTracks || theTime)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = ReadTextString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, 0UL)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x03)))
                                break;
                            if ((returnValue = WriteVariableLen (tempFile,
                                    strlen (theString))))
                                break;
                            if ((returnValue = WriteString (tempFile, theString)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "trackname"))
                            {if (!numOfTracks || theTime)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = ReadTextString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, 0UL)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x03)))
                                break;
                            if ((returnValue = WriteVariableLen (tempFile,
                                    strlen (theString))))
                                break;
                            if ((returnValue = WriteString (tempFile, theString)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "instname") ||
                                StringsEqual (currCommand, "instrumentname") ||
                                StringsEqual (currCommand, "in"))
                            {if (!numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = ReadTextString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x04)))
                                break;
                            if ((returnValue = WriteVariableLen (tempFile,
                                    strlen (theString))))
                                break;
                            if ((returnValue = WriteString (tempFile, theString)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "lyric") ||
                                StringsEqual (currCommand, "l"))
                            {if ((returnValue = ReadTextString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x05)))
                                break;
                            if ((returnValue = WriteVariableLen (tempFile,
                                    strlen (theString))))
                                break;
                            if ((returnValue = WriteString (tempFile, theString)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "mark"))
                            {if (numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = ReadTextString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x06)))
                                break;
                            if ((returnValue = WriteVariableLen (tempFile,
                                    strlen (theString))))
                                break;
                            if ((returnValue = WriteString (tempFile, theString)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "cue"))
                            {if ((returnValue = ReadTextString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x07)))
                                break;
                            if ((returnValue = WriteVariableLen (tempFile,
                                    strlen (theString))))
                                break;
                            if ((returnValue = WriteString (tempFile, theString)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "o") ||
                                StringsEqual (currCommand, "owari") ||
                                StringsEqual (currCommand, "endtrack"))
                            {if (numOfTracks && trackTime != lastTrackTime)
                                {returnValue = 1;
                                TunePrint ("**Warning: track %lu is ",
                                    numOfTracks + 1);
                                if (trackTime > lastTrackTime)
                                    theNum = trackTime - lastTrackTime;
                                else
                                    theNum = lastTrackTime - trackTime;
                                TunePrint ("%g semibreves (%lu) ",
                                    ((double) theNum) / 384.0, theNum);
                                if (trackTime > lastTrackTime)
                                    TunePrint ("longer");
                                else
                                    TunePrint ("shorter");
                                TunePrint (" than track %lu.\n\n", numOfTracks);}
                            lastTrackTime = trackTime;
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x2F)))
                                break;
                            returnValue = WriteByte (tempFile, 0);
                            theStatus = 0;
                            break;}
                        else if (StringsEqual (currCommand, "bpm") ||
                                StringsEqual (currCommand, "beatsperminute") ||
                                StringsEqual (currCommand, "crotchetsperminute") ||
                                StringsEqual (currCommand, "quarternotesperminute") ||
                                StringsEqual (currCommand, "tempo"))
                            {if (numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetNumber (tuneFile, &theNum)))
                                {errorType = kArgNotNum;
                                break;}
                            if (!theNum || theNum > 60000000UL)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            theNum = 60000000UL / theNum;
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x51)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 3)))
                                break;
                            if ((returnValue = WriteByte (tempFile,
                                    (theNum >> 16) & 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile,
                                    (theNum >> 8) & 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theNum & 0xFF)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "timesig") ||
                                StringsEqual (currCommand, "timesignature"))
                            {if (numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetNumber (tuneFile, &theNum)))
                                {errorType = kArgNotNum;
                                break;}
                            if (!theNum || theNum > 224)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            timeSigN = theNum;
                            if ((returnValue = GetNumber (tuneFile, &theNum)))
                                {errorType = kArgNotNum;
                                break;}
                            if (!theNum || theNum > 32)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            timeSigD = 0;
                            while (!(theNum & 0x01))
                                {theNum >>= 1;
                                ++timeSigD;}
                            if (theNum != 1)
                                {returnValue = 1;
                                theNum <<= timeSigD;
                                errorType = kBadArgNum;
                                break;}
                            if ((returnValue = GetNumber (tuneFile, &theNum)))
                                {errorType = kArgNotNum;
                                break;}
                            if (!theNum || theNum > timeSigN)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            if (((timeSigN / theNum) * theNum) != timeSigN)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            clocksPerClick = (timeSigN / theNum) * (96 >> timeSigD);
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x58)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 4)))
                                break;
                            if ((returnValue = WriteByte (tempFile, timeSigN)))
                                break;
                            if ((returnValue = WriteByte (tempFile, timeSigD)))
                                break;
                            if ((returnValue = WriteByte (tempFile, clocksPerClick)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 8)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "keysig") ||
                                StringsEqual (currCommand, "keysignature"))
                            {if (numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if (StringsEqual (theString, "cfmaj"))
                                {theNum = 249;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "afmin"))
                                {theNum = 249;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "gfmaj"))
                                {theNum = 250;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "efmin"))
                                {theNum = 250;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "dfmaj"))
                                {theNum = 251;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "bfmin"))
                                {theNum = 251;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "afmaj"))
                                {theNum = 252;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "fmin"))
                                {theNum = 252;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "efmaj"))
                                {theNum = 253;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "cmin"))
                                {theNum = 253;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "bfmaj"))
                                {theNum = 254;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "gmin"))
                                {theNum = 254;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "fmaj"))
                                {theNum = 255;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "dmin"))
                                {theNum = 255;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "cmaj"))
                                {theNum = 0;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "amin"))
                                {theNum = 0;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "gmaj"))
                                {theNum = 1;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "emin"))
                                {theNum = 1;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "dmaj"))
                                {theNum = 2;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "bmin"))
                                {theNum = 2;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "amaj"))
                                {theNum = 3;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "fsmin"))
                                {theNum = 3;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "emaj"))
                                {theNum = 4;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "csmin"))
                                {theNum = 4;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "bmaj"))
                                {theNum = 5;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "gsmin"))
                                {theNum = 5;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "fsmaj"))
                                {theNum = 6;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "dsmin"))
                                {theNum = 6;
                                strcpy (theString, "min");}
                            else if (StringsEqual (theString, "csmaj"))
                                {theNum = 7;
                                strcpy (theString, "maj");}
                            else if (StringsEqual (theString, "asmin"))
                                {theNum = 7;
                                strcpy (theString, "min");}
                            else
                                {if (strlen (theString) > 2 || theString [0] < '0' ||
                                        theString [0] > '7')
                                    {returnValue = 1;
                                    errorType = kBadArgString;
                                    break;}
                                theNum = theString [0] - '0';
                                if (theNum && theString [1] == 'f')
                                    theNum = 256UL - theNum;
                                else if (theNum && theString [1] != 's')
                                    {returnValue = 1;
                                    errorType = kBadArgString;
                                    break;}
                                if ((returnValue = GetString (tuneFile, theString)))
                                    {errorType = kNoArgs;
                                    break;}
                                if (!StringsEqual (theString, "min") &&
                                        !StringsEqual (theString, "maj") &&
                                        !StringsEqual (theString, "minor") &&
                                        !StringsEqual (theString, "major"))
                                    {returnValue = 1;
                                    errorType = kBadArgString;
                                    break;}}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if ((returnValue = WriteByte (tempFile, 0xFF)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0x59)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 2)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;
                            if (StringsEqual (theString, "min") ||
                                    StringsEqual (theString, "minor"))
                                theNum = 1;
                            else
                                theNum = 0;
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;
                            theStatus = 0;}
                        else if (StringsEqual (currCommand, "drum") ||
                                StringsEqual (currCommand, "dr"))
                            {if (!numOfTracks)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            if (!(gXNote = StringToKitNote (theString)))
                                {returnValue = 1;
                                errorType = kBadArgString;
                                break;}
                            theChannel = 0x09;}
                        else if (StringsEqual (currCommand, "nodrum") ||
                                StringsEqual (currCommand, "nd"))
                            {if (!numOfTracks || theChannel != 0x09)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            theChannel = altChannel;}
                        else if (StringsEqual (currCommand, "redrum") ||
                                StringsEqual (currCommand, "rd"))
                            {if (!numOfTracks || theChannel == 0x09 || !gXNote)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            theChannel = 0x09;}
                        else if ((theNum = StringToKitNote (currCommand)) ||
                                StringsEqual (currCommand, "x"))
                            {if (!numOfTracks || theChannel != 0x09)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if (StringsEqual (currCommand, "x"))
                                theNum = gXNote;
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            if (theStatus != 0x90 + theChannel)
                                {theStatus = 0x90 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theStress)))
                                break;
                            if (GetNoteValue (tuneFile, &theTime))
                                theTime = lastTime;
                            if (!theTime || theTime > 0x0FFFFFFF)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                theNum = theTime;
                                break;}
                            lastTime = theTime;
                            trackTime += theTime;
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if (theStress == 64 && theStatus == 0x90 + theChannel)
                                theStress = 0;
                            else
                                {theStatus = 0x80 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theStress)))
                                break;
                            theStress = pStress;}
                        else if (StringsEqual (currCommand, "i") ||
                                StringsEqual (currCommand, "instrument"))
                            {if (theChannel == 0x09)
                                theChannel = altChannel;
                            if (!numOfTracks || theChannel > 0x0F)
                                {returnValue = 1;
                                TunePrint ("Only 15 different tracks can ");
                                TunePrint ("contain instrument commands.\n");
                                errorType = kReportedError;
                                break;}
                            if (GetNumber (tuneFile, &theNum))
                                {if ((returnValue = GetString (tuneFile, theString)))
                                    {errorType = kNoArgs;
                                    break;}
                                else if ((returnValue =
                                        StringToInstNum (theString, &theNum)))
                                    {errorType = kBadArgString;
                                    break;}}
                            if (theNum > 127)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if (theStatus != 0xC0 + theChannel)
                                {theStatus = 0xC0 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;
                            instUsed = 1;}
                        else if (StringsEqual (currCommand, "vol") ||
                                StringsEqual (currCommand, "volume"))
                            {if (!numOfTracks || (!instUsed && theChannel != 0x09))
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetNumber (tuneFile, &theNum)))
                                {errorType = kArgNotNum;
                                break;}
                            if (theNum > 127)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if (theStatus != 0xB0 + theChannel)
                                {theStatus = 0xB0 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, 0x07)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;}
                        else if (StringsEqual (currCommand, "pan") ||
                                StringsEqual (currCommand, "stereolocation"))
                            {if (!numOfTracks || (!instUsed && theChannel != 0x09))
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetNumber (tuneFile, &theNum)))
                                {errorType = kArgNotNum;
                                break;}
                            if (theNum > 127)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if (theStatus != 0xB0 + theChannel)
                                {theStatus = 0xB0 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, 0x0A)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;}
                        else if (StringsEqual (currCommand, "suson") ||
                                StringsEqual (currCommand, "sustainon"))
                            {if (!numOfTracks || (!instUsed && theChannel != 0x09))
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if (theStatus != 0xB0 + theChannel)
                                {theStatus = 0xB0 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, 0x40)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 127)))
                                break;}
                        else if (StringsEqual (currCommand, "susoff") ||
                                StringsEqual (currCommand, "sustainoff"))
                            {if (!numOfTracks || (!instUsed && theChannel != 0x09))
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if (theStatus != 0xB0 + theChannel)
                                {theStatus = 0xB0 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, 0x40)))
                                break;
                            if ((returnValue = WriteByte (tempFile, 0)))
                                break;}
                        else if (StringsEqual (currCommand, "ch") ||
                                StringsEqual (currCommand, "chord"))
                            {if (!numOfTracks || !instUsed || theChannel == 0x09)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            gNumOfNotes = 0;
                            /*  Iterate through the notes of the chord. */
                            for (;;)
                                {if (!(returnValue = GetNoteValue (tuneFile, &theTime)))
                                    break;
                                if ((returnValue = GetString (tuneFile, theString)))
                                    {errorType = kNoArgs;
                                    break;}
                                if (gNumOfNotes >= sizeof (gNotes))
                                    {returnValue = 1;
                                    TunePrint ("There are too many notes ");
                                    TunePrint ("for the \"%s\" command.\n",
                                        currCommand);
                                    errorType = kReportedError;
                                    break;}
                                stringLength = strlen (theString) - 1;
                                if (theString [stringLength] >= '0' &&
                                        theString [stringLength] <= '9')
                                    theNum = theString [stringLength] - '0';
                                else
                                    {theNum = lastOctave;
                                    ++stringLength;}
                                if (stringLength > 2 ||
                                        theString [0] < 'a' ||
                                        theString [0] > 'g' ||
                                        (stringLength == 2 &&
                                        theString [1] != 'f' &&
                                        theString [1] != 's' &&
                                        theString [1] != 'n'))
                                    {returnValue = 1;
                                    errorType = kBadArgString;
                                    break;}
                                lastOctave = theNum;
                                theNum = NoteToNum (theString, theNum, theAuto);
                                if (-theTrans > (int) theNum)
                                    {returnValue = 1;
                                    errorType = kBigTrans;
                                    break;}
                                theNum = (unsigned long) (((int) theNum) + theTrans);
                                if (theNum > 127UL)
                                    {returnValue = 1;
                                    errorType = kBigTrans;
                                    break;}
                                gNotes [gNumOfNotes] = theNum;
                                if ((returnValue = CheckDupChordNote ()))
                                    {TunePrint ("A note appears more than once ");
                                    TunePrint ("in a \"%s\" command.\n", currCommand);
                                    errorType = kReportedError;
                                    break;}
                                if ((returnValue =
                                        WriteVariableLen (tempFile, theTime)))
                                    break;
                                theTime = 0UL;
                                if (theStatus != 0x90 + theChannel)
                                    {theStatus = 0x90 + theChannel;
                                    if ((returnValue = WriteByte (tempFile,
                                            theStatus)))
                                        break;}
                                if ((returnValue = WriteByte (tempFile, theNum)))
                                    break;
                                if ((returnValue = WriteByte (tempFile, theStress)))
                                    break;
                                ++gNumOfNotes;}
                            if (returnValue)
                                break;
                            if (!gNumOfNotes)
                                {returnValue = 1;
                                TunePrint ("There are no notes ");
                                TunePrint ("for the \"%s\" command.\n", currCommand);
                                errorType = kReportedError;
                                break;}
                            if (!theTime || theTime > 0x0FFFFFFF)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                theNum = theTime;
                                break;}
                            lastTime = theTime;
                            trackTime += theTime;
                            if (theStress == 64 && theStatus == 0x90 + theChannel)
                                theStress = 0;
                            theChar = 0;
                            /*  Iterate through the notes of the chord. */
                            do
                                {if ((returnValue = WriteVariableLen (tempFile,
                                        theTime)))
                                    break;
                                theTime = 0UL;
                                if (theStress && theStatus != 0x80 + theChannel)
                                    {theStatus = 0x80 + theChannel;
                                    if ((returnValue = WriteByte (tempFile,
                                            theStatus)))
                                        break;}
                                if ((returnValue = WriteByte (tempFile,
                                        gNotes [theChar++])))
                                    break;
                                if ((returnValue = WriteByte (tempFile, theStress)))
                                    break;}
                            while (theChar < gNumOfNotes);
                            theStress = pStress;}
                        else if (StringsEqual (currCommand, "noteon"))
                            {if (!numOfTracks || !instUsed || theChannel == 0x09)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            stringLength = strlen (theString) - 1;
                            if (theString [stringLength] >= '0' &&
                                    theString [stringLength] <= '9')
                                theNum = theString [stringLength] - '0';
                            else
                                {theNum = lastOctave;
                                ++stringLength;}
                            if (stringLength > 2 ||
                                    theString [0] < 'a' ||
                                    theString [0] > 'g' ||
                                    (stringLength == 2 &&
                                    theString [1] != 'f' &&
                                    theString [1] != 's' &&
                                    theString [1] != 'n'))
                                {returnValue = 1;
                                errorType = kBadArgString;
                                break;}
                            lastOctave = theNum;
                            theNum = NoteToNum (theString, theNum, theAuto);
                            if (-theTrans > (int) theNum)
                                {returnValue = 1;
                                errorType = kBigTrans;
                                break;}
                            theNum = (unsigned long) (((int) theNum) + theTrans);
                            if (theNum > 127UL)
                                {returnValue = 1;
                                errorType = kBigTrans;
                                break;}
                            if ((returnValue =
                                    WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if (theStatus != 0x90 + theChannel)
                                {theStatus = 0x90 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theStress)))
                                break;
                            theStress = pStress;}
                        else if (StringsEqual (currCommand, "noteoff"))
                            {if (!numOfTracks || !instUsed || theChannel == 0x09)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            if ((returnValue = GetString (tuneFile, theString)))
                                {errorType = kNoArgs;
                                break;}
                            stringLength = strlen (theString) - 1;
                            if (theString [stringLength] >= '0' &&
                                    theString [stringLength] <= '9')
                                theNum = theString [stringLength] - '0';
                            else
                                {theNum = lastOctave;
                                ++stringLength;}
                            if (stringLength > 2 ||
                                    theString [0] < 'a' ||
                                    theString [0] > 'g' ||
                                    (stringLength == 2 &&
                                    theString [1] != 'f' &&
                                    theString [1] != 's' &&
                                    theString [1] != 'n'))
                                {returnValue = 1;
                                errorType = kBadArgString;
                                break;}
                            lastOctave = theNum;
                            theNum = NoteToNum (theString, theNum, theAuto);
                            if (-theTrans > (int) theNum)
                                {returnValue = 1;
                                errorType = kBigTrans;
                                break;}
                            theNum = (unsigned long) (((int) theNum) + theTrans);
                            if (theNum > 127UL)
                                {returnValue = 1;
                                errorType = kBigTrans;
                                break;}
                            if ((returnValue =
                                    WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if (theStress == 64 && theStatus == 0x90 + theChannel)
                                theStress = 0;
                            else if (theStatus != 0x80 + theChannel)
                                {theStatus = 0x80 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theStress)))
                                break;
                            theStress = pStress;}
                        else
                            {stringLength = strlen (currCommand) - 1;
                            if (currCommand [stringLength] >= '0' &&
                                    currCommand [stringLength] <= '9')
                                theNum = currCommand [stringLength] - '0';
                            else
                                {theNum = lastOctave;
                                ++stringLength;}
                            if (stringLength > 2 ||
                                    currCommand [0] < 'a' ||
                                    currCommand [0] > 'g' ||
                                    (stringLength == 2 &&
                                    currCommand [1] != 'f' &&
                                    currCommand [1] != 's' &&
                                    currCommand [1] != 'n'))
                                {returnValue = 1;
                                errorType = kReportedError;
                                TunePrint ("\"%s\" is not a Tune command.\n",
                                    currCommand);
                                break;}
                            if (!numOfTracks || !instUsed || theChannel == 0x09)
                                {returnValue = 1;
                                errorType = kBadPlace;
                                break;}
                            lastOctave = theNum;
                            theNum = NoteToNum (currCommand, theNum, theAuto);
                            if (-theTrans > (int) theNum)
                                {returnValue = 1;
                                errorType = kBigTrans;
                                break;}
                            theNum = (unsigned long) (((int) theNum) + theTrans);
                            if (theNum > 127UL)
                                {returnValue = 1;
                                errorType = kBigTrans;
                                break;}
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            if (theStatus != 0x90 + theChannel)
                                {theStatus = 0x90 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theStress)))
                                break;
                            if (GetNoteValue (tuneFile, &theTime))
                                theTime = lastTime;
                            if (!theTime || theTime > 0x0FFFFFFF)
                                {returnValue = 1;
                                errorType = kBadArgNum;
                                theNum = theTime;
                                break;}
                            lastTime = theTime;
                            trackTime += theTime;
                            if ((returnValue = WriteVariableLen (tempFile, theTime)))
                                break;
                            theTime = 0UL;
                            if (theStress == 64 && theStatus == 0x90 + theChannel)
                                theStress = 0;
                            else
                                {theStatus = 0x80 + theChannel;
                                if ((returnValue = WriteByte (tempFile, theStatus)))
                                    break;}
                            if ((returnValue = WriteByte (tempFile, theNum)))
                                break;
                            if ((returnValue = WriteByte (tempFile, theStress)))
                                break;
                            theStress = pStress;}}
                    if (returnValue)
                        break;
                    if (!(theNum = ftell (tempFile)))
                        {if (numOfTracks < 2)
                            {returnValue = 1;
                            errorType = kTooFewTracks;}
                        break;}
                    if (!numOfTracks)
                        {if ((returnValue = WriteString (midiFile, "MThd")))
                            break;
                        if ((returnValue = WriteBigEndianLength (midiFile, 6UL)))
                            break;
                        if ((returnValue = WriteByte (midiFile, 0)))
                            break;
                        if ((returnValue = WriteByte (midiFile, 1)))
                            break;
                        if ((returnValue = WriteByte (midiFile, 0)))
                            break;
                        if ((returnValue = WriteByte (midiFile, 0)))
                            break;
                        if ((returnValue = WriteByte (midiFile, 0)))
                            break;
                        if ((returnValue = WriteByte (midiFile, 96)))
                            break;}
                    rewind (tempFile);
                    if ((returnValue = WriteString (midiFile, "MTrk")))
                        break;
                    if ((returnValue = WriteBigEndianLength (midiFile, theNum)))
                        break;
                    do
                        {if ((returnValue = ReadByte (tempFile, &theChar)))
                            break;
                        if ((returnValue = WriteByte (midiFile, theChar)))
                            break;}
                    while (--theNum);
                    if (returnValue)
                        break;
                    rewind (tempFile);
                    if (numOfTracks)
                        {if (theChannel == 0x09)
                            theChannel = altChannel;
                        if (instUsed)
                            ++theChannel;
                        if (theChannel == 0x09)
                            ++theChannel;}
                    ++numOfTracks;}
                if (!returnValue)
                    {fseek (midiFile, 10L, SEEK_SET);
                    if (!(returnValue =
                            WriteByte (midiFile, (numOfTracks >> 8) & 0xFF)))
                        returnValue = WriteByte (midiFile, numOfTracks & 0xFF);}
                if (returnValue)
                    {if (errorType == kErrorWritingFile)
                        {TunePrint ("An error occurred in writing ");
                        TunePrint ("the MIDI file to disk.\n");}
                    else if (errorType == kLastCommandNotO)
                        {TunePrint ("\"%s\" doesn't end with an ", gTuneFileName);
                        TunePrint ("end-of-track command.\n");}
                    else if (errorType == kTuneUnreadable)
                        {TunePrint ("TuneToMidi can't read \"");
                        if (gIncludeDepth)
                            TunePrint ("%s", gIncludeNameStack [gIncludeDepth - 1]);
                        else
                            TunePrint ("%s", gTuneFileName);
                        TunePrint (".\"\n");
                        if ((theNum = GetLineNumber (tuneFile, ftell (tuneFile))))
                            {TunePrint ("The unreadable part begins in line %lu.\n",
                                theNum);}}
                    else if (errorType == kTooFewTracks)
                        TunePrint ("\"%s\" has fewer than two tracks.\n",
                            gTuneFileName);
                    else
                        {if (errorType == kArgNotNum)
                            GetString (tuneFile, theString);
                        errorLocationE = ftell (tuneFile);
                        if (!feof (tuneFile))
                            --errorLocationE;
                        if (errorType == kBadPlace)
                            {if (currCommand [0] == 'a' || currCommand [0] == 'e' ||
                                    currCommand [0] == 'i' || currCommand [0] == 'o')
                                TunePrint ("An");
                            else
                                TunePrint ("A");
                            TunePrint (" \"%s\" command is not appropriate\n",
                                currCommand);
                            TunePrint ("at this point in the Tune file.\n");}
                        else if (errorType == kBadArgString || errorType == kArgNotNum)
                            {TunePrint ("\"%s\" is an inappropriate argument\n",
                                theString);
                            TunePrint ("for the \"%s\" command.\n", currCommand);}
                        else if (errorType == kBadArgNum)
                            {TunePrint ("\"%lu\" is an inappropriate argument\n",
                                theNum);
                            TunePrint ("for the \"%s\" command.\n", currCommand);}
                        else if (errorType == kNoArgs)
                            {TunePrint ("An argument for the ");
                            TunePrint ("\"%s\" command could not be read.\n",
                                currCommand);}
                        else if (errorType == kBigTrans)
                            TunePrint ("This note is transposed too high or low.\n");
                        if ((theNum = GetLineNumber (tuneFile, errorLocationS)))
                            {TunePrint ("\nThe erroneous command begins ");
                            TunePrint ("in line %lu of\n\"", theNum);
                            if (gIncludeDepth)
                                TunePrint ("%s", gIncludeNameStack [gIncludeDepth - 1]);
                            else
                                TunePrint ("%s", gTuneFileName);
                            TunePrint (".\"\n");
                            if (!ReadTextStringN (tuneFile, theString,
                                    errorLocationE - errorLocationS))
                                TunePrint ("-----\n%s\n-----\n", theString);}}}
                while (gIncludeDepth)
                    {fclose (tuneFile);
                    tuneFile = gIncludeStack [--gIncludeDepth];
                    free (gIncludeNameStack [gIncludeDepth]);}
                fclose (tuneFile);
                fclose (midiFile);
                fclose (tempFile);
                if (returnValue)
                    {remove (gMidiFileName);
                    TuneBeep ();}
                else
                    TunePrint ("\"%s\" was successfully compiled into\n\"%s.\"\n",
                        gTuneFileName, gMidiFileName);
                if (!outputSpec)
                    free (gMidiFileName);}
            TunePrint ("==============\n");
            return (returnValue ? EXIT_FAILURE : EXIT_SUCCESS);}

        int     CheckDupChordNote (void)

            {unsigned long  theIndex, theNote;
            int             returnValue;

            theIndex = gNumOfNotes;
            theNote = gNotes [theIndex];
            returnValue = 0;
            while (theIndex)
                {if (gNotes [--theIndex] == theNote)
                    {returnValue = 1;
                    break;}}
            return (returnValue);}

        int     CheckSelfRef (void)

            {int            returnValue;
            long            fileLocation;
            unsigned long   theIndex;

            returnValue = 0;
            theIndex = gDefDepth;
            fileLocation = gDefStartStack [--theIndex];
            while (theIndex)
                {if (gDefStartStack [--theIndex] == fileLocation)
                    {returnValue = 1;
                    break;}}
            return (returnValue);}

        void    SkipTextCommands (FILE *tuneFile, const char *theString)

            {if (StringsEqual (theString, "include") ||
                    StringsEqual (theString, "inc") ||
                    StringsEqual (theString, "rem") ||
                    StringsEqual (theString, "remark") ||
                    StringsEqual (theString, "text") ||
                    StringsEqual (theString, "copr") ||
                    StringsEqual (theString, "copyright") ||
                    StringsEqual (theString, "seqtitle") ||
                    StringsEqual (theString, "sequencetitle") ||
                    StringsEqual (theString, "trackname") ||
                    StringsEqual (theString, "instname") ||
                    StringsEqual (theString, "instrumentname") ||
                    StringsEqual (theString, "in") ||
                    StringsEqual (theString, "lyric") ||
                    StringsEqual (theString, "l") ||
                    StringsEqual (theString, "mark") ||
                    StringsEqual (theString, "cue"))
                WindToEndOfLine (tuneFile);
            else if (StringsEqual (theString, "comment"))
                {while (!feof (tuneFile))
                    {if (WindToEndOfLine (tuneFile))
                        break;}}
            return;}

unsigned long   NoteToNum (char *theString, unsigned long theOct, int theAuto)

            {unsigned long  theNum;

            theNum = (theOct * 12UL) + 12UL;
            if (theString [0] == 'b')
                theNum += 11UL;
            else if (theString [0] == 'a')
                theNum += 9UL;
            else if (theString [0] == 'g')
                theNum += 7UL;
            else if (theString [0] == 'f')
                theNum += 5UL;
            else if (theString [0] == 'e')
                theNum += 4UL;
            else if (theString [0] == 'd')
                theNum += 2UL;
            if (theString [1] == 'f')
                --theNum;
            else if (theString [1] == 's')
                ++theNum;
            else if (theAuto && theString [1] != 'n')
                {if (theString [0] == 'b')
                    {if (theAuto > 6)
                        ++theNum;
                    else if (theAuto < 0)
                        --theNum;}
                else if (theString [0] == 'a')
                    {if (theAuto > 4)
                        ++theNum;
                    else if (theAuto < -2)
                        --theNum;}
                else if (theString [0] == 'g')
                    {if (theAuto > 2)
                        ++theNum;
                    else if (theAuto < -4)
                        --theNum;}
                else if (theString [0] == 'f')
                    {if (theAuto > 0)
                        ++theNum;
                    else if (theAuto < -6)
                        --theNum;}
                else if (theString [0] == 'e')
                    {if (theAuto > 5)
                        ++theNum;
                    else if (theAuto < -1)
                        --theNum;}
                else if (theString [0] == 'd')
                    {if (theAuto > 3)
                        ++theNum;
                    else if (theAuto < -3)
                        --theNum;}
                else if (theAuto > 1)
                    ++theNum;
                else if (theAuto < -5)
                    --theNum;}
            return (theNum);}

        int     GetNoteValue (FILE *tuneFile, unsigned long *theNum)

            {char   theString [256];
            int     returnValue;
            long    fileLocation;

            fileLocation = ftell (tuneFile);
            if (!GetNumber (tuneFile, theNum))
                return (0);
            fseek (tuneFile, fileLocation, SEEK_SET);
            if (!(returnValue = GetString (tuneFile, theString)))
                {if (StringsEqual (theString, "vs64"))
                    *theNum = 24576;
                else if (StringsEqual (theString, "vs48"))
                    *theNum = 18432;
                else if (StringsEqual (theString, "vs36"))
                    *theNum = 13824;
                else if (StringsEqual (theString, "vs32"))
                    *theNum = 12288;
                else if (StringsEqual (theString, "vs24"))
                    *theNum = 9216;
                else if (StringsEqual (theString, "vs16"))
                    *theNum = 6144;
                else if (StringsEqual (theString, "vs12"))
                    *theNum = 4608;
                else if (StringsEqual (theString, "vs8"))
                    *theNum = 3072;
                else if (StringsEqual (theString, "vs6"))
                    *theNum = 2304;
                else if (StringsEqual (theString, "vs4"))
                    *theNum = 1536;
                else if (StringsEqual (theString, "vs3"))
                    *theNum = 1152;
                else if (StringsEqual (theString, "vs2"))
                    *theNum = 768;
                else if (StringsEqual (theString, "vs1"))
                    *theNum = 384;
                else if (StringsEqual (theString, "v1"))
                    *theNum = 384;
                else if (StringsEqual (theString, "v2"))
                    *theNum = 192;
                else if (StringsEqual (theString, "v4"))
                    *theNum = 96;
                else if (StringsEqual (theString, "v8"))
                    *theNum = 48;
                else if (StringsEqual (theString, "v16"))
                    *theNum = 24;
                else if (StringsEqual (theString, "v32"))
                    *theNum = 12;
                else if (StringsEqual (theString, "vd1"))
                    *theNum = 576;
                else if (StringsEqual (theString, "vd2"))
                    *theNum = 288;
                else if (StringsEqual (theString, "vd4"))
                    *theNum = 144;
                else if (StringsEqual (theString, "vd8"))
                    *theNum = 72;
                else if (StringsEqual (theString, "vd16"))
                    *theNum = 36;
                else if (StringsEqual (theString, "vd32"))
                    *theNum = 18;
                else if (StringsEqual (theString, "vt2"))
                    *theNum = 128;
                else if (StringsEqual (theString, "vt4"))
                    *theNum = 64;
                else if (StringsEqual (theString, "vt8"))
                    *theNum = 32;
                else if (StringsEqual (theString, "vt16"))
                    *theNum = 16;
                else if (StringsEqual (theString, "vt32"))
                    *theNum = 8;
                else if (StringsEqual (theString, "64w"))
                    *theNum = 24576;
                else if (StringsEqual (theString, "48w"))
                    *theNum = 18432;
                else if (StringsEqual (theString, "36w"))
                    *theNum = 13824;
                else if (StringsEqual (theString, "32w"))
                    *theNum = 12288;
                else if (StringsEqual (theString, "24w"))
                    *theNum = 9216;
                else if (StringsEqual (theString, "16w"))
                    *theNum = 6144;
                else if (StringsEqual (theString, "12w"))
                    *theNum = 4608;
                else if (StringsEqual (theString, "8w"))
                    *theNum = 3072;
                else if (StringsEqual (theString, "6w"))
                    *theNum = 2304;
                else if (StringsEqual (theString, "4w"))
                    *theNum = 1536;
                else if (StringsEqual (theString, "3w"))
                    *theNum = 1152;
                else if (StringsEqual (theString, "2w"))
                    *theNum = 768;
                else if (StringsEqual (theString, "1w"))
                    *theNum = 384;
                else if (StringsEqual (theString, "ww"))
                    *theNum = 384;
                else if (StringsEqual (theString, "hh"))
                    *theNum = 192;
                else if (StringsEqual (theString, "qq"))
                    *theNum = 96;
                else if (StringsEqual (theString, "ee"))
                    *theNum = 48;
                else if (StringsEqual (theString, "ss"))
                    *theNum = 24;
                else if (StringsEqual (theString, "tt"))
                    *theNum = 12;
                else if (StringsEqual (theString, "wwd"))
                    *theNum = 576;
                else if (StringsEqual (theString, "hhd"))
                    *theNum = 288;
                else if (StringsEqual (theString, "qqd"))
                    *theNum = 144;
                else if (StringsEqual (theString, "eed"))
                    *theNum = 72;
                else if (StringsEqual (theString, "ssd"))
                    *theNum = 36;
                else if (StringsEqual (theString, "ttd"))
                    *theNum = 18;
                else if (StringsEqual (theString, "hh3"))
                    *theNum = 128;
                else if (StringsEqual (theString, "qq3"))
                    *theNum = 64;
                else if (StringsEqual (theString, "ee3"))
                    *theNum = 32;
                else if (StringsEqual (theString, "ss3"))
                    *theNum = 16;
                else if (StringsEqual (theString, "tt3"))
                    *theNum = 8;
                else if (StringsEqual (theString, "www"))
                    *theNum = 576;
                else if (StringsEqual (theString, "hhh"))
                    *theNum = 288;
                else if (StringsEqual (theString, "qqq"))
                    *theNum = 144;
                else if (StringsEqual (theString, "eee"))
                    *theNum = 72;
                else if (StringsEqual (theString, "sss"))
                    *theNum = 36;
                else if (StringsEqual (theString, "ttt"))
                    *theNum = 18;
                else if (StringsEqual (theString, "semibreve"))
                    *theNum = 384;
                else if (StringsEqual (theString, "minim"))
                    *theNum = 192;
                else if (StringsEqual (theString, "crotchet"))
                    *theNum = 96;
                else if (StringsEqual (theString, "quaver"))
                    *theNum = 48;
                else if (StringsEqual (theString, "semiquaver"))
                    *theNum = 24;
                else if (StringsEqual (theString, "demisemiquaver"))
                    *theNum = 12;
                else if (StringsEqual (theString, "whole"))
                    *theNum = 384;
                else if (StringsEqual (theString, "half"))
                    *theNum = 192;
                else if (StringsEqual (theString, "quarter"))
                    *theNum = 96;
                else if (StringsEqual (theString, "eighth"))
                    *theNum = 48;
                else if (StringsEqual (theString, "sixteenth"))
                    *theNum = 24;
                else if (StringsEqual (theString, "thirtysecond"))
                    *theNum = 12;
                else
                    returnValue = 1;}
            if (returnValue)
                fseek (tuneFile, fileLocation, SEEK_SET);
            return (returnValue);}

        int     StringToNumber (const char *theString, unsigned long *theNum)

            {int            returnValue;
    const   char            *strPtr;
            char            theChar;
            unsigned long   theValue;

            returnValue = 0;
            strPtr = theString;
            theValue = 0UL;
            while ((theChar = *(strPtr++)))
                {if (theChar < '0' || theChar > '9')
                    {returnValue = 1;
                    break;}
                theChar -= '0';
                theValue *= 10UL;
                if (theValue > (~0UL) - theChar)
                    {returnValue = 1;
                    break;}
                theValue += theChar;}
            if (!returnValue)
                *theNum = theValue;
            return (returnValue);}

        int     GetSignedNumber (FILE *tuneFile, int *theNum)

            {char           theString [256];
            int             returnValue, absValue;
            long            fileLocation;
            unsigned long   ulValue;

            fileLocation = ftell (tuneFile);
            if (!(returnValue = GetString (tuneFile, theString)))
                {if ((theString [0] == '+' || theString [0] == '-') &&
                        theString [1] != '\0')
                    returnValue = StringToNumber (&(theString [1]),
                        &ulValue);
                else
                    returnValue = StringToNumber (theString, &ulValue);}
            if (!returnValue)
                {absValue = ulValue;
                if (ulValue != ((unsigned long) absValue))
                    returnValue = 1;}
            if (returnValue)
                fseek (tuneFile, fileLocation, SEEK_SET);
            else if (*theString == '-')
                *theNum = -absValue;
            else
                *theNum = absValue;
            return (returnValue);}

        int     GetNumber (FILE *tuneFile, unsigned long *theNum)

            {char   theString [256];
            int     returnValue;
            long    fileLocation;

            fileLocation = ftell (tuneFile);
            if (!(returnValue = GetString (tuneFile, theString)))
                {if (theString [0] == '+' && theString [1] != '\0')
                    returnValue = StringToNumber (&(theString [1]), theNum);
                else
                    returnValue = StringToNumber (theString, theNum);}
            if (returnValue)
                fseek (tuneFile, fileLocation, SEEK_SET);
            return (returnValue);}

        int     GetString (FILE *tuneFile, char *theString)

            {int            returnValue;
            char            theChar;
            unsigned long   theLength;

            returnValue = 0;
            theLength = 0UL;
            do
                {if (fread (&theChar, 1, 1, tuneFile) != 1)
                    {returnValue = 1;
                    break;}}
            while (theChar == 0x20 || theChar == 0x09 ||
                    theChar == 0x0A || theChar == 0x0C ||
                    theChar == 0x0D);
            if (!returnValue)
                {if (theChar < 0x20 || theChar > 0x7E)
                    returnValue = 1;
                else
                    {if (theChar >= 'A' && theChar <= 'Z')
                        theChar += 'a' - 'A';
                    theString [theLength++] = theChar;
                    while (fread (&theChar, 1, 1, tuneFile) == 1)
                        {if (theChar == 0x20 || theChar == 0x09 ||
                                theChar == 0x0A || theChar == 0x0C ||
                                theChar == 0x0D)
                            break;
                        if (theChar < 0x20 || theChar > 0x7E)
                            {returnValue = 1;
                            break;}
                        if (theLength == 255)
                            {returnValue = 1;
                            break;}
                        if (theChar >= 'A' && theChar <= 'Z')
                            theChar += 'a' - 'A';
                        theString [theLength++] = theChar;}}}
            theString [theLength] = '\0';
            return (returnValue);}

        int     WriteBigEndianLength (FILE *midiFile, unsigned long theLength)

            {unsigned char  theChar;

            theChar = (theLength >> 24) & 0xFF;
            if (fwrite (&theChar, 1, 1, midiFile) != 1)
                return (1);
            theChar = (theLength >> 16) & 0xFF;
            if (fwrite (&theChar, 1, 1, midiFile) != 1)
                return (1);
            theChar = (theLength >> 8) & 0xFF;
            if (fwrite (&theChar, 1, 1, midiFile) != 1)
                return (1);
            theChar = theLength & 0xFF;
            if (fwrite (&theChar, 1, 1, midiFile) != 1)
                return (1);
            return (0);}

        int     WriteByte (FILE *midiFile, unsigned char theChar)

            {unsigned char  charToWrite;

            charToWrite = theChar;
            return (fwrite (&charToWrite, 1, 1, midiFile) != 1);}

        int     ReadByte (FILE *midiFile, unsigned char *theChar)

            {return (fread (theChar, 1, 1, midiFile) != 1);}

        int     WriteVariableLen (FILE *midiFile, unsigned long theLength)

            {unsigned long  lengthToWrite;
            unsigned char   byteA, byteB, byteC, byteD;

            lengthToWrite = theLength;
            byteD = lengthToWrite & 0x7F;
            if ((lengthToWrite >>= 7))
                byteC = (lengthToWrite & 0x7F) | 0x80;
            else
                byteC = 0x00;
            if ((lengthToWrite >>= 7))
                byteB = (lengthToWrite & 0x7F) | 0x80;
            else
                byteB = 0x00;
            if ((lengthToWrite >>= 7))
                byteA = (lengthToWrite & 0x7F) | 0x80;
            else
                byteA = 0x00;
            if (byteA)
                {if (fwrite (&byteA, 1, 1, midiFile) != 1)
                    return (1);}
            if (byteB)
                {if (fwrite (&byteB, 1, 1, midiFile) != 1)
                    return (1);}
            if (byteC)
                {if (fwrite (&byteC, 1, 1, midiFile) != 1)
                    return (1);}
            if (fwrite (&byteD, 1, 1, midiFile) != 1)
                return (1);
            return (0);}

        int     WriteString (FILE *midiFile, const char *theString)

            {int    returnValue;
    const   char    *strPtr;

            returnValue = 0;
            strPtr = theString;
            while (*strPtr)
                {if ((returnValue = WriteByte (midiFile, *(strPtr++))))
                    break;}
            return (returnValue);}

        int     ReadTextStringN (FILE *tuneFile, char *theString,
                            unsigned long lengthToRead)

            {int            returnValue;
            char            theChar, lastChar;
            unsigned long   theLength, lengthLeft;

            theLength = 0UL;
            lengthLeft = lengthToRead;
            theChar = '\0';
            returnValue = 0;
            while (theLength < lengthLeft)
                {lastChar = theChar;
                if (fread (&theChar, 1, 1, tuneFile) != 1)
                    {returnValue = 1;
                    break;}
                if (theChar == 0x0A && lastChar == 0x0D)
                    {--lengthLeft;
                    continue;}
                if (theChar == 0x0A || theChar == 0x0C ||
                        theChar == 0x0D)
                    {if (theLength)
                        theString [theLength] = '\n';
                    else
                        {--lengthLeft;
                        continue;}}
                else
                    theString [theLength] = theChar;
                if (++theLength == 255)
                    break;}
            theString [theLength] = '\0';
            return (returnValue);}

        int     ReadTextString (FILE *tuneFile, char *theString)

            {int            returnValue;
            char            theChar;
            unsigned long   theLength;

            returnValue = 0;
            theLength = 0UL;
            do
                {if (fread (&theChar, 1, 1, tuneFile) != 1)
                    {returnValue = 1;
                    break;}}
            while (theChar == 0x20 || theChar == 0x09);
            if (!returnValue)
                {if (theChar < 0x20)
                    returnValue = 1;
                else
                    {theString [theLength++] = theChar;
                    while (fread (&theChar, 1, 1, tuneFile) == 1)
                        {if (theChar == 0x0A || theChar == 0x0C ||
                                theChar == 0x0D)
                            break;
                        if (theChar < 0x20 && theChar != 0x09)
                            {returnValue = 1;
                            break;}
                        if (theLength == 255)
                            {returnValue = 1;
                            break;}
                        theString [theLength++] = theChar;}}}
            theString [theLength] = '\0';
            return (returnValue);}

        int     WindToEndOfLine (FILE *tuneFile)

            {int    returnValue;
            char    theChar;

            returnValue = 0;
            while (fread (&theChar, 1, 1, tuneFile) == 1)
                {if (theChar == 0x0A || theChar == 0x0C || theChar == 0x0D)
                    break;
                if (theChar < 0x20 && theChar != 0x09)
                    {returnValue = 1;
                    break;}}
            return (returnValue);}

unsigned long   GetLineNumber (FILE *tuneFile, long theOffset)

            {unsigned long  theLineNumber;
            long            theIndex;
            char            theChar, lastChar;

            rewind (tuneFile);
            theIndex = 0;
            theLineNumber = 1;
            theChar = '\0';
            while (theIndex < theOffset)
                {++theIndex;
                lastChar = theChar;
                if (fread (&theChar, 1, 1, tuneFile) != 1)
                    break;
                if (theChar == 0x0A && lastChar == 0x0D)
                    continue;
                if (theChar == 0x0A || theChar == 0x0C ||
                        theChar == 0x0D)
                    ++theLineNumber;}
            if (theIndex < theOffset)
                theLineNumber = 0;
            return (theLineNumber);}

        int     StringToInstNum (char *theString, unsigned long *theNum)

            {if (StringsEqual (theString, "piano"))
                *theNum = 0;
            else if (StringsEqual (theString, "grandpiano"))
                *theNum = 0;
            else if (StringsEqual (theString, "brightpiano"))
                *theNum = 1;
            else if (StringsEqual (theString, "electricpiano"))
                *theNum = 2;
            else if (StringsEqual (theString, "honkytonkpiano"))
                *theNum = 3;
            else if (StringsEqual (theString, "rhodespiano"))
                *theNum = 4;
            else if (StringsEqual (theString, "electricpiano1"))
                *theNum = 4;
            else if (StringsEqual (theString, "chorusedpiano"))
                *theNum = 5;
            else if (StringsEqual (theString, "electricpiano2"))
                *theNum = 5;
            else if (StringsEqual (theString, "harpsichord"))
                *theNum = 6;
            else if (StringsEqual (theString, "clavinet"))
                *theNum = 7;
            else if (StringsEqual (theString, "celesta"))
                *theNum = 8;
            else if (StringsEqual (theString, "glockenspiel"))
                *theNum = 9;
            else if (StringsEqual (theString, "musicbox"))
                *theNum = 10;
            else if (StringsEqual (theString, "vibraphone"))
                *theNum = 11;
            else if (StringsEqual (theString, "marimba"))
                *theNum = 12;
            else if (StringsEqual (theString, "xylophone"))
                *theNum = 13;
            else if (StringsEqual (theString, "tubularbells"))
                *theNum = 14;
            else if (StringsEqual (theString, "dulcimer"))
                *theNum = 15;
            else if (StringsEqual (theString, "santur"))
                *theNum = 15;
            else if (StringsEqual (theString, "drawbarorgan"))
                *theNum = 16;
            else if (StringsEqual (theString, "hammondorgan"))
                *theNum = 16;
            else if (StringsEqual (theString, "percussiveorgan"))
                *theNum = 17;
            else if (StringsEqual (theString, "rockorgan"))
                *theNum = 18;
            else if (StringsEqual (theString, "churchorgan"))
                *theNum = 19;
            else if (StringsEqual (theString, "organ"))
                *theNum = 19;
            else if (StringsEqual (theString, "reedorgan"))
                *theNum = 20;
            else if (StringsEqual (theString, "accordion"))
                *theNum = 21;
            else if (StringsEqual (theString, "frenchaccordion"))
                *theNum = 21;
            else if (StringsEqual (theString, "harmonica"))
                *theNum = 22;
            else if (StringsEqual (theString, "tangoaccordion"))
                *theNum = 23;
            else if (StringsEqual (theString, "bandneon"))
                *theNum = 23;
            else if (StringsEqual (theString, "nylonguitar"))
                *theNum = 24;
            else if (StringsEqual (theString, "steelguitar"))
                *theNum = 25;
            else if (StringsEqual (theString, "guitar"))
                *theNum = 25;
            else if (StringsEqual (theString, "jazzguitar"))
                *theNum = 26;
            else if (StringsEqual (theString, "cleanguitar"))
                *theNum = 27;
            else if (StringsEqual (theString, "mutedguitar"))
                *theNum = 28;
            else if (StringsEqual (theString, "overdrivenguitar"))
                *theNum = 29;
            else if (StringsEqual (theString, "distortionguitar"))
                *theNum = 30;
            else if (StringsEqual (theString, "guitarharmonics"))
                *theNum = 31;
            else if (StringsEqual (theString, "bass"))
                *theNum = 32;
            else if (StringsEqual (theString, "fingeredbass"))
                *theNum = 33;
            else if (StringsEqual (theString, "pickedbass"))
                *theNum = 34;
            else if (StringsEqual (theString, "fretlessbass"))
                *theNum = 35;
            else if (StringsEqual (theString, "slapbass1"))
                *theNum = 36;
            else if (StringsEqual (theString, "slapbass2"))
                *theNum = 37;
            else if (StringsEqual (theString, "synthbass1"))
                *theNum = 38;
            else if (StringsEqual (theString, "synthbass2"))
                *theNum = 39;
            else if (StringsEqual (theString, "violin"))
                *theNum = 40;
            else if (StringsEqual (theString, "viola"))
                *theNum = 41;
            else if (StringsEqual (theString, "cello"))
                *theNum = 42;
            else if (StringsEqual (theString, "contrabass"))
                *theNum = 43;
            else if (StringsEqual (theString, "tremolostrings"))
                *theNum = 44;
            else if (StringsEqual (theString, "pizzicatostrings"))
                *theNum = 45;
            else if (StringsEqual (theString, "harp"))
                *theNum = 46;
            else if (StringsEqual (theString, "timpani"))
                *theNum = 47;
            else if (StringsEqual (theString, "strings"))
                *theNum = 48;
            else if (StringsEqual (theString, "stringensemble1"))
                *theNum = 48;
            else if (StringsEqual (theString, "slowstrings"))
                *theNum = 49;
            else if (StringsEqual (theString, "stringensemble2"))
                *theNum = 49;
            else if (StringsEqual (theString, "synthstrings1"))
                *theNum = 50;
            else if (StringsEqual (theString, "synthstrings2"))
                *theNum = 51;
            else if (StringsEqual (theString, "choiraahs"))
                *theNum = 52;
            else if (StringsEqual (theString, "choiroohs"))
                *theNum = 53;
            else if (StringsEqual (theString, "synthvoice"))
                *theNum = 54;
            else if (StringsEqual (theString, "orchestrahit"))
                *theNum = 55;
            else if (StringsEqual (theString, "trumpet"))
                *theNum = 56;
            else if (StringsEqual (theString, "trombone"))
                *theNum = 57;
            else if (StringsEqual (theString, "tuba"))
                *theNum = 58;
            else if (StringsEqual (theString, "mutedtrumpet"))
                *theNum = 59;
            else if (StringsEqual (theString, "frenchhorn"))
                *theNum = 60;
            else if (StringsEqual (theString, "brasssection"))
                *theNum = 61;
            else if (StringsEqual (theString, "synthbrass1"))
                *theNum = 62;
            else if (StringsEqual (theString, "synthbrass2"))
                *theNum = 63;
            else if (StringsEqual (theString, "sopranosax"))
                *theNum = 64;
            else if (StringsEqual (theString, "altosax"))
                *theNum = 65;
            else if (StringsEqual (theString, "tenorsax"))
                *theNum = 66;
            else if (StringsEqual (theString, "baritonesax"))
                *theNum = 67;
            else if (StringsEqual (theString, "oboe"))
                *theNum = 68;
            else if (StringsEqual (theString, "englishhorn"))
                *theNum = 69;
            else if (StringsEqual (theString, "bassoon"))
                *theNum = 70;
            else if (StringsEqual (theString, "clarinet"))
                *theNum = 71;
            else if (StringsEqual (theString, "piccolo"))
                *theNum = 72;
            else if (StringsEqual (theString, "flute"))
                *theNum = 73;
            else if (StringsEqual (theString, "recorder"))
                *theNum = 74;
            else if (StringsEqual (theString, "panflute"))
                *theNum = 75;
            else if (StringsEqual (theString, "blownbottle"))
                *theNum = 76;
            else if (StringsEqual (theString, "shakuhachi"))
                *theNum = 77;
            else if (StringsEqual (theString, "whistle"))
                *theNum = 78;
            else if (StringsEqual (theString, "ocarina"))
                *theNum = 79;
            else if (StringsEqual (theString, "squarewave"))
                *theNum = 80;
            else if (StringsEqual (theString, "lead1"))
                *theNum = 80;
            else if (StringsEqual (theString, "sawtoothwave"))
                *theNum = 81;
            else if (StringsEqual (theString, "lead2"))
                *theNum = 81;
            else if (StringsEqual (theString, "calliope"))
                *theNum = 82;
            else if (StringsEqual (theString, "lead3"))
                *theNum = 82;
            else if (StringsEqual (theString, "chiffer"))
                *theNum = 83;
            else if (StringsEqual (theString, "lead4"))
                *theNum = 83;
            else if (StringsEqual (theString, "charang"))
                *theNum = 84;
            else if (StringsEqual (theString, "lead5"))
                *theNum = 84;
            else if (StringsEqual (theString, "voicesolo"))
                *theNum = 85;
            else if (StringsEqual (theString, "lead6"))
                *theNum = 85;
            else if (StringsEqual (theString, "fifths"))
                *theNum = 86;
            else if (StringsEqual (theString, "lead7"))
                *theNum = 86;
            else if (StringsEqual (theString, "basspluslead"))
                *theNum = 87;
            else if (StringsEqual (theString, "lead8"))
                *theNum = 87;
            else if (StringsEqual (theString, "fantasia"))
                *theNum = 88;
            else if (StringsEqual (theString, "pad1"))
                *theNum = 88;
            else if (StringsEqual (theString, "warm"))
                *theNum = 89;
            else if (StringsEqual (theString, "pad2"))
                *theNum = 89;
            else if (StringsEqual (theString, "polysynth"))
                *theNum = 90;
            else if (StringsEqual (theString, "pad3"))
                *theNum = 90;
            else if (StringsEqual (theString, "choirspacevoice"))
                *theNum = 91;
            else if (StringsEqual (theString, "pad4"))
                *theNum = 91;
            else if (StringsEqual (theString, "bowedglass"))
                *theNum = 92;
            else if (StringsEqual (theString, "pad5"))
                *theNum = 92;
            else if (StringsEqual (theString, "metallicpro"))
                *theNum = 93;
            else if (StringsEqual (theString, "pad6"))
                *theNum = 93;
            else if (StringsEqual (theString, "halo"))
                *theNum = 94;
            else if (StringsEqual (theString, "pad7"))
                *theNum = 94;
            else if (StringsEqual (theString, "sweep"))
                *theNum = 95;
            else if (StringsEqual (theString, "pad8"))
                *theNum = 95;
            else if (StringsEqual (theString, "rain"))
                *theNum = 96;
            else if (StringsEqual (theString, "fx1"))
                *theNum = 96;
            else if (StringsEqual (theString, "soundtrack"))
                *theNum = 97;
            else if (StringsEqual (theString, "fx2"))
                *theNum = 97;
            else if (StringsEqual (theString, "crystal"))
                *theNum = 98;
            else if (StringsEqual (theString, "fx3"))
                *theNum = 98;
            else if (StringsEqual (theString, "atmosphere"))
                *theNum = 99;
            else if (StringsEqual (theString, "fx4"))
                *theNum = 99;
            else if (StringsEqual (theString, "brightness"))
                *theNum = 100;
            else if (StringsEqual (theString, "fx5"))
                *theNum = 100;
            else if (StringsEqual (theString, "goblins"))
                *theNum = 101;
            else if (StringsEqual (theString, "fx6"))
                *theNum = 101;
            else if (StringsEqual (theString, "echoes"))
                *theNum = 102;
            else if (StringsEqual (theString, "drops"))
                *theNum = 102;
            else if (StringsEqual (theString, "fx7"))
                *theNum = 102;
            else if (StringsEqual (theString, "scifi"))
                *theNum = 103;
            else if (StringsEqual (theString, "fx8"))
                *theNum = 103;
            else if (StringsEqual (theString, "sitar"))
                *theNum = 104;
            else if (StringsEqual (theString, "banjo"))
                *theNum = 105;
            else if (StringsEqual (theString, "shamisen"))
                *theNum = 106;
            else if (StringsEqual (theString, "koto"))
                *theNum = 107;
            else if (StringsEqual (theString, "kalimba"))
                *theNum = 108;
            else if (StringsEqual (theString, "bagpipe"))
                *theNum = 109;
            else if (StringsEqual (theString, "fiddle"))
                *theNum = 110;
            else if (StringsEqual (theString, "shanai"))
                *theNum = 111;
            else if (StringsEqual (theString, "tinklebell"))
                *theNum = 112;
            else if (StringsEqual (theString, "agogo"))
                *theNum = 113;
            else if (StringsEqual (theString, "steeldrums"))
                *theNum = 114;
            else if (StringsEqual (theString, "woodblock"))
                *theNum = 115;
            else if (StringsEqual (theString, "taiko"))
                *theNum = 116;
            else if (StringsEqual (theString, "melodictom"))
                *theNum = 117;
            else if (StringsEqual (theString, "synthdrum"))
                *theNum = 118;
            else if (StringsEqual (theString, "reversecymbal"))
                *theNum = 119;
            else if (StringsEqual (theString, "fretnoise"))
                *theNum = 120;
            else if (StringsEqual (theString, "breathnoise"))
                *theNum = 121;
            else if (StringsEqual (theString, "seashore"))
                *theNum = 122;
            else if (StringsEqual (theString, "birdtweet"))
                *theNum = 123;
            else if (StringsEqual (theString, "telephonering"))
                *theNum = 124;
            else if (StringsEqual (theString, "helicopter"))
                *theNum = 125;
            else if (StringsEqual (theString, "applause"))
                *theNum = 126;
            else if (StringsEqual (theString, "gunshot"))
                *theNum = 127;
            else
                return (1);
            return (0);}

unsigned char   StringToKitNote (const char *theString)

            {if (StringsEqual (theString, "acousticbass"))
                return (35);
            if (StringsEqual (theString, "bass"))
                return (35);
            if (StringsEqual (theString, "bass1"))
                return (36);
            if (StringsEqual (theString, "sidestick"))
                return (37);
            if (StringsEqual (theString, "acousticsnare"))
                return (38);
            if (StringsEqual (theString, "snare"))
                return (38);
            if (StringsEqual (theString, "handclap"))
                return (39);
            if (StringsEqual (theString, "electricsnare"))
                return (40);
            if (StringsEqual (theString, "lowfloortom"))
                return (41);
            if (StringsEqual (theString, "closedhighhat"))
                return (42);
            if (StringsEqual (theString, "highfloortom"))
                return (43);
            if (StringsEqual (theString, "pedalhighhat"))
                return (44);
            if (StringsEqual (theString, "lowtom"))
                return (45);
            if (StringsEqual (theString, "openhighhat"))
                return (46);
            if (StringsEqual (theString, "lowmidtom"))
                return (47);
            if (StringsEqual (theString, "highmidtom"))
                return (48);
            if (StringsEqual (theString, "crashcymbal1"))
                return (49);
            if (StringsEqual (theString, "hightom"))
                return (50);
            if (StringsEqual (theString, "ridecymbal1"))
                return (51);
            if (StringsEqual (theString, "chinesecymbal"))
                return (52);
            if (StringsEqual (theString, "ridebell"))
                return (53);
            if (StringsEqual (theString, "tambourine"))
                return (54);
            if (StringsEqual (theString, "splashcymbal"))
                return (55);
            if (StringsEqual (theString, "cowbell"))
                return (56);
            if (StringsEqual (theString, "crashcymbal2"))
                return (57);
            if (StringsEqual (theString, "vibraslap"))
                return (58);
            if (StringsEqual (theString, "ridecymbal2"))
                return (59);
            if (StringsEqual (theString, "highbongo"))
                return (60);
            if (StringsEqual (theString, "lowbongo"))
                return (61);
            if (StringsEqual (theString, "mutehighconga"))
                return (62);
            if (StringsEqual (theString, "openhighconga"))
                return (63);
            if (StringsEqual (theString, "lowconga"))
                return (64);
            if (StringsEqual (theString, "hightimbale"))
                return (65);
            if (StringsEqual (theString, "lowtimbale"))
                return (66);
            if (StringsEqual (theString, "highagogo"))
                return (67);
            if (StringsEqual (theString, "lowagogo"))
                return (68);
            if (StringsEqual (theString, "cabasa"))
                return (69);
            if (StringsEqual (theString, "maracas"))
                return (70);
            if (StringsEqual (theString, "shortwhistle"))
                return (71);
            if (StringsEqual (theString, "longwhistle"))
                return (72);
            if (StringsEqual (theString, "shortguiro"))
                return (73);
            if (StringsEqual (theString, "longguiro"))
                return (74);
            if (StringsEqual (theString, "claves"))
                return (75);
            if (StringsEqual (theString, "highwoodblock"))
                return (76);
            if (StringsEqual (theString, "lowwoodblock"))
                return (77);
            if (StringsEqual (theString, "mutecuica"))
                return (78);
            if (StringsEqual (theString, "opencuica"))
                return (79);
            if (StringsEqual (theString, "mutetriangle"))
                return (80);
            if (StringsEqual (theString, "opentriangle"))
                return (81);
            return (0);}

        int     StringToStress (const char *theString, unsigned long *theNum)

            {if (StringsEqual (theString, "pianissimo"))
                *theNum = 16;
            else if (StringsEqual (theString, "piano"))
                *theNum = 32;
            else if (StringsEqual (theString, "mezzopiano"))
                *theNum = 48;
            else if (StringsEqual (theString, "mezzoforte"))
                *theNum = 64;
            else if (StringsEqual (theString, "forte"))
                *theNum = 96;
            else if (StringsEqual (theString, "fortissimo"))
                *theNum = 127;
            else
                return (1);
            return (0);}
