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 BOOLFALSE;
olddc: Graphics.DisplayContext;
printChar: BOOLFALSE;
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: BOOLFALSE;
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: BOOLFALSE;
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.