-- 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;