--Author: John Maxwell --last modified: December 15, 1981 4:06 PM DIRECTORY CursorDefs, Beam USING [Draw,SetStems], Graphics USING [DrawScreenArea, SetPaint, SetTexture], Interface USING [InsertNote, Object], MusicDefs, Note USING [Draw, DrawTie, SetAccidental, SetEmbellishment], Piece USING [AddSync, DeleteSync, NearestNote, NearestObject, RemoveSync], ProcessDefs USING [SetTimeout], Real USING [FixI], Score USING [GetKey, Redraw], Selection, -- USING everything Sheet USING [AlternateTime, DrawClef, DrawOctava, FindLine, FindSection, GetStyle, Height, NearestStaff, NearestTime, NextLine, NextStaff, NormalPitch, OctavaHeight, PriorStaff, Reset, ScreenPoint, SetClef, SetOctava], Sync USING [Draw, GetScoreIndex, GetStaff, Octava], Utility; -- USING everything InterfaceImplB:MONITOR IMPORTS Beam, Graphics, Interface, MusicDefs, Note, Piece, ProcessDefs, Real, Score, Selection, Sheet, Sync, Utility EXPORTS Interface = BEGIN OPEN Graphics, MusicDefs; timeout:CONDITION; Error:SIGNAL = CODE; --****************************************************************** --deleting objects --****************************************************************** count:PUBLIC BOOLEAN; DeleteGraphical:PUBLIC PROCEDURE = BEGIN type:EventType; obj:ObjectType; s:SyncPTR_NIL; time,carry,next:Time; p:UnspecifiedPTR_NIL; value,oldClef,oldStyle:INTEGER_0; SetBrush[black,invert]; WHILE YellowBug[] DO [obj,p] _ Piece.NearestObject[]; IF p#NIL THEN SELECT obj FROM note => Note.Draw[p]; measure => Sync.Draw[p]; leftBeam => []_Beam.Draw[p]; rightBeam=> []_Beam.Draw[p]; ENDCASE; Wait[1]; IF p#NIL THEN SELECT obj FROM note => Note.Draw[p]; measure => Sync.Draw[p]; leftBeam => []_Beam.Draw[p]; rightBeam=> []_Beam.Draw[p]; ENDCASE; ENDLOOP; IF p#NIL AND obj=note THEN Selection.RemoveNote[p]; IF obj#measure OR p=NIL THEN RETURN; s _ LOOPHOLE[p,SyncPTR]; IF voice AND s.type IN [clef..octava2] THEN RETURN; type _ s.type; time _ s.time; value _ s.value; IF type=clef THEN oldClef _ Clef[value,time]; --IF type=staves THEN y _ sheet[Sheet.FindLine[time]].y; IF type=staves THEN { next _ sheet[Sheet.NextLine[Sheet.FindLine[time]]].time; oldStyle _ Sheet.GetStyle[next]}; carry _ GetCarry[s]; Piece.DeleteSync[s]; SetDirty[time,time]; IF type=keySignature THEN SetDirty[time,carry]; IF type=keySignature OR type=clef THEN ResetSheet[time,time]; IF type=clef AND oldClef#Clef[value,time] THEN SetDirty[time,carry]; IF type=staves THEN { Sheet.Reset[]; IF Sheet.GetStyle[time]#value THEN SetDirty[begin,endTime]; IF Sheet.GetStyle[next]#oldStyle THEN SetDirty[begin,endTime]}; -- IF sheet[Sheet.FindLine[time]].y#y THEN SetDirty[begin,endTime]}; IF type IN [octava1..octava2] THEN Sheet.Reset[]; Score.Redraw[min,max]; count_TRUE; END; ChangeSpelling:PROCEDURE[object:Interface.Object] = BEGIN n:NotePTR; min _1000000; max _ -1; SetBrush[black,invert]; WHILE BlueBug[] DO IF (n_Piece.NearestNote[])=NIL THEN LOOP; Note.Draw[n]; Note.Draw[n]; ENDLOOP; SetBrush[black,paint]; IF n=NIL OR n.rest THEN RETURN; IF voice AND n.voice#selectedVoice THEN RETURN; SELECT object FROM doubleFlat => Note.SetAccidental[n,doubleFlat]; flat => Note.SetAccidental[n,flat]; natural => Note.SetAccidental[n,natural]; inKey => Note.SetAccidental[n,inKey]; sharp => Note.SetAccidental[n,sharp]; doubleSharp=> Note.SetAccidental[n,doubleSharp]; ENDCASE; IF flash THEN {Flash[]; RETURN}; IF n.spelled#inKey THEN n.show_TRUE ELSE n.show_FALSE; Score.Redraw[min,max]; END; Embellish:PROCEDURE[object:Interface.Object] = BEGIN x,y:INTEGER; n:NotePTR_NIL; min _1000000; max _ -1; SetBrush[black,invert]; WHILE BlueBug[] DO [x,y] _ Sheet.ScreenPoint[]; IF (n _ Piece.NearestNote[x,y])=NIL THEN LOOP; Note.Draw[n]; Note.Draw[n]; ENDLOOP; SetBrush[black,paint]; IF n=NIL OR n.rest THEN RETURN; SELECT object FROM trill => Note.SetEmbellishment[n,trill]; mordent1 => Note.SetEmbellishment[n,mordent1]; mordent2 => Note.SetEmbellishment[n,mordent2]; ENDCASE; Score.Redraw[min,max]; END; --****************************************************************** --inserting objects --****************************************************************** Insert:PROCEDURE[object:Interface.Object] = BEGIN OPEN CursorDefs; tempCursor:Cursor _ cursor^; cursor^ _ ALL[0]; SELECT object FROM staves,measure,repeat1,repeat2,doubleMeasure,endMeasure => InsertMeasure[object]; bass,treble => InsertClefChange[object]; octava => {cursor^ _ tempCursor; InsertOctava[object]}; doubleFlat,flat,natural,inKey,sharp,doubleSharp => ChangeSpelling[object]; trill,mordent1,mordent2 => Embellish[object]; note,rest => Interface.InsertNote[object]; ENDCASE => ERROR; cursor^ _ tempCursor; count _ TRUE; END; InsertMeasure: PROCEDURE[object:Interface.Object] = BEGIN x,y:INTEGER; s:SyncPTR _ Utility.NewSync[]; SELECT object FROM measure => s.type _ measure; staves => s.type _ staves; repeat1 => s.type _ repeat1; repeat2 => s.type _ repeat2; endMeasure => s.type _ endMeasure; doubleMeasure => s.type _ doubleMeasure; ENDCASE => ERROR; [x,y] _ Sheet.ScreenPoint[]; [s.time,] _ Sheet.NearestTime[x,y]; SetBrush[black,invert]; WHILE BlueBug[] DO Sync.Draw[s]; Sync.Draw[s]; [x,y] _ Sheet.ScreenPoint[]; [s.time,] _ Sheet.NearestTime[]; ENDLOOP; IF YellowBug[] THEN RETURN; IF object=staves THEN { s.value _ Sheet.GetStyle[s.time]; LOOPHOLE[s.event,Staves] _ style[s.value]}; Piece.AddSync[score,s]; SetDirty[s.time,s.time]; Score.Redraw[min,max]; END; InsertClefChange: PROCEDURE[object:Interface.Object] = BEGIN old,new:Section; sync:SyncPTR_NIL; pitch,height:INTEGER; oldTime,newTime:Time_0; change:BOOLEAN_FALSE; oldStaff,newStaff,oldClef:INTEGER_10; SELECT object FROM bass => pitch _ 27; treble => pitch _ 48; ENDCASE => Error; SetBrush[black,invert]; [newTime,height] _ Sheet.NearestTime[]; newStaff _ Sheet.NearestStaff[newTime,height]; WHILE BlueBug[] DO [newTime,height] _ Sheet.NearestTime[]; newStaff _ Sheet.NearestStaff[newTime,height]; IF newTime=oldTime AND newStaff=oldStaff THEN LOOP; IF oldStaff#10 THEN Sheet.DrawClef[pitch,oldStaff,oldTime]; Sheet.DrawClef[pitch,newStaff,newTime]; oldTime _ newTime; oldStaff _ newStaff; ENDLOOP; Sheet.DrawClef[pitch,newStaff,newTime]; IF YellowBug[] THEN RETURN; old _ sheet[Sheet.FindLine[newTime]]; oldClef _ Clef[newStaff,newTime]; Sheet.SetClef[pitch,newStaff,newTime]; new _ sheet[Sheet.FindLine[newTime]]; IF flash THEN {Flash[]; RETURN}; IF old#new THEN SetDirty[new.time,new.time]; -- how much of the score does this affect? SetDirty[newTime,newTime]; IF pitch=oldClef THEN {Score.Redraw[min,max]; RETURN}; FOR i:CARDINAL IN [0..scoreLength) DO IF score[i].time#newTime THEN LOOP; IF score[i].type#clef THEN LOOP; IF score[i].value#newStaff THEN LOOP; sync_score[i]; EXIT; ENDLOOP; IF sync#NIL THEN SetDirty[sync.time,GetCarry[sync]]; Score.Redraw[min,max]; END; InsertOctava: PROCEDURE[object:Interface.Object] = BEGIN begin,end,oldEnd:Time_ -1; staff,oldStaff,alternate:INTEGER_1; pitch,height,oldHeight,octHeight,limit:INTEGER_0; SetBrush[black,invert]; [begin,oldHeight] _ Sheet.NearestTime[]; staff _ Sheet.NearestStaff[begin,oldHeight]; WHILE BlueBug[] DO [end,height,staff] _ Slide[oldEnd,oldHeight,oldStaff]; IF end=oldEnd AND height=oldHeight THEN LOOP; -- WE HAVE A MOVEMENT IF oldEnd#-1 THEN Sheet.DrawOctava[pitch,oldStaff,octHeight,begin,oldEnd]; oldEnd _ end; oldStaff _ staff; oldHeight _ height; octHeight _ height - Sheet.Height[end,,staff]; pitch _ (IF Sheet.NormalPitch[staff]=27 THEN 15 ELSE 60); Sheet.DrawOctava[pitch,staff,octHeight,begin,end]; ENDLOOP; Sheet.DrawOctava[pitch,staff,octHeight,begin,end]; IF YellowBug[] THEN RETURN; IF begin>=end THEN RETURN; Sheet.SetOctava[pitch,staff,octHeight,begin,end]; IF flash THEN {Flash[]; RETURN}; Score.Redraw[begin,end]; END; Slide:PROCEDURE[oldTime:Time,oldHeight:INTEGER,oldStaff:CARDINAL] RETURNS[time:Time,height:INTEGER,staff:CARDINAL] = BEGIN limit:INTEGER; staves:StavesPTR; staff _ oldStaff; [time,height] _ Sheet.NearestTime[]; IF oldTime#-1 AND ABS[time-oldTime]>200 AND time>oldTime THEN [time,height] _ Sheet.AlternateTime[time,height,-1]; IF oldTime#-1 AND ABS[time-oldTime]>200 AND time= limit THEN { -- we went above an upper limit IF staff=oldStaff THEN { -- must be last line [time,height] _ Sheet.AlternateTime[time,height,-1]; staff _ staves.sl}; RETURN}; staff _ oldStaff; END; --****************************************************************** --moving things --****************************************************************** MoveGraphical:PUBLIC PROCEDURE[object:Interface.Object] = BEGIN s:SyncPTR; p:UnspecifiedPTR_NIL; obj:ObjectType; IF object#none THEN BEGIN Insert[object]; RETURN; END; SetBrush[black,invert]; WHILE BlueBug[] DO [obj,p] _ Piece.NearestObject[]; IF p=NIL THEN LOOP; s _ LOOPHOLE[p]; IF voice AND s.type IN [clef..octava2] THEN LOOP; SELECT obj FROM measure => { IF s.type IN [octava1..octava2] THEN MoveOctava[s] ELSE MoveMeasure[s]}; leftBeam => MoveBeam[p]; rightBeam=> ChangeTilt[p]; tie=> MoveTie[p]; ENDCASE; ENDLOOP; IF p#NIL THEN count_TRUE; END; MoveMeasure:PROCEDURE[s:SyncPTR] = BEGIN old:Time=s.time; SetBrush[black,invert]; SetDirty[s.time,s.time]; WHILE BlueBug[] DO Sync.Draw[s]; s.time _ Sheet.NearestTime[].time; Sync.Draw[s]; ENDLOOP; Sync.Draw[s]; SetDirty[s.time,s.time]; SELECT s.type FROM clef => MoveClef[s,old,s.time]; staves => MoveStaves[s,old,s.time]; keySignature => MoveKey[s,old,s.time]; ENDCASE => {Piece.RemoveSync[score,s]; Piece.AddSync[score,s]}; Score.Redraw[min,max]; END; MoveClef:PROCEDURE[s:SyncPTR,old,new:Time] = BEGIN oldCarry:Time; time:Time=s.time; newClef,clef:INTEGER; newClef_Clef[s.value,s.time]; s.time _ old; oldCarry _ GetCarry[s]; s.time _ new; Piece.RemoveSync[score,s]; Piece.AddSync[score,s]; ResetSheet[min,max]; clef_Sync.GetStaff[s,s.value].pitch; IF clef#newClef THEN SetDirty[new,GetCarry[s]]; IF clef#Clef[s.value,old] THEN SetDirty[old,oldCarry]; END; MoveStaves:PROCEDURE[s:SyncPTR,old,new:Time] = BEGIN next:Time; nextStyle,oldStyle,newStyle:INTEGER; next _ sheet[Sheet.NextLine[Sheet.FindLine[MAX[old,new]]]].time; nextStyle _ Sheet.GetStyle[next]; -- y _ sheet[Sheet.FindLine[old]].y; oldStyle _ Sheet.GetStyle[old]; newStyle _ Sheet.GetStyle[new]; s.time _ new; Piece.RemoveSync[score,s]; Piece.AddSync[score,s]; Sheet.Reset[]; IF nextStyle#Sheet.GetStyle[next] THEN SetDirty[begin,endTime]; IF oldStyle#Sheet.GetStyle[old] THEN SetDirty[begin,endTime]; IF newStyle#Sheet.GetStyle[new] THEN SetDirty[begin,endTime]; END; MoveKey:PROCEDURE[s:SyncPTR,old,new:Time] = BEGIN oldCarry:Time; newKey:INTEGER; s.time _ old; oldCarry _ GetCarry[s]; newKey _ Score.GetKey[new]; s.time _ new; Piece.RemoveSync[score,s]; Piece.AddSync[score,s]; ResetSheet[min,max]; IF new>old AND newKey#s.value THEN SetDirty[new,GetCarry[s]]; IF new=octava2.time THEN { Piece.DeleteSync[octava1]; -- deletes octava2 as well Score.Redraw[min,max]; RETURN}; Piece.RemoveSync[score,s]; Piece.AddSync[score,s]; -- Remove/Add keeps the score sorted Sheet.Reset[]; Score.Redraw[min,max]; END; MoveBeam:PROCEDURE[b:BeamPTR] = BEGIN height,y:INTEGER_0; SetBrush[black,invert]; y _ MouseY^; WHILE BlueBug[] DO height_b.height+(y-MouseY^); IF height=b.height THEN LOOP; [] _ Beam.Draw[b]; b.height_height; y_MouseY^; Beam.SetStems[b]; [] _ Beam.Draw[b]; ENDLOOP; Score.Redraw[b.sync1.time,b.sync2.time]; END; ChangeTilt:PROCEDURE[b:BeamPTR] = BEGIN height,oldHeight,y:INTEGER_0; l:REAL _ 1; SetBrush[black,invert]; oldHeight _ b.height + Real.FixI[b.tilt*(b.sync2.time-b.sync1.time)]; y _ MouseY^; WHILE BlueBug[] DO height_oldHeight+(y-MouseY^); IF height=oldHeight THEN LOOP; [] _ Beam.Draw[b]; b.tilt_l*(height-b.height)/(b.sync2.time-b.sync1.time); oldHeight _ height; y_MouseY^; Beam.SetStems[b]; [] _ Beam.Draw[b]; ENDLOOP; Score.Redraw[b.sync1.time,b.sync2.time]; END; MoveTie:PROCEDURE[n:NotePTR] = BEGIN y:INTEGER; time:Time; time _ (n.sync.time+n.tie.sync.time)/2; y _ MouseY^; SetBrush[black,invert]; WHILE BlueBug[] DO IF y=MouseY^ THEN LOOP; Note.DrawTie[n]; n.tieHeight _ n.tieHeight+(y-MouseY^); y _ MouseY^; Note.DrawTie[n]; ENDLOOP; Score.Redraw[n.tie.sync.time,n.sync.time]; END; --****************************************************************** --utility procedures --****************************************************************** ResetSheet:PROCEDURE[t1,t2:Time] = BEGIN line:CARDINAL; old1,old2:Section; new1,new2:Section; -- get state before reset line _ Sheet.FindLine[MIN[t1,t2]]; old1 _ sheet[line]; line _ Sheet.NextLine[line]; old2 _ sheet[line]; Sheet.Reset[]; -- get state after reset line _ Sheet.FindLine[MIN[t1,t2]]; new1 _ sheet[line]; line _ Sheet.NextLine[line]; new2 _ sheet[line]; -- compare before and after IF old1#new1 THEN SetDirty[new1.time,new1.time+15]; IF old2#new2 THEN SetDirty[new2.time,new2.time+15]; IF old1.key#new1.key THEN SetDirty[begin,endTime]; IF old2.key#new2.key THEN SetDirty[begin,endTime]; END; GetCarry:PROCEDURE[s:SyncPTR] RETURNS[Time] = BEGIN index:CARDINAL; IF s.type#clef AND s.type#keySignature THEN RETURN[s.time]; -- is this insertion/deletion a NOOP? IF s.type=keySignature AND Score.GetKey[s.time-1]=s.value THEN RETURN[s.time]; index_Sync.GetScoreIndex[s]; IF s.type=clef THEN FOR i:CARDINAL IN (index..scoreLength] DO IF i=scoreLength THEN RETURN[endTime]; IF score[i].type NOT IN SheetSwitch THEN LOOP; IF score[i].type = staves AND ~Similar[s,score[i]] THEN RETURN[score[i].time]; IF score[i].type = staves THEN LOOP; IF Sync.GetStaff[score[i],score[i].value].y#Sync.GetStaff[s,s.value].y THEN LOOP; RETURN[score[i].time]; ENDLOOP; IF s.type=keySignature THEN FOR i:CARDINAL IN (index..scoreLength] DO IF i=scoreLength THEN RETURN[endTime]; IF score[i].type # keySignature THEN LOOP; RETURN[score[i].time]; ENDLOOP; RETURN[s.time]; END; Similar:PROCEDURE[s1,s2:SyncPTR] RETURNS[BOOLEAN] = BEGIN n,o:BOOLEAN; oldS,newS:StavesPTR; oldS _ LOOPHOLE[@s1.event]; newS _ LOOPHOLE[@s2.event]; IF oldS.sl#newS.sl THEN RETURN[FALSE]; FOR i:CARDINAL IN [1..newS.sl] DO n _ newS.staff[i].y=newS.staff[i-1].y; o _ oldS.staff[i].y=oldS.staff[i-1].y; IF n#o THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; END; Clef:PROCEDURE[staff:CARDINAL,time:Time] RETURNS[INTEGER] = BEGIN staves:StavesPTR = sheet[Sheet.FindSection[time]].staves; RETURN[staves.staff[staff].pitch]; END; Flash:PUBLIC PROCEDURE = BEGIN SetBrush[black,invert]; Graphics.DrawScreenArea[context]; Wait[1]; Graphics.DrawScreenArea[context]; flash _ FALSE; END; Wait:PUBLIC ENTRY PROCEDURE[ticks:CARDINAL] = BEGIN FOR i:CARDINAL IN [0..ticks) DO WAIT timeout; ENDLOOP; END; ProcessDefs.SetTimeout[@timeout,1]; END.. e12(896)\1111i16I70b5B18b15B2927i17I5104i13I71b13B4717i18I2089b5B148b4B (635)