<> <> <> <> <> 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: CEDAR 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; <<******************************************************************>> <> <<******************************************************************>> count: PUBLIC BOOL; DeleteGraphical: PUBLIC PROC = { 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 { 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 type IN [octava1..octava2] THEN Sheet.Reset[]; Score.Redraw[min, max]; count _ TRUE; }; ChangeSpelling: PROC[object: Interface.Object] = { 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]; }; Embellish: PROC[object: Interface.Object] = { 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]; }; <<******************************************************************>> <> <<******************************************************************>> Insert: PROC[object: Interface.Object] = { 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; }; InsertMeasure: PROC[object: Interface.Object] = { 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]; }; InsertClefChange: PROC[object: Interface.Object] = { old, new: Section; sync: SyncPTR _ NIL; pitch, height: INTEGER; oldTime, newTime: Time _ 0; change: BOOL _ 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]; <> 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]; }; InsertOctava: PROC[object: Interface.Object] = { 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; <> 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]; }; Slide: PROC[oldTime: Time, oldHeight: INTEGER, oldStaff: CARDINAL] RETURNS[time: Time, height: INTEGER, staff: CARDINAL] = { 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> staves _ sheet[Sheet.FindSection[time]].staves; staff _ Sheet.NextStaff[oldStaff, time]; limit _ staves.staff[staff].y+32; IF staff=oldStaff THEN limit _ limit-32-staves.offset; IF oldHeight <= limit THEN { -- we went below a lower limit IF staff=oldStaff THEN { -- must be next line [time, height] _ Sheet.AlternateTime[time, height, 1]; staff _ 0}; RETURN}; <> staff _ Sheet.PriorStaff[oldStaff, time]; limit _ staves.staff[staff].y; IF staff=oldStaff THEN limit _ limit+32+staves.offset; IF height >= 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; }; <<******************************************************************>> <> <<******************************************************************>> MoveGraphical: PUBLIC PROC[object: Interface.Object] = { s: SyncPTR; p: UnspecifiedPTR _ NIL; obj: ObjectType; IF object#none THEN { Insert[object]; RETURN; }; 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; }; MoveMeasure: PROC[s: SyncPTR] = { 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]; }; MoveClef: PROC[s: SyncPTR, old, new: Time] = { 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]; }; MoveStaves: PROC[s: SyncPTR, old, new: Time] = { next: Time; nextStyle, oldStyle, newStyle: INTEGER; next _ sheet[Sheet.NextLine[Sheet.FindLine[MAX[old, new]]]].time; nextStyle _ Sheet.GetStyle[next]; <> 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]; }; MoveKey: PROC[s: SyncPTR, old, new: Time] = { 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]; }; MoveBeam: PROC[b: BeamPTR] = { 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]; }; ChangeTilt: PROC[b: BeamPTR] = { 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]; }; MoveTie: PROC[n: NotePTR] = { 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]; }; <<******************************************************************>> <> <<******************************************************************>> ResetSheet: PROC[t1, t2: Time] = { line: CARDINAL; old1, old2: Section; new1, new2: Section; <> line _ Sheet.FindLine[MIN[t1, t2]]; old1 _ sheet[line]; line _ Sheet.NextLine[line]; old2 _ sheet[line]; Sheet.Reset[]; <> line _ Sheet.FindLine[MIN[t1, t2]]; new1 _ sheet[line]; line _ Sheet.NextLine[line]; new2 _ sheet[line]; <> 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]; }; GetCarry: PROC[s: SyncPTR] RETURNS[Time] = { index: CARDINAL; IF s.type#clef AND s.type#keySignature THEN RETURN[s.time]; <> 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]; }; Similar: PROC[s1, s2: SyncPTR] RETURNS[BOOL] = { n, o: BOOL; 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]; }; Clef: PROC[staff: CARDINAL, time: Time] RETURNS[INTEGER] = { staves: StavesPTR = sheet[Sheet.FindSection[time]].staves; RETURN[staves.staff[staff].pitch]; }; Flash: PUBLIC PROC = { SetBrush[black, invert]; Graphics.DrawScreenArea[context]; Wait[1]; Graphics.DrawScreenArea[context]; flash _ FALSE; }; Wait: PUBLIC ENTRY PROC[ticks: CARDINAL] = { FOR i: CARDINAL IN [0..ticks) DO WAIT timeout; ENDLOOP; }; ProcessDefs.SetTimeout[@timeout, 1]; END.