{$R-} {Range checking off}
 (*{$B-} {Boolean complete evaluation off}*)
 {$S+} {Stack checking on}
 {$I-} {I/O checking off}
 {$M 65500,16384,655360} {Turbo 3 default stack and heap} 
Program lily; { Reads the temporary files from Samples.pas and generates lily    pond input for notation }
uses dos,crt; {, crt Standard Turbo Units }
{ To do:
   - Read a set of options from the *.mac file, including tempo, name, instrument    names, metric divisions, etc.
   - Get a clear idea of all the notes in the input file
   - Make sure you process all the notes in the input (edge cases)
   - If you are still in a chord at the end, do something about it
   }
Type
   AudNoteType = Record
   Octave: Byte; { 0..11 }
   ToneInScale: Byte; { 0..MaxEqual }
   Velocity: Byte; { Loudness 0..127, if over 200, set it to zero 7/29/02 - changed    to 200 9/12/03 }
   Rand: Byte; { Random chance that note will play 0 - 16 }
   Stereo: Byte; { Stereo 0 left 15 right }
   Perturb: Byte; { 0 is no change, 100 is 100 plus or minus }
   Glisand: Byte; { 0 is flat, 1-10 are tables }
   Upsample: Byte; { 0 is normal, 1 is next higher, 255 is next lower }
   Envelope: Byte; { Pick an Envelope Function Table 0 to 100 }
   Duration: Integer; { 0..32767 }
   HoldDuration: Integer; { 0..32767 }
   WarpDuration: Integer; { 0..32767 }
   { Next: AudNotePtr; }
   Next: LongInt; { file position, not a pointer any more }
   end;
   ChannelType = Record
   First: Longint; { points to a record location in the file }
   Current: Longint; { Last written spot }
   StartTime: LongInt; { Sum of Durations }
   Instrument: Byte; { 1 to 129 named instruments }
   FunctionTable: Byte; { unique function table set }
   end;
   DurationType = Record
   Time: Integer;
   Lily: String[10];
   end;
Const
   MaxChans = 128 - 1; { channels 0 to 127 }
   MaxDurs = 11;
   MeasureMax = 256; { samples beats per measure }
   Composer = 'Prent Rodgers';
   SongName = 'Next Piece';
   TimeSig = '4/4';
   Var
   AudNoteFile: File of AudNoteType;
   ChannelFile: File of ChannelType;
   LilyFile: Text;
   i, Io, Ioresult: Integer;
   InChord: Boolean;
   Channels: ChannelType;
   AudNote: AudNoteType;
   NoteNames: Array[0..42] of String[3]; { A letter followed by either: b, --,    -, space, +, ++, # }
   LilyNames: Array[0..42] of String[5]; { A letter followed by a set of characters    }
   Octaves: Array[0..6] of String[4]; { comma or half quotes repeated }
   Durations: Array[0..MaxDurs] of DurationType;
   MeasureDur: Integer;
   { lilypond accepts double flat, 1 1/2 flat, flat, half flat, natural, half sharp,    sharp, 1 1/2 sharp, double sharp }
   { LilyPond Name : eses, eseh, es, eh, blank, ih, is, isih, isis }
   { Samples name: b -- - space + ++ #
   { Appearance bb bbline b back b natural + # ## x }
   { Glyph name : Accidental-2 - #
   Accidental-1 - ++
   Accidental-3 - ##
   Accidental-0 - natural
   Accidental--2 - b
   Accidental--3 - bb with a line though it
   Accidental-4 - big x double sharp
   Accidental--1 - backwards flat - 1/2 flat }
Procedure Init;
   Begin
   NoteNames[0 ] := 'C '; LilyNames[ 0] := 'c';
   NoteNames[1 ] := 'C+ '; LilyNames[ 1] := 'cih';
   NoteNames[2 ] := 'C++'; LilyNames[ 2] := 'cis';
   NoteNames[3 ] := 'C# '; LilyNames[ 3] := 'cisih';
   NoteNames[4 ] := 'Db '; LilyNames[ 4] := 'deseh';
   NoteNames[5 ] := 'D--'; LilyNames[ 5] := 'des';
   NoteNames[6 ] := 'D- '; LilyNames[ 6] := 'deh';
   NoteNames[7 ] := 'D '; LilyNames[ 7] := 'd';
   NoteNames[8 ] := 'D+ '; LilyNames[ 8] := 'dih';
   NoteNames[9 ] := 'D++'; LilyNames[ 9] := 'dis';
   NoteNames[10] := 'D# '; LilyNames[10] := 'disih';
   NoteNames[11] := 'Eb '; LilyNames[11] := 'eeseh';
   NoteNames[12] := 'E--'; LilyNames[12] := 'ees';
   NoteNames[13] := 'E- '; LilyNames[13] := 'eeh';
   NoteNames[14] := 'E '; LilyNames[14] := 'e';
   NoteNames[15] := 'E+ '; LilyNames[15] := 'eih';
   NoteNames[16] := 'E++'; LilyNames[16] := 'eis';
   NoteNames[17] := 'F- '; LilyNames[17] := 'feh';
   NoteNames[18] := 'F '; LilyNames[18] := 'f';
   NoteNames[19] := 'F+ '; LilyNames[19] := 'fih';
   NoteNames[20] := 'F++'; LilyNames[20] := 'fis';
   NoteNames[21] := 'F# '; LilyNames[21] := 'fisih';
   NoteNames[22] := 'Gb '; LilyNames[22] := 'geseh';
   NoteNames[23] := 'G--'; LilyNames[23] := 'ges';
   NoteNames[24] := 'G- '; LilyNames[24] := 'geh';
   NoteNames[25] := 'G '; LilyNames[25] := 'g';
   NoteNames[26] := 'G+ '; LilyNames[26] := 'gih';
   NoteNames[27] := 'G++'; LilyNames[27] := 'gis';
   NoteNames[28] := 'G# '; LilyNames[28] := 'gisih';
   NoteNames[29] := 'Ab '; LilyNames[29] := 'aeseh';
   NoteNames[30] := 'A--'; LilyNames[30] := 'aes';
   NoteNames[31] := 'A- '; LilyNames[31] := 'aeh';
   NoteNames[32] := 'A '; LilyNames[32] := 'a';
   NoteNames[33] := 'A+ '; LilyNames[33] := 'aih';
   NoteNames[34] := 'A++'; LilyNames[34] := 'ais';
   NoteNames[35] := 'A# '; LilyNames[35] := 'aisih';
   NoteNames[36] := 'Bb '; LilyNames[36] := 'beseh';
   NoteNames[37] := 'B--'; LilyNames[37] := 'bes';
   NoteNames[38] := 'B- '; LilyNames[38] := 'beh';
   NoteNames[39] := 'B '; LilyNames[39] := 'b';
   NoteNames[40] := 'B+ '; LilyNames[40] := 'bih';
   NoteNames[41] := 'B++'; LilyNames[41] := 'bis';
   NoteNames[42] := 'C- '; LilyNames[42] := 'ceh';
   Octaves[0] := Chr(44) + Chr(44) + Chr(44);
   Octaves[1] := Chr(44) + Chr(44);
   Octaves[2] := Chr(44);
   Octaves[3] := '';
   Octaves[4] := Chr(39);
   Octaves[5] := Chr(39) + Chr(39);
   Octaves[6] := Chr(39) + Chr(39) + Chr(39);
   Durations[ 0].Time := 8; Durations[ 0].Lily := '32';
   Durations[ 1].Time := 12; Durations[ 1].Lily := '24'; { 12 = sixteenth triplet    \times 2/3 notename 16 }
   Durations[ 2].Time := 16; Durations[ 2].Lily := '16';
   Durations[ 3].Time := 24; Durations[ 3].Lily := '16.';
   Durations[ 4].Time := 32; Durations[ 4].Lily := '8';
   Durations[ 5].Time := 48; Durations[ 5].Lily := '8.';
   Durations[ 6].Time := 64; Durations[ 6].Lily := '4';
   Durations[ 7].Time := 96; Durations[ 7].Lily := '4.';
   Durations[ 8].Time := 112; Durations[ 8].Lily := '4..';
   Durations[ 9].Time := 128; Durations[ 9].Lily := '2';
   Durations[10].Time := 192; Durations[10].Lily := '2.';
   Durations[11].Time := 256; Durations[11].Lily := '1';
   (*
   { resolution in blue }
   Durations[ 0].Time := 2; Durations[ 0].Lily := '64';
   Durations[ 1].Time := 4; Durations[ 1].Lily := '32';
   Durations[ 2].Time := 8; Durations[ 2].Lily := '16';
   Durations[ 3].Time := 16; Durations[ 3].Lily := '8';
   Durations[ 4].Time := 32; Durations[ 4].Lily := '4';
   Durations[ 5].Time := 48; Durations[ 5].Lily := '4.';
   Durations[ 6].Time := 64; Durations[ 6].Lily := '2';
   Durations[ 7].Time := 96; Durations[ 7].Lily := '2.';
   Durations[ 8].Time := 112; Durations[ 8].Lily := '2..';
   Durations[ 9].Time := 144; Durations[ 9].Lily := '2...';
   Durations[10].Time := 192; Durations[10].Lily := '1.';
   Durations[11].Time := 256; Durations[11].Lily := '1..';
   *)
   Io := 0;
   Ioresult := 0;
   Assign(ChannelFile,'Chann.fil');
   {$i-}
   ReSet(ChannelFile);
   {$i+}
   Io := Ioresult;
   If Io <> 0 then
   Begin
   Writeln('Could not open ChannelFile. Io = ',io);
   Writeln('File was called Chann.fil');
   Halt(Io);
   end;
   Assign(AudNoteFile,'Notes.fil');
   {$i-}
   ReSet(AudNoteFile);
   {$i+}
   Io := Ioresult;
   If Io <> 0 then
   Begin
   Writeln('Could not open AudNoteFile. Io = ',io);
   Writeln('File was called Notes.fil');
   Halt(Io);
   end;
   Assign(LilyFile,'samples.ly');
   {$i-}
   ReWrite(LilyFile);
   {$i+}
   Io := Ioresult;
   If Io <> 0 then
   Begin
   Writeln('Could not create LilyFile. Io = ',io);
   Writeln('File was called samples.ly');
   Halt(Io);
   end;
   end; { init }
Procedure SetUpLily;
   Begin
   Writeln(LilyFile,'% Generated automatically by: lily.pas from samples.pas');
   Writeln(LilyFile,' \header {');
   Writeln(LilyFile,' composer = "',Composer,'"');
   Writeln(LilyFile,' title = "',SongName,'"');
   Writeln(LilyFile,' enteredby = "PJR"');
   Writeln(LilyFile,' }');
 Writeln(LilyFile,' \score {');
   Writeln(LilyFile,' \notes {');
   Writeln(LilyFile,' \simultaneous {');
   end; { SetUpLily }
Function GetDuration(NoteLength: Integer): Integer;
Var i: Integer;
 Begin
   { Array index: 0 1 2 3 4 5 6 7 8 9 10 11 }
   { Array values: 8, 12, 16, 24, 32, 48, 64, 96, 112, 128, 192, 256 }
   { Lily duration:'32' '24' '16' '16.' '8' '8.' '4' '4.' '4..' '2' '2.' '1'
   { Return index to the array value closest to actual value }
   i := 0;
   While (NoteLength > Durations[i].Time) do
   Begin
   i := i + 1;
   end;
   GetDuration := i;
   end; { GetDuration }
Procedure ProcessAudNotes;
 Begin
   MeasureDur := 0;
   InChord := False;
   Seek(AudNoteFile,Channels.First);
   Repeat
   { Writeln('Line 220. Read(AudNoteFile,',AudNote.next); }
   Read(AudNoteFile,AudNote);
   With AudNote do
   Begin
   Writeln(LilyFile,'%',Octave:6, ' ',
   NoteNames[ToneInScale], Velocity:6, Rand:6,
   Duration:6, HoldDuration:6, Glisand:6);
   If Not InChord and (Duration = 0) then
   Begin
   InChord := True;
   Writeln(LilyFile,'< ',LilyNames[ToneInScale],Octaves[Octave-1]);
   end
   Else if InChord and (Duration = 0) then
   Begin
   Writeln(LilyFile,LilyNames[ToneInScale],Octaves[Octave-1]);
   end
   Else if InChord and (Duration > 0) then
   Begin
   InChord := False;
   Writeln(LilyFile,LilyNames[ToneInScale],Octaves[Octave-1]);
   { Need to check if hold is less than durations, and if it is convert to
   short note and a rest, or at least a stacatto above the note }
   Writeln(LilyFile,'> ',Durations[GetDuration(Duration)].Lily);
   MeasureDur := MeasureDur + Duration;
   end
   Else if Rand>0 then
   Begin
   Writeln(LilyFile,LilyNames[ToneInScale],Octaves[Octave-1],
   Durations[GetDuration(Duration)].Lily);
   MeasureDur := MeasureDur + Duration;
   end
   Else
   Begin
   Writeln(LilyFile,'r', Durations[GetDuration(Duration)].Lily);
   MeasureDur := MeasureDur + Duration;
   end;
   If Glisand > 0 then Writeln(LilyFile,'\glissando ');
   If MeasureDur >= MeasureMax then
   Begin
   MeasureDur := 0;
   Writeln(LilyFile,'|');
   end;
   end;
   { Writeln('Line 263. Seek(AudNoteFile,',Audnote.Next); }
   If AudNote.Next <> -1 then Seek(AudNoteFile,AudNote.Next);
   Until (AudNote.Next = -1) or (eof (AudNoteFile));
   end; { ProcessAudNote }
Procedure StartNewStaff;
 Begin
   i := i + 1;
   If i = 3 then Writeln(LilyFile,' \new Staff {\clef bass')
   Else Writeln(LilyFile,' \new Staff {\clef treble');
   Writeln(LilyFile,' \time ',TimeSig);
   Writeln(LilyFile,' \property Staff.instrument = "C',i:4,' I',
   Channels.Instrument:4,' F',Channels.FunctionTable,'"');
   Writeln(LilyFile,'% First Channel is Instrument:',
   Channels.Instrument, ' FunctionTable: ',Channels.FunctionTable);
   Writeln(LilyFile,'% Oct Note Velo Rand Dur Hold Gliss');
   end; { StartNewStaff }
Procedure EndStaff;
 Begin
   Writeln(LilyFile,' }');
   end; { EndStaff }
Procedure EndScore;
 Begin
   Writeln(LilyFile,' }');
   Writeln(LilyFile,' }');
   Writeln(LilyFile, ' \paper { ');
   Writeln(LilyFile, ' } } ');
   end; { EndScore }
Begin
   Init;
   SetUpLily;
   Seek(ChannelFile,0);
   Read(ChannelFile,Channels);
   i := 0;
   While Not Eof(ChannelFile) do
   Begin
   StartNewStaff;
   ProcessAudNotes;
   EndStaff;
   Read(ChannelFile,Channels);
   { Writeln('Line 307. Read(ChannelFile. Channels.First = ',Channels.First); }
   end;
   StartNewStaff;
   ProcessAudNotes;
   EndStaff;
   EndScore;
   Close(LilyFile);
   end.