UtilityImpl.mesa
Copyright (C) 1981, 1984 Xerox Corporation. All rights reserved.
Author: John Maxwell
last modified: December 18, 1981 8: 45 AM
Edited by Doug Wyatt, June 14, 1984 1:16:50 pm PDT
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;
****************************************************************************
graphics procedures
****************************************************************************
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];
};
**********************************************************
printing the score
**********************************************************
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;
};
****************************************************************************
Basic Allocation Procedures
****************************************************************************
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, consistency checking
****************************************************************************
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 i<scoreLength THEN WriteError[sync, i,-1,"=NIL"];
IF score[i]=NIL THEN LOOP;
IF i#0 AND score[i-1].time>score[i].time THEN
WriteError[sync, i,-1,"out of place"];
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<chordHeapLength
THEN
WriteError[chord, i,-1,"=NIL"];
IF chordHeap[i]=NIL THEN LOOP;
IF chordHeap[i].note[0]=NIL THEN WriteError[chord, i,-1,"empty"];
nilFound ← FALSE;
s ← NIL;
FOR j
IN [0..chordLength)
DO
n ← chordHeap[i].note[j];
IF n#
NIL
AND nilFound
THEN WriteError[chord, i, j,"not compact"];
IF n=NIL THEN { nilFound ← TRUE; LOOP; };
IF s=NIL THEN s ← n.sync;
IF s#n.sync THEN WriteError[chord, i, j,"wrong sync"];
ENDLOOP;
ENDLOOP;
FOR i
IN [0..maxBeamHeapLength)
DO
IF beamHeap[i]#
NIL
AND i>=beamHeapLength
THEN
WriteError[beam, i,-1,"beyond beamHeapLength"];
IF beamHeap[i]=
NIL
AND i<beamHeapLength
THEN
WriteError[beam, i,-1,"=NIL"];
IF beamHeap[i]=NIL THEN LOOP;
IF beamHeap[i].chord[0]=endOfBeam THEN WriteError[beam, i,-1,"empty"];
TestBeam[i, beamHeap[i]];
sync1 ← Sync.GetScoreIndex[beamHeap[i].sync1]#scoreLength;
sync2 ← Sync.GetScoreIndex[beamHeap[i].sync2]#scoreLength;
IF NOT sync1 THEN WriteError[beam, i,-1,"sync1 not in score"];
IF NOT sync2 THEN WriteError[beam, i,-1,"sync2 not in score"];
ENDLOOP;
RETURN[dataError];
};
TestBeam:
PROC[i:
CARDINAL, pointer: BeamPTR] = {
j, k: CARDINAL;
beam: BeamPTR ← beamHeap[i];
nilFound, sync1, sync2: BOOL ← FALSE;
FOR j
IN [0..beamLength)
DO
IF beam.chord[j]#endOfBeam
AND nilFound
THEN
WriteError[beam, i, j,"not compact"];
IF beam.chord[j]=endOfBeam
THEN {
nilFound ← TRUE; LOOP; };
WITH ev: beam.chord[j]
SELECT
FROM
note => {
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 i<scoreLength THEN WriteError[sync, i,-1,"=NIL"];
IF score[i]=NIL THEN LOOP;
IF i#0
AND score[i-1].time>score[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<chordHeapLength
THEN
WriteError[chord, i,-1,"=NIL"];
IF chordHeap[i]=NIL THEN LOOP;
IF chordHeap[i].note[0]=NIL THEN Utility.FreeChord[@chordHeap[i]];
nilFound ← FALSE;
s ← NIL;
FOR j
IN [0..chordLength)
DO
n ← chordHeap[i].note[j];
IF n#
NIL
AND nilFound
THEN WriteError[chord, i, j,"not compact"];
IF n=NIL THEN { nilFound ← TRUE; LOOP; };
IF s=NIL THEN s ← n.sync;
IF s#n.sync THEN chordHeap[i].note[j].sync ← s;
ENDLOOP;
ENDLOOP;
FOR i
IN [0..maxBeamHeapLength)
DO
IF beamHeap[i]#
NIL
AND i>=beamHeapLength
THEN
WriteError[beam, i,-1,"beyond beamHeapLength"];
IF beamHeap[i]=
NIL
AND i<beamHeapLength
THEN
WriteError[beam, i,-1,"=NIL"];
IF beamHeap[i]=NIL THEN LOOP;
IF beamHeap[i].chord[1]=endOfBeam THEN Utility.FreeBeam[@beamHeap[i]];
CleanUpBeam[i, beamHeap[i]];
sync1 ← sync2 ← FALSE;
FOR j
IN [0..scoreLength)
DO
IF score[j]=beamHeap[i].sync1 THEN sync1 ← TRUE;
IF score[j]=beamHeap[i].sync2 THEN sync2 ← TRUE;
ENDLOOP;
IF NOT sync1 THEN WriteError[beam, i,-1,"sync1 not in score"];
IF NOT sync2 THEN WriteError[beam, i,-1,"sync2 not in score"];
ENDLOOP;
};
CleanUpBeam:
PROC[i:
CARDINAL, pointer: BeamPTR] = {
j, k: CARDINAL;
beam: BeamPTR ← beamHeap[i];
nilFound: BOOL ← FALSE;
FOR j
IN [0..beamLength)
DO
IF beam.chord[j]#endOfBeam
AND nilFound
THEN
WriteError[beam, i, j,"not compact"];
IF beam.chord[j]=endOfBeam
THEN {
nilFound ← TRUE; LOOP; };
WITH ev: beam.chord[j]
SELECT
FROM
note => 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.