<> <> <> <> <> 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; <<****************************************************************************>> <> <<****************************************************************************>> Draw: PUBLIC PROC[b: BeamPTR] RETURNS[INTEGER, INTEGER] = { start: Time; a: BeamArray; slope: REAL _ 5; i, end: CARDINAL; inVoice: BOOL; nonGrace: BOOL _ FALSE; 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: BOOL _ FALSE; 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; <> 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; <> 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=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 {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 xnstaffLength 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 _ x0staffLength; 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.