UNIT TP_MIDI;

INTERFACE
uses DOS,
     TP_decl,
     TP_Misc,
     TP_debug,
     TP_heap1,
     TP_M2TF2;

Procedure InsertRest(VAR ThisTrack : TrackRecord);
Procedure ReadMetaEvent( VAR ThisTrack : TrackRecord);
Function EndOfTrackReached(VAR ThisTrack:TrackRecord):boolean;
Procedure WriteTexHeader;
Function GetPortees: String;
Function StaffIndex(No : Byte): String;
Procedure Quantize(VAR N : NoteRecPoint);
Procedure ReadDeltaTime(VAR ThisTrack : TrackRecord);
Procedure ReadEvent(VAR ThisTrack : TrackRecord);
Procedure ChangeContext(N : NoteRecPoint);

IMPLEMENTATION
(********************************************)
   Function StaffIndex(No : Byte): String;
(********************************************)
Begin
Case No  OF
   1  :  StaffIndex:='i';
   2  :  StaffIndex:='ii';
   3  :  StaffIndex:='iii';
   4  :  StaffIndex:='iv';
   5  :  StaffIndex:='v';
   6  :  StaffIndex:='vi';
   7  :  StaffIndex:='vii';
   8  :  StaffIndex:='viii';
   9  :  StaffIndex:='ix';
   10 :  StaffIndex:='x';
Else
   ErrorExit(8);
End; (* case *)
End;


(**********************************************)
   Function GetPortees: String;
(**********************************************)
VAR TmpSTr          : String;
    curinstr,
    curtr,staff,
    StartStaff,
    nStaffsInInstr  : Byte;
    StartFound      : Boolean;
Begin
TmpStr:='';
StartFound:=FALSE;
For curinstr:=1 to 1  Do (* this version only supports one instrument *)
    Begin
    staff:=1;
    For curtr:=ntracks downto 1 do
       With TrackArray[TrackOrder[curtr]] Do
          Begin
          If Not Skip Then
             Begin
             If NOT StartFound Then
                 Begin
                 If Instrument Then
                    Begin
                    StartStaff:=Staff;
                    StartFound:=TRUE;
                    nStaffsInInstr:=1;
                    End
                 End
             Else
                 Begin
                 If Instrument Then INC(nStaffsInInstr);
                 End;
             Inc(Staff);
             End
          End; (* With *)
    TmpStr:='\nbportees'+StaffIndex(StartStaff)+'='+B2S(nStaffsInInstr);
    End; (* for next curinstr *)
GetPortees:=TmpStr;
End;

(**********************************************)
   Procedure WriteTexHeader;
(**********************************************)
{$IFDEF ST}
Var Year,Month,Day,DoW : Integer;
{$ENDIF}
{$IFDEF PC}
Var Year,Month,Day,DoW : Word;
{$ENDIF}
Begin
      GetDate(Year,Month,Day,DoW);
      WriteLn(TexFile,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
      WriteLn(TexFile,'%    TEX translation of MIDI File :');
      With MidiFileName Do
      WriteLn(TexFile,'%          ',n,e);
      WriteLn(TexFile,'% ');
      WriteLn(TexFile,'%        Written by Hans Kuykens');
      WriteLn(TeXFile,'%  this translation of date : '+W2S(Day)+'-'+W2S(Month)+'-'+W2S(Year));
      WriteLn(TexFile,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
      WriteLn(TexFile,'\input musicnft');
      WriteLn(TexFile,'\input musictex');
      WriteLn(TexFile,'\input musicadd');
      WriteLn(TexFile,'\input musictrp');
      WriteLn(TexFile,'\normal');
      If SizingChanged Then
         Begin
         WriteLn(TexFile,'\hsize '+I2S(ScoreWidth div 10)+'mm \vsize '+I2S(ScoreHeight div 10)+'mm');
         WriteLn(TexFile,'\musicsize='+I2S(MusicSize));
         WriteLn(TeXFile,'\elemskip=',I2S(Round(Elemskip/PT)),'pt%');
         End;
      If ninstruments>0 Then
         Begin
         WriteLn(TexFile,'\def\nbinstruments{'+B2S(ntracks-NoOfSkips-(nTracksInInstr-1))+'}');
         WriteLn(TeXFile,GetPortees);
         End
      Else
         WriteLn(TexFile,'\def\nbinstruments{'+B2S(ntracks-NoOfSkips)+'}');
      
      (*WriteLn(TexFile,'\signaturegenerale{0}'); *)
      WriteLn(TexFile,'\generalsignature{'+SI2S(PieceContr.KeySign)+'}\relax');

      WriteLn(TeXFile,'%\centerline{\enorme PUT A NAME HERE and remove %}');
      With TeXFileName DO
      WriteLn(TeXFile,'\medskip\centerline{\moyen '+n+e+'}');
      WriteLn(TeXFile,'\rightline{translation by MIDI2TeX}');
      WriteLn(TeXFile,'\rightline{by H.J.P. Kuykens}');      
End; (* WriteTexHeader *)

(********************************************)
    Procedure FinishTeXHeader(num,den : Byte);
(********************************************)
VAR  i,j,k  :  Byte;

(*-----------------------------------------------*)
  function FindStaff(ThisTrack : Integer):Integer;
(*-----------------------------------------------*)
(* Watch it ! If the track is in an instrument than the parameter string *)
(* must be altered of cleftoks#                                          *)
VAR i,j : Integer;
Begin
i:=ntracks;
j:=1;
While TrackOrder[i]<>ThisTrack Do
  Begin
  If NOT TrackArray[TrackOrder[i]].SKIP Then Inc(J);
  Dec(i);
  End;
FindStaff:=j;
End; (* FindStaff *)

(*-----------------------------------------------*)
  function FindClefStaff(ThisTrack : Integer):String;
(*-----------------------------------------------*)
VAR i,j ,k : Integer;
    C      : String[2];
Begin
i:=ntracks;
j:=1;
k:=1;
Str(Ord(TrackArray[TrackOrder[ThisTrack]].Clef),C);
While TrackOrder[i]<>ThisTrack Do
  Begin
  If NOT TrackArray[TrackOrder[i]].SKIP Then
     If TrackArray[TrackOrder[i]].Instrument Then
        Inc(k)
     ELse
        Inc(J);
  Dec(i);
  End;
case k of
   1 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{'+C+'}{0}{0}{0}}';
   2 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{0}{'+C+'}{0}{0}}';
   3 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{0}{0}{'+C+'}{0}}';
   4 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{0}{0}{0}{'+C+'}}';
Else
   Warning('Something wrong with cleftoks#, check it out !');
   FindClefStaff:='\cleftoks??';
End;

End; (* FindClefStaff *)

Begin
WriteLn(TexFile,'\generalmeter{\meterfrac{',Num,'}{',Power(2,Den),'}}%');
(* determine clefs *)
For i:=1 to ntracks do
  Begin
  If TrackArray[i].Clef>VIOLIN Then
     Begin
     WriteLn(TeXFile,FindClefStaff(i));
     End;
  End;
WriteLn(TexFile,'%\raggedlinestrue % uncomment for ragged right lines ');
WriteLn(TeXFile,'%\relativeaccidentals');
WriteLn(TexFile,'\debutmorceau');
TeXHeaderFinished:=TRUE;
End;

(********************************************)
    Procedure ChangeContext(N : NoteRecPoint);
(********************************************)
Begin
With N^ DO
   Case Event Of
      KEYSIGN   : Begin
                  WriteLn(TeXFile,'\signaturegenerale{'+B2S(NoteVal)+'}\changecontext%');
                  With PieceContr DO
                          Begin
                          KeySign:=NoteVal;
                          Minor:=Velocity;
                          End;
                  End;
      SIGNATURE : Begin
                  WriteLn(TexFile,'\generalmeter{\meterfrac{',Noteval,'}{',Power(2,Velocity),'}}%');
                  WriteLn(TeXFile,'\changecontext%');
                  With PieceContr DO
                          Begin
                          Num:=NoteVal;Den:=Velocity;
                          TicksPerMeasure:=4*Division*Num div Power(2,Den);
                          If NOT PartOverRule Then
                             PartTime:=TicksPerMeasure div Num;
                          nparts:=TicksPerMeasure div PartTime;
                          Twindow:=Division div 16;
                          
                          End;
                  End;
   End; (* case *)
End;

(*****************************************************)
    Procedure Quantize(VAR N : NoteRecPoint); (* Still needs updating !!! *)
(*****************************************************)
VAR dt : Longint;
    T  : MeasureTime;
Begin
With N^ Do
   Begin
   dt:=TimeDiff(EndTime,StartTime);
   if dt>QuantTime Then
      Begin
      (* quantize notelength first *)
      dt:=QuantTime*Round(dt/QuantTime); 
      SetTime(T,0,dt);
      (* quantize start time and end time*)
      StartTime.MPart:=QuantTime*Round(StartTime.MPart/QuantTime);
      AddTime(StartTime,T,EndTime);
      End
   End;
End;

(*******************************************************)
    Procedure ReadDeltaTime(VAR ThisTrack : TrackRecord);
(*******************************************************)
VAR delta : LONGINT ;
Begin
With ThisTrack DO
   Begin
      OldOldTime:=OldTime;
      OldTime:=CurTime;
      delta:=ReadVarLen(FilRec);
  (*    WriteDebugInfo('read deltatime :'+LI2S(delta)); *)
      With CurTime DO 
         IF PieceContr.TicksPerMeasure=0 Then
            INC(Mpart,delta)
         Else
            Begin         
            INC(MPart,delta);
            WITH PieceContr DO
              IF MPart>=TicksPerMeasure Then
                  BEGIN
                  Measure:=Measure+ (MPart div TicksPerMeasure);
                  MPart:=MPart MOD TicksPerMeasure;
                  End;
            End;
   End;
End; 

(******************************************************)
    Procedure InsertRest(VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N        : NoteRecPoint;
    TmpTime1,
    TmpTime2 : MeasureTime;
Begin
SetTime(TmpTime1,MeasureCount,0);
SetTime(TmpTime2,MeasureCount+1,0);
With ThisTrack Do
  Begin
  N:=GetFreeNote;
  N^.Event:=REST;
  (*
  If (TimeDiff(TmpTime2,LastNoteOffTime)>0) AND
     (TimeDiff(TmpTime1,LastNoteOffTime)<=0) Then
     N^.STartTime:=LastNoteOffTime
  Else
     N^.STartTime:=TmpTime1;
  If TimeDiff(TmpTime2,CurTime)<0 Then
     N^.EndTime:=TmpTime2
  Else
     N^.EndTime:=CurTime;
  *)
  N^.EndTime:=CurTime;
  N^.STartTime:=LastNoteOffTime;
  Append(NoteList,N);
  WriteDebugInfo('Inserted Rest between '+W2S(N^.StartTime.Measure)+':'+LI2S(N^.StartTime.MPart)+
                  ' and '+W2S(N^.EndTime.Measure)+':'+LI2S(N^.EndTime.MPart));
  End;
End;



(******************************************************)
    Procedure ReadNoteOn(MidCode : Byte;
                         VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N,P  : NoteRecPoint;
    dt : LongInt;
    TmpVal,TmpVel : Byte;
Begin

With ThisTrack Do
    Begin
    TmpVal:=ReadByte(FilRec);
    TmpVel:=ReadByte(FilRec); (* if TmpVel=0 Than it is a Note OFF ! *)

    If TmpVel>0 Then
        Begin

        If (NotesSounding=0) Then
           Begin
           dt:=TimeDiff(CurTime,LastNoteOffTime);
           If Quantizing Then
              Begin
              If dt>QuantTime Then (* only insert rest if longer than QuantTime *)
                InsertRest(ThisTrack)
              End
           Else
              If dt>=(PieceContr.Division div 4) Then (* only insert rest if longer than 1/16th note *)
                 InsertRest(ThisTrack)
           End
        Else (* There are notes sounding, check if same note is already on *)
           Begin
           FirstNote(NoteList,N);
           P:=NIL;
           while N<>P do
              Begin
              If P=NIL then P:=N;
              If (N^.NoteVal=TmpVal) AND (N^.Event=NOTEON) Then (* close this note down *)
                 Begin
                 N^.EndTime:=CurTime;
                 N^.Event:=NOTEOFF;
                 LastNoteOffTime:=CurTime;
                 If NotesSounding>0 Then
                    Dec(NotesSounding);
                 WriteDebugInfo('Closed down a double note');
                 End;
              NextNote(N,N);
              End
           End;

           N:=GetFreeNote;
           Append(NoteList,N);
           With N^ Do
              Begin
              MidiChnl:=MidCode MOD 15;
              NoteVal:=TmpVal;
              Velocity:=TmpVel;
              Event:=NOTEON;
              StartTime:=CurTime;
              SetTime(EndTime,1000,0); (* set EndTime to infinity *)
              WriteDebugInfo((*W2S(NoteArPoint)+*)'NoteOn : '+B2S(NoteVal)+' Vel : '+B2S(velocity)+
                                     ' at '+W2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
              End;
           Inc(NotesSounding);
           End
        Else (* the Velocity value is 0 set Note Off *)
           Begin
           WriteDebugInfo('NoteOff : '+B2S(TmpVal)+
                                 ' at '+W2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
           If NoteList.Size>0 Then
              Begin
              LastNote(NoteList,N);  (* dit gaat soms fout ... ? *)
              FirstNote(NoteList,P); (* een maat kan beginnen met een NoteOff !!!! *)
              While (NOT EqualsNote(N,TmpVal)) AND (N<>P) Do
                 PrevNote(N,N);

              if N=NIL Then
                 ErrorExit(6)
              else
                 if NOT EqualsNote(N,TmpVal) Then
                    WriteDebugInfo('Could not find note-ON for this note-OFF')
                 else
                    Begin
                    If N^.Event=NOTEON Then
                       Begin
                       N^.EndTime:=CurTime;
                       N^.Event:=NOTEOFF;
                       End
                    Else
                       WriteDebugInfo('Note was already OFF, probably a double note...');
                    End;
              LastNoteOffTime:=CurTime;
              If NotesSounding>0 Then
                 Dec(NotesSounding);
              End (* If NoteList.Size > 0 *)
           Else
              WriteDebugInfo('There can`t be a NoteOff if there are no notes at all !');
           End; (* Set Note Off *)
    End; (* With ThisTrack *)
End; (* ReadNoteOn *)

(******************************************************)
    Procedure ReadNoteOff(MidCode : Byte;
                          VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N,P         : NoteRecPoint;
    MidiChnl,
    velo,
    Note        : Byte;
Begin
With ThisTrack Do
    Begin
    MidiChnl:=MidCode MOD 15;   
    Note:=ReadByte(FilRec);
    velo:=ReadByte(FilRec);
    WriteDebugInfo('NoteOff : '+B2S(Note)+
                          ' at '+W2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
    If NoteList.Size>0 Then
       Begin
       LastNote(NoteList,N);  (* dit gaat soms fout ... ? *)
       FirstNote(NoteList,P); (* een maat kan beginnen met een NoteOff !!!! *)
       While (NOT EqualsNote(N,Note)) AND (N<>P) Do
          PrevNote(N,N);

       if N=NIL Then
          ErrorExit(6)
       else
          if NOT EqualsNote(N,Note) Then
             WriteDebugInfo('Could not find note-ON for this note-OFF')
          else
             Begin
             If N^.Event=NOTEON Then
                Begin
                N^.EndTime:=CurTime;
                N^.Event:=NOTEOFF;
                End
             Else
                WriteDebugInfo('Note was already OFF, probably a double note...');
             End;
       LastNoteOffTime:=CurTime;
       If NotesSounding>0 Then
          Dec(NotesSounding);
       End (* If NoteList.Size > 0 *)
    Else
       WriteDebugInfo('There can`t be a NoteOff if there are no notes at all !');
    End; (* with this track *)
End; (* ReadNoteOff *)


(******************************************************)
    Procedure ReadMetaText(Len : Byte;
                           VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N : NoteRecPoint;
Begin
With ThisTrack Do
    Begin
    N:=GetFreeNote;
    Append(NoteList,N);
    With N^ Do
       Begin
       Event:=TXT;
       If MaxAvail>SizeOf(String20Type) Then
            GetMem(MetaTxt,SizeOf(String20Type))
       Else
            ErrorExit(9);
       StartTime:=CurTime;
       EndTime:=CurTime;
       EndTime.Measure:=EndTime.Measure+1;
       MetaTxt^:=ReadString(FilRec,Len);     
       WriteDebugInfo('MetaText :' + MetaTxt^ + ' at '+I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
       End;
    End;
End; (* ReadText *)

(******************************************************)
    Procedure ReadDamper(MidiCode : byte;
                         VAR ThisTrack : TrackRecord);
(******************************************************)
VAR N : NoteRecPoint;
Begin
With ThisTrack Do
    Begin
    N:=GetFreeNote;
    Append(NoteList,N);
    With N^ Do
       Begin
       Event:=PEDAL;
       Velocity:=ReadByte(ThisTrack.FilRec);
       StartTime:=CurTime;
       EndTime:=CurTime;
       EndTime.Measure:=EndTime.Measure+1;
       WriteDebugInfo('Pedal : at '+I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
       End;
    End;
End; (* ReadDamper *)


(**********************************************************)
    Procedure ReadMetaEvent( VAR ThisTrack : TrackRecord);
(**********************************************************)
VAR 
     DumStr       :  String[255];   
     i,
     DumInt       :  Integer; 
     DumByte,
     MetaType     :  Byte;
     MetaByteCnt  :  Word;
     MetaLength   :  LongInt;
     N            :  NoteRecPoint;
  
Begin
With ThisTrack Do 
    Begin
    MetaType:=ReadByte(FilRec);
    MetaLength:=ReadVarLen(FilRec);
    WriteDebugInfo(' Read Meta event type : '+B2S(MetaType)+' of '+
                            LI2S(MetaLength)+' bytes');
    MetaByteCnt:=0;
    case MetaType Of
        0   :       Begin
                    DumByte:=ReadByte(FilRec);
                    DumInt:=ReadInteger(FilRec);
                    End;
        1..7:       Begin  (* Text events *)
                    (* DumStr:=ReadString(FilRec,MetaLength); *)
                    ReadMetaText(MetaLength,ThisTrack);
                    End;
        32  :       DumByte:=ReadByte(FilRec); (* MIDI Chnl Prefix *)
        47  :       Begin EndOfTrackRead:=TRUE; End; (* End of Track *)
        81  :       Begin (* set tempo *)
                    With PieceContr Do
                        Begin
                        Tempo:=ReadByte(FilRec);Tempo:=Tempo SHL 8;
                        Tempo:=Tempo+ReadByte(FilRec);Tempo:=Tempo SHL 8;
                        Tempo:=Tempo+ReadByte(FilRec);
                        End;
                    End;
        84  :       Begin (* SMPTE OffSet *)
                    DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
                    DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
                    DumByte:=ReadByte(FilRec);
                    End;
        88  :       Begin (* Time Sign *)
                    
                    If TeXHeaderFinished then (* store the value on the note list *)
                       Begin
                       N:=GetFreeNote;
                       Append(NoteList,N);
                       With N^ Do
                          Begin
                          Event:=SIGNATURE;
                          NoteVal:=ReadByte(FilRec); (* NUM *)
                          Velocity:=ReadByte(FilRec); (* DEN *)
                          DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
                          StartTime:=CurTime;
                          EndTime:=CurTime;
                          WriteDebugInfo('Signature : ' + B2S(NoteVal)+'/'+ I2S(Power(2,Velocity)) +' at '+
                                          I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
                          End
                       End
                    Else
                       With PieceContr Do
                           Begin
                           Num:=ReadByte(FilRec);Den:=ReadByte(FilRec);
                           FinishTeXHeader(Num,Den);
                           DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
                           TicksPerMeasure:=4*Division*Num div Power(2,Den);
                           If NOT PartOverRule Then
                             PartTime:=TicksPerMeasure div Num
                           Else
                             PartTime:=4*Division div PartType;
                           nparts:=TicksPerMeasure div PartTime;
                           Twindow:=Division div 16;
                           If Quantizing Then QuantTime:=Division*4 div QuantTime;
                           WriteDebugInfo('4*'+I2S(Division)+'*'+B2S(Num)+' div '+
                                                   B2S(Den)+' = '+W2S(TicksPerMeasure)+' Ticks per measure');
                           End;
                    End;
        89  :       Begin  (* Key signature *)
                    If TeXHeaderFinished then (* store the value on the note list *)
                       Begin
                       N:=GetFreeNote;
                       Append(NoteList,N);
                       With N^ Do
                          Begin
                          Event:=KEYSIGN;
                          NoteVal:=ReadByte(FilRec); (* KeySign *)
                          Velocity:=ReadByte(FilRec); (* Minor *)
                          StartTime:=CurTime;
                          EndTime:=CurTime;
                          
                          WriteDebugInfo('Keysign  : ' + B2S(NoteVal) + ' at '+
                                         I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
                          End
                       End
                    Else
                       With PieceContr DO
                          Begin
                          KeySign:=ReadByte(FilRec);
                          Minor:=ReadByte(FilRec);
                          If KeySign>0 Then
                              WriteDebugInfo('KeySignature : '+B2S(KeySign)+' sharps ')
                          Else
                              WriteDebugInfo('KeySignature : '+B2S(KeySign)+' flats ');
                          End; (* with *)
                    End;
        127 :       Begin (* specials.... *)
                    For i:=1 to MetaLength Do DumByte:=ReadByte(FilRec);
                    End;            
    End; (* case *)                   
    End;
End; (* ReadMetaEvent *)


(*****************************************************)
    Procedure ReadEvent(VAR ThisTrack : TrackRecord);
(*****************************************************)
VAR DumByte,
    MidiCode : Byte;
Begin
With ThisTrack Do
    Begin
    MidiCode:=ReadByte(FilRec);
    case MidiCode Of
         $90..$9F :  Begin ReadNoteOn(MidiCode,ThisTrack); StatusByte:=MidiCode; End;
         $80..$8F :  Begin ReadNoteOff(MidiCode,ThisTrack); StatusByte:=MidiCode; End;
         $FF      :  Begin ReadMetaEvent(ThisTrack); StatusByte:=MidiCode; End;
         $A0..$AF :  Begin For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
                            StatusByte:=MidiCode; End;(* polypress. *)
         $B0..$BF :  Begin
                     DumByte:=ReadByte(FilRec);
                     case DumByte of
                        $40 : ReadDamper(MidiCode,ThisTrack); { this is a damper pedal }
                     Else
                        DumByte:=ReadByte(FilRec);
                     End; { case }
                     StatusByte:=MidiCode;
                     End;(* control change *)
         $C0..$CF :  Begin DumByte:=ReadByte(FilRec); StatusByte:=MidiCode; End;(* progr. change *)
         $D0..$DF :  Begin DumByte:=ReadByte(FilRec);
                     StatusByte:=MidiCode; End;(* channel pressure *)
         $E0..$EF :  Begin For i:=1 to 2 Do DumByte:=ReadByte(FilRec); StatusByte:=MidiCode; End;(* pitch wheel *)
         $F8      :  Begin (* do nothing *) End; (* timing clock *)
         $F0      :  Begin
                     Repeat (* SysEx code *)
                       DumByte:=ReadByte(FilRec);
                     until DumByte=$F7;
                     StatusByte:=00;
                     End;
         $F1      :  DumByte:=ReadByte(FilRec);(* quarter frame *)
         Else        (* WriteDebugInfo(' Unknown MidiEvent, type : '+B2S(MidiCode)); *)
                     (* This is a running status *)
                     Begin
                     RestoreLastRead(FilRec); (* This will NOT work ALWAYS !!! *)
                     case StatusByte Of
                          $90..$9F :  ReadNoteOn(StatusByte,ThisTrack);
                          $80..$8F :  ReadNoteOff(StatusByte,ThisTrack);
                          $FF      :  ReadMetaEvent(ThisTrack);
                          $A0..$AF :  For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
                          $B0..$BF :  For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
                          $C0..$CF :  DumByte:=ReadByte(FilRec);
                          $D0..$DF :  DumByte:=ReadByte(FilRec);
                          $E0..$EF :  For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
                          $F8      :  Begin (* do nothing *) End; (* timing clock *)
                          $F0      :  Repeat (* SysEx code *)
                                        DumByte:=ReadByte(FilRec);
                                      until DumByte=$F7;
                          $F1      :  DumByte:=ReadByte(FilRec);(* quarter frame *)
                     End; (* case *)
                     End;
    end;
    End;
End; (* ReadEvent *)           


(**************************************************************)
      Function EndOfTrackReached(VAR ThisTrack:TrackRecord):boolean;
(*************************************************************)
Begin
With ThisTrack Do
  If EndOfTrackRead AND
     (SpillList.Size=0) AND
     (NoteList.Size=0) Then
     EndOfTrackReached:=TRUE
  Else
     EndOfTrackReached:=FALSE;
End;

Begin
End.