BeamImplB.mesa
Copyright (C) 1981, 1984 Xerox Corporation. All rights reserved.
Author: John Maxwell
last modified: December 11, 1981 9: 03 AM
Edited by Doug Wyatt, June 14, 1984 3:34:20 pm PDT
DIRECTORY
Beam USING [Draw, Grace, InVoice],
Chord USING [Draw, Width],
Graphics USING [DrawArea, EnterPoint, MoveTo, SetTexture, StartAreaPath],
MusicDefs,
Note USING [Draw, Width],
Real USING [FixI],
Sheet USING [FindLine, Height, MapHeight, NextLine],
StringDefs USING [AppendDecimal],
Utility USING [DrawLine, DrawString, SetFont];
BeamImplB: CEDAR PROGRAM
IMPORTS Beam, Chord, Graphics, MusicDefs, Note, Real, Sheet, StringDefs, Utility
EXPORTS Beam
= BEGIN OPEN Graphics, MusicDefs, Utility;
****************************************************************************
displaying beams
****************************************************************************
Draw: PUBLIC PROC[b: BeamPTR] RETURNS[INTEGER, INTEGER] = {
start: Time;
a: BeamArray;
slope: REAL ← 5;
i, end: CARDINAL;
inVoice: BOOL;
nonGrace: BOOLFALSE;
thickness, lineHeight: INTEGER;
level, space, s, k, up, d: CARDINAL ← 0;
x0, y0, xn, yn, xi, yi, overX: REAL ← 1;
j, value, beamValue: NoteValue ← unknown;
dotted, oldDotted, stemUp, none: BOOLFALSE;
IF NOT show.notehead THEN {DrawPhysicalBeam[b]; RETURN[0, 0]};
IF NOT b.beamed THEN { DrawNTuple[b]; RETURN[0, 0]; };
start ← b.sync1.time;
[x0, y0] ← Sheet.MapHeight[b.sync1.time, b.height+Sheet.Height[b.sync1.time,, b.staff]];
overX ← sheet[Sheet.FindLine[b.sync2.time]].x;
inVoice ← ~(voice AND NOT Beam.InVoice[b, selectedVoice]);
IF b.tilt > -x0/slope AND b.tilt < x0/slope THEN space ← 5 ELSE space ← 7;
IF Beam.Grace[b] THEN {space ← space-2; thickness ← 1} ELSE thickness ← 2;
first we figure out where everything is going to be
FOR i IN [0..beamLength) DO
IF b.chord[i] = endOfBeam THEN
{ a[i].dotted ← FALSE; end ← i; EXIT; };
WITH n: b.chord[i] SELECT FROM
note => {
IF show.display#graphical THEN n.n.delta ← 0;
IF i=0 THEN start ← start + n.n.delta + (IF n.n.stemUp THEN Note.Width[n.n] ELSE 0);
IF i=0 THEN x0 ← x0 + n.n.delta + (IF n.n.stemUp THEN Note.Width[n.n] ELSE 0);
a[i].x ← n.n.sync.time - start + n.n.delta;
IF n.n.stemUp THEN a[i].x ← a[i].x + Note.Width[n.n];
a[i].y ← y0 + b.tilt*a[i].x;
a[i].value ← n.n.value;
a[i].stemUp ← n.n.stemUp;
a[i].dotted ← n.n.dotted;
};
chord=> {
IF show.display#graphical THEN n.c.delta ← 0;
IF i=0 THEN start ← start + n.c.delta + (IF n.c.stemUp THEN Chord.Width[n.c] ELSE 0);
IF i=0 THEN x0 ← x0 + n.c.delta + (IF n.c.stemUp THEN Chord.Width[n.c] ELSE 0);
a[i].x ← n.c.note[0].sync.time - start + n.c.delta;
IF n.c.stemUp THEN a[i].x ← a[i].x + Chord.Width[n.c];
a[i].y ← y0 + b.tilt*a[i].x;
a[i].value ← n.c.note[0].value;
a[i].stemUp ← n.c.stemUp;
a[i].dotted ← n.c.note[0].dotted;
};
beam => { x: Time ← 0;
WITH ev: n.b.chord[0] SELECT FROM
note => IF (a[i].stemUp ← ev.n.stemUp) THEN x ← Note.Width[ev.n];
chord => IF (a[i].stemUp ← ev.c.stemUp) THEN x ← Chord.Width[ev.c];
ENDCASE;
IF i=0 THEN start ← start +x;
IF i=0 THEN x0 ← x0 + x;
a[i].x ← n.b.sync1.time - start+x;
a[i].y ← y0 + b.tilt*a[i].x;
a[i].value ← eighth;
a[i].dotted ← FALSE;
n.b.tilt ← b.tilt;
n.b.staff ← b.staff;
n.b.height ← Real.FixI[b.height+a[i].y-y0];
IF i#beamLength-1 AND b.chord[i+1]#endOfBeam THEN LOOP;
FOR j: CARDINAL IN [0..beamLength) DO
IF n.b.chord[j]=endOfBeam THEN EXIT;
WITH ev: n.b.chord[j] SELECT FROM
note => IF ev.n.stemUp THEN x ← 8 ELSE x ← 0;
chord => IF ev.c.stemUp THEN x ← 8 ELSE x ← 0;
ENDCASE;
ENDLOOP;
a[i].stemUp ← (x#0);
a[i].x ← n.b.sync2.time- start+ x;
a[i].y ← y0 + b.tilt*a[i].x;
};
ENDCASE;
ENDLOOP;
then we draw the beams and components
i ← Sheet.FindLine[b.sync1.time];
lineHeight ← sheet[i].y-sheet[Sheet.NextLine[i]].y;
FOR j IN [eighth..unknown) DO
none ← TRUE;
FOR i IN [0..end) DO
IF none THEN IF a[i].value>=j
THEN { none ← FALSE; s ← i; }
ELSE LOOP;
IF (i<end-1 AND j=eighth) OR (i<end-1 AND a[i+1].value>=j) THEN LOOP;
up ← d ← 0;
FOR k IN [s..i] DO IF a[k].stemUp THEN up ← up+1 ELSE d ← d+1; ENDLOOP;
stemUp ← (up>d);
xn ← a[i].x + x0; yn ← a[i].y; xi ← a[s].x + x0;
none ← TRUE;
IF xi=xn THEN SELECT TRUE FROM -- half beam
i=0 => {xn ← xn+10; yn ← yn+b.tilt*10};
i=end-1 => xi ← xi-10;
a[i-1].value<a[i+1].value => {xn ← xn+10; yn ← yn+b.tilt*10};
a[i-1].value>a[i+1].value => xi ← xi-10;
a[i+1].dotted => {xn ← xn+10; yn ← yn+b.tilt*10};
ENDCASE => xi ← xi-10;
IF stemUp THEN yn ← yn - space*level ELSE yn ← yn + space*level;
yi ← yn + b.tilt*(xi-xn);
Graphics.SetTexture[context, IF inVoice THEN black ELSE light];
DrawClippedRect[xi, yi, xn-1, yn, overX, b.tilt, thickness, lineHeight];
FOR k IN [s..i] DO
IF a[k].value#j THEN LOOP;
IF a[k].stemUp=TRUE AND stemUp=FALSE THEN
a[k].y ← a[k].y + space*level;
IF a[k].stemUp=FALSE AND stemUp=TRUE THEN
a[k].y ← a[k].y - space*level;
yi ← a[k].y;
IF a[k].stemUp AND a[k].x+x0>=staffLength+8 OR
NOT a[k].stemUp AND a[k].x+x0>=staffLength
THEN yi ← a[k].y - lineHeight;
IF ~print AND AnyBug[] THEN RETURN[0, 0]; -- impatient user
WITH ev: b.chord[k] SELECT FROM
note => Note.Draw[ev.n, Real.FixI[yi]];
chord=> Chord.Draw[ev.c, Real.FixI[yi]];
beam=> [] ← Beam.Draw[ev.b];
ENDCASE;
ENDLOOP;
ENDLOOP;
level ← level+1;
ENDLOOP;
IF b.ntuple#0 AND ~(print AND b.invisible) THEN
{
string: STRING ← [10];
IF xn<x0 THEN xn ← xn+staffLength;
xi ← (x0+xn-10)/2;
y0 ← Real.FixI[y0+b.tilt*(xi-x0)+(IF stemUp THEN 4 ELSE -12)];
IF xi>staffLength THEN { xi ← xi-staffLength; y0 ← y0-lineHeight; };
MoveTo[context,[xi, y0]];
StringDefs.AppendDecimal[string, b.ntuple];
SELECT TRUE FROM
b.invisible => Graphics.SetTexture[context, grey];
inVoice => Graphics.SetTexture[context, black];
ENDCASE => Graphics.SetTexture[context, light];
SetFont[context, text, 12];
DrawString[context, string];
SetFont[context, music, 8];
};
RETURN[i, i];
};
BeamArray: TYPE = ARRAY [0..beamLength) OF BeamRecord;
BeamRecord: TYPE = RECORD[value: NoteValue, stemUp, dotted: BOOL, x, y: REAL];
DrawNTuple: PROC[b: BeamPTR] = {
inVoice: BOOL;
x, y, x1, y1: INTEGER;
height1, height2, i, j: INTEGER ← beamLength;
up0, upN: BOOL;
string: STRING ← [10];
IF print AND b.invisible THEN RETURN;
inVoice ← ~(voice AND NOT Beam.InVoice[b, selectedVoice]);
height1 ← b.height+Sheet.Height[0,, b.staff];
[x, y] ← Sheet.MapHeight[b.sync1.time, height1];
[x1,] ← Sheet.MapHeight[b.sync2.time, height1];
y1 ← Real.FixI[y+ b.tilt*(x1+12-x)];
height2 ← Real.FixI[height1+y1-y];
SELECT TRUE FROM
b.invisible => Graphics.SetTexture[context, grey];
inVoice => Graphics.SetTexture[context, black];
ENDCASE => Graphics.SetTexture[context, light];
DrawLine[x-2, y, x1+10, y1];
WITH n: b.chord[0] SELECT FROM
note => up0 ← (Sheet.Height[n.n.sync.time, n.n.pitch, n.n.staff]>height1);
chord=> up0 ← (Sheet.Height[n.c.note[0].sync.time, n.c.note[0].pitch, n.c.note[0].staff]>height1);
beam => up0 ← (n.b.height+Sheet.Height[n.b.sync1.time,, n.b.staff]>height1);
ENDCASE;
FOR i IN [0..beamLength)
DO IF b.chord[i]=endOfBeam THEN { j ← i; EXIT; };
ENDLOOP;
IF j#0 THEN j ← j-1;
WITH n: b.chord[j] SELECT FROM
note => upN ← (Sheet.Height[n.n.sync.time, n.n.pitch, n.n.staff]>height2);
chord=> upN ← (Sheet.Height[n.c.note[0].sync.time, n.c.note[0].pitch, n.c.note[0].staff]>height2);
beam => upN ← (n.b.height+Sheet.Height[n.b.sync1.time,, n.b.staff]>height2);
ENDCASE;
IF up0 THEN DrawLine[x-2, y, x-2, y+4]
ELSE DrawLine[x-2, y, x-2, y-4];
IF upN THEN DrawLine[x1+10, y1, x1+10, y1+4]
ELSE DrawLine[x1+10, y1, x1+10, y1-4];
FOR i IN [0..beamLength) DO
IF b.chord[i]=endOfBeam THEN EXIT;
WITH n: b.chord[i] SELECT FROM
note => Note.Draw[n.n];
chord=> Chord.Draw[n.c];
beam => [] ← Beam.Draw[n.b];
ENDCASE;
ENDLOOP;
MoveTo[context,[(x+x1)/2, y+b.tilt*(x1-x)/2+(IF up0 THEN -15 ELSE 5)]];
SELECT TRUE FROM
b.invisible => Graphics.SetTexture[context, grey];
inVoice => Graphics.SetTexture[context, black];
ENDCASE => Graphics.SetTexture[context, light];
StringDefs.AppendDecimal[string, b.ntuple];
SetFont[context, text, 12];
DrawString[context, string];
SetFont[context, music, 8];
};
DrawPhysicalBeam: PROC[b: BeamPTR] = {
i: CARDINAL;
FOR i IN [0..beamLength) DO
IF b.chord[i] = endOfBeam THEN EXIT;
WITH ev: b.chord[i] SELECT FROM
note => Note.Draw[ev.n];
chord=> Chord.Draw[ev.c];
beam => DrawPhysicalBeam[ev.b];
ENDCASE;
ENDLOOP;
};
DrawClippedRect: PROC[x0, y0, xn, yn, delta: REAL,
tilt: REAL, thickness, lineHeight: INTEGER] = {
xi: REAL ← xn;
yi: REAL ← yn;
clip: BOOL;
clip ← x0<staffLength AND xn>staffLength;
IF clip THEN { xi ← staffLength; yi ← y0 + tilt*(xi-x0); };
IF x0> staffLength THEN
{ y0 ← y0 - lineHeight; yi ← yi - lineHeight;
x0 ← x0 - staffLength+ delta;
xi ← xi - staffLength+ delta;
};
StartAreaPath[context];
EnterPoint[context,[x0, y0-thickness]];
EnterPoint[context,[x0, y0+thickness]];
EnterPoint[context,[xi+1, yi+thickness]];
EnterPoint[context,[xi+1, yi-thickness]];
DrawArea[context];
IF NOT clip THEN RETURN;
xi ← delta;
xn ← xn - staffLength+ delta;
yn ← yn - lineHeight;
yi ← yn - tilt*(xn-xi);
StartAreaPath[context];
EnterPoint[context,[xi, yi+thickness]];
EnterPoint[context,[xi, yi-thickness]];
EnterPoint[context,[xn+1, yn-thickness]];
EnterPoint[context,[xn+1, yn+thickness]];
DrawArea[context];
};
Drawn: PUBLIC PROC[b: BeamPTR] RETURNS[BOOL] = {
i: CARDINAL;
IF b=NIL THEN FOR i IN [0..3) DO beamQueue[i] ← NIL; ENDLOOP;
IF b=NIL THEN RETURN[FALSE];
FOR i IN [0..3) DO
IF beamQueue[i]=b THEN RETURN[TRUE]; ENDLOOP;
beamIndex ← beamIndex+1;
IF beamIndex = 3 THEN beamIndex ← 0;
beamQueue[beamIndex] ← b;
RETURN[FALSE];
};
beamQueue: ARRAY [0..3) OF BeamPTR;
beamIndex: CARDINAL ← 0;
END.