<> <> <> <> <> DIRECTORY BcplFontFileDefs USING [OpenSDFontFile, CloseSDFontFile, SplineCommandPtr, SplineDataPtr, GetSplineCommands], Beam USING [AddBeam, AddChord, AddNote, GetHeapIndex, Remove], Chord USING [GetHeapIndex, RemoveNote], Cubic USING [Bezier, BezierToCoeffs, Coeffs], Device USING [Free, Handle, Object], Graphics USING [DisplayContext, DisplayChar, DisplayString, DrawArea, DrawTo, EnterCubic, EnterPoint, FontId, FreeContext, GetPosition, Map, MoveTo, NewBoundary, NewContext, RelMoveTo, Scale, SetFont, SetLineWidth, SetColor, StartAreaPath, Texture, Translate, UserToScreen, Vec], IODefs USING [WriteLine, WriteNumber, WriteString], Memory USING [NewZone], MusicDefs, Note USING [GetBackTie], OpaqueDevice, Piece USING [Length, RemoveSync], PressDefs USING [PressFileDescriptor, PutText, SetFont], PressDevice USING [NewPressDevice], PressDeviceImpl USING [DataRef], Real USING [FixC], Score USING [], Sync USING [GetScoreIndex, Octava, RemoveNote], SystemDefs USING [AllocateHeapNode, AllocateSegment, FreeHeapNode, FreeSegment], StringDefs USING [AppendLongNumber], Utility USING [FreeBeam, FreeChord, FreeSync, SetFont]; UtilityImpl: CEDAR PROGRAM IMPORTS BcplFontFileDefs, Beam, Chord, Cubic, Device, Graphics, IODefs, Memory, MusicDefs, Note, Piece, PressDefs, PressDevice, PressDeviceImpl, Real, StringDefs, Sync, SystemDefs, Utility EXPORTS MusicDefs, OpaqueDevice, Score, Utility SHARES PressDeviceImpl = BEGIN OPEN Graphics, MusicDefs; <<****************************************************************************>> <> <<****************************************************************************>> context: PUBLIC DisplayContext; text, music: PUBLIC FontId; light: PUBLIC Graphics.Texture _ 102041B; DrawLine: PUBLIC PROC[x1, y1, x2, y2: INTEGER] = { MoveTo[context,[x1, y1]]; DrawTo[context,[x2, y2]]; }; DrawCubic: PUBLIC PROC[x1, y1, x2, y2, height: INTEGER] = { c: Cubic.Coeffs; b1, b2: Cubic.Bezier; StartAreaPath[context]; EnterPoint[context,[x1, y1]]; b1 _ [[x1, y1],[(4*x1+x2)/5, height+y1],[(x1+4*x2)/5, height+y1],[x2, y2]]; c _ Cubic.BezierToCoeffs[b1]; EnterCubic[context,@c]; EnterPoint[context,[x2, y2-width1]]; b2 _ [[x2, y2-width1],[(x1+4*x2)/5, height-width2+y1], [(4*x1+x2)/5, height-width2+y1],[x1, y1-width1]]; c _ Cubic.BezierToCoeffs[b2]; EnterCubic[context,@c]; DrawArea[context]; }; width1: INTEGER _ 0; width2: INTEGER _ 3; SetFont: PUBLIC PROC[dc: DisplayContext, font: FontId, size: INTEGER]= { OPEN PressDeviceImpl; l: REAL _ 1; Graphics.SetFont[dc, font, size]; IF NOT print THEN {Graphics.SetFont[dc, font, size]; RETURN}; IF printChar THEN { fontname: STRING _ [16]; ph: POINTER TO PressDefs.PressFileDescriptor; ptsize, face, rotation: CARDINAL _ 0; ph _ LOOPHOLE[device.data, PressDeviceImpl.DataRef].pressHandle; IF font=music THEN fontname _ "MOCKINGBIRD" ELSE fontname _ "TIMESROMAN"; ptsize _ IF font=music THEN LOOPHOLE[-24] ELSE 8; face _ 0; --PressDefs.EncodeFace['n,'n,'n] PressDefs.SetFont[ph, fontname, ptsize, face, rotation]; } ELSE { BcplFontFileDefs.CloseSDFontFile[]; IF font=music THEN BcplFontFileDefs.OpenSDFontFile["music8.sd"] ELSE BcplFontFileDefs.OpenSDFontFile["timesroman.sd"]; IF font=text THEN Scale[context,[12, 12]] ELSE Scale[context,[l/12, l/12]]; }; }; DrawString: PUBLIC PROC[dc: DisplayContext, s: STRING] = { screen, pos: Vec _ GetPosition[context]; IF NOT print THEN {DisplayString[dc, s]; RETURN}; IF printChar THEN { ph: POINTER TO PressDefs.PressFileDescriptor; ph _ LOOPHOLE[device.data, PressDeviceImpl.DataRef].pressHandle; screen _ UserToScreen[context, pos]; IF screen.x<0 OR screen.y<0 THEN RETURN; PressDefs.PutText[ph, s, Real.FixC[screen.x], Real.FixC[screen.y]]} ELSE { FOR i: CARDINAL IN [0..s.length) DO DrawChar[dc, s[i]]; RelMoveTo[dc,[5, 0]]; ENDLOOP}; }; DrawChar: PUBLIC PROC[dc: Graphics.DisplayContext, c: CHARACTER]= { screen, pos: Vec _ GetPosition[context]; Move: PROC[v: POINTER TO Vec] = { NewBoundary[dc]; EnterPoint[dc, v^] }; Draw: PROC[v: POINTER TO Vec] = { EnterPoint[dc, v^] }; ECubic: PROC[c: POINTER TO Cubic.Coeffs] = { EnterCubic[dc, c] }; IF NOT print THEN { DisplayChar[dc, c]; RETURN; }; IF printChar THEN { s: STRING _ [1]; ph: POINTER TO PressDefs.PressFileDescriptor; ph _ LOOPHOLE[device.data, PressDeviceImpl.DataRef].pressHandle; s.length _ 1; s[0] _ c; screen _ UserToScreen[context, pos]; IF screen.x<0 OR screen.y<0 THEN RETURN; PressDefs.PutText[ph, s, Real.FixC[screen.x], Real.FixC[screen.y]]; } ELSE { Translate[context, pos]; StartAreaPath[context, IF c='P OR c='X THEN FALSE ELSE TRUE]; DoSDChar[c, Move, Draw, ECubic]; DrawArea[context]; Translate[context,[-pos.x,-pos.y]]; }; }; ndp: BcplFontFileDefs.SplineDataPtr _ NIL; ncp: BcplFontFileDefs.SplineCommandPtr _ NIL; DoSDChar: PROC[char: CHARACTER, Move: PROC[v: POINTER TO Vec], Draw: PROC[v: POINTER TO Vec], DCubic: PROC[c: POINTER TO Cubic.Coeffs]] = { pos: Vec _ [0, 0]; tscp, scp: BcplFontFileDefs.SplineCommandPtr; sdp: BcplFontFileDefs.SplineDataPtr; IF char=154C AND ndp#NIL THEN {sdp _ ndp; scp _ ncp} ELSE [sdp, scp] _ BcplFontFileDefs.GetSplineCommands[char, SystemDefs.AllocateHeapNode]; IF char=154C AND ndp=NIL THEN {ndp _ sdp; ncp _ scp}; tscp _ scp; UNTIL scp=NIL DO WITH scp SELECT FROM MoveTo => {pos _ [x, y]; Move[@pos]}; DrawTo => {pos _ [x, y]; Draw[@pos]}; DrawCurve => { c: Cubic.Coeffs _ [c3: [x2, y2], c2: [x1, y1], c1: [x0, y0], c0: pos]; DCubic[@c]; pos _ [pos.x+x0+x1+x2, pos.y+y0+y1+y2]; }; NewObject => NULL; EndDefinition => EXIT; ENDCASE; scp _ scp.next; ENDLOOP; IF char#154C THEN UNTIL (scp _ tscp)=NIL DO tscp _ scp.next; SystemDefs.FreeHeapNode[scp]; ENDLOOP; }; PointSize: PROC[n: INTEGER] RETURNS[INTEGER] = INLINE { SELECT scale FROM 1 => RETURN[n]; 2 => RETURN[2*n/3]; 4 => RETURN[n/4]; ENDCASE; RETURN[n]; }; <<**********************************************************>> <> <<**********************************************************>> print: PUBLIC BOOL _ FALSE; olddc: Graphics.DisplayContext; printChar: BOOL _ FALSE; DeviceObject: PUBLIC TYPE = Device.Object; -- exported to OpaqueDevice device: Device.Handle; OpenPressDevice: PUBLIC PROC[splines: BOOL] RETURNS[Device.Handle] = { l: REAL _ 1; pos: Graphics.Vec; printChar _ ~splines AND scale=2; print _ TRUE; olddc _ context; device _ PressDevice.NewPressDevice["music.press"]; context _ Graphics.NewContext[device]; pos _ Graphics.Map[olddc, context,[0, 0]]; pos.x _ pos.x+8; pos.y _ pos.y+28; Graphics.Translate[context, pos]; Graphics.SetLineWidth[context, 1]; IF scale=2 THEN Scale[context,[(2*l)/3,(2*l)/3]] ELSE Scale[context,[l/scale, l/scale]]; SetColor[context,[0, 0, 0]]; IF NOT printChar THEN { Graphics.Scale[context,[12, 12]]; -- to offset bug in something BcplFontFileDefs.OpenSDFontFile["music8.sd"]; [ndp, ncp] _ BcplFontFileDefs.GetSplineCommands[0154C, SystemDefs.AllocateHeapNode]}; Utility.SetFont[context, music, 8]; RETURN[device]; }; ClosePressDevice: PUBLIC PROC[device: POINTER TO Device.Handle]= { tncp: BcplFontFileDefs.SplineCommandPtr; Graphics.FreeContext[@context]; Device.Free[device]; IF NOT printChar THEN { BcplFontFileDefs.CloseSDFontFile[]; UNTIL ncp=NIL DO tncp _ ncp.next; SystemDefs.FreeHeapNode[ncp]; ncp _ tncp; ENDLOOP; }; context _ olddc; print _ FALSE; }; <<****************************************************************************>> <> <<****************************************************************************>> zone: UNCOUNTED ZONE = Memory.NewZone["musicZone"]; chordHeap: PUBLIC POINTER TO ARRAY [0..maxChordHeapLength) OF ChordPTR _ NIL; chordHeapLength: PUBLIC CARDINAL; beamHeap: PUBLIC POINTER TO ARRAY [0..maxBeamHeapLength) OF BeamPTR _ NIL; beamHeapLength: PUBLIC CARDINAL; InitStorage: PUBLIC PROC = { i, j: CARDINAL; IF beamHeap#NIL THEN FOR i IN [0..beamHeapLength) DO IF beamHeap[i]#NIL THEN zone.FREE[@beamHeap[i]]; ENDLOOP; IF beamHeap=NIL THEN { beamHeap_ SystemDefs.AllocateSegment[maxBeamHeapLength*SIZE[BeamPTR]]; beamHeap^ _ ALL[NIL]; }; beamHeapLength _ 0; IF chordHeap#NIL THEN FOR i IN [0..chordHeapLength) DO IF chordHeap[i]#NIL THEN zone.FREE[@chordHeap[i]]; ENDLOOP; IF chordHeap=NIL THEN { chordHeap_ SystemDefs.AllocateSegment[maxChordHeapLength*SIZE[ChordPTR]]; chordHeap^ _ ALL[NIL]; }; chordHeapLength _ 0; IF score#NIL THEN FOR i IN [0..scoreLength) DO FOR j IN [0..syncLength) DO IF score[i].event[j]=NIL THEN EXIT; zone.FREE[@score[i].event[j]]; ENDLOOP; zone.FREE[@score[i]]; ENDLOOP; IF score=NIL THEN score _ NewPiece[maxScoreLength]; scoreLength _ 0; selectionLength _ 0; selection _ ALL[NIL]; }; NewPiece: PUBLIC PROC[length: CARDINAL] RETURNS[p: PiecePTR] = { p _ LOOPHOLE[SystemDefs.AllocateSegment[length*SIZE[SyncPTR]]]; FOR i: CARDINAL IN [0..length) DO p[i] _ NIL; ENDLOOP; }; FreePiece: PUBLIC PROC[p: POINTER TO PiecePTR] = { FOR i: CARDINAL DECREASING IN [0..Piece.Length[p^]) DO IF p[i]=NIL THEN LOOP; IF p[i].type=notes THEN FOR j: CARDINAL IN [0..syncLength) DO IF p[i].event[j]=NIL THEN EXIT; p[i].event[j].sync _ NIL; -- so FreeNote doesn't free p[i] p[i].event[j].tied _ FALSE; FreeNote[@p[i].event[j], p^]; ENDLOOP; FreeSync[@p[i]]; ENDLOOP; SystemDefs.FreeSegment[p^]; p^ _ NIL; }; NewSync: PUBLIC PROC RETURNS[p: SyncPTR] = { p _ zone.NEW[SyncRec]; p^ _ []; --defaults to the values listed in MusicDefs RETURN; }; FreeSync: PUBLIC PROC[s: LONG POINTER TO SyncPTR] = { IF s^.type=notes THEN FOR i: CARDINAL IN [0..syncLength) DO IF s^.event[i]=NIL THEN EXIT; IF s^.event[i]#NIL THEN ERROR; ENDLOOP; zone.FREE[s]; }; NewChord: PUBLIC PROC RETURNS[p: ChordPTR] = { p _ zone.NEW[ChordRec]; p^ _ [, 0, ALL[NIL]]; chordHeap[chordHeapLength] _ p; chordHeapLength _ chordHeapLength + 1; RETURN; }; FreeChord: PUBLIC PROC[c: LONG POINTER TO ChordPTR] = { IF c.note[1]#NIL THEN {zone.FREE[c]; RETURN}; -- don't need to carefully dismantle IF c.note[0]#NIL THEN { c.note[0].chord _ NIL; IF c.note[0].beam#NIL THEN FOR i: CARDINAL IN [0..beamLength) DO IF c.note[0].beam.chord[i]#[chord[c^]] THEN LOOP; c.note[0].beam.chord[i] _ [note[c.note[0]]]; EXIT; ENDLOOP}; chordHeapLength _ chordHeapLength - 1; chordHeap[Chord.GetHeapIndex[c^]] _ chordHeap[chordHeapLength]; chordHeap[chordHeapLength] _ NIL; zone.FREE[c]; }; NewBeam: PUBLIC PROC RETURNS[p: BeamPTR] = { IF beamHeapLength=maxBeamHeapLength THEN ERROR; p _ zone.NEW[BeamRec]; p^ _ [0, TRUE, 0, 0, NIL, NIL, NIL, 0, FALSE, 0, 1, ALL[endOfBeam]]; beamHeap[beamHeapLength] _ p; beamHeapLength _ beamHeapLength + 1; }; FreeBeam: PUBLIC PROC[b: LONG POINTER TO BeamPTR] = { IF b.chord[1]#endOfBeam THEN {zone.FREE[b]; RETURN}; -- don't need to carefully dismantle IF b.chord[0]#endOfBeam THEN WITH ev: b.chord[0] SELECT FROM note => {ev.n.beam _ NIL; IF b.beam#NIL THEN Beam.AddNote[b.beam, ev.n]}; chord=> {FOR j: CARDINAL IN [0..chordLength) DO IF ev.c.note[j]=NIL THEN EXIT; ev.c.note[j].beam _ NIL; ENDLOOP; IF b.beam#NIL THEN Beam.AddChord[b.beam, ev.c]}; beam => {ev.b.beam _ NIL; IF b.beam#NIL THEN Beam.AddBeam[b.beam, ev.b]}; ENDCASE; IF b^.beam#NIL THEN Beam.Remove[b^.beam, NIL, NIL, b^]; beamHeapLength _ beamHeapLength -1; beamHeap[Beam.GetHeapIndex[b^]] _ beamHeap[beamHeapLength]; beamHeap[beamHeapLength] _ NIL; zone.FREE[b]; }; NewNote: PUBLIC PROC RETURNS[p: NotePTR] = { p _ zone.NEW[NoteRec]; p^ _ []; --defaults to the values listed in MusicDefs RETURN; }; FreeNote: PUBLIC PROC[n: LONG POINTER TO NotePTR, p: PiecePTR] = { s: SyncPTR _ n.sync; IF n^.tied THEN Note.GetBackTie[n^].tie _ NIL; IF n^.tie#NIL THEN n^.tie.tied _ FALSE; IF n^.chord#NIL THEN Chord.RemoveNote[n^.chord, n^]; IF n^.beam#NIL THEN Beam.Remove[n^.beam, n^, NIL, NIL]; IF n^.sync#NIL THEN Sync.RemoveNote[n^.sync, n^]; IF s#NIL AND s.event[0]=NIL THEN { Piece.RemoveSync[p, s]; FreeSync[@s]}; zone.FREE[n]; }; <<****************************************************************************>> <> <<****************************************************************************>> FileStats: PUBLIC PROC = { OPEN IODefs, Utility; i, j: CARDINAL; memory: LONG INTEGER; highWater, notes: INTEGER _ 0; number: STRING _ [20]; WriteLine[""]; memory _ 2*maxBeamHeapLength+2*maxChordHeapLength+ 2*maxScoreLength; memory _memory+ LONG[scoreLength]*SIZE[SyncRec]; WriteString["scoreLength= "]; WriteNumber[scoreLength,[10, FALSE, TRUE, 4]]; FOR i IN [0..scoreLength) DO FOR j IN [0..syncLength) DO IF score[i].event[j] =NIL THEN { highWater _ MAX[highWater, j]; EXIT; } ELSE notes _ notes + 1; ENDLOOP; ENDLOOP; memory _ memory + LONG[notes]*SIZE[NoteRec]; WriteString["; #notes= "]; WriteNumber[notes,[10, FALSE, TRUE, 5]]; WriteString["; maxUsageOfSyncs= "]; WriteNumber[highWater,[10, FALSE, TRUE, 2]]; WriteLine[""]; highWater _ 0; WriteString[" #chords="]; WriteNumber[chordHeapLength,[10, FALSE, TRUE, 3]]; FOR i IN [0..chordHeapLength) DO FOR j IN [0..chordLength) DO IF chordHeap[i].note[j] #NIL THEN LOOP; highWater _ MAX[highWater, j]; EXIT; ENDLOOP; ENDLOOP; WriteString["; maxUsageOfChords= "]; WriteNumber[highWater,[10, FALSE, TRUE, 2]]; memory _ memory + LONG[chordHeapLength]*SIZE[ChordRec]; memory _ memory + LONG[beamHeapLength]*SIZE[BeamRec]; WriteLine[""]; highWater _ 0; WriteString[" #beams ="]; WriteNumber[beamHeapLength,[10, FALSE, TRUE, 3]]; FOR i IN [0..beamHeapLength) DO FOR j IN [0..beamLength) DO IF beamHeap[i].chord[j] #endOfBeam THEN LOOP; highWater _ MAX[highWater, j]; EXIT; ENDLOOP; ENDLOOP; WriteString["; maxUsageOfBeams= "]; WriteNumber[highWater,[10, FALSE, TRUE, 2]]; WriteLine[""]; WriteString["sync="]; WriteNumber[SIZE[SyncRec],[10, FALSE, TRUE, 2]]; WriteString["; note="]; WriteNumber[SIZE[NoteRec],[10, FALSE, TRUE, 2]]; WriteString["; chord="]; WriteNumber[SIZE[ChordRec],[10, FALSE, TRUE, 2]]; WriteString["; beam="]; WriteNumber[SIZE[BeamRec],[10, FALSE, TRUE, 2]]; WriteString["; memory="]; StringDefs.AppendLongNumber[number, memory, 10]; WriteString[number]; WriteLine[""]; }; Test: PUBLIC PROC RETURNS[BOOL] = { i, j, k: CARDINAL; n: NotePTR; s: SyncPTR; lastBeam: BeamPTR _ NIL; nilFound, beamFound: BOOL; sync1, sync2: BOOL; dataError _ FALSE; FOR i IN [0..maxScoreLength) DO IF score[i]#NIL AND i>=scoreLength THEN WriteError[sync, i,-1,"beyond scoreLength"]; IF score[i]=NIL AND iscore[i].time THEN>> <> IF score[i].type IN [octava1..octava2] AND Sync.Octava[Sync.Octava[score[i]]]#score[i] THEN WriteError[sync, i,-1,"=octava with no matching end."]; IF score[i].type#notes AND score[i].event[0]#NIL THEN WriteError[sync, i,-1,"measure with note attached!"]; IF score[i].type#notes THEN LOOP; IF score[i].type=notes AND score[i].event[0]=NIL THEN WriteError[sync, i,-1,"empty"]; nilFound _ FALSE; FOR j IN [0..syncLength) DO n _ score[i].event[j]; IF n#NIL AND nilFound THEN WriteError[sync, i, j,"not compact"]; IF n=NIL THEN { nilFound _ TRUE; LOOP; }; IF n.sync#score[i] THEN WriteError[sync, i, j,"n.sync#score[i]"]; IF n.beam=NIL THEN LOOP; IF n.beam=lastBeam THEN LOOP; beamFound _ FALSE; FOR k IN [0..beamHeapLength) DO IF beamHeap[k]#n.beam THEN LOOP; beamFound _ TRUE; lastBeam _ n.beam; EXIT; ENDLOOP; IF NOT beamFound THEN WriteError[sync, i, j,"non-existant beam"]; ENDLOOP; ENDLOOP; FOR i IN [0..maxChordHeapLength) DO IF chordHeap[i]#NIL AND i>=chordHeapLength THEN WriteError[chord, i,-1,"beyond chordHeapLength"]; IF chordHeap[i]=NIL AND i=beamHeapLength THEN WriteError[beam, i,-1,"beyond beamHeapLength"]; IF beamHeap[i]=NIL AND i { IF ev.n.beam#pointer THEN WriteError[beam, i, j,"wrong beam"]; IF ev.n.sync=pointer.sync1 THEN sync1 _ TRUE; IF ev.n.sync=pointer.sync2 THEN sync2 _ TRUE; }; chord=> { IF ev.c.note[0].sync=pointer.sync1 THEN sync1 _ TRUE; IF ev.c.note[0].sync=pointer.sync2 THEN sync2 _ TRUE; FOR k IN [0..chordLength) DO IF ev.c.note[k]=NIL THEN LOOP; IF ev.c.note[k].beam#pointer THEN WriteError[beam, i, j,"wrong beam"]; ENDLOOP; }; beam => { IF ev.b.beam#pointer THEN WriteError[beam, i, j,"wrong beam"]; IF ev.b.sync1=pointer.sync1 THEN sync1 _ TRUE; IF ev.b.sync2=pointer.sync2 THEN sync2 _ TRUE; }; ENDCASE; ENDLOOP; IF NOT sync1 THEN WriteError[beam, i,-1,"bad sync1"]; IF NOT sync2 THEN WriteError[beam, i,-1,"bad sync2"]; }; WriteError: PROC[t: Type, i, j: INTEGER, s: STRING] = { OPEN IODefs; SELECT t FROM sync => { WriteString["sync"]; WriteNumber[i,[10, FALSE, TRUE, 4]]; IF j>-1 THEN { WriteString[", event"]; WriteNumber[j,[10, FALSE, TRUE, 2]]; }; }; chord=> { WriteString["chord"]; WriteNumber[i,[10, FALSE, TRUE, 4]]; IF j>-1 THEN { WriteString[", note"]; WriteNumber[j,[10, FALSE, TRUE, 2]]; }; }; beam => { WriteString["beam"]; WriteNumber[i,[10, FALSE, TRUE, 4]]; IF j>-1 THEN { WriteString[", chord"]; WriteNumber[j,[10, FALSE, TRUE, 2]]; }; }; ENDCASE; dataError _ TRUE; WriteString[": "]; WriteLine[s]; }; Type: TYPE = {sync, chord, beam, none}; dataError: BOOL; CleanUp: PROC = { i, j, k: CARDINAL; n: NotePTR; s: SyncPTR; nilFound, beamFound: BOOL; sync1, sync2: BOOL; FOR i IN [0..maxScoreLength) DO IF score[i]#NIL AND i>=scoreLength THEN WriteError[sync, i,-1,"beyond scoreLength"]; IF score[i]=NIL AND iscore[i].time THEN WriteError[sync, i,-1,"out of place"]; IF score[i].type#notes AND score[i].event[0]#NIL THEN WriteError[sync, i,-1,"measure with note attached!"]; IF score[i].type#notes THEN LOOP; IF score[i].type=notes AND score[i].event[0]=NIL THEN WriteError[sync, i,-1,"empty"]; nilFound _ FALSE; FOR j IN [0..syncLength) DO n _ score[i].event[j]; IF n#NIL AND nilFound THEN WriteError[sync, i, j,"not compact"]; IF n=NIL THEN { nilFound _ TRUE; LOOP; }; IF n.sync#score[i] THEN n.sync _ score[i]; IF n.beam=NIL THEN LOOP; beamFound _ FALSE; FOR k IN [0..beamHeapLength) DO IF beamHeap[k]#n.beam THEN LOOP; beamFound _ TRUE; EXIT; ENDLOOP; IF NOT beamFound THEN score[i].event[j].beam _ NIL; ENDLOOP; ENDLOOP; FOR i IN [0..maxChordHeapLength) DO IF chordHeap[i]#NIL AND i>=chordHeapLength THEN WriteError[chord, i,-1,"beyond chordHeapLength"]; IF chordHeap[i]=NIL AND i=beamHeapLength THEN WriteError[beam, i,-1,"beyond beamHeapLength"]; IF beamHeap[i]=NIL AND i IF ev.n.beam#pointer THEN ev.n.beam _ pointer; chord=> FOR k IN [0..chordLength) DO IF ev.c.note[k]=NIL THEN LOOP; IF ev.c.note[k].beam#pointer THEN ev.c.note[k].beam _ pointer; ENDLOOP; ENDCASE; ENDLOOP; }; CleanUpSheets: PROC = { sheet: Staves; FOR i: CARDINAL DECREASING IN [0..scoreLength) DO IF score[i].type NOT IN SheetSwitch THEN LOOP; sheet _ LOOPHOLE[score[i].event]; FOR j: CARDINAL IN [0..sheet.sl] DO IF sheet.staff[j].pitch#0 THEN LOOP; Utility.FreeSync[@score[i]]; EXIT; ENDLOOP; ENDLOOP; }; END.