-- Author: John Maxwell
-- Last Edited by: Maxwell, November 22, 1983 10:13 am
DIRECTORY
Beam USING [AddItem, GetHeapIndex, New, SetSyncs],
Chord USING [GetHeapIndex],
Directory USING [Lookup],
Event USING [GetScoreIndex, KeySignature, Measure, Metrenome, SetStave, Staves, Sync, TimeSignature],
FileStream USING [Create],
MusicDefs,
MusicFileDefs,
Note USING [GetSyncIndex],
Piece USING [New, Overflow],
Score USING [FileStats, Look, SetKey, SetMetrenome, Test],
Sheet USING [Reset, SetBegin],
Stream USING [Delete, GetBlock, Handle, PutBlock],
Utility USING [NewSegment];
FilerImpl: MONITOR
IMPORTS Beam, Chord, Directory, FileStream, MusicDefs, Note, Piece, Score, Sheet, Stream, Event, Utility
EXPORTS Score =
BEGIN
OPEN MusicDefs, MusicFileDefs;
Error: SIGNAL;
-- ****************************************************************************
-- buffer for stream
-- ****************************************************************************
stream: Stream.Handle;
buffer: ARRAY [0..bufferLength) OF INTEGER;
bufferIndex: CARDINAL ← 0;
bufferLength: CARDINAL = 500;
Get: PROCEDURE[stream: Stream.Handle] RETURNS[data: UNSPECIFIED] =
INLINE BEGIN GetBlock[stream, @data, 1]; END;
GetBlock: PROCEDURE[stream: Stream.Handle, p: POINTER, length: CARDINAL] =
-- a hack to speed up disk transfers by batching them together
BEGIN
array: POINTER TO ARRAY[0..1000) OF INTEGER ← LOOPHOLE[p];
IF p = NIL THEN BEGIN
[] ← Stream.GetBlock[stream, [@buffer, 0, 2*bufferLength]];
bufferIndex ← 0;
RETURN;
END;
FOR i: CARDINAL IN [0..length) DO
array[i] ← buffer[bufferIndex];
bufferIndex ← bufferIndex+1;
IF bufferIndex < bufferLength THEN LOOP;
[] ← Stream.GetBlock[stream, [@buffer, 0, 2*bufferLength]];
bufferIndex ← 0;
ENDLOOP;
END;
Put: PROCEDURE[stream: Stream.Handle, data: INTEGER] = INLINE {PutBlock[stream, @data, 1]};
PutBlock: PROCEDURE[stream: Stream.Handle, p: POINTER, length: CARDINAL] =
BEGIN
array: POINTER TO ARRAY[0..1000) OF INTEGER ← LOOPHOLE[p];
IF length = 0 THEN IF bufferIndex # 0 THEN {
[] ← Stream.PutBlock[stream, [@buffer, 0, 2*bufferIndex]];
bufferIndex ← 0};
FOR i: CARDINAL IN [0..length) DO
IF bufferIndex >= bufferLength THEN {
[] ← Stream.PutBlock[stream, [@buffer, 0, 2*bufferIndex]];
bufferIndex ← 0};
buffer[bufferIndex] ← array[i];
bufferIndex ← bufferIndex + 1;
ENDLOOP;
END;
-- ****************************************************************************
-- filein
-- ****************************************************************************
version: INTEGER;
FileIn: PUBLIC ENTRY PROCEDURE[fileName: STRING] RETURNS[score: ScorePTR] =
BEGIN ENABLE Piece.Overflow => {IF score = old THEN score ← new; RESUME};
view: ViewFormat;
newMax: CARDINAL;
stream ← FileStream.Create[Directory.Lookup[fileName] -- Stream.Read -- ];
GetBlock[stream, NIL, 0]; -- pre-fills the buffer
version ← Get[stream];
IF version # versionID THEN Error; -- need a different error here
score ← Piece.New[3000];
-- Utility.InitStorage[score];
-- format in score
IF Get[stream] # scoreID THEN Error;
score.length ← Get[stream];
FOR i: CARDINAL IN [0..score.length) DO
event: EventFormat; -- local storage
score[i] ← ReadEvent[@event];
SELECT score[i].type FROM
sync => {
sync: SyncPTR ← Event.Sync[score[i]];
FOR j: CARDINAL IN [0..sync.length) DO
tie: TieFormat;
note: NoteFormat;
sync.note[j] ← ReadNote[@note];
sync.note[j].sync ← sync;
score.maxVoice ← MAX[note.voice, score.maxVoice];
IF note.tie THEN ReadTie[score, sync.note[j], @tie];
ENDLOOP};
staves => {
format: SheetFormat;
staves: StavesPTR ← Event.Staves[score[i]];
ReadSheet[score, staves, @format];
IF event.type = staves AND event.value = -1
THEN FindStyle[score, staves]
ELSE staves.value ← event.value;
};
ENDCASE;
IF score[i].time = -1 AND score[i].type = staves
AND Event.Staves[score[i]].staves = style THEN { -- sort the score
temp: EventPTR = score[i];
FOR j: CARDINAL DECREASING IN [0..i) DO score[j+1] ← score[j]; ENDLOOP;
score[0] ← temp;
score[0].time ← 0};
ENDLOOP;
-- format in chordheap
IF Get[stream] # chordHeapID THEN Error;
newMax ← Get[stream]+100;
score.chordHeap ← Utility.NewSegment[SIZE[ChordHeapRec[newMax]], newMax, SIZE[ChordHeapRec[0]]-1];
FOR i: CARDINAL IN [0..score.chordHeap.length) DO
chord: ChordFormat;
score.chordHeap[i] ← ReadChord[@chord];
FOR j: CARDINAL IN [0..chord.length) DO
pointer: RelativePTR;
GetBlock[stream, @pointer, SIZE[RelativePTR]];
score.chordHeap[i].note[j] ← Event.Sync[score[pointer.heap]].note[pointer.index];
score.chordHeap[i].note[j].chord ← score.chordHeap[i];
ENDLOOP;
ENDLOOP;
-- format in beamheap
IF Get[stream] # beamHeapID THEN Error;
newMax ← Get[stream]+100;
score.beamHeap ← Utility.NewSegment[SIZE[BeamHeapRec[newMax]], newMax, SIZE[BeamHeapRec[0]]-1];
FOR i: CARDINAL IN [0..score.beamHeap.length) DO
score.beamHeap[i] ← Beam.New[score, 4];
ENDLOOP;
FOR i: CARDINAL IN [0..score.beamHeap.length) DO
beamFormat: BeamFormat;
beam: BeamPTR ← score.beamHeap[i];
ReadBeam[beam, @beamFormat];
FOR j: CARDINAL IN [0..beamFormat.length) DO
beam ← Beam.AddItem[score, beam, ReadBeamEntry[score, beam]];
ENDLOOP;
ENDLOOP;
FOR i: CARDINAL IN [0..score.beamHeap.length) DO
Beam.SetSyncs[score.beamHeap[i]];
ENDLOOP;
-- format in spares
IF Get[stream] # nullID THEN Error;
IF Get[stream] # nullID THEN Error;
IF Get[stream] # nullID THEN Error;
IF Get[stream] # nullID THEN Error;
IF Get[stream] # nullID THEN Error;
IF Get[stream] # nullID THEN Error;
IF Get[stream] # nullID THEN Error;
IF Get[stream] # nullID THEN Error;
IF Get[stream] # nullID THEN Error;
ReadView[score, @view];
-- clean up and return
bufferIndex ← 0;
Stream.Delete[stream];
score.command ← TRUE;
Score.FileStats[score];
Sheet.SetBegin[score.sheet, 0];
END;
ReadEvent: PROCEDURE[format: POINTER TO EventFormat] RETURNS[event: EventPTR] =
BEGIN
Subtract: PROC[a, b: UNSPECIFIED] RETURNS[UNSPECIFIED] = INLINE
BEGIN RETURN[LOOPHOLE[a, CARDINAL] - LOOPHOLE[b, CARDINAL]]; END;
GetBlock[stream, @format, SIZE[EventFormat]];
IF format.identifier # eventID THEN Error;
SELECT format.type FROM
notes => event ← zone.NEW[EventRec.sync[format.length + 2]];
keySignature => {
event ← zone.NEW[EventRec.keySignature];
Event.KeySignature[event].key ← format.value};
timeSignature => {
event ← zone.NEW[EventRec.timeSignature];
Event.TimeSignature[event].ts ← LOOPHOLE[format.value]};
metrenome => {
event ← zone.NEW[EventRec.metrenome];
Event.Metrenome[event].metrenome ← format.value};
IN [measure..timeSignature) => {
measure: MusicFileDefs.EventTypeFormat ← measure;
event ← zone.NEW[EventRec.measure];
Event.Measure[event].measure ← Subtract[format.type, measure]};
IN [staves.. spare14) => {
staves: MusicFileDefs.EventTypeFormat ← staves;
event ← zone.NEW[EventRec.staves];
Event.Staves[event].staves ← Subtract[format.type, staves]};
ENDCASE => ERROR;
event.time ← format.time;
END;
ReadNote: PROCEDURE[format: POINTER TO NoteFormat] RETURNS[note: NotePTR] =
BEGIN
GetBlock[stream, @format, SIZE[NoteFormat]];
IF format.identifier # noteID THEN Error;
note ← zone.NEW[NoteRec];
note.pitch ← format.pitch;
note.voice ← format.voice;
note.value ← format.value;
note.spelled ← format.spelled;
note.rest ← format.rest;
note.dotted ← format.dotted;
note.doubleDotted ← format.doubleDotted;
note.grace ← format.grace;
note.stemUp ← format.stemUp;
note.embellish ← format.embellish;
note.staff ← format.staff;
note.toc ← format.toc;
note.duration ← format.duration;
END;
ReadTie: PROC[score: ScorePTR, note: NotePTR, format: POINTER TO TieFormat] =
BEGIN
GetBlock[stream, @format, SIZE[TieFormat]];
IF format.identifier # tieID THEN Error;
note.tie ← Event.Sync[score[format.heap]].note[format.index];
note.tieHeight ← format.height;
note.tie.tied ← TRUE;
END;
ReadSheet: PROCEDURE[score: ScorePTR, staves: StavesPTR, format: POINTER TO SheetFormat] =
BEGIN
-- old.event ← LOOPHOLE[staves↑];
-- staves ← LOOPHOLE[@old.event];
-- IF version < 3 THEN ConvertSheet2[old];
GetBlock[stream, @format, SIZE[SheetFormat]];
staves.height ← format.height;
staves.offset ← format.offset;
staves.length ← format.sl-1;
FOR i: CARDINAL IN [0..staves.length) DO
staves.staff[i] ← format.staff[i];
ENDLOOP;
END;
FindStyle: PROCEDURE[score: ScorePTR, staves: StavesPTR] =
BEGIN
index: INTEGER ← 1;
FOR i: CARDINAL IN [1..staves.length) DO
IF staves.staff[i].y = staves.staff[i-1].y THEN LOOP;
index ← index+1;
ENDLOOP;
IF index = 4 AND staves.staff[0].pitch = 72 THEN index ← 0;
staves.value ← index;
Event.SetStave[score, staves, score.style[index]];
END;
ReadChord: PROCEDURE[format: POINTER TO ChordFormat] RETURNS[chord: ChordPTR] =
BEGIN
IF format.identifier # chordID THEN Error;
GetBlock[stream, @format, SIZE[ChordFormat]];
chord ← zone.NEW[ChordRec[format.length + 2]];
chord.stemUp ← format.stemUp;
chord.length ← format.length;
END;
ReadBeam: PROCEDURE[beam: BeamPTR, format: POINTER TO BeamFormat] =
BEGIN
GetBlock[stream, @format, SIZE[BeamFormat]];
IF format.identifier # beamID THEN Error;
beam.tilt ← format.tilt;
beam.beamed ← format.beamed;
beam.ntuple ← format.ntuple;
beam.against ← format.against;
beam.height ← format.height;
beam.invisible ← format.invisible;
beam.staff ← format.staff;
beam.length ← format.length;
END;
ReadBeamEntry: PROC[score: ScorePTR, beam: BeamPTR] RETURNS[vp: VariousPTR] =
BEGIN
pointer: RelativePTR;
GetBlock[stream, @pointer, SIZE[RelativePTR]];
SELECT pointer.heap FROM
beams => BEGIN
b: BeamPTR ← score.beamHeap[pointer.index];
b.beam ← beam;
vp ← [beam[b]];
END;
chords => BEGIN
c: ChordPTR ← score.chordHeap[pointer.index];
FOR k: CARDINAL IN [0..c.length) DO
c.note[k].beam ← beam;
ENDLOOP;
vp ← [chord[c]];
END;
ENDCASE => BEGIN
n: NotePTR ← Event.Sync[score[pointer.heap]].note[pointer.index];
n.beam ← beam;
vp ← [note[n]];
END;
END;
ReadView: PROCEDURE[score: ScorePTR, view: POINTER TO ViewFormat] =
BEGIN ENABLE Piece.Overflow => IF score = old THEN score ← new;
GetBlock[stream, @view, SIZE[ViewFormat]];
IF view.display = physical
THEN score.sheet.density ← view.scale
ELSE score.sheet.justification ← view.scale;
SELECT view.sheet FROM -- convert from old indices to new ones
1 => Score.Look[score, style, , 0];
6, 7 => Score.Look[score, style, , 1];
2 => Score.Look[score, style, , 2];
4, 5 => Score.Look[score, style, , 3];
3 => Score.Look[score, style, , 4];
ENDCASE;
score.sheet.accidental ← view.accidental;
score.sheet.sync ← view.sync;
score.sheet.notehead ← view.notehead;
score.sheet.display ← view.display;
score.sheet.noCarry ← view.noCarry;
Score.Look[score, hardcopy, view.hardcopy, ];
IF version = 1 THEN Score.SetKey[score, 0, LAST[Time], view.key];
IF version = 1 THEN Score.SetMetrenome[score, 0, LAST[Time], view.speed];
Sheet.Reset[score];
END;
-- ****************************************************************************
-- fileout
-- ****************************************************************************
FileOut: PUBLIC ENTRY PROCEDURE[score: ScorePTR, fileName: STRING]
RETURNS[BOOLEAN] =
BEGIN
OPEN FileStream;
beam: BeamFormat ← []; -- fills in default values
view: ViewFormat ← [];
sheet: SheetFormat ← [];
event: EventFormat ← [];
chord: ChordFormat ← [];
IF Score.Test[score] THEN RETURN[FALSE];
stream ← FileStream.Create[Directory.Lookup[fileName] -- Stream.Write+Stream.Append-- ];
-- stream.reset[stream];
-- format out score
Put[stream, versionID];
Put[stream, scoreID];
Put[stream, score.length];
FOR i: CARDINAL IN [0..score.length) DO
sync: SyncPTR;
tie: TieFormat ← [];
note: NoteFormat ← [];
WriteEvent[score[i], @event];
IF score[i].type = staves THEN WriteSheet[Event.Staves[score[i]], @sheet];
IF score[i].type # sync THEN LOOP;
sync ← Event.Sync[score[i]];
FOR j: CARDINAL IN [0..sync.length) DO
WriteNote[sync[j], @note];
IF sync[j].tie # NIL THEN WriteTie[score, sync[j], @tie];
ENDLOOP;
ENDLOOP;
-- format out chordheap
Put[stream, chordHeapID];
Put[stream, score.chordHeap.length];
FOR i: CARDINAL IN [0..score.chordHeap.length) DO
pointer: RelativePTR;
WriteChord[score.chordHeap[i], @chord];
pointer.heap ← Event.GetScoreIndex[score, score.chordHeap[i].note[0].sync];
FOR j: CARDINAL IN [0..score.chordHeap[i].length) DO
note: NotePTR ← score.chordHeap[i].note[j];
pointer.index ← Note.GetSyncIndex[note.sync, note];
[] ← PutBlock[stream, @pointer, SIZE[RelativePTR]];
ENDLOOP;
ENDLOOP;
-- format out beamheap
Put[stream, beamHeapID];
Put[stream, score.beamHeap.length];
FOR i: CARDINAL IN [0..score.beamHeap.length) DO
WriteBeam[score.beamHeap[i], @beam];
[] ← PutBlock[stream, @beam, SIZE[BeamFormat]];
FOR j: CARDINAL IN [0..score.beamHeap[i].length) DO
pointer: RelativePTR;
WITH ev: score.beamHeap[i].chord[j] SELECT FROM
note => BEGIN
pointer.heap ← Event.GetScoreIndex[score, ev.n.sync];
pointer.index ← Note.GetSyncIndex[Event.Sync[score[pointer.heap]], ev.n];
END;
chord => BEGIN
pointer.heap ← chords;
pointer.index ← Chord.GetHeapIndex[score.chordHeap, ev.c];
END;
beam => BEGIN
pointer.heap ← beams;
pointer.index ← Beam.GetHeapIndex[score.beamHeap, ev.b];
END;
ENDCASE;
[] ← PutBlock[stream, @pointer, SIZE[RelativePTR]];
ENDLOOP;
ENDLOOP;
-- format out nine spares
Put[stream, nullID];
Put[stream, nullID];
Put[stream, nullID];
Put[stream, nullID];
Put[stream, nullID];
Put[stream, nullID];
Put[stream, nullID];
Put[stream, nullID];
Put[stream, nullID];
-- format out view
WriteView[score, @view];
-- clean up and return
[] ← PutBlock[stream, NIL, 0]; -- clean up buffer
Stream.Delete[stream];
score.command ← TRUE;
RETURN[TRUE];
END;
WriteEvent: PROCEDURE[data: EventPTR, format: POINTER TO EventFormat] =
BEGIN
Add: PROC[a, b: UNSPECIFIED] RETURNS[UNSPECIFIED] = INLINE
BEGIN RETURN[LOOPHOLE[a, CARDINAL] + LOOPHOLE[b, CARDINAL]]; END;
format.time ← data.time;
format.type ← LOOPHOLE[data.type];
format.ignore ← FALSE;
format.value ← 0;
format.length ← 0;
SELECT data.type FROM
measure => format.type ← Add[format.type, Event.Measure[data].measure];
sync => format.length ← Event.Sync[data].length;
timeSignature => format.value ← LOOPHOLE[Event.TimeSignature[data].ts];
keySignature => format.value ← Event.KeySignature[data].key;
metrenome => format.value ← Event.Metrenome[data].metrenome;
staves => {
format.type ← Add[format.type, Event.Staves[data].staves];
format.ignore ← TRUE};
ENDCASE => ERROR;
[] ← PutBlock[stream, @format, SIZE[EventFormat]];
END;
WriteNote: PROCEDURE[note: NotePTR, format: POINTER TO NoteFormat] =
BEGIN
format.pitch ← note.pitch;
format.voice ← note.voice;
format.value ← note.value;
format.spelled ← note.spelled;
format.rest ← note.rest;
format.dotted ← note.dotted;
format.doubleDotted ← note.doubleDotted;
format.grace ← note.grace;
format.stemUp ← note.stemUp;
format.embellish ← note.embellish;
format.tie ← note.tie # NIL;
format.staff ← note.staff;
format.toc ← note.toc;
format.duration ← note.duration;
[] ← PutBlock[stream, @format, SIZE[NoteFormat]];
END;
WriteTie: PROC[score: ScorePTR, note: NotePTR, format: POINTER TO TieFormat] =
BEGIN
format.height ← note.tieHeight;
format.heap ← Event.GetScoreIndex[score, note.tie.sync];
format.index ← Note.GetSyncIndex[note.tie.sync, note.tie];
[] ← PutBlock[stream, @format, SIZE[TieFormat]];
END;
WriteSheet: PROCEDURE[staves: StavesPTR, sheet: POINTER TO SheetFormat] =
BEGIN
sheet.height ← staves.height;
sheet.offset ← staves.offset;
sheet.sl ← staves.length+1;
FOR i: CARDINAL IN [0..staves.length) DO
sheet.staff[i] ← staves.staff[i];
ENDLOOP;
[] ← PutBlock[stream, @sheet, SIZE[SheetFormat]];
END;
WriteChord: PROCEDURE[chord: ChordPTR, format: POINTER TO ChordFormat] =
BEGIN
format.stemUp ← chord.stemUp;
format.length ← chord.length;
[] ← PutBlock[stream, @format, SIZE[ChordFormat]];
END;
WriteBeam: PROCEDURE[beam: BeamPTR, format: POINTER TO BeamFormat] =
BEGIN
format.tilt ← beam.tilt;
format.beamed ← beam.beamed;
format.ntuple ← beam.ntuple;
format.against ← beam.against;
format.height ← beam.height;
format.invisible ← beam.invisible;
format.staff ← beam.staff;
format.length ← beam.length;
[] ← PutBlock[stream, @format, SIZE[BeamFormat]];
END;
WriteView: PROCEDURE[score: ScorePTR, view: POINTER TO ViewFormat] =
BEGIN
IF score.sheet.display = physical
THEN view.scale ← score.sheet.density
ELSE view.scale ← score.sheet.justification;
view.accidental ← score.sheet.accidental;
view.notehead ← score.sheet.notehead;
view.sync ← score.sheet.sync;
view.display ← score.sheet.display;
view.noCarry ← score.sheet.noCarry;
view.hardcopy ← score.sheet.hardcopy;
[] ← PutBlock[stream, @view, SIZE[ViewFormat]];
END;
END...
PutReals: PROCEDURE =
BEGIN
i: CARDINAL;
FOR i IN [0..score.beamHeap.length) DO
IF beamHeap[i] = NIL THEN LOOP;
beamHeap[i].tilt ← RealConvert.Mesa5ToIeee[beamHeap[i].tilt];
ENDLOOP;
END;
-- ****************************************************************************
-- filein, fileout pianorolls
-- ****************************************************************************
FileInOld: PUBLIC PROCEDURE[s: STRING] =
BEGIN
OPEN DataDefs;
i, length: CARDINAL ← 0;
pn: PhysicalNote;
note: NotePTR;
sync: EventPTR ← NIL;
oldToc: Time;
inputStream: DiskHandle;
inputStream ← NewWordStream[s, Read];
inputStream.reset[inputStream];
length ← inputStream.get[inputStream];
[] ← inputStream.get[inputStream];
NewScore[];
WHILE NOT inputStream.endof[inputStream] DO
[] ← ReadBlock[@pn, SIZE[PhysicalNote]];
IF pn.duration < 4 THEN LOOP;
IF pn.pitch > 80 OR pn.pitch < -7 THEN LOOP;
note ← NewNote[];
note↑ ← []; -- defaults to the values listed in musicDefs
note.toc ← pn.toc;
note.duration ← pn.duration;
note.pitch ← pn.pitch;
SELECT TRUE FROM
note.pitch IN [67..80] => BEGIN note.stemUp ← FALSE; note.staff ← 0; END;
note.pitch IN [56..66] => BEGIN note.stemUp ← TRUE; note.staff ← 0; END;
note.pitch IN [43..55] => BEGIN note.stemUp ← FALSE; note.staff ← 1; END;
note.pitch IN [32..42] => BEGIN note.stemUp ← TRUE; note.staff ← 1; END;
note.pitch IN [22..31] => BEGIN note.stemUp ← FALSE; note.staff ← 2; END;
note.pitch IN [10..21] => BEGIN note.stemUp ← TRUE; note.staff ← 2; END;
note.pitch IN [ 0.. 9] => BEGIN note.stemUp ← FALSE; note.staff ← 3; END;
note.pitch IN [-7..-1] => BEGIN note.stemUp ← TRUE; note.staff ← 3; END;
ENDCASE;
IF ABS[note.toc - oldToc] > 200
THEN BEGIN
AddEventToPiece[sync, score];
oldToc ← note.toc;
sync ← NewEvent[];
END;
sync.time ← note.toc/256;
AddToEvent[sync, note];
i ← i + 1;
IF i = length THEN EXIT;
ENDLOOP;
AddEventToPiece[sync, score];
inputStream.destroy[inputStream];
ActionDefs.Look[accidental, FALSE, ];
ActionDefs.Look[sheet, , 1];
ActionDefs.Look[notehead, FALSE, ];
selectionLength ← 0;
SortScore[];
UtilityDefs.DrawScore[TRUE];
END;
FileOutOld: PUBLIC PROCEDURE[s: STRING] =
BEGIN
OPEN StreamDefs;
i, j: CARDINAL;
pNote: PhysicalNote;
n: NotePTR;
inputStream: DiskHandle;
inputStream ← NewWordStream[s, Write+Append];
inputStream.reset[inputStream];
inputStream.put[0];
inputStream.put[0];
FOR i IN [0..score.length) DO
FOR j IN [0..syncLength) DO
IF (n ← score[i][j]) = NIL THEN EXIT;
IF score[i][j].rest THEN LOOP;
IF n.duration = 0 THEN LOOP;
pNote ← [n.pitch, n.duration, 50, n.toc];
[] ← WriteBlock[@pNote, SIZE[PhysicalNote]];
ENDLOOP;
ENDLOOP;
inputStream.destroy[inputStream];
UtilityDefs.DrawScore[TRUE];
END;
END....
-- ************************************************************************
-- filein, fileout old .logical format
-- ************************************************************************
FileInOld: PUBLIC PROCEDURE[s: STRING] =
BEGIN
OPEN StreamDefs;
i, j, noChords, noBeams: CARDINAL;
rchord: RChord;
rbeam: RBeam;
convert: BOOLEAN ← FALSE;
inputStream: DiskHandle;
inputStream ← NewWordStream[s, Read];
inputStream.reset[inputStream];
IF append THEN InitAppend[] ELSE NewScore[];
score.length ← inputStream.get[inputStream]+start;
maxVoice ← 0;
FOR i IN [start..score.length) DO score[i] ← NewEvent[]; ENDLOOP;
FOR i IN [start..score.length) DO
[] ← ReadBlock[inputStream, score[i], SIZE[Event]];
score[i].time ← score[i].time + offset;
FOR j IN [0..syncLength) DO
IF score[i][j] = NIL THEN EXIT;
[] ← ReadBlock[inputStream, score[i][j] ← NewNote[], SIZE[Note]];
score[i][j].sync ← score[i];
IF skipBeams THEN score[i][j].beam ← NIL;
maxVoice ← MAX[maxVoice, score[i][j].voice];
ENDLOOP;
ENDLOOP;
noChords ← inputStream.get[inputStream];
FOR i IN [0..noChords) DO
[] ← ReadBlock[inputStream, @rchord, SIZE[RChord]];
RestoreChord[@rchord, NewChord[]];
ENDLOOP;
noBeams ← inputStream.get[inputStream];
FOR i IN [0..noBeams) DO
[] ← ReadBlock[inputStream, @rbeam, SIZE[RBeam]];
IF skipBeams THEN LOOP;
RestoreBeam[@rbeam, NewBeam[]];
IF rbeam.beam.tilt > 3 OR rbeam.beam.tilt < -3 THEN convert ← TRUE;
ENDLOOP;
IF NOT inputStream.endof[inputStream] THEN FileInSheet[inputStream];
inputStream.destroy[inputStream];
IF convert THEN Convert[];
UtilityDefs.ResetSheet[];
-- UtilityDefs.DrawScore[TRUE];
END;
FileInSheet: PROCEDURE[stream: StreamDefs.DiskHandle] =
BEGIN
OPEN StreamDefs;
[] ← ReadBlock[stream, @keyArray, 2*keyLength];
[] ← ReadBlock[stream, @show, SIZE[DocumentProfile]];
[] ← ReadBlock[stream, @metrenome, SIZE[INTEGER]];
[] ← ReadBlock[stream, @TF, SIZE[CARDINAL]];
[] ← ReadBlock[stream, @sheet, SIZE[Staves]];
sheet.staff[4] ← [0, 0]; sheet.staff[5] ← [0, 0];
KeyIndexToEvent[];
END;
KeyIndexToEvent: PROCEDURE =
BEGIN
k: CARDINAL;
FOR k IN [0..keyLength) DO
keyArray[k].sync ← score[LOOPHOLE[keyArray[k].sync, CARDINAL]];
ENDLOOP;
END;
skipBeams: BOOLEAN ← FALSE;
bstart, cstart: CARDINAL ← 0;
offset: Time ← 0;
append: BOOLEAN ← FALSE;
InitAppend: PROCEDURE =
BEGIN
start ← score.length;
bstart ← score.beamHeap.length;
cstart ← score.chordHeap.length;
IF score.length # 0 THEN offset ← score[score.length-1].time+10;
END;
RestoreChord: PROCEDURE[r: POINTER TO RChord, chord: ChordPTR] =
BEGIN
i: CARDINAL;
chord↑ ← [r.stem, 0, ALL[NIL]];
FOR i IN [0..chordLength) DO
IF r.n[i] = 100 THEN EXIT;
chord.note[i] ← score[r.s+start][r.n[i]];
ENDLOOP;
END;
RestoreBeam: PROCEDURE[r: POINTER TO RBeam, beam: BeamPTR] =
BEGIN
i, j: CARDINAL;
beam↑ ← r.beam;
beam.sync1 ← score[LOOPHOLE[beam.sync1, CARDINAL]+start];
beam.sync2 ← score[LOOPHOLE[beam.sync2, CARDINAL]+start];
FOR i IN [0..beamLength) DO
IF r.n[i].type = null THEN EXIT;
SELECT r.n[i].type FROM
note => beam.chord[i] ←
[note[score[r.n[i].sync+start][r.n[i].index]]];
chord => beam.chord[i] ← [chord[chordHeap[r.n[i].index+cstart]]];
beam => beam.chord[i] ← [beam[beamHeap[r.n[i].index+bstart]]];
null => beam.chord[i] ← endOfBeam;
ENDCASE => NULL; -- later ERROR
ENDLOOP;
FOR i IN [0..beamLength) DO
WITH ev: beam.chord[i] SELECT FROM
note => IF ev.n # NIL THEN ev.n.beam ← beam;
chord => FOR j IN [0..chordLength) DO
IF ev.c.note[j] # NIL THEN ev.c.note[j].beam ← beam;
ENDLOOP;
beam => SetBeamPTRToBeam[ev.b, beam];
ENDCASE;
ENDLOOP;
END;
RChord: TYPE = RECORD[s: CARDINAL, stem: BOOLEAN,
n: ARRAY [0..chordLength) OF CARDINAL];
RBeam: TYPE = RECORD[beam: BeamedSet, n: ARRAY [0..beamLength) OF VPointer];
VPointer: TYPE = RECORD[type: {note, chord, beam, null}, sync: CARDINAL, index: CARDINAL];
FileOutOld: PUBLIC PROCEDURE[s: STRING] =
BEGIN
OPEN StreamDefs;
i, j: CARDINAL;
rchord: RChord;
rbeam: RBeam;
inputStream: DiskHandle;
IF UtilityDefs.Test[] THEN ERROR; -- PLEASE save MESA.TYPESCRIPT for me to examine!
-- to try to recover, SEt Root & SEt Module to utility,
-- Interpret Procedure: cleanUp,
-- SEt Root & Module to MusicData,
-- Interpret Procedure: fo (for "FileOut"),
-- save the mesa.typescript somewhere(like ivy) and then
-- reinvoke mockingbird and filein temp.logical.
-- If this doesn't work, I may still be able to recover
-- part of the format if you save temp.logical somewhere.
inputStream ← NewWordStream[s, Write+Append];
inputStream.reset[inputStream];
inputStream.put[inputStream, score.length];
FOR i IN [0..score.length) DO
[] ← WriteBlock[inputStream, score[i], SIZE[Event]];
FOR j IN [0..syncLength) DO
IF score[i][j] = NIL THEN EXIT;
[] ← WriteBlock[inputStream, score[i][j], SIZE[Note]];
ENDLOOP;
ENDLOOP;
inputStream.put[inputStream, score.chordHeap.length];
FOR i IN [0..score.chordHeap.length) DO
rchord ← RelativeChord[chordHeap[i]];
[] ← WriteBlock[inputStream, @rchord, SIZE[RChord]];
ENDLOOP;
inputStream.put[inputStream, score.beamHeap.length];
FOR i IN [0..score.beamHeap.length) DO
rbeam ← RelativeBeam[beamHeap[i]];
[] ← WriteBlock[inputStream, @rbeam, SIZE[RBeam]];
ENDLOOP;
FileOutSheet[inputStream];
inputStream.destroy[inputStream];
command ← TRUE;
UtilityDefs.DrawScore[TRUE];
END;
FileOutSheet: PROCEDURE[stream: StreamDefs.DiskHandle] =
BEGIN
OPEN StreamDefs;
KeyEventToIndex[];
[] ← WriteBlock[stream, @keyArray, 2*keyLength];
[] ← WriteBlock[stream, @show, SIZE[DocumentProfile]];
[] ← WriteBlock[stream, @metrenome, SIZE[INTEGER]];
[] ← WriteBlock[stream, @TF, SIZE[CARDINAL]];
[] ← WriteBlock[stream, @sheet, SIZE[Staves]];
KeyIndexToEvent[];
END;
KeyEventToIndex: PROCEDURE =
BEGIN
i, k: CARDINAL;
syncFound: BOOLEAN;
FOR k IN [0..keyLength) DO
syncFound ← FALSE;
FOR i IN [0..score.length] DO
IF score[i] # keyArray[k].sync THEN LOOP;
syncFound ← TRUE;
keyArray[k].sync ← LOOPHOLE[i];
EXIT;
ENDLOOP;
IF NOT syncFound THEN ERROR;
ENDLOOP;
END;
RelativeChord: PROCEDURE[c: ChordPTR] RETURNS[RChord] =
BEGIN
i, j: CARDINAL;
r: RChord ← [0, c.stemUp, ALL[100]];
FOR i IN [0..score.length) DO
IF score[i] = c.note[0].sync THEN BEGIN r.s ← i; EXIT; END;
ENDLOOP;
FOR i IN [0..chordLength) DO
IF c.note[i] = NIL THEN EXIT;
FOR j IN [0..syncLength) DO
IF score[r.s][j] # c.note[i] THEN LOOP;
r.n[i] ← j; EXIT;
ENDLOOP;
ENDLOOP;
RETURN[r];
END;
RelativeBeam: PROCEDURE[b: BeamPTR] RETURNS[RBeam] =
BEGIN
i, j: CARDINAL;
r: RBeam;
r.beam ← b↑;
r.n ← ALL[[null, 0, 0]];
FOR i IN [0..score.length) DO
IF r.beam.sync1 = score[i] THEN r.beam.sync1 ← LOOPHOLE[i];
IF r.beam.sync2 = score[i] THEN r.beam.sync2 ← LOOPHOLE[i];
ENDLOOP;
IF LOOPHOLE[r.beam.sync1, CARDINAL] > score.length THEN ERROR;
IF LOOPHOLE[r.beam.sync2, CARDINAL] > score.length THEN ERROR;
FOR i IN [0..beamLength) DO
IF b.chord[i] = endOfBeam THEN EXIT;
WITH ev: b.chord[i] SELECT FROM
chord => BEGIN
r.n[i].type ← chord;
FOR j IN [0..score.chordHeap.length) DO
IF chordHeap[j] = ev.c THEN r.n[i].index ← j;
ENDLOOP;
END;
beam => BEGIN
r.n[i].type ← beam;
FOR j IN [0..score.beamHeap.length) DO
IF beamHeap[j] = ev.b THEN r.n[i].index ← j;
ENDLOOP;
END;
note => BEGIN
r.n[i].type ← note;
FOR j IN [0..score.length) DO
IF score[j] = ev.n.sync THEN r.n[i].sync ← j;
ENDLOOP;
FOR j IN [0..syncLength) DO
IF score[r.n[i].sync][j] = ev.n
THEN r.n[i].index ← j;
ENDLOOP;
END;
ENDCASE;
ENDLOOP;
RETURN[r];
END;
ConvertSheet2: PROCEDURE[old: EventPTR] =
BEGIN
staves: StavesPTR ← LOOPHOLE[@old.event];
IF old.value = -1 THEN {old.type ← staves; RETURN};
IF staves.staff[old.value].pitch = 15 THEN {
old.type ← octava1;
staves.height ← -30;
RETURN};
IF staves.staff[old.value].pitch = 60 THEN {
old.type ← octava1;
staves.height ← 60;
RETURN};
FOR i: CARDINAL DECREASING IN [0..score.length) DO
-- is the present clef change the latter part of an octava pair?
IF score[i].type NOT IN SheetSwitch THEN LOOP;
staves ← LOOPHOLE[@score[i].event];
SELECT staves.staff[old.value].pitch FROM
15 => old.type ← octava2;
60 => old.type ← octava2;
ENDCASE => old.type ← clef;
RETURN; ENDLOOP;
END;
FO: PROCEDURE RETURNS[STRING] =
BEGIN
RETURN[IF FileOut["temp.music"]
THEN "filed out on temp.music"
ELSE "fileout aborted"];
END;