/***************************/
/* readmidi.c              */
/***************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "midi.h"
#include "maintypes.h"
#include "defines.h"
#include "readmidi.h"

#ifdef DEBUG
static void ausgabe()
{
       printf("MThd = %s, chunk_length = %d\n", head.MThd , head.chunk_length);
       printf("format = %d, tracks = %d, per_quarter = %x\n",
               head.format, head.tracks, head.per_quarter);

       printf("Mtrk = %s, Track_chunk_length = %d\n",
               THead.MTrk, THead.chunk_length);
}
#endif

static unsigned long get_valid_time(ti)
       unsigned long ti;
{
       if (ti < bartime) {
               if (ti < lastbartime) {
                       converter = 0;
                       sequencecounter = 0;
               }
               else {
                       converter = lastbartime;
                       sequencecounter = (double) lastbartime;
               }
       }
       else {
               converter = bartime;
               sequencecounter = (double) bartime;
       }
       while (ti > converter) {
               lastsc = sequencecounter;
               sequencecounter += one64tel;
               converter = (unsigned long) sequencecounter;
       }
       if (ti < converter) ti = (unsigned long) lastsc;
       return(ti);
}

static char midi_getc(fpointer)
       FILE *fpointer;
{
       if (THead.chunk_length-- < 0) {
               fprintf(stderr, "midi_getc: Length Underflow\n");
               exit(10);
       }
       return(getc(fpointer));
}

static void midi_ungetc(c, fpointer)
       FILE *fpointer;
       char c;
{
       THead.chunk_length++;
       ungetc(c, fpointer);
}

static unsigned int ReadVarLen()
{
       unsigned int value;
       unsigned char c;

       if ((value = midi_getc(fp)) & 0x80) {
               value  &= 0x7f;
               do {
                       value = (value << 7) + ((c = midi_getc(fp)) & 0x7f);
               }
               while (c & 0x80);
       }

       return(value);
}


static void ReadMidiTrackName(delta)
       int delta;
{
       int len, i;

       len = ReadVarLen();
       for (i = 0; i < len; i++) {
               if (i < 80 - 1) TrackName[Track_Nr][i] = midi_getc(fp);
               else midi_getc(fp);
       }
       if (i<80) TrackName[Track_Nr][i] = '\0';
       else TrackName[Track_Nr][79] = '\0';

#ifdef DEBUG
       printf("MIDI_TRACK_NAME (%s) at %d\n", TrackName[Track_Nr], delta);
#endif

}

static void ReadMidiSequSpec(delta)
       int delta;
{
       int len, i;
       char Str[80];
#ifdef DEBUG
       int j;
#endif

       len = ReadVarLen();
       for (i = 0; i < len; i++) {
               if (i < 80 - 1) Str[i] = midi_getc(fp);
       }
       Str[i] = '\0';
#ifdef DEBUG
       printf("MIDI_SEQUENCER_SPECIFIC at %d:\n", delta);
       for (j = 0; j < i; j++)
               printf("\t0x%x\n", Str[j]);
#endif
}

#ifdef DEBUG
static char *p2str(oct, pit)
       int oct, pit;
{
       static char Str[10];
       static char *p_table[12] = {"C", "Cis", "D", "Dis",
                                  "E",  "F",  "Fis", "G",
                                  "Gis", "A", "B",  "H"};

       sprintf(Str, "%s%d", p_table[pit], oct);
       return(Str);
}
#endif

static void ReadMidiToneVal(oct, pit, laut)
       int *oct, *pit, *laut;
{
       int w;
       unsigned char inthelp;

       w = midi_getc(fp);
       *laut = midi_getc(fp);

       /* allow only octaves 0 - 5 */
       if ((w>24) && (w<95)) {
               *oct = (w / 12) - 2;
               *pit = (w % 12);
       }
       else {
               *oct = 6;
               *pit = 0;
       }

       inthelp = 12 * (*oct) + (*pit);
       if (max[Track_Nr] < inthelp) max[Track_Nr] = inthelp;
       if (min[Track_Nr] > inthelp) min[Track_Nr] = inthelp;
}

static void erzeuge_note(octave, pitch, laut, begin, dauer, channel)
       int octave, pitch, laut, dauer, channel;
       unsigned long int begin;
{
       if (firstnotetimeflag == -1) {
               firstnotetime = begin;
               firstnotetimeflag = 0;
       }
       /* if there were no TimeSig */
       if ((valid == 0) && (begin > firstnotetime)) {
               valid++;
               if ((!printonly) || (Track_Nr == (printonly -1))) {
                       if ((!notes_flag) && (nom0) && (Track_Nr))
                               ins_dyn_event(Track_Nr, 't', 0, nom0, denom0, 0, 0, 0, 0, 0);
                       else
                               ins_dyn_event(Track_Nr, 't', 0, 4, 4, 0, 0, 0, 0, 0);
               }
       }

       /* if there were no KeySig */
       if ((valid2 == 0) && (begin > firstnotetime)) {
               valid2++;
               if ((!printonly) || (Track_Nr == (printonly -1))) {
                       if ((!notes_flag) && (key0) && (Track_Nr))
                               ins_dyn_event(Track_Nr, 'k', 0, key0, 0, 0, 0, 0, 0, 0);
                       else
                               ins_dyn_event(Track_Nr, 'k', 0, 0, 0, 0, 0, 0, 0, 0);
               }
       }

#ifdef DEBUG
       fprintf(stdout, "NOTE into dyn_event_list inserted\n");
       fprintf(stdout, "oct: %d\t pit: %d\t laut: %x\t beg: %lx\t durat: %x\n",
               octave, pitch, laut, begin, dauer);
#endif
       /* notes_flag shows that notes of first track were read */
       /*                                                      */
       /* because f.e. rosegarden writes empty first track     */
       /* with takt and key info for all other tracks          */

       if (Track_Nr == 0) notes_flag = 1;

       if (((!printonly) || (Track_Nr == (printonly -1))) && (octave != 6))
               ins_dyn_event(Track_Nr, 'n', 0, 0, 0, octave, pitch, laut, get_valid_time(begin), dauer);
}

static void ReadMidiNoteOff(channel, delta)
       int channel, delta;
{
       int dauer, octave, pitch, laut, la;
       unsigned long int begin;

       ReadMidiToneVal(&octave, &pitch, &laut);

#ifdef DEBUG
       printf("MIDI_NOTE_OFF at %d(%ld): Channel: %d, pitch = %s, laut = 0x%x\n",
               delta, zeit, channel, p2str(octave, pitch), laut);
#endif
       dauer = note_delete(octave, pitch, &la, zeit, &begin, channel);
#ifdef DEBUG
       printf("Generate_Note with begin = %ld, absolute time = %ld, duration = %d\n",
                       begin, zeit, dauer);
#endif
       erzeuge_note(octave, pitch, la, begin, dauer, channel);
}

static void ReadMidiNoteOn(channel, delta)
       int channel, delta;
{
       int dauer, octave, pitch, laut, la;
       unsigned long int begin;

       ReadMidiToneVal(&octave, &pitch, &laut);

       if (laut) {
               note_insert(octave, pitch, laut, zeit, channel);
       }
       else {
               dauer = note_delete(octave, pitch, &la, zeit, &begin, channel);
#ifdef DEBUG
               printf("Generate_Note with begin = %ld, absolute time = %ld, duration = %d\n",
                               begin, zeit, dauer);
#endif
               erzeuge_note(octave, pitch, la, begin, dauer, channel);
       }
#ifdef DEBUG
       printf("MIDI_NOTE_ON at %d(%ld): Channel: %d, pitch = %s, laut = 0x%x\n",
               delta, zeit, channel, p2str(octave, pitch), laut);
#endif
}

static void ReadMidiPolyAftertouch(channel, delta)
       int channel, delta;
{
       char dum1, dum2;

       dum1 = midi_getc(fp); dum2 = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_POLY_AFTERTOUCH: 0x%x, 0x%x, 0x%x\n", channel, dum1, dum2);
#endif
}

static void ReadMidiCtrlChange(channel, delta)
       int channel, delta;
{
       char dum1, dum2;

       dum1 = midi_getc(fp); dum2 = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_CTRL_CHANGE: 0x%x, 0x%x, 0x%x\n", channel, dum1, dum2);
#endif
}

static void ReadMidiProgChange(channel, delta)
       int channel, delta;
{
       char dum1;

       dum1 = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_PROG_CHANGE: 0x%x, 0x%x\n", channel, dum1);
#endif
}

static void ReadMidiChnlAftertouch(channel, delta)
       int channel, delta;
{
       char dum1;

       dum1 = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_CHNL_AFTERTOUCH: 0x%x, 0x%x\n", channel, dum1);
#endif
}

static void ReadMidiPitchBend(channel, delta)
       int channel, delta;
{
       char dum1, dum2;

       dum1 = midi_getc(fp); dum2 = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_PITCH_BEND: 0x%x, 0x%x, 0x%x\n", channel, dum1, dum2);
#endif
}

static void ReadMidiSongPositionPtr(delta)
       int delta;
{
       char dum1, dum2;

       dum1 = midi_getc(fp); dum2 = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_SONG_POSITION_PTR: 0x%x, 0x%x\n", dum1, dum2);
#endif
}

static void ReadMidiSongSelect(delta)
       int delta;
{
       char dum1;

       dum1 = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_SONG_SELECT: 0x%x\n", dum1);
#endif
}

static void ReadMidiSystemExclusive()
{
       int dum;
       unsigned int value;

       dum = ReadVarLen();
       while ((value = midi_getc(fp)) != MIDI_EOX);
#ifdef DEBUG
       printf("MIDI_SYSTEM_EXCLUSIVE\n");
#endif
}

static void ReadMidiSetTempo(delta)
       int delta;
{
       unsigned int len, tempo;

       len = midi_getc(fp);
       if (len == 0x03) {
               tempo = 0;
               while(len--) {
                       tempo *= 0x100;
                       tempo += (unsigned int) (0xff & midi_getc(fp));
               }
#ifdef DEBUG
               D_Tempo = (double) tempo / 1000000.0;
               printf("MIDI_SET_TEMPO at %d: Tempo = %d(%f)\n", delta, tempo, D_Tempo);
#endif
       }
       else { /* system reset detect */
               midi_ungetc(len, fp);
               midi_ungetc(0x51, fp);
       }
}

static void ReadMidiTimeSig(delta)
       int delta;
{
       int dummy, nn, dd, cc, bb, dominator;

       dummy = midi_getc(fp);
       if (dummy == 0x04) {
               valid = 1;      /* means: TimeSig detected */
               nn = midi_getc(fp);
               dd = midi_getc(fp);
               cc = midi_getc(fp);
               bb = midi_getc(fp);
               dominator = (1 << dd);
               help = taktzeit;
               taktzeit = head.per_quarter * nn * 4 / dominator;
               diskrete_tz = diskrete_tz + taktzeit - help;
               if ((!Track_Nr) && (!nom0)) {
                       nom0 = nn;
                       denom0 = dominator;
               }
               if ((!printonly) || (Track_Nr == (printonly -1)))
                       ins_dyn_event(Track_Nr, 't', 0, nn, dominator, 0, 0, 0, get_valid_time(zeit), 0);

#ifdef DEBUG
               printf("Takt: %x\n",taktzeit);
               printf("MIDI_TIME_SIGNATURE at %d: Takt:%d/%d\nMIDI-clocks per Metronom: %d,",
                       delta, nn, dominator, cc);
               printf("%d 32nd per MIDI-Quarter\n", bb);
#endif
       }
       else { /* system reset detect */
               midi_ungetc(dummy, fp);
               midi_ungetc(0x58, fp);
       }
}

static void ReadMidiTextEvent(delta)
       int delta;
{
       unsigned int len;
       int value;

       len = ReadVarLen();
       while (len--) value = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_TEXT_EVENT\n");
#endif
}

static void ReadMidiCopyrightNotice(delta)
       int delta;
{
       unsigned int len;
       int value;

       len = ReadVarLen();
       while (len--) value = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_COPYRIGHT_NOTICE\n");
#endif
}

static void ReadMidiInstrumentName(delta)
       int delta;
{
       unsigned int len;
       int value=0;

       len = ReadVarLen();
       while (len--) Staffs[Track_Nr][value++] = midi_getc(fp);
       Staffs[Track_Nr][value] = 0;
#ifdef DEBUG
       printf("MIDI_INSTRUMENT_NAME: %s\n",Staffs[Track_Nr]);
#endif
}

static void ReadMidiLyrik(delta)
       int delta;
{
       unsigned int len;
       char *ptr, *ptrhelp;

       len = ReadVarLen();
       if ((ptr = (char *) malloc (len+1)) == NULL) {
               fprintf(stderr, "mallocC error\n");
               exit(10);
       }
       ptrhelp = ptr;
       while (len--) {
               *ptrhelp = midi_getc(fp);
               ptrhelp++;
       }
       *ptrhelp = 0;
#ifdef DEBUG
       printf("MIDI_LYRIC\n");
#endif
       if ((!printonly) || (Track_Nr == (printonly -1)))
               ins_dyn_event(Track_Nr, 'l', ptr, 0, 0, 0, 0, 0, get_valid_time(zeit), 0);
}

static void ReadMidiTextMarker(delta)
       int delta;
{
       unsigned int len;
       int value;

       len = ReadVarLen();
       while (len--) value = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_TEXT_MARKER\n");
#endif
}

static void ReadMidiCuePoint(delta)
       int delta;
{
       unsigned int len;
       int value;

       len = ReadVarLen();
       while (len--) value = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_CUE_POINT\n");
#endif
}

static void ReadMidiChannelPrefix(delta)
       int delta;
{
       int dum1, dum2;
       dum1 = midi_getc(fp);
       if (dum1 == 0x01) {
               dum2 = midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_CHANNEL_PREFIX\n");
#endif
       }
       else { /* system reset detect */
               midi_ungetc(dum1, fp);
               midi_ungetc(0x20, fp);
       }
}

static void ReadMidiSmpteOffset(delta)
       int delta;
{
       int dum;

       if (delta != 0) { /* system reset detect */
               midi_ungetc(0x54, fp);
       }
       else {
               dum = midi_getc(fp);
               if (dum == 0x05) {
                       midi_getc(fp); midi_getc(fp); midi_getc(fp);
                       midi_getc(fp); midi_getc(fp);
#ifdef DEBUG
       printf("MIDI_SMPTE_OFFSET\n");
#endif
               }
               else { /* system reset detect */
                       midi_ungetc(dum, fp);
                       midi_ungetc(0x54, fp);
               }
       }
}

static void ReadMidiSequenceNumber(MetaEvent, delta)
       int delta;
       unsigned char MetaEvent;
{
       int value;

       value = midi_getc(fp);
       if (value != 0x02) { /* system reset detect */
               midi_ungetc(value, fp);
               midi_ungetc(0x00, fp);
       }
       else {
               value = midi_getc(fp); value = midi_getc(fp);
               value = midi_getc(fp); value = midi_getc(fp);
#ifdef DEBUG
               printf("MIDI_SEQUENCE_NUMBER\n");
#endif
       }
}

static void ReadMidiKeySig(delta)
       int delta;
{
       int dum, sign;

       dum = midi_getc(fp);
       if (dum != 0x02) { /* system reset detect */
               midi_ungetc(dum, fp);
               midi_ungetc(0x59, fp);
       }
       else {
               valid2 = 1; /* KeySig detected */
               sign = midi_getc(fp);
               /* manipulate sign */
               if ((sign & 0x80) && (sign & 0x08)) {
                       sign = sign ^ 0xf;
                       sign++;
               }
               if ((!Track_Nr) && (!key0)) key0 = sign;
               if ((!printonly) || (Track_Nr == (printonly -1)))
                       ins_dyn_event(Track_Nr, 'k', 0, sign, 0, 0, 0, 0, get_valid_time(zeit), 0);
               T_genus = (0xff & sign);
               Signature = (0xff & midi_getc(fp));
#ifdef DEBUG
               printf("MIDI_KEY_SIGNATURE at %d: T_genus = ", delta);
               switch (T_genus)  {
                       case MINOR: printf("MINOR"); break;
                       case MAJOR: printf("MAJOR"); break;
                       default: printf("unknown"); break;
               }
               printf(" Signature = %d\n", Signature);
#endif
       }
}

static void ReadMidiEndOfTrack(delta)
       int delta;
{
       int dum, dauer, octave, pitch, laut, channel;
       unsigned long int begin;

       dum = midi_getc(fp);
       if (dum == 0) {
               dum = midi_getc(fp);    /* read - deltatime */
               while (dum == 0) {      /* falls nach EOTrack noch Folgeelement */
                       midi_ungetc(dum, fp);
                       ReadEvent();
                       dum = midi_getc(fp);
               }
               midi_ungetc(dum, fp);
               while ((dauer = search_note(&octave, &pitch, &laut, zeit, &begin, &channel)) != -1) {
#ifdef DEBUG
                       printf("erzeuge_note mit begin = %ld, zeit = %ld, dauer = %d\n",
                               begin, zeit, dauer);
#endif
                       erzeuge_note(octave, pitch, laut, begin, dauer, channel);
               }

               if (THead.chunk_length) {
                       fprintf(stderr, "Warning: ReadMidiEndOfTrack: Sync_Error THead.chunk_length = %d\n",
                       THead.chunk_length);
                       while (THead.chunk_length >= 0) midi_getc(fp);
               }
#ifdef DEBUG
               printf("MIDI_END_OF_TRACK at %d\n", delta);
#endif
       }
       else { /* system reset detect */
               midi_ungetc(dum, fp);
               midi_ungetc(0x2f, fp);
       }
}

static int ReadMidiMetaEvent(delta)
       int delta;
{
       unsigned char MetaEvent;
       int not_eot = 1;

       switch(MetaEvent = midi_getc(fp)) {
               case MIDI_SEQUENCE_NUMBER: ReadMidiSequenceNumber(MetaEvent,delta); break;
               case MIDI_TEXT_EVENT: ReadMidiTextEvent(delta); break;
               case MIDI_TRACK_NAME: ReadMidiTrackName(delta); break;
               case MIDI_SET_TEMPO: ReadMidiSetTempo(delta); break;
               case MIDI_TIME_SIGNATURE: ReadMidiTimeSig(delta); break;
               case MIDI_END_OF_TRACK: ReadMidiEndOfTrack(delta); not_eot = 0; break;
               case MIDI_KEY_SIGNATURE: ReadMidiKeySig(delta); break;
               case MIDI_SEQUENCER_SPECIFIC: ReadMidiSequSpec(delta); break;
               case MIDI_CHANNEL_PREFIX: ReadMidiChannelPrefix(delta); break;
               case MIDI_SMPTE_OFFSET: ReadMidiSmpteOffset(delta); break;
               case MIDI_COPYRIGHT_NOTICE: ReadMidiCopyrightNotice(delta); break;
               case MIDI_INSTRUMENT_NAME: ReadMidiInstrumentName(delta); break;
               case MIDI_LYRIC: ReadMidiLyrik(delta); break;
               case MIDI_TEXT_MARKER: ReadMidiTextMarker(delta); break;
               case MIDI_CUE_POINT: ReadMidiCuePoint(delta); break;
               default: /* system reset detect */
                       midi_ungetc(MetaEvent, fp); break;
       }
       return(not_eot);
}

static int ReadEvent()
{
       unsigned char Event_Type;
       int delta, not_eot = 1;

       delta = ReadVarLen();
       zeit += delta;

       while (zeit >= diskrete_tz) {
               if ((!printonly) || (Track_Nr == (printonly -1))) {
                       lastbartime = bartime;
                       bartime = diskrete_tz;
                       ins_dyn_event(Track_Nr, 'b', 0, 0, 0, 0, 0, 0, diskrete_tz, taktzeit);
               }
               diskrete_tz += taktzeit;
       }

       Event_Type = midi_getc(fp);
r_event:
       if ((0xf0 & Event_Type) == MIDI_NOTE_OFF) {
               ReadMidiNoteOff((Event_Type & 0xf), delta);
       }
       else if ((0xf0  & Event_Type) ==  MIDI_NOTE_ON) {
               ReadMidiNoteOn((Event_Type & 0xf), delta);
       }
       else if ((0xf0  & Event_Type) ==  MIDI_POLY_AFTERTOUCH) {
               ReadMidiPolyAftertouch((Event_Type & 0xf), delta);
       }
       else if ((0xf0  & Event_Type) ==  MIDI_CTRL_CHANGE) {
               ReadMidiCtrlChange((Event_Type  & 0xf), delta);
       }
       else if ((0xf0  & Event_Type) ==  MIDI_PROG_CHANGE) {
               ReadMidiProgChange((Event_Type  & 0xf), delta);
       }
       else if ((0xf0  & Event_Type) ==  MIDI_CHNL_AFTERTOUCH) {
               ReadMidiChnlAftertouch((Event_Type & 0xf), delta);
       }
       else if ((0xf0  & Event_Type) ==  MIDI_PITCH_BEND) {
               ReadMidiPitchBend((Event_Type & 0xf), delta);
       }
       else if ((0xf0  & Event_Type) ==  MIDI_SYSTEM_MSG) {
               if (Event_Type == MIDI_FILE_META_EVENT) {
                       not_eot = ReadMidiMetaEvent(delta);
               }
               else {
                       /* treatment of all other 0xfx-events */
                       switch (0xf & Event_Type) {
                               case MIDI_SONG_POSITION_PTR: /* 0xf2 */
                                       ReadMidiSongPositionPtr(delta);
                                       break;
                               case MIDI_SONG_SELECT: /* 0xf3 */
                                       ReadMidiSongSelect(delta);
                                       break;
                               case MIDI_SYSTEM_EXCLUSIVE: /* 0xf0 */
                                       ReadMidiSystemExclusive();
                                       break;
                               case MIDI_TUNE_REQUEST: /* 0xf6 */
                               case MIDI_TIMING_CLOCK: /* 0xf8 */
                               case MIDI_START: /* 0xfa */
                               case MIDI_CONTINUE: /* 0xfb */
                               case MIDI_STOP: /* 0xfc */
                               case MIDI_ACTIVE_SENSING: /* 0xfe */
                                       midi_getc(fp);
                                       break;
                               default:
                                       fprintf(stderr, "Event: 0x%x unknown\n", Event_Type);
                                       fprintf(stderr, "Fileoffset: %lu\n", ftell(fp));
                                       exit(10);
                       }
               }
       }
       else if (Running_Event) {
#ifdef DEBUG
               printf("Running Event\n");
#endif
               midi_ungetc(Event_Type, fp);

               Event_Type = Running_Event;
               goto r_event;
       }
       else {
               fprintf(stderr, "Event: 0x%x unknown\n", Event_Type);
               fprintf(stderr, "Fileoffset: %lu\n", ftell(fp));
               exit(10);
       }
       Running_Event = Event_Type;
       return(not_eot);
}


static void read_track()
{
       zeit = 0;
       THead.MTrk[0] = getc(fp); THead.MTrk[1] = getc(fp);
       THead.MTrk[2] = getc(fp); THead.MTrk[3] = getc(fp);
       THead.MTrk[4] = '\0';
       if (strcmp(THead.MTrk, MIDI_TRACK_HEADER)) {
               fprintf(stderr, "read_track: Sync_error(%s)\n", THead.MTrk);
               exit(10);
       }
       THead.chunk_length  = 0x1000000 * getc(fp);
       THead.chunk_length += 0x10000 * getc(fp);
       THead.chunk_length += 0x100 * getc(fp);
       THead.chunk_length += getc(fp);
#ifdef DEBUG
       ausgabe();
#endif
       Running_Event = 0;
       while (ReadEvent());
}

static void usage(conststrg)
       char *conststrg;
{
       fprintf(stderr,"usage:\t%s [-<nr>] <midifile> [<texfile>]\n", conststrg);
       fprintf(stderr,"\t%s -c <midifile>\n", conststrg);
       exit(10);
}

void main(argc, argv)
       int argc;
       char *argv[];
{
       int lenhelp;
       char opthelp;

       if (argc < 2) usage(argv[0]);

       if ((argc == 3) && (!strcmp(argv[1],"-c"))) {
               if ((fp = fopen(argv[2], "r")) == NULL) {
                       fprintf(stderr, "cannot open %s\n", argv[1]);
                       exit(10);
               }
               count = 1;
       }
       else {
               count = 0;
               if (*argv[1] == '-') {
                       if ((argc == 2) || (*argv[2] == '-') || (argc > 4)) usage(argv[0]);
                       opthelp = 1;
                       printonly = (char) atoi((argv[1])+1);
                       if (!printonly) printonly = 20;
               }
               else {
                       if (argc > 3) usage(argv[0]);
                       printonly = 0;  /* print every track */
                       opthelp = 0;
               }

               if ((fp = fopen(argv[1+opthelp], "r")) == NULL) {
                       fprintf(stderr, "cannot open %s\n", argv[1+opthelp]);
                       exit(10);
               }

               /* fill the array for the name of tex file */
               if (argc == (3+opthelp)) {
                       if (!strcmp(argv[1+opthelp], argv[2+opthelp])) {
                               fprintf(stderr, "cannot process one file to itself\n");
                               exit(10);
                       }
                       strcpy(texfilename, argv[2+opthelp]);
               }
               else {  /* mainmark1: try to select a nice name for texfile */
                       strcpy(texfilename, argv[1+opthelp]);
                       lenhelp = strlen(texfilename) - 4;

                       /* delete midi file extension */
                       if ((!strcmp(&(texfilename[lenhelp]),".mid")) ||
                           (!strcmp(&(texfilename[lenhelp]),".MID")))
                               texfilename[lenhelp] = 0;
                       else {
                               if ((!strcmp(&(texfilename[lenhelp+1]),".mf")) ||
                                   (!strcmp(&(texfilename[lenhelp+1]),".MF")))
                                       texfilename[lenhelp+1] = 0;
                       }
                       if ((texfilename[0] > 64) && (texfilename[0] < 91))
                               strcat(texfilename, ".TEX");
                       else
                               strcat(texfilename, ".tex");
               }

       }

       /* mainmark2 */
       head.MThd[0] = getc(fp); head.MThd[1] = getc(fp);
       head.MThd[2] = getc(fp); head.MThd[3] = getc(fp); head.MThd[4] = '\0';
       if (strcmp(head.MThd, MIDI_FILE_HEADER)) {
               fprintf(stderr, "specified file probably not a midi-file or corrupted\n");
               exit(10);
       }

       head.chunk_length = 0x1000000 * getc(fp);
       head.chunk_length += 0x10000 * getc(fp);
       head.chunk_length += 0x100 * getc(fp);
       head.chunk_length += getc(fp);

       if (head.chunk_length != 6) {
               fprintf(stderr, "wrong header chunk length\n");
               exit(10);
       }

       head.format = 0x100 * getc(fp); head.format += getc(fp);
       head.tracks = 0x100 * getc(fp); head.tracks += getc(fp);

       /* mainmark3 */
       if (count) {
               printf("%d tracks detected\n", head.tracks);
               exit(0);
       }

       if (printonly && (printonly > head.tracks)) {
               printf("can't build tex-file of specified track \n");
               exit(0);
       }

       if ((!printonly) && ((head.tracks) > 9))
               fprintf(stderr, "Warning: printing out so many tracks together may look very ugly\n");

       head.per_quarter = 0x100 * (0xff & getc(fp));
       head.per_quarter += (0xff & getc(fp));
       if (head.format != 1) {
               fprintf(stderr, "Format %d not supported\n", head.format);
               exit(10);
       }

       if (head.per_quarter & 0x8000) {
               fprintf(stderr, "SMPTE-Time Code not supported\n");
               exit(10);
       }

       /* mainmark4 */
       one64tel = (double) head.per_quarter / 16;

       /* mainmark5 */
       nom0 = 0;
       key0 = 0;
       notes_flag = 0;
       for (lenhelp = 0; lenhelp < MAXTRACKS; lenhelp++) {
               Staffs[lenhelp][0]=0;
               max[lenhelp]=0;
               min[lenhelp]=255;
       }
       taktzeit = 4 * head.per_quarter;
       dyn_init();

       /* mainmark6 */
       if (!printonly)
               for (Track_Nr = 0; Track_Nr < head.tracks; Track_Nr++) {
                       valid = 0;      /* no TimeSig */
                       valid2 = 0;     /* no KeySig  */

                       /* following variables allow event begin only at fixed time-points */
                       lastbartime = 0;
                       bartime = 0;

                       firstnotetimeflag = -1;
                       diskrete_tz = taktzeit;
                       read_track();
                       if (min[Track_Nr] > 0x1f) region[Track_Nr] = 1;
                       else    if (max[Track_Nr] < 0x2a) region[Track_Nr] = 2;
                               else region[Track_Nr] = 0;
#ifdef DEBUG
                       printf("region: %x min: %x max: %x\n", region[Track_Nr], min[Track_Nr], max[Track_Nr]);
                       printf("call now split_notes()\n");
#endif
                       split_notes(Track_Nr, head.per_quarter);
#ifdef DEBUG
                       printf("call now detect_accords()\n");
#endif
                       detect_accords(region[Track_Nr], Track_Nr);
#ifdef DEBUG
                       printf("call now insert_notetimes_and_slurs()\n");
#endif
                       insert_notetimes_and_slurs(region[Track_Nr], Track_Nr, head.per_quarter);
#ifdef DEBUG
                       printf("call now detect_note_positions_with_signs()\n");
#endif
                       detect_note_positions_with_signs(Track_Nr);
#ifdef DEBUG
                       printf("call now set_slur_regions()\n");
#endif
                       set_slur_regions(Track_Nr);
#ifdef DEBUG
                       printf("call now reset_treat_info()\n");
#endif
                       reset_treat_info(Track_Nr);
#ifdef DEBUG
                       printf("call now beam_detect()\n");
#endif
                       beam_detect(region[Track_Nr], Track_Nr);
#ifdef DEBUG
                       printf("call now set_beam_regions()\n");
#endif
                       set_beam_regions(Track_Nr);
#ifdef DEBUG
                       printf("call now reset_treat_info()\n");
#endif
                       reset_treat_info(Track_Nr);
#ifdef DEBUG
                       printf("call now slur_geometry()\n");
#endif
                       slur_geometry(Track_Nr);
#ifdef DEBUG
                       printf("call now detect_rests()\n");
#endif
                       detect_rests(Track_Nr, region[Track_Nr], head.per_quarter);
#ifdef DEBUG
                       printf("call now reset_treat_info()\n");
#endif
                       reset_treat_info(Track_Nr);
#ifdef DEBUG
                       printf("call now beam_geometry()\n");
#endif
                       beam_geometry(Track_Nr);
#ifdef DEBUG
                       printf("call now reset_treat_info()\n");
#endif
                       reset_treat_info(Track_Nr);
#ifdef DEBUG
                       printf("call now calculate_rest_positions()\n");
#endif
                       calculate_rest_positions(Track_Nr);
#ifdef DEBUG
                       printf("call now set_loudness_infos()\n");
#endif
                       set_loudness_infos(Track_Nr);
               }
       else {
               for (Track_Nr = 0; Track_Nr < printonly; Track_Nr++) {
                       valid = 0;      /* no TimeSig */
                       valid2 = 0;     /* no KeySig  */

                       /* following variables allow event begin only at fixed time-points */
                       lastbartime = 0;
                       bartime = 0;

                       firstnotetimeflag = -1;
                       diskrete_tz = taktzeit;
                       read_track();
               }
               if ((printonly == 1) && (notes_flag == 0)) {
                       fprintf(stderr, "sorry, first track is empty\n");
               }
               else {
                       Track_Nr--;
                       if (min[Track_Nr] > 0x1f) region[Track_Nr] = 1;
                       else    if (max[Track_Nr] < 0x2a) region[Track_Nr] = 2;
                               else region[Track_Nr] = 0;
#ifdef DEBUG
                       printf("region: %x min: %x max: %x\n", region[Track_Nr], min[Track_Nr], max[Track_Nr]);
#endif
                       split_notes(Track_Nr, head.per_quarter);
                       detect_accords(region[Track_Nr], Track_Nr);
                       insert_notetimes_and_slurs(region[Track_Nr], Track_Nr, head.per_quarter);
                       detect_note_positions_with_signs(Track_Nr);
                       set_slur_regions(Track_Nr);
                       reset_treat_info(Track_Nr);
                       beam_detect(region[Track_Nr], Track_Nr);
                       set_beam_regions(Track_Nr);
                       reset_treat_info(Track_Nr);
                       slur_geometry(Track_Nr);
                       detect_rests(Track_Nr, region[Track_Nr], head.per_quarter);
                       reset_treat_info(Track_Nr);
                       beam_geometry(Track_Nr);
                       reset_treat_info(Track_Nr);
                       calculate_rest_positions(Track_Nr);
                       set_loudness_infos(Track_Nr);
               }
       }

#ifdef DEBUG
       debug_out();
#endif
       /* mainmark7 */
       if ((tfp = fopen(texfilename, "w")) ==  NULL) {
               fprintf(stderr, "cannot open %s\n", texfilename);
               exit(10);
       }

#ifdef DEBUG
       printf("writing texfile\n");
#endif
       write_texfile();
       fclose(fp); /* close MIDI-file */
       fclose(tfp); /* close TEX-file */
}