DIRECTORY Beam USING [AddItem, SetSyncs], Event USING [SetStave], FS USING [GetName, OpenFileFromStream, StreamOpen], IO USING [Close, EndOfStream, STREAM, UnsafeGetBlock, UnsafePutBlock], MusicDefs USING [BeamHeapPTR, BeamHeapRec, BeamPTR, BeamRec, ChordHeapPTR, ChordHeapRec, ChordPTR, ChordRec, EventPTR, EventRec, KeySignaturePTR, MeasurePTR, MetronomePTR, NotePTR, NoteRec, ScorePTR, StavesPTR, SyncPTR, Time, TimeSignaturePTR, VariousPTR], MusicFileDefs USING [BeamFormat, beams, ChordFormat, chords, EventFormat, ID, NoteFormat, RelativePTR, SheetFormat, StaffFormat, TieFormat, ViewFormat], Piece USING [New], Rope USING [ROPE], Score USING [FileStats, Look, SetKey, SetMetronome], Sheet USING [Reset, SetBegin]; FilerImpl: CEDAR PROGRAM IMPORTS Beam, Event, FS, IO, Piece, Score, Sheet EXPORTS Score = BEGIN OPEN MusicDefs, MusicFileDefs; STREAM: TYPE ~ IO.STREAM; ROPE: TYPE ~ Rope.ROPE; Error: ERROR ~ CODE; Get: PROC[stream: STREAM] RETURNS[data: INTEGER] = TRUSTED { IF stream.UnsafeGetBlock[[base: LOOPHOLE[LONG[@data]], count: 2]]<2 THEN ERROR IO.EndOfStream[stream] ELSE RETURN[data] }; GetBlock: UNSAFE PROC[stream: STREAM, p: LONG POINTER, length: CARDINAL] = UNCHECKED { count: INT ~ length*2; -- bytes IF stream.UnsafeGetBlock[[base: LOOPHOLE[p], count: count]] IF staves.staves=style THEN { -- sort the score IF dontSort THEN ERROR; FOR j: NAT DECREASING IN[0..i) DO score[j+1] _ score[j]; ENDLOOP; score[0] _ staves; staves.time _ 0; }; ENDCASE; ENDLOOP; }; IF GetID[stream]#chordHeapID THEN ERROR Error ELSE { -- read the chord heap length: NAT ~ Get[stream]; -- number of chords in file chordHeap: ChordHeapPTR ~ NEW[ChordHeapRec[length+100] _ [chord: ]]; chordHeap.length _ length; FOR i: NAT IN[0..chordHeap.length) DO chordHeap[i] _ ReadChord[stream, score]; ENDLOOP; score.chordHeap _ chordHeap; }; IF GetID[stream]#beamHeapID THEN ERROR Error ELSE { -- read the beam heap length: NAT ~ Get[stream]; -- number of beams in file beamHeap: BeamHeapPTR ~ NEW[BeamHeapRec[length+100] _ [beam: ]]; beamHeap.length _ length; FOR i: NAT IN[0..beamHeap.length) DO beamHeap[i] _ NEW[BeamRec[12] _ [chord: ]]; ENDLOOP; score.beamHeap _ beamHeap; FOR i: NAT IN[0..beamHeap.length) DO ReadBeam[stream, score, score.beamHeap[i]]; ENDLOOP; FOR i: NAT IN[0..beamHeap.length) DO Beam.SetSyncs[score.beamHeap[i]]; ENDLOOP; }; THROUGH [0..9) DO -- nine spares IF GetID[stream]#nullID THEN ERROR Error; ENDLOOP; ReadView[stream, score, version]; -- read view stream.Close[]; score.command _ TRUE; Score.FileStats[score]; Sheet.SetBegin[score.sheet, 0]; }; ReadEvent: PROC[stream: STREAM, score: ScorePTR] RETURNS[event: EventPTR] = { format: EventFormat; TRUSTED{GetBlock[stream, @format, SIZE[EventFormat]]}; IF format.identifier#eventID THEN ERROR Error; SELECT format.type FROM notes => { sync: SyncPTR ~ NEW[EventRec[sync][MAX[format.length, 10]] _ [ time: format.time, variant: sync[length: format.length, note: ]]]; FOR j: NAT IN[0..format.length) DO note: NotePTR ~ ReadNote[stream, score]; sync.note[j] _ note; note.sync _ sync; ENDLOOP; RETURN[sync]; }; keySignature => { event: KeySignaturePTR ~ NEW[EventRec[keySignature] _ [ time: format.time, variant: keySignature[key: format.value]]]; RETURN[event]; }; timeSignature => { event: TimeSignaturePTR ~ NEW[EventRec[timeSignature] _ [ time: format.time, variant: timeSignature[ts: LOOPHOLE[format.value]]]]; RETURN[event]; }; metronome => { event: MetronomePTR ~ NEW[EventRec[metronome] _ [ time: format.time, variant: metronome[metronome: format.value]]]; RETURN[event]; }; IN[measure..timeSignature) => { event: MeasurePTR ~ NEW[EventRec[measure] _ [ time: format.time, variant: measure[]]]; event.measure _ SELECT format.type FROM measure => $measure, repeat1 => $repeat1, repeat2 => $repeat2, endMeasure => $endMeasure, doubleMeasure => $doubleMeasure, m5 => $m5, ENDCASE => ERROR; RETURN[event]; }; IN[staves..spare5) => { staves: StavesPTR ~ NEW[EventRec[staves] _ [ time: format.time, variant: staves[]]]; staves.staves _ SELECT format.type FROM staves => $style, clef => $clef, octava1 => $octava1, octava2 => $octava2, ENDCASE => ERROR; ReadSheet[stream, staves]; IF format.value=-1 THEN FindStyle[score, staves] ELSE staves.value _ format.value; RETURN[staves]; }; ENDCASE => ERROR; }; ReadNote: PROC[stream: STREAM, score: ScorePTR] RETURNS[note: NotePTR] = { format: NoteFormat; TRUSTED{GetBlock[stream, @format, SIZE[NoteFormat]]}; IF format.identifier#noteID THEN ERROR Error; note _ 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; IF format.tie THEN ReadTie[stream, score, note]; score.maxVoice _ MAX[note.voice, score.maxVoice]; }; ReadTie: PROC[stream: STREAM, score: ScorePTR, note: NotePTR] = { format: TieFormat; TRUSTED{GetBlock[stream, @format, SIZE[TieFormat]]}; IF format.identifier#tieID THEN ERROR Error; WITH score[format.heap] SELECT FROM sync: SyncPTR => note.tie _ sync.note[format.index]; ENDCASE => ERROR; note.tieHeight _ format.height; note.tie.tied _ TRUE; }; ReadSheet: PROC[stream: STREAM, staves: StavesPTR] = { format: SheetFormat; TRUSTED{GetBlock[stream, @format, SIZE[SheetFormat]]}; staves.height _ format.height; staves.offset _ format.offset; staves.length _ format.sl+1; FOR i: NAT IN[0..staves.length) DO staff: StaffFormat ~ format.staff[i]; staves.staff[i] _ [pitch: staff.pitch, y: staff.y]; ENDLOOP; }; FindStyle: PROC[score: ScorePTR, staves: StavesPTR] = { index: INTEGER _ 1; FOR i: NAT IN[1..staves.length) DO IF staves.staff[i].y#staves.staff[i-1].y THEN 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]]; }; ReadChord: PROC[stream: STREAM, score: ScorePTR] RETURNS[chord: ChordPTR] = { format: ChordFormat; TRUSTED{GetBlock[stream, @format, SIZE[ChordFormat]]}; IF format.identifier#chordID THEN ERROR Error; chord _ NEW[ChordRec[format.length+2] _ [note: ]]; chord.stemUp _ format.stemUp; chord.length _ format.length; FOR j: NAT IN[0..chord.length) DO pointer: RelativePTR; TRUSTED{GetBlock[stream, @pointer, SIZE[RelativePTR]]}; WITH score[pointer.heap] SELECT FROM sync: SyncPTR => { note: NotePTR ~ sync.note[pointer.index]; chord.note[j] _ note; note.chord _ chord; }; ENDCASE => ERROR; ENDLOOP; }; ReadBeam: PROC[stream: STREAM, score: ScorePTR, beam: BeamPTR] = { format: BeamFormat; TRUSTED{GetBlock[stream, @format, SIZE[BeamFormat]]}; IF format.identifier#beamID THEN ERROR 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; FOR i: NAT IN[0..format.length) DO vp: VariousPTR ~ ReadBeamEntry[stream, score, beam]; Beam.AddItem[score, beam, vp]; ENDLOOP; }; ReadBeamEntry: PROC[stream: STREAM, score: ScorePTR, beam: BeamPTR] RETURNS[vp: VariousPTR] = { pointer: RelativePTR; TRUSTED{GetBlock[stream, @pointer, SIZE[RelativePTR]]}; SELECT pointer.heap FROM beams => RETURN[score.beamHeap[pointer.index]]; chords => RETURN[score.chordHeap[pointer.index]]; ENDCASE; WITH score[pointer.heap] SELECT FROM sync: SyncPTR => RETURN[sync.note[pointer.index]]; ENDCASE => ERROR; }; SkipBeam: PROC[stream: STREAM] = { format: BeamFormat; TRUSTED{GetBlock[stream, @format, SIZE[BeamFormat]]}; IF format.identifier#beamID THEN ERROR Error; FOR i: NAT IN[0..format.length) DO SkipBeamEntry[stream] ENDLOOP; }; SkipBeamEntry: PROC[stream: STREAM] = { pointer: RelativePTR; TRUSTED{GetBlock[stream, @pointer, SIZE[RelativePTR]]}; }; ReadView: PROC[stream: STREAM, score: ScorePTR, version: INTEGER] = { view: ViewFormat; TRUSTED{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.SetMetronome[score, 0, LAST[Time], view.speed]; Sheet.Reset[score]; }; SkipView: PROC[stream: STREAM] = { view: ViewFormat; TRUSTED{GetBlock[stream, @view, SIZE[ViewFormat]]}; }; END. FileOut: PUBLIC PROC[score: ScorePTR, fileName: STRING] RETURNS[BOOLEAN] = { 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-- ]; 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; 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; 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 => { pointer.heap _ Event.GetScoreIndex[score, ev.n.sync]; pointer.index _ Note.GetSyncIndex[Event.Sync[score[pointer.heap]], ev.n]; }; chord => { pointer.heap _ chords; pointer.index _ Chord.GetHeapIndex[score.chordHeap, ev.c]; }; beam => { pointer.heap _ beams; pointer.index _ Beam.GetHeapIndex[score.beamHeap, ev.b]; }; ENDCASE; [] _ PutBlock[stream, @pointer, SIZE[RelativePTR]]; ENDLOOP; ENDLOOP; 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]; WriteView[score, @view]; [] _ PutBlock[stream, NIL, 0]; -- clean up buffer Stream.Delete[stream]; score.command _ TRUE; RETURN[TRUE]; }; WriteEvent: PROC[data: EventPTR, format: POINTER TO EventFormat] = { Add: PROC[a, b: UNSPECIFIED] RETURNS[UNSPECIFIED] = INLINE { RETURN[LOOPHOLE[a, CARDINAL] + LOOPHOLE[b, CARDINAL]]; }; 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; metronome => format.value _ Event.Metronome[data].metronome; staves => { format.type _ Add[format.type, Event.Staves[data].staves]; format.ignore _ TRUE}; ENDCASE => ERROR; [] _ PutBlock[stream, @format, SIZE[EventFormat]]; }; WriteNote: PROC[note: NotePTR, format: POINTER TO NoteFormat] = { 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]]; }; WriteTie: PROC[score: ScorePTR, note: NotePTR, format: POINTER TO TieFormat] = { 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]]; }; WriteSheet: PROC[staves: StavesPTR, sheet: POINTER TO SheetFormat] = { 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]]; }; WriteChord: PROC[chord: ChordPTR, format: POINTER TO ChordFormat] = { format.stemUp _ chord.stemUp; format.length _ chord.length; [] _ PutBlock[stream, @format, SIZE[ChordFormat]]; }; WriteBeam: PROC[beam: BeamPTR, format: POINTER TO BeamFormat] = { 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]]; }; WriteView: PROC[score: ScorePTR, view: POINTER TO ViewFormat] = { 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]]; }; ^FilerImpl.mesa Copyright (C) 1983, 1984 Xerox Corporation. All rights reserved. Author: John Maxwell Last Edited by: Maxwell, November 22, 1983 10:13 am Last Edited by: Doug Wyatt, June 15, 1984 2:14:10 pm PDT **************************************************************************** word-size stream operations **************************************************************************** **************************************************************************** filein **************************************************************************** **************************************************************************** fileout **************************************************************************** stream.reset[stream]; format out score format out chordheap format out beamheap format out nine spares format out view clean up and return Ê0˜™J™@Jšœ™Jšœ3™3Jšœ8™8J™—šÏk ˜ Jšœœ˜ Jšœœ ˜Jšœœ,˜4Jšœœœ#˜GJšœ œò˜Jšœœ7œL˜˜Jšœœ˜Jšœœœ˜Jšœœ*˜5Jšœœ˜J˜—Jšœ œ˜Jšœœœ˜0Jšœ˜ Jšœœœ˜&J˜Jšœœœœ˜Jšœœœ˜J˜Jšœœœ˜J˜JšœL™LJ™JšœL™LJ˜š Ïnœœ œœœœ˜<šœœœ˜HJšœœ˜—Jšœœ˜J˜—J˜šžœœœ œœœ œ œ˜VJšœœ Ïc˜šœœ˜FJšœœ˜—Jšœ˜—J˜š žœœ œœœ˜4Jšœœœ˜?Jšœ˜—J˜šžœœ œœœ œœ˜MJšœœ˜JšœB˜B—šœœœ˜"J˜(J˜&Jšœ˜—Jšœ˜ J˜—šœ˜šœœ˜7Jšœ>˜>—Jšœ˜J˜—šœ˜šœœ˜9Jšœ.œ˜H—Jšœ˜J˜—šœ˜šœœ˜1JšœA˜A—Jšœ˜J˜—šœ˜šœœ˜-Jšœ(˜(—šœœ ˜'Jšœ>˜>Jšœ;˜;Jšœ œœ˜—Jšœ˜Jšœ˜—šœ˜šœœ˜,Jšœ'˜'—šœœ ˜'Jšœ5˜5Jšœœœ˜&—J˜Jšœœ˜0Jšœ˜!Jšœ ˜J˜—Jšœœ˜—Jšœ˜J™—šžœœ œœ˜JJ˜Jšœœ˜5Jšœœœ˜-Jšœœ˜J˜J˜J˜J˜J˜J˜J˜(J˜J˜J˜"J˜J˜J˜ Jšœ œ˜0Jšœœ˜1Jšœ˜J˜—šžœœ œ%˜AJšœ˜Jšœœ˜4Jšœœœ˜,šœœ˜#J˜4Jšœœ˜—J˜Jšœœ˜Jšœ˜J˜—šž œœ œ˜6Jšœ˜Jšœœ˜6J˜J˜J˜šœœœ˜"J˜%J˜3Jšœ˜—Jšœ˜J˜—šž œœ(˜7Jšœœ˜šœœœ˜"Jšœ'œ˜>Jšœ˜—Jšœ œœ ˜7J˜J˜2Jšœ˜J˜—šž œœ œœ˜MJ˜Jšœœ˜6Jšœœœ˜.Jšœœ'˜2J˜J˜šœœœ˜!J˜Jšœœ˜7šœœ˜$˜J˜)J˜)J˜—Jšœœ˜—Jšœ˜—Jšœ˜J˜—šžœœ œ%˜BJšœ˜Jšœœ˜5Jšœœœ˜-J˜J˜J˜J˜J˜J˜"J˜šœœœ˜"Jšœ4˜4Jšœ˜Jšœ˜—Jšœ˜J˜—šž œœ œ!˜CJšœ˜J˜Jšœœ˜7šœ˜Jšœ œ ˜/Jšœ œ!˜1Jšœ˜—šœœ˜$Jšœœ˜2Jšœœ˜—Jšœ˜J˜—šžœœ œ˜"Jšœ˜Jšœœ˜5Jšœœœ˜-Jš œœœœœ˜AJšœ˜J˜—šž œœ œ˜'J˜Jšœœ˜7Jšœ˜J˜—šžœœ œœ˜EJšœ˜Jšœœ˜3šœ˜Jšœ!˜%Jšœ(˜,—šœ œŸ'˜>J˜%J˜&J˜%J˜&J˜%Jšœ˜—J˜)J˜J˜%J˜#J˜#J˜-Jšœ œœ˜AJšœ œœ˜IJšœ˜Jšœ˜J˜—šžœœ œ˜"Jšœ˜Jšœœ˜3Jšœ˜J˜—Jšœ˜J˜JšœL™LJšœ™JšœL™LJ˜šžœœœœ˜8Jšœœ˜Jšœ ˜JšœŸ˜1J˜J˜J˜J˜Jšœœœœ˜)Jšœ6Ÿœ˜XJšœ™Jšœ™J˜J˜J˜šœœœ˜'J˜J˜J˜J˜Jšœœ,˜JJšœœœ˜"J˜šœœœ˜&J˜Jšœœœ ˜9Jšœ˜—Jšœ˜—Jšœ™J˜J˜$šœœœ˜1J˜J˜'J˜Pšœœœ ˜4J˜+J˜3Jšœ œ˜3Jšœ˜—Jšœ˜—Jšœ™J˜J˜#šœœœ˜0J˜$Jšœœ˜/šœœœ˜3J˜šœ œ˜/šœ ˜ J˜5J˜IJšœ˜—šœ ˜ J˜J˜:Jšœ˜—šœ ˜ J˜J˜8Jšœ˜—Jšœ˜—Jšœ œ˜3Jšœ˜—Jšœ˜—Jšœ™J˜J˜J˜J˜J˜J˜J˜J˜J˜Jšœ™J˜Jšœ™JšœœŸ˜1J˜Jšœœ˜Jšœœ˜ Jšœ˜J˜—šž œœœœ˜Dš žœœ œœ œ˜:Jš œœœœœœ˜;—J˜Jšœœ ˜"Jšœœ˜J˜J˜šœ ˜J˜GJ˜0Jšœ œ˜G˜