<> <> <> <> <> DIRECTORY CursorDefs, Beam USING [SetStems], Chord USING [Draw], Graphics USING [SetPaint, SetTexture], InlineDefs USING [LowHalf], Interface USING [count, Object, Wait], MusicDefs, Note USING [Draw, Duration, FindChord, GetBackTie, SetAccidental], Piece USING [AddSync, CleanUpSyncs, NearestSync], Score USING [GetKey, NormalAcc, PriorNote, Redraw, ShowPitch], Selection, -- USING everything Sheet USING [FindSection, Height, NearestStaff, NearestTime], Sync USING [AddNote, Adjust], Utility; -- USING everything InterfaceImplC: CEDAR PROGRAM IMPORTS Beam, Chord, Graphics, InlineDefs, Interface, MusicDefs, Note, Piece, Score, Selection, Sheet, Sync, Utility EXPORTS Interface = BEGIN OPEN Graphics, MusicDefs; Error: SIGNAL = CODE; <<******************************************************************>> <> <<******************************************************************>> defaultSync: SyncRec _ []; InsertNote: PUBLIC PROC[object: Interface.Object] = { time: Time; height, key: INTEGER; n: NotePTR _ Utility.NewNote[]; n.value _ IF object=rest THEN quarter ELSE unknown; n.rest _ (object=rest); n.voice _ (IF voice THEN selectedVoice ELSE 0); FOR i: CARDINAL IN [0..selectionLength) DO IF selection[i]=NIL THEN LOOP; n.value _ selection[i].value; n.dotted _ selection[i].dotted; n.grace _ selection[i].grace; EXIT; ENDLOOP; n.sync _ @defaultSync; n.duration _ InlineDefs.LowHalf[7*(Note.Duration[n, 128]/8)]; [time, height] _ Sheet.NearestTime[]; n.show _ FALSE; n.sync.time _ time; key _ Score.GetKey[time]; n.staff _ Sheet.NearestStaff[time, height]; IF n.rest THEN [n.pitch, n.spelled] _RestPosition[height, key, n.staff, time] ELSE [n.pitch, n.spelled] _ DefaultPitch[height, key, n.staff, time]; n.stemUp _ StemDirection[n.pitch, n.staff, time]; n.voice _ IF voice THEN selectedVoice ELSE 0; IF voice THEN maxVoice _ MAX[maxVoice, selectedVoice]; SetBrush[black, invert]; Note.Draw[n]; MoveNote[n]; Selection.Clear[]; Selection.AddNote[n]; command _ TRUE; }; DefaultPitch: PROC[height, key: INTEGER, staff: CARDINAL, time: Time] RETURNS[pitch: INTEGER, spelled: Accidental] = { prior: NotePTR; normal: Accidental; index: CARDINAL = SyncIndex[time]; pitch _ WhiteKey[time, height, staff]; pitch _ Score.ShowPitch[pitch, natural, key]; height _ Sheet.Height[time, pitch, staff]; prior _ Score.PriorNote[pitch, height, index]; IF show.noCarry OR prior=NIL THEN IF Score.NormalAcc[key, pitch] =natural THEN IF key<0 THEN RETURN[pitch-1, inKey] ELSE RETURN[pitch+1, inKey] ELSE RETURN[pitch, inKey]; pitch _ prior.pitch; spelled _ prior.spelled; IF spelled =inKey THEN RETURN; IF spelled =doubleSharp THEN RETURN; IF spelled =doubleFlat THEN RETURN; <> normal _ Score.NormalAcc[key, pitch]; IF normal#inKey THEN RETURN; normal _ Score.NormalAcc[0, pitch]; IF spelled=natural AND normal=inKey THEN spelled _ inKey; IF spelled=flat AND key<0 AND normal=sharp THEN spelled _ inKey; IF spelled=sharp AND key>=0 AND normal=sharp THEN spelled _ inKey; }; Spell: PROC[a: Accidental] RETURNS[CARDINAL] = INLINE {RETURN[SELECT a FROM doubleSharp => 4, sharp => 3, natural, inKey => 2, flat => 1, ENDCASE => 0]}; SyncIndex: PROC[time: Time] RETURNS[s: CARDINAL] = INLINE { s _ Piece.NearestSync[score, time]; IF score[s]#NIL AND score[s].time>=time THEN RETURN[s]; FOR i: CARDINAL DECREASING IN [0..s+10) DO IF score[i]=NIL THEN LOOP; IF score[i].time>time THEN LOOP; RETURN[i+1]; ENDLOOP; }; <<******************************************************************>> <> <<******************************************************************>> MoveNote: PUBLIC PROC[n: NotePTR] = { OPEN CursorDefs; c: ChordPTR; i: CARDINAL; oldTime, time: Time; scale, offset: INTEGER; spell, oldSpell: INTEGER; pitch, oldPitch: INTEGER; note: NotePTR; s: SyncPTR; tempCursor: Cursor _ cursor^; backtie, forwardtie: NotePTR _ NIL; oldHeight, height, x, y, key: INTEGER; backEqual, forwardEqual: BOOL; yellow: {up, down1, clicked, down2} _ up; AccMode: PROC = { scale _ 5; oldSpell _ spell _ Spell[IF n.spelled=inKey THEN DefaultAcc[Score.GetKey[oldTime], n.pitch] ELSE n.spelled]; oldPitch _ 1000; -- forces a move offset _ oldSpell*4*scale+2*scale; pitch _ Score.ShowPitch[n.pitch, n.spelled, key]; oldHeight _ Sheet.Height[n.sync.time, pitch, n.staff]; y _ MouseY^; oldSpell _ 6}; NonAccMode: PROC = { scale _ 1; offset _ scale*10; oldPitch _ 1000; -- forces a move pitch _ Score.ShowPitch[n.pitch, n.spelled, key]; oldHeight _ Sheet.Height[n.sync.time, pitch, n.staff]; y _ MouseY^}; IF n=NIL THEN RETURN; cursor^ _ ALL[0]; c _ Note.FindChord[n]; SetBrush[black, invert]; oldTime _ n.sync.time; min _ max _ time _ oldTime; IF n.tie#NIL THEN { backEqual_ (n.tie.pitch=n.pitch); backtie _ n.tie; n.tie _ NIL}; IF n.tied THEN { forwardtie _ Note.GetBackTie[n]; forwardEqual _ (forwardtie.pitch=n.pitch)}; defaultSync.event _ ALL[NIL]; FOR i IN [0..chordLength) DO IF c=NIL AND i>0 THEN EXIT; IF c=NIL THEN note _ n ELSE note _ c.note[i]; IF note=NIL THEN EXIT; Selection.RemoveNote[note]; IF note.beam#NIL THEN { min _ MIN[min, note.beam.sync1.time]; max _ MAX[max, note.beam.sync2.time]}; IF note.sync#NIL THEN { min _ MIN[min, note.sync.time]; max _ MAX[max, note.sync.time]}; Sync.AddNote[@defaultSync, note]; ENDLOOP; Piece.CleanUpSyncs[score]; defaultSync.time _ oldTime; x _ MouseX^; y _ MouseY^; key _ Score.GetKey[oldTime]; NonAccMode[]; oldPitch _ pitch; WHILE BlueBug[] DO Interface.Wait[1]; SELECT yellow FROM down1 => IF ~YellowBug[] THEN yellow _ clicked; clicked => IF YellowBug[] THEN yellow _ down2; down2 => IF ~YellowBug[] THEN {yellow _ up; NonAccMode[]}; up => IF YellowBug[] THEN {yellow _ down1; AccMode[]}; ENDCASE; time _ oldTime+(MouseX^-x); [height, spell] _ Scale[oldHeight,(y+offset-MouseY^), scale]; key _ Score.GetKey[time]; pitch _ WhiteKey[time, height, n.staff]; IF yellow=up THEN oldSpell _ spell; IF pitch=oldPitch AND spell=oldSpell AND time=n.sync.time THEN LOOP; <> IF c#NIL THEN Chord.Draw[c] ELSE Note.Draw[n]; n.sync.time _ time; IF pitch#oldPitch AND ~n.rest AND yellow=up THEN { n.show _ FALSE; [n.pitch, n.spelled] _ DefaultPitch[height, key, n.staff, time]}; IF spell#oldSpell AND ~n.rest THEN { flash _ FALSE; n.show _ TRUE; SetAccidental[n, pitch, spell]}; oldPitch _ pitch; oldSpell _ spell; Sync.Adjust[n.sync]; IF n.rest THEN [n.pitch, n.spelled]_ RestPosition[height, key, n.staff, time]; <> IF c#NIL THEN Chord.Draw[c] ELSE Note.Draw[n]; ENDLOOP; <> IF show.display=physical AND c#NIL THEN FOR i IN [0..chordLength) DO IF c.note[i]=NIL THEN EXIT; c.note[i].toc _ c.note[i].sync.time*TF; ENDLOOP ELSE n.toc _ n.sync.time*TF; IF c#NIL THEN Chord.Draw[c] ELSE Note.Draw[n]; s _ score[Piece.NearestSync[p: score, t: time, notesOnly: TRUE]]; IF s=NIL OR ABS[s.time-time]>2 THEN { s _ Utility.NewSync[]; s.time _ time; Piece.AddSync[score, s]; }; IF c#NIL THEN FOR i IN [0..chordLength) DO IF c.note[i]=NIL THEN LOOP; Sync.AddNote[s, c.note[i]]; ENDLOOP; IF c=NIL THEN Sync.AddNote[s, n]; IF n.beam#NIL THEN Beam.SetStems[n.beam]; Selection.AddNote[NIL]; cursor^ _ tempCursor; flash _ FALSE; WHILE YellowBug[] DO NULL; ENDLOOP; n.tie _ backtie; <> WHILE backtie#NIL AND backEqual DO note _ backtie; backtie _ backtie.tie; IF backtie#NIL THEN backEqual_ (backtie.pitch=note.pitch); note.pitch _ pitch; note.spelled _ n.spelled; min _ MIN[min, note.sync.time]; max _ MAX[max, note.sync.time]; ENDLOOP; WHILE forwardtie#NIL AND forwardEqual DO note _ forwardtie; forwardtie _ Note.GetBackTie[forwardtie]; IF forwardtie#NIL THEN forwardEqual _ (forwardtie.pitch=note.pitch); note.pitch _ pitch; note.spelled _ n.spelled; min _ MIN[min, note.sync.time]; max _ MAX[max, note.sync.time]; ENDLOOP; SetDirty[s.time, s.time]; Score.Redraw[min, max]; Piece.CleanUpSyncs[score]; Interface.count _ TRUE; }; tryX: INTEGER _ 3; Scale: PROC[oldHeight, delta, scale: INTEGER] RETURNS[height, spell: INTEGER]= { height _ oldHeight+ModDiv[delta,(5*scale)]; spell _ Mod[delta, 20*scale]/(4*scale); }; WhiteKey: PROC[t: Time, height: INTEGER, staff: CARDINAL] RETURNS[INTEGER]= { delta: INTEGER; staffHeight: INTEGER = Sheet.Height[t,, staff]; pitch: INTEGER _ sheet[Sheet.FindSection[t]].staves.staff[staff].pitch; delta _ ModDiv[(height-staffHeight), 4]; IF delta>=0 THEN FOR i: CARDINAL IN [0..ABS[delta]) DO SELECT Mod[pitch, 12] FROM 0, 7 => pitch _ pitch+1; ENDCASE => pitch _ pitch + 2; ENDLOOP ELSE FOR i: CARDINAL IN [0..ABS[delta]) DO SELECT Mod[pitch, 12] FROM 1, 8 => pitch _ pitch-1; ENDCASE => pitch _ pitch - 2; ENDLOOP; RETURN[pitch]; }; ModDiv: PROC[top, bottom: INTEGER] RETURNS[d: INTEGER] = INLINE {d _ top/bottom; IF top<0 AND Mod[top, bottom]#0 THEN d_ d-1}; DefaultAcc: PROC[key, pitch: INTEGER] RETURNS[Accidental] = { SELECT Score.NormalAcc[0, pitch] FROM inKey => RETURN[natural]; sharp => RETURN[IF key<0 THEN flat ELSE sharp]; ENDCASE => ERROR; }; SetAccidental: PROC[n: NotePTR, pitch, spell: INTEGER] = { <> <> IF n.rest THEN RETURN; SELECT spell FROM 0=>{n.pitch _ pitch-2; Note.SetAccidental[n, doubleFlat]}; 1=>{n.pitch _ pitch-1; Note.SetAccidental[n, flat]}; 2=>{n.pitch _ pitch; Note.SetAccidental[n, natural]}; 3=>{n.pitch _ pitch+1; Note.SetAccidental[n, sharp]}; 4=>{n.pitch _ pitch+2;Note.SetAccidental[n, doubleSharp]}; ENDCASE => ERROR; IF flash THEN Error; <> <> <> <> <> <> <> <=0 AND normal=sharp THEN n.spelled _ inKey;>> }; RestPosition: PROC[height, key: INTEGER, staff: CARDINAL, time: Time] RETURNS[pitch: INTEGER, spelled: Accidental] = { w: INTEGER = 8; staffHeight: INTEGER = Sheet.Height[time,, staff]; height _ 8*ModDiv[(height-staffHeight), w] +w-4+staffHeight; pitch _ WhiteKey[time, height, staff]; pitch _ Score.ShowPitch[pitch, natural, key]; spelled _ natural; }; StemDirection: PROC[pitch, staff: INTEGER, t: Time] RETURNS[BOOL] = { RETURN[Sheet.Height[t, pitch, staff]