--Author: John Maxwell
--last modified: December 15, 1981 4:52 PM

DIRECTORY
Beam USING [SetStems],
Graphics USING [DisplayContext, DrawRectangle, GetTexture, MakeFont, MoveTo, Scale, SetLineWidth, SetPaint, SetTexture, Texture, Vec],
InlineDefs USING [LowHalf],
MusicDefs,
Piece USING [AddSync, RemoveSync],
Score USING [BuildCache, cache, cacheLength, DrawKey, Look],
Selection USING [AddLine],
Sheet USING [default, FindLine, FindSection, Map, NextLine, NormalPitch, OctavaHeight, PriorLine, Reset, SetBegin],
StringDefs USING [AppendDecimal],
Sync USING [GetScoreIndex, Hidden, SetStave],
Utility USING [DrawChar, DrawLine, DrawString, NewSync, SetFont];

SheetImplA:PROGRAM
IMPORTS Beam, Graphics, InlineDefs, MusicDefs, Piece, Score, Selection, Sheet, StringDefs, Sync, Utility
EXPORTS MusicDefs, Sheet =
BEGIN
OPEN MusicDefs, Score, Sheet;

begin
:PUBLIC Time;
endTime:PUBLIC Time;
scale,staffLength:PUBLIC INTEGER;

--****************************************************************************
--
the sheet consists of an array of Sections
--****************************************************************************

sheet
:PUBLIC ARRAY [0..sheetLength) OF Section;

Initialize:PUBLIC PROCEDURE[dc:Graphics.DisplayContext] =
BEGIN
context ← dc;
music ← Graphics.MakeFont["music"];
text ← Graphics.MakeFont["TimesRoman"];
Utility.SetFont[context,music,8];
style ← ALL[[NIL,0,0,0,[[0,0],[0,0],[0,0],[0,0]]]];
-- pianoroll
style[0] ← [NIL,0,60,3,,];
style[0].staff ←[[72,-32],[48,-88],[27,-136],[3,-196]];
-- one staff
style[1] ← [NIL,0,80,3,,];
style[1].staff ←[[48,-32],[48,-32],[48,-32],[48,-32]];
-- two staffs
style[2] ← [NIL,0,85,3,,];
style[2].staff ←[[48,-32],[48,-32],[27,-125],[27,-125]];
style[12] ← [NIL,0,85,3,,];
style[12].staff ←[[48,-32],[48,-32],[27,-150],[27,-150]];
-- three staffs
style[3] ← [NIL,0,75,3,,];
style[3].staff ←[[48,-32],[48,-32],[27,-110],[27,-185]];
style[13] ← [NIL,0,75,3,,];
style[13].staff ←[[48,-32],[48,-32],[27,-130],[27,-220]];
-- four staffs
style[4] ← [NIL,0,75,3,,];
style[4].staff ←[[48,-32],[48,-110],[27,-185],[27,-260]];
show ← [,TRUE,TRUE,FALSE,FALSE,TRUE,graphical];
selection ← ALL[NIL];
selectionLength ← 0;
begin ← 0;
scale ← 1;
staffLength ← 550;
TF ← 256;
Score.Look[sheet,,2];
Selection.AddLine[0,0];
END;

Reset:PUBLIC PROCEDURE=
BEGIN
sync:SyncPTR←NIL;
staves:StavesPTR←NIL;
page,pitch:INTEGER←2;
v,j,last,next:CARDINAL←0;
time,break,lastBreak,cacheTime:Time ← 0;
top,height,x,sc,lastHeight:INTEGER ← 0;
Score.BuildCache[];
IF scale=2 THEN sc←3 ELSE sc←2*scale;
[staves,last,next] ← NextStyle[NIL,0,0,100];
IF staves=NIL THEN RETURN;

FOR i:CARDINAL IN [0..cacheLength] DO
IF i#cacheLength AND cache[i].type NOT IN SheetSwitch THEN LOOP;
IF i=cacheLength
THEN cacheTime←LONG[staffLength]*sheetLength
ELSE cacheTime←cache[i].time;
WHILE time<cacheTime OR cacheTime=break DO -- fill in all of the sections between
IF j=sheetLength THEN EXIT;
sheet[j].page ← 0;
sheet[j].time ← time;
IF j#0 AND sheet[j].time=sheet[j-1].time
THEN sheet[j].key ← sheet[j-1].key
ELSE sheet[j].key ← Key[time,break];
IF time<break THEN x←x+InlineDefs.LowHalf[time-sheet[j-1].time];
IF time>=break THEN { -- new line
height ← height-lastHeight;
x← MAX[8,ABS[8*(sheet[j].key)]];
lastBreak ← break;
break ← lastBreak+staffLength-x;
[staves,last,next] ← NextStyle[staves,last,next,break-20];
lastHeight ← -staves.staff[staves.sl].y+staves.offset;
IF top-height>(650*sc)/2 THEN { -- new page
top ← height; sheet[j].page←page; page←page+1}};
sheet[j].x ← x;
sheet[j].y ← height;
sheet[j].staves ← staves;
time ← MIN[break,cacheTime];
j ← j + 1;
ENDLOOP;
IF i=cacheLength THEN EXIT;
IF cache[i].type=staves THEN LOOP;
Sync.SetStave[staves,cache[i]];
staves←LOOPHOLE[@cache[i].event];
IF cache[i].type#clef THEN LOOP;
IF Sync.Hidden[0,Sync.GetScoreIndex[cache[i]],lastBreak] THEN time←lastBreak;
ENDLOOP;
IF scale=2 THEN Paginate[];
Sheet.SetBegin[begin];
FOR i:CARDINAL IN [0..beamHeapLength) DO
IF beamHeap[i].sync2.time<min THEN LOOP;
IF beamHeap[i].sync1.time>max THEN LOOP;
Beam.SetStems[beamHeap[i]];
ENDLOOP;
END;

NextStyle:PROCEDURE[old:StavesPTR,last,next:CARDINAL, break:Time] RETURNS[StavesPTR,CARDINAL,CARDINAL] =
BEGIN
temp,new:StavesPTR;
newLast,newNext:CARDINAL←0;
new ← old;
newLast ← last;
newNext ← next;
FOR i:CARDINAL IN [next..cacheLength) DO
IF cache[i].time>=break+40 THEN EXIT;
IF cache[i].type#staves THEN LOOP;
newNext ← i;
IF cache[i].time>=break THEN EXIT;
temp ← LOOPHOLE[@cache[i].event];
IF temp=old THEN LOOP;
IF new#NIL AND i#next AND new.staff[new.sl].y<temp.staff[temp.sl].y THEN LOOP;
new ← temp;
newLast ← i;
ENDLOOP;
IF newLast=last AND old#NIL THEN RETURN[old,newLast,newNext];
Sync.SetStave[old,cache[newLast]];
RETURN[new,newLast,newNext];
END;

Key:PROCEDURE[time,break:Time] RETURNS[key:INTEGER←0] =
INLINE BEGIN
sync:SyncPTR←NIL;
FOR i:CARDINAL IN [0..cacheLength) DO
IF cache[i].time>=time+staffLength THEN EXIT;
IF cache[i].type#keySignature THEN LOOP;
IF cache[i].time<time THEN {key←cache[i].value; LOOP};
IF time=break THEN {sync←cache[i]; EXIT};
ENDLOOP;
IF sync=NIL THEN RETURN;
IF ~Sync.Hidden[0,Sync.GetScoreIndex[sync],break] THEN RETURN;
RETURN[sync.value];
END;

limit:INTEGER←1050;

Paginate:PROCEDURE =
BEGIN
min:INTEGER=75;
start:INTEGER=40;
page:CARDINAL←2;
height:INTEGER←-start;
line,last:CARDINAL←1;
count,first:CARDINAL←0;
FOR line←0,Sheet.NextLine[line] WHILE line#last DO
height ← height-sheet[line].staves.staff[3].y+min;
count ← count+1;
IF height<limit THEN {last←line; LOOP};
IF count#1 THEN {-- subtract out the last line
count←count-1;
height ← height+sheet[line].staves.staff[3].y-min};
-- layout the page
LayoutPage[count,first,line,limit+count*min-start-height];
sheet[line].page ← page;
page←page+1;
-- set up for next page
first←line; line←last;
count ← 0;
height ← -start;
ENDLOOP;
END;

LayoutPage:PROCEDURE[lines,first,last,space:CARDINAL] =
BEGIN
oldHeight,height:INTEGER←sheet[first].y;
-- layout this page
FOR i:CARDINAL IN (first..sheetLength) DO
IF sheet[i].y#oldHeight THEN {--new line
IF i>last THEN EXIT;
oldHeight←sheet[i].y;
height←sheet[i-1].y+sheet[i-1].staves.staff[3].y;
height←height-space/lines};
sheet[i].y←height;
sheet[i].page←0;
ENDLOOP;
END;

FindLine:PUBLIC PROCEDURE[t:Time] RETURNS[l:INTEGER] =
BEGIN
start:CARDINAL←0;
FOR i:CARDINAL IN [0..sheetLength-1) DO
IF sheet[i].time#sheet[i+1].time THEN {start←i; EXIT};
ENDLOOP;
l ← start;
FOR i:CARDINAL ←start, NextLine[i] DO
IF sheet[i].time<=t THEN l←i ELSE RETURN;
IF i=sheetLength-1 THEN RETURN;
ENDLOOP;
END;

FindSection:PUBLIC PROCEDURE[t:Time] RETURNS[INTEGER] =
BEGIN
IF t>=sheet[current].time
THEN BEGIN
IF current=sheetLength-1 THEN RETURN[current];
WHILE t>=sheet[current+1].time DO
current ← current+1;
IF current=sheetLength-1 THEN RETURN[current];
ENDLOOP;
RETURN[current];
END
ELSE BEGIN
WHILE current#0 AND t<sheet[current].time DO
current ← current -1;
ENDLOOP;
RETURN[current];
END;
END;

current:CARDINAL ← 0;

--****************************************************************************
--
procedures that change the staves attributes
--****************************************************************************

SetStyle:PUBLIC PROCEDURE[index:INTEGER,t1,t2:Time] =
BEGIN
old:INTEGER←-1;
temp,sync:SyncPTR←NIL;
endOfScore:Time=EndOfScore[];
IF index NOT IN [0..20] THEN {flash←TRUE; RETURN};
IF style[index].sl=0 THEN {flash←TRUE; RETURN};
SetDirty[begin,endTime];
sync← NearestMeasure[t1,10];
temp← NearestMeasure[t2,10];
IF sync#NIL THEN t1 ← sync.time+1;
IF temp#NIL THEN t2 ← temp.time-1;
--get the old style
FOR i:CARDINAL IN [0..cacheLength) DO
IF cache[i].type#staves THEN LOOP;
IF cache[i].time>=t1-1 THEN EXIT;
old ← cache[i].value;
ENDLOOP;
--change all of the current staves to the new style
FOR i:CARDINAL DECREASING IN [0..cacheLength) DO
IF cache[i].time>t2 THEN LOOP;
IF cache[i].time<t1-5 THEN EXIT;
IF cache[i].type#staves THEN LOOP;
cache[i].value←index;
ENDLOOP;
--insert new staves
IF old#index THEN {
IF sync#NIL THEN Piece.RemoveSync[score,sync];
IF sync=NIL THEN {sync←Utility.NewSync[]; sync.time←t1};
sync.type ← staves;
sync.value ← index;
sync.event ← LOOPHOLE[style[index]];
Piece.AddSync[score,sync]};
IF old#index AND old#-1 AND t2#endOfScore THEN {
IF temp#NIL THEN Piece.RemoveSync[score,temp];
IF temp=NIL THEN {temp←Utility.NewSync[]; temp.time←t2};
temp.type ← staves;
temp.value ← old;
temp.event ← LOOPHOLE[style[old]];
Piece.AddSync[score,temp]};
--reset world
Sheet.Reset[];
Sheet.SetBegin[begin];
FOR i:CARDINAL IN [0..beamHeapLength) DO
Beam.SetStems[beamHeap[i]];
ENDLOOP;
Selection.AddLine[t1,t2];
END;

NearestMeasure:PROCEDURE[time,delta:Time] RETURNS[SyncPTR] =
BEGIN
s:SyncPTR ← NIL;
FOR i:CARDINAL IN [0..scoreLength) DO
IF score[i].type#measure AND score[i].type#staves THEN LOOP;
IF ABS[score[i].time-time]>delta THEN LOOP;
delta ← ABS[score[i].time-time];
s ← score[i];
ENDLOOP;
RETURN[s];
END;

style:PUBLIC ARRAY [0..20] OF Staves;

GetStyle:PUBLIC PROCEDURE[time:Time] RETURNS[INTEGER] =
BEGIN
equal:BOOLEAN;
staves:StavesPTR = sheet[Sheet.FindLine[time]].staves;
IF staves=NIL THEN RETURN[-1];
FOR i:CARDINAL IN [0..20] DO
IF style[i].sl#staves.sl THEN LOOP;
equal←TRUE;
FOR j:CARDINAL IN [0..style[i].sl] DO
IF style[i].staff[j].y#staves.staff[j].y THEN {equal←FALSE; EXIT};
ENDLOOP;
IF equal THEN RETURN[i];
ENDLOOP;
RETURN[-1];
END;

--****************************************************************************
--
clefs switches
--****************************************************************************

SetClef
:PUBLIC PROCEDURE[pitch,staff:INTEGER,time:Time] =
BEGIN
s:SyncPTR←NIL;
staves:StavesPTR;
--make up a sync
s ← Utility.NewSync[];
staves ← LOOPHOLE[@s.event];
staves↑ ← sheet[Sheet.FindSection[time]].staves↑;
staves.staff[staff].pitch ← pitch;
s.type ← clef;
s.time ← time;
s.value ← staff;
Piece.AddSync[score,s];
Sheet.Reset[];
END;

DrawClef:PUBLIC PROCEDURE[pitch,staff:INTEGER,time:Time] =
BEGIN
x,y:INTEGER;
l:CARDINAL←Sheet.FindLine[time];
IF time IN (sheet[l].time..sheet[l].time+15] THEN time←sheet[l].time;
[x,y] ← Sheet.Map[time,,staff];
IF sheet[l].time=time THEN x←-21;
Graphics.MoveTo[context,[x,y+16]];
IF voice THEN Graphics.SetTexture[context,light];
SELECT TRUE FROM
x=-21 AND pitch=27 => Utility.DrawChar[context,121C];
x=-21 AND pitch=48 => Utility.DrawChar[context,120C];
pitch=27 => Utility.DrawChar[context,131C];
pitch=48 => Utility.DrawChar[context,130C];
ENDCASE;
END;

--****************************************************************************
--
octava
--****************************************************************************

SetOctava
:PUBLIC PROCEDURE[pitch,staff,height:INTEGER,t1,t2:Time] =
BEGIN
s:SyncPTR←NIL;
current:INTEGER;
section:CARDINAL;
staves:StavesPTR;
normal:INTEGER = Sheet.NormalPitch[staff];
IF t1>=t2 THEN RETURN;
--check to make sure that the staff is clear
FOR i:CARDINAL IN [0..cacheLength) DO
IF cache[i].time<t1 THEN LOOP;
IF cache[i].time>t2 THEN EXIT;
IF cache[i].type NOT IN SheetSwitch THEN LOOP;
staves ← LOOPHOLE[@cache[i].event];
current ← staves.staff[staff].pitch;
IF current=normal THEN LOOP;
flash ← TRUE; RETURN;
ENDLOOP;
section ← Sheet.FindSection[t1];
IF sheet[section].staves.staff[staff].pitch#normal THEN {flash←TRUE; RETURN};
--add the first sync
s ← Utility.NewSync[];
staves ← LOOPHOLE[@s.event];
staves↑ ← sheet[section].staves↑;
staves.staff[staff].pitch ← pitch;
staves.height ← Sheet.OctavaHeight[pitch,height];
s.type ← octava1;
s.time ← t1;
s.value ← staff;
Piece.AddSync[score,s];
--add the second sync
s ← Utility.NewSync[];
staves ← LOOPHOLE[@s.event];
staves↑ ← sheet[Sheet.FindSection[t2]].staves↑;
staves.staff[staff].pitch ← normal;
s.type ← octava2;
s.time ← t2;
s.value ← staff;
Piece.AddSync[score,s];
Sheet.Reset[];
END;

DrawOctava
:PUBLIC PROCEDURE[pitch,staff,height:INTEGER,t1,t2:Time] =
BEGIN
x1,x2,y:INTEGER←0;
section1,section2:CARDINAL;
IF t1>t2 THEN RETURN;
IF pitch#60 AND pitch#15 THEN RETURN;
height ← Sheet.OctavaHeight[pitch,height];
Utility.SetFont[context,text,12];
section1 ← Sheet.FindSection[t1];
section2 ← Sheet.FindSection[t2];
IF voice THEN Graphics.SetTexture[context,light];
FOR i:CARDINAL IN [section1..section2] DO
IF i+1=sheetLength THEN EXIT;
IF sheet[i].time<begin THEN LOOP;
IF sheet[i].time>=endTime THEN EXIT;
IF sheet[i].time=sheet[i+1].time THEN LOOP;
[x1,] ← Sheet.Map[MAX[t1,sheet[i].time],,staff];
[x2,y] ← Sheet.Map[MIN[t2,sheet[i+1].time-1],,staff];
IF x1>staffLength-15 AND i=section1 THEN LOOP;
x2←x2+1; y ← y+height;
IF x1<10 OR i=section1 THEN BEGIN
Graphics.MoveTo[context,[x1,y-8]];
Utility.DrawChar[context,’8];
x1 ← x1+7; END;
IF x1<x2 THEN DrawDottedLine[x1,y,x2,y];
IF i=section2 THEN Utility.DrawLine[x2,y,x2,y-(IF height>0 THEN 7 ELSE -7)];
ENDLOOP;
Utility.SetFont[context,music,8];
END;

DrawDottedLine:PROCEDURE[x1,y,x2,y2:INTEGER] =
INLINE BEGIN
x:INTEGER;
IF NOT print THEN BEGIN
Graphics.SetTexture[context,146314B];
Utility.DrawLine[x1,y,x2,y];
Graphics.SetTexture[context,black];
RETURN; END;
x←x1;
WHILE x<x2 DO
Utility.DrawLine[x,y,MIN[x+3,x2],y];
x ← x+5;
ENDLOOP;
END;
--****************************************************************************
--
drawing the sheet
--****************************************************************************

HiLite:PUBLIC PROCEDURE[tex:Graphics.Texture,t1,t2:Time] =
BEGIN
OPEN Graphics;
x1,y1,x2,y2,lastY:INTEGER;
v1,v2:Graphics.Vec;
offset:INTEGER ← IF tex=white THEN 58 ELSE 40;
section1,section2,i,j:CARDINAL;
IF t1 >= t2 THEN RETURN;
--EnableClipping[context];
Graphics.SetPaint[context,IF tex=white THEN replace ELSE invert];
Graphics.SetTexture[context,tex];
i ← Sheet.FindLine[t1];
j ← Sheet.PriorLine[i];
IF i=j THEN lastY←100 ELSE lastY←sheet[j].y;
j ← section1 ← FindSection[t1];
section2 ← FindSection[t2];
FOR i IN [section1..section2] DO
IF sheet[i].time>endTime THEN EXIT;
IF i#section2 AND sheet[i].time=sheet[i+1].time THEN LOOP;
IF tex#white AND i#section2 AND sheet[i].y=sheet[i+1].y THEN LOOP;
offset ← sheet[i].staves.offset;
IF tex=white THEN offset←offset/2 ELSE offset←offset/4;
[x1,y1] ← Sheet.Map[MAX[t1,sheet[j].time],,0];
[x2,y2] ← Sheet.Map[MIN[t2,sheet[i+1].time-1],,sheet[i].staves.sl];
y1 ← y1+offset+34; y2 ← y2-offset;
IF x2<staffLength-1 OR tex=white THEN x2←x2+1 ELSE x2←x2+16;
IF tex=white AND sheet[i].y#lastY AND x1=sheet[i].x THEN x1←-25;
lastY ← sheet[i].y;
v1 ← [x1,y1]; v2 ← [x2,y2];
IF tex=white THEN SetBrush[white,replace];
Graphics.DrawRectangle[context,v1,v2];
IF tex=white THEN DrawStaves[sheet[i],x1,x2];
j ← i+1;
ENDLOOP;
--EnableClipping[context];
Graphics.SetPaint[context,paint];
END;

Draw
:PUBLIC PROCEDURE =
BEGIN
x:INTEGER;
j:CARDINAL;
staves:StavesPTR = sheet[0].staves;
sheetHeight:INTEGER = staves.staff[staves.sl].y;
IF begin=0 THEN Utility.DrawLine[-23,0,-23,sheetHeight];
endTime ← begin;
IF scale=2 THEN x←3 ELSE x←2*scale;

FOR j ← Sheet.FindLine[begin], Sheet.NextLine[j] DO
IF sheet[j].y-top<(-650*x)/2 THEN {endTime←sheet[j].time; EXIT};
DrawStaves[sheet[j],-25,staffLength];
ENDLOOP;
END;

DrawStaves:PROCEDURE[l:Section,start,length:INTEGER] =
BEGIN
sheetHeight:INTEGER ← l.staves.staff[l.staves.sl].y;
i:CARDINAL;
y:INTEGER ← l.y-top;
oldStaff ← [0,0];
Graphics.SetTexture[context,black];
IF start=-25 THEN Utility.DrawLine[start,y,start,y+sheetHeight];
IF start=-25 AND show.accidental THEN Score.DrawKey[l.key,l.time];
IF l.page>1 THEN BEGIN
s:STRING ← [5];
StringDefs.AppendDecimal[s,l.page];
Graphics.MoveTo[context,[staffLength+10,y+30]];
Utility.SetFont[context,text,12];
Utility.DrawString[context,s];
Utility.SetFont[context,music,8];
END;
IF scale>3 THEN
BEGIN
Graphics.SetLineWidth[context,8];
IF length=staffLength THEN Utility.DrawLine[length,y,length,y+sheetHeight];
IF NOT show.notehead THEN Graphics.SetTexture[context,grey];

Utility.DrawLine[start,y,length,y];
Utility.DrawLine[start,y+sheetHeight,length,y+sheetHeight];
Graphics.SetTexture[context,black];
Graphics.SetLineWidth[context,4];
END
ELSE FOR i IN [0..l.staves.sl] DO
DrawStaff[l.staves.staff[i],y,start,length]
ENDLOOP;
END;

DrawStaff: PROCEDURE[s:Staff,y,start,length:INTEGER] =
BEGIN
w:REAL←1;
ll,ur:Graphics.Vec;
i:CARDINAL;
tex:Graphics.Texture ← Graphics.GetTexture[context];
IF s=oldStaff THEN RETURN;
oldStaff ← s;
y ← y + s.y;
Graphics.SetTexture[context,IF show.notehead THEN black ELSE grey];
IF print THEN w←w/2;
ll ← [start,y-w];
ur ←[length,y+w];
FOR i IN [0..5) DO
Graphics.DrawRectangle[context,ll,ur];
ll.y ← ll.y+8;
ur.y ← ur.y+8;
ENDLOOP;
Graphics.SetTexture[context,black];
IF start<0 THEN Graphics.SetPaint[context,paint];
IF (s.pitch=27 OR s.pitch=15) AND start<0 THEN {
Graphics.MoveTo[context,[-21,y+16]];
Utility.DrawChar[context,121C]};
IF (s.pitch=48 OR s.pitch=60) AND start<0 THEN {
Graphics.MoveTo[context,[-21,y+16]];
Utility.DrawChar[context,120C]};
Graphics.SetTexture[context,tex];
END;

oldStaff:Staff;
d:CARDINAL = 8;

--****************************************************************************
--
changing the view on the sheet
--****************************************************************************

top:PUBLIC INTEGER ← 0;

SetBegin:PUBLIC PROCEDURE[now:Time] =
BEGIN
l:Section ← sheet[Sheet.FindLine[now]];
begin ← l.time;
top ← l.y;
END;

Scroll:PUBLIC PROCEDURE[lines:INTEGER] =
BEGIN
section:CARDINAL←Sheet.FindLine[begin];
IF lines<0
THEN FOR i:CARDINAL IN [0..ABS[lines]) DO
IF section=0 THEN EXIT;
section ← Sheet.PriorLine[section];
ENDLOOP
ELSE FOR i:CARDINAL IN [0..ABS[lines]) DO
section ← Sheet.NextLine[section];
IF section=sheetLength THEN RETURN;
ENDLOOP;
Sheet.SetBegin[sheet[section].time];
min ← 0; max ← EndOfScore[];
END;

Scale:PUBLIC PROCEDURE[newScale:INTEGER] =
BEGIN
one:REAL = 1;
two:REAL = 2;
IF scale=newScale THEN RETURN;
--reset to 1
SELECT scale FROM
2 => Graphics.Scale[context,[3/two,3/two]];
4 => Graphics.Scale[context,[4,4]];
ENDCASE;
staffLength ← 550;
--now move to the desired scale
SELECT newScale FROM
1 => {scale ← 1;
staffLength ← staffLength;
Graphics.SetLineWidth[context,1]};
2 => {scale ← 2; --
actually 3/2
staffLength ← (3*staffLength)/2;
Graphics.Scale[context,[two/3,two/3]];
Graphics.SetLineWidth[context,2]};
4 => {scale ← 4;
staffLength ← 4*staffLength;
Graphics.Scale[context,[one/4,one/4]];
Graphics.SetLineWidth[context,4]};
ENDCASE;
Sheet.Reset[];
Sheet.SetBegin[begin];
min ← 0; max ← EndOfScore[];
END;

END..