BeamImplA.mesa
Copyright (C) 1981, 1984 Xerox Corporation. All rights reserved.
Author: John Maxwell
last modified: November 28, 1981 8: 35 AM
Edited by Doug Wyatt, June 14, 1984 3:32:49 pm PDT
DIRECTORY
Beam USING [Remove, SetSyncs, Sort, time],
Chord USING [Beam, Sort],
MusicDefs,
Real USING [FixI],
Sheet USING [Height],
Utility USING [FreeBeam];
BeamImplA: CEDAR PROGRAM
IMPORTS Beam, Chord, MusicDefs, Real, Sheet, Utility
EXPORTS Beam, MusicDefs
= BEGIN OPEN MusicDefs, Utility;
GetHeapIndex: PUBLIC PROC[p: BeamPTR] RETURNS[NAT] = INLINE
{FOR i: NAT IN [0..beamHeapLength) DO
IF beamHeap[i]=p THEN RETURN[i];
ENDLOOP;
RETURN[beamHeapLength]};
Height: PROC[b: BeamPTR, time: Time] RETURNS[h: INTEGER] = INLINE
{h ← b.height+Sheet.Height[b.sync1.time,, b.staff];
IF time#b.sync1.time THEN h ← h + Real.FixI[(time-b.sync1.time)*b.tilt]};
Length: PROC[b: BeamPTR] RETURNS[NAT] = INLINE
{FOR i: NAT IN [0..beamLength] DO
IF i=beamLength THEN RETURN[i];
IF b.chord[i]=endOfBeam THEN RETURN[i];
ENDLOOP;
ERROR};
time: PUBLIC PROC[chord: VariousPTR] RETURNS[Time] = INLINE
{WITH chord SELECT FROM
n: NotePTR => RETURN[n.sync.time];
c: ChordPTR => RETURN[c.note[0].sync.time];
b: BeamPTR => RETURN[IF b.sync1#NIL THEN b.sync1.time ELSE 0];
ENDCASE => ERROR
};
**************************************************************************
data abstractions for a beam
CONSTRAINT: IF b.chord[i]=NIL THEN b.chord[j]=NIL for all j>i
CONSTRAINT: b.chord[i].sync.time<=b.chord[i+1].sync.time for all i
**************************************************************************
Add: PUBLIC PROC[beam: BeamPTR, x: VariousPTR] ~ {
WITH x SELECT FROM
n: NotePTR => AddNote[beam, n];
c: ChordPTR => AddChord[beam, c];
b: BeamPTR => AddBeam[beam, b];
ENDCASE => ERROR;
};
AddNote: PROC[b: BeamPTR, n: NotePTR] = {
oldBeam: BeamPTR=n.beam;
i, j: CARDINAL ← beamLength-1;
FOR i IN [0..beamLength) DO IF b.chord[i]=n THEN RETURN; ENDLOOP;
IF b.sync1=NIL THEN b.sync1 ← n.sync;
IF b.sync2=NIL THEN b.sync2 ← n.sync;
IF n.sync.time < b.sync1.time THEN b.sync1 ← n.sync;
IF n.sync.time > b.sync2.time THEN b.sync2 ← n.sync;
FOR i IN [0..beamLength) DO
IF b.chord[i]=endOfBeam THEN { j ← i; EXIT; };
IF Beam.time[b.chord[i]]>n.sync.time THEN j ← i;
IF j#beamLength-1 THEN EXIT;
ENDLOOP;
IF b.chord[beamLength-1]#endOfBeam THEN Overflow[beam];
FOR i DECREASING IN (j..beamLength) DO
b.chord[i] ← b.chord[i-1];
ENDLOOP;
b.chord[j] ← n;
n.beam ← b;
IF oldBeam#NIL AND oldBeam#b THEN Beam.Remove[n.beam, n, NIL, NIL];
IF b.beam#NIL THEN Beam.SetSyncs[b.beam];
};
AddChord: PROC[b: BeamPTR, c: ChordPTR] = {
i, j: CARDINAL ← beamLength-1;
oldBeam: BeamPTR = Chord.Beam[c];
FOR i IN [0..beamLength) DO IF b.chord[i]=c THEN RETURN; ENDLOOP;
IF b.sync1=NIL THEN b.sync1 ← c.note[0].sync;
IF b.sync2=NIL THEN b.sync2 ← c.note[0].sync;
IF c.note[0].sync.time < b.sync1.time THEN b.sync1 ← c.note[0].sync;
IF c.note[0].sync.time > b.sync2.time THEN b.sync2 ← c.note[0].sync;
FOR i IN [0..beamLength) DO
IF b.chord[i]=endOfBeam THEN { j ← i; EXIT; };
IF Beam.time[b.chord[i]]>c.note[0].sync.time THEN j ← i;
IF j#beamLength-1 THEN EXIT;
ENDLOOP;
IF b.chord[beamLength-1]#endOfBeam THEN Overflow[beam];
FOR i DECREASING IN (j..beamLength) DO
b.chord[i] ← b.chord[i-1];
ENDLOOP;
b.chord[j] ← c;
FOR i IN [0..chordLength) DO
IF c.note[i]=NIL THEN EXIT;
c.note[i].beam ← b;
ENDLOOP;
IF oldBeam#NIL AND oldBeam#b THEN Beam.Remove[oldBeam, NIL, c, NIL];
IF b.beam#NIL THEN Beam.SetSyncs[b.beam];
};
AddBeam: PROC[b: BeamPTR, new: BeamPTR] = {
oldBeam: BeamPTR=b.beam;
i, j: CARDINAL ← beamLength-1;
FOR i IN [0..beamLength) DO IF b.chord[i]=new THEN RETURN; ENDLOOP;
IF b.sync1=NIL THEN b.sync1 ← new.sync1;
IF b.sync2=NIL THEN b.sync2 ← new.sync2;
IF new.sync1.time < b.sync1.time THEN b.sync1 ← new.sync1;
IF new.sync2.time > b.sync2.time THEN b.sync2 ← new.sync2;
FOR i IN [0..beamLength) DO
IF b.chord[i]=endOfBeam THEN { j ← i; EXIT; };
IF Beam.time[b.chord[i]]>new.sync1.time THEN j ← i;
IF j#beamLength-1 THEN EXIT;
ENDLOOP;
IF b.chord[beamLength-1]#endOfBeam THEN Overflow[beam];
FOR i DECREASING IN (j..beamLength) DO
b.chord[i] ← b.chord[i-1];
ENDLOOP;
b.chord[j] ← new;
new.beam ← b;
IF oldBeam#NIL AND oldBeam#b THEN Beam.Remove[oldBeam, NIL, NIL, new];
IF b.beam#NIL THEN Beam.SetSyncs[b.beam];
};
Remove: PUBLIC PROC[beam: BeamPTR, n: NotePTR, c: ChordPTR, b: BeamPTR] = {
i, j: CARDINAL;
found: BOOLFALSE;
sync1, sync2: SyncPTR ← NIL;
IF beam=NIL THEN RETURN;
FOR i IN [0..beamLength) DO
IF beam.chord[i]=endOfBeam THEN EXIT;
IF beam.chord[i]#b AND beam.chord[i]#c AND
beam.chord[i]#n THEN LOOP;
IF beam.chord[i]=n THEN n.beam ← NIL;
IF beam.chord[i]=b THEN b.beam ← NIL;
IF beam.chord[i]=c THEN FOR j IN [0..chordLength) DO
IF c.note[j]=NIL THEN EXIT;
c.note[j].beam ← NIL;
ENDLOOP;
FOR j IN [i..beamLength-1) DO
beam.chord[j] ← beam.chord[j+1];
ENDLOOP;
beam.chord[beamLength-1] ← endOfBeam;
found ← TRUE;
ENDLOOP;
IF NOT found THEN RETURN;
IF beam.chord[1]=endOfBeam THEN {FreeBeam[@beam]; RETURN};
reset beamsyncs if needed
IF n#NIL THEN sync1 ← n.sync;
IF c#NIL THEN sync2 ← c.note[0].sync;
IF b#NIL THEN { sync1 ← b.sync1; sync2 ← b.sync2; };
IF beam.sync1=sync1 OR beam.sync1=sync2 THEN beam.sync1 ← NIL;
IF beam.sync2=sync2 OR beam.sync2=sync1 THEN beam.sync2 ← NIL;
IF beam.sync1=NIL OR beam.sync2=NIL THEN Beam.SetSyncs[beam];
};
Sort: PUBLIC PROC[b: BeamPTR] = {
i, j: CARDINAL;
temp: VariousPTR;
FOR i IN [0..beamLength) DO
IF b.chord[i] = endOfBeam THEN EXIT;
FOR j IN (i..beamLength) DO
IF b.chord[j] = endOfBeam THEN EXIT;
IF Beam.time[b.chord[i]] <= Beam.time[b.chord[j]] THEN LOOP;
temp ← b.chord[i];
b.chord[i] ← b.chord[j];
b.chord[j] ← temp;
ENDLOOP;
ENDLOOP;
};
SetSyncs: PUBLIC PROC[b: BeamPTR] = {
i: CARDINAL;
sync1, sync2: SyncPTR;
b.sync1 𡤋.sync2 ← NIL;
FOR i IN [0..beamLength) DO
IF b.chord[i]=endOfBeam THEN EXIT;
sync1 ← sync2 ← NIL;
WITH ev: b.chord[i] SELECT FROM
note => sync1 ← ev.n.sync;
chord=> sync2 ← ev.c.note[0].sync;
beam => { sync1 ← ev.b.sync1; sync2 ← ev.b.sync2; };
ENDCASE;
IF sync1=NIL THEN sync1 ← sync2;
IF sync2=NIL THEN sync2 ← sync1;
IF b.sync1=NIL THEN b.sync1 ← sync1;
IF b.sync2=NIL THEN b.sync2 ← sync2;
IF sync1=NIL OR sync2=NIL THEN LOOP;
IF b.sync1.time>sync1.time THEN b.sync1 ← sync1;
IF b.sync2.time<=sync2.time THEN b.sync2 ← sync2;
ENDLOOP;
Beam.Sort[b];
IF b.beam # NIL THEN SetSyncs[b.beam];
};
SetStems: PUBLIC PROC[b: BeamPTR] = {
make the chord stems consistent with the position of the beam
i: CARDINAL;
height, heighti, heightb: INTEGER;
time1, timei: Time ← b.sync1.time;
IF NOT b.beamed THEN RETURN;
determine the staff
heightb ← b.height+Sheet.Height[b.sync1.time,, b.staff];
FOR i IN [0..beamLength) DO
IF b.chord[i]=endOfBeam THEN EXIT;
WITH ev: b.chord[i] SELECT FROM
note => {
heighti ← Sheet.Height[ev.n.sync.time, ev.n.pitch, ev.n.staff];
timei ← Beam.time[b.chord[i]];
height ← Real.FixI[heightb+b.tilt*(timei-time1)];
ev.n.stemUp ← (height > heighti);
b.staff ← ev.n.staff};
chord=> {
[] ← Chord.Sort[ev.c, FALSE];
heighti ← Sheet.Height[ev.c.note[0].sync.time, ev.c.note[0].pitch, ev.c.note[0].staff];
timei ← Beam.time[b.chord[i]];
height ← Real.FixI[heightb+b.tilt*(timei-time1)];
ev.c.stemUp ← (height > heighti);
b.staff ← ev.c.note[0].staff};
beam => {
ev.b.tilt ← b.tilt;
height ← Real.FixI[heightb+b.tilt*(ev.b.sync1.time-time1)];
ev.b.height ← height-Sheet.Height[0,, ev.b.staff];
SetStems[ev.b];
b.staff ← ev.b.staff};
ENDCASE;
ENDLOOP;
b.height ← heightb - Sheet.Height[b.sync1.time,, b.staff];
};
**************************************************************************
beam attributes
**************************************************************************
Grace: PUBLIC PROC[b: BeamPTR] RETURNS[BOOL] = {
a grace beam doesn't have ANY non-grace notes
i, j: CARDINAL;
FOR i IN [0..beamLength) DO
IF b.chord[i]=endOfBeam THEN EXIT;
WITH ev: b.chord[i] SELECT FROM
note => IF ~ev.n.grace THEN RETURN[FALSE];
chord => FOR j IN [0..chordLength) DO
IF ev.c.note[j]=NIL THEN EXIT;
IF ~ev.c.note[j].grace THEN RETURN[FALSE];
ENDLOOP;
beam => IF ~Grace[ev.b] THEN RETURN[FALSE];
ENDCASE;
ENDLOOP;
RETURN[TRUE];
};
InVoice: PUBLIC PROC[b: BeamPTR, voice: CARDINAL] RETURNS[BOOL] = {
i, j: CARDINAL;
FOR i IN [0..beamLength) DO
IF b.chord[i]=endOfBeam THEN EXIT;
WITH ev: b.chord[i] SELECT FROM
note => IF ev.n.voice=voice THEN RETURN[TRUE];
chord => FOR j IN [0..chordLength) DO
IF ev.c.note[j]=NIL THEN EXIT;
IF ev.c.note[j].voice=voice THEN RETURN[TRUE];
ENDLOOP;
beam => IF InVoice[ev.b, voice] THEN RETURN[TRUE];
ENDCASE;
ENDLOOP;
RETURN[FALSE];
};
END.