{$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.