<> <> <> <> <> DIRECTORY CursorDefs, Beam USING [SetStems], Chord USING [Draw], Event USING [AddNote, Adjust, Sync], Inline USING [LowHalf], Interface USING [count, Object, Wait], MusicDefs, Note USING [Draw, Duration, FindChord, GetBackTie, SetAccidental], Piece USING [AddEvent, CleanUpEvents, NearestEvent, Overflow], Score USING [GetKey, NormalAcc, PriorNote, Redraw, ShowPitch], Selection, -- USING everything Sheet USING [FindSection, Height, NearestStaff, NearestTime], UserTerminal USING [mouse, GetCursorPattern, SetCursorPattern]; InterfaceImplC: CEDAR PROGRAM IMPORTS Beam, Chord, Inline, Interface, MusicDefs, Note, Piece, Score, Selection, Sheet, Event, UserTerminal EXPORTS Interface = BEGIN OPEN MusicDefs, UserTerminal; Error: SIGNAL = CODE; <<******************************************************************>> <> <<******************************************************************>> defaultSync: SyncPTR _ zone.NEW[EventRec.sync[3]]; InsertNote: PUBLIC PROC[score: ScorePTR, object: Interface.Object] = { ENABLE Piece.Overflow => IF score = old THEN score _ new; time: Time; height, key: INTEGER; n: NotePTR _ zone.NEW[NoteRec]; n.value _ IF object = rest THEN quarter ELSE unknown; n.rest _ (object = rest); n.voice _ (IF score.sheet.voice # noVoice THEN score.sheet.voice ELSE 0); FOR i: CARDINAL IN [0..Selection.selection.length) DO IF Selection.selection[i] = NIL THEN LOOP; n.value _ Selection.selection[i].value; n.dotted _ Selection.selection[i].dotted; n.grace _ Selection.selection[i].grace; EXIT; ENDLOOP; n.sync _ defaultSync; n.duration _ Inline.LowHalf[7*(Note.Duration[n, 128]/8)]; [time, height] _ Sheet.NearestTime[score.sheet, ]; n.show _ FALSE; n.sync.time _ time; key _ Score.GetKey[score, time]; n.staff _ Sheet.NearestStaff[score.sheet, time, height]; IF n.rest THEN [n.pitch, n.spelled] _ RestPosition[score, height, key, n.staff, time] ELSE [n.pitch, n.spelled] _ DefaultPitch[score, height, key, n.staff, time]; n.stemUp _ StemDirection[score, n.pitch, n.staff, time]; n.voice _ IF score.sheet.voice # noVoice THEN score.sheet.voice ELSE 0; IF score.sheet.voice # noVoice THEN score.maxVoice _ MAX[score.maxVoice, score.sheet.voice]; SetBrush[score, black, invert]; Note.Draw[score, n]; MoveNote[score, n]; Selection.Clear[]; Selection.AddNote[score, n]; score.command _ TRUE; }; DefaultPitch: PROC[score: ScorePTR, height, key: INTEGER, staff: CARDINAL, time: Time] RETURNS[pitch: INTEGER, spelled: Accidental] = { prior: NotePTR; normal: Accidental; index: CARDINAL = EventIndex[score, time]; pitch _ WhiteKey[score, time, height, staff]; pitch _ Score.ShowPitch[score.sheet, pitch, natural, key]; height _ Sheet.Height[score.sheet, time, pitch, staff]; prior _ Score.PriorNote[score, pitch, height, index]; IF score.sheet.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]}; EventIndex: PROC[score: ScorePTR, time: Time] RETURNS[s: CARDINAL] = INLINE { s _ Piece.NearestEvent[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[score: ScorePTR, n: NotePTR] = { OPEN CursorDefs; s: SyncPTR; c: ChordPTR; oldTime, time: Time; scale, offset: INTEGER; spell, oldSpell: INTEGER; pitch, oldPitch: INTEGER; tempCursor: Cursor _ GetCursorPattern[]; 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[score, oldTime], n.pitch] ELSE n.spelled]; oldPitch _ 1000; -- forces a move offset _ oldSpell*4*scale+2*scale; pitch _ Score.ShowPitch[score.sheet, n.pitch, n.spelled, key]; oldHeight _ Sheet.Height[score.sheet, n.sync.time, pitch, n.staff]; y _ mouse.y; oldSpell _ 6}; NonAccMode: PROC = { scale _ 1; offset _ scale*10; oldPitch _ 1000; -- forces a move pitch _ Score.ShowPitch[score.sheet, n.pitch, n.spelled, key]; oldHeight _ Sheet.Height[score.sheet, n.sync.time, pitch, n.staff]; y _ mouse.y}; IF n = NIL THEN RETURN; SetCursorPattern[ALL[0]]; c _ Note.FindChord[n]; SetBrush[score, black, invert]; oldTime _ n.sync.time; score.sheet.dirty1 _ score.sheet.dirty2 _ 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[score, n]; forwardEqual _ (forwardtie.pitch = n.pitch)}; FOR i: CARDINAL IN [0..defaultSync.length) DO defaultSync.note[i] _ NIL; ENDLOOP; FOR i: CARDINAL IN [0..IF c = NIL THEN 1 ELSE c.length) DO note: NotePTR _ IF c = NIL THEN n ELSE c.note[i]; Selection.RemoveNote[note]; IF note.beam # NIL THEN SetDirty[score, note.beam.sync1.time, note.beam.sync2.time]; IF note.sync # NIL THEN SetDirty[score, note.sync.time, note.sync.time]; defaultSync _ Event.AddNote[score, defaultSync, note]; ENDLOOP; Piece.CleanUpEvents[score]; defaultSync.time _ oldTime; x _ mouse.x; y _ mouse.y; key _ Score.GetKey[score, 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+(mouse.x-x); [height, spell] _ Scale[oldHeight, (y+offset-mouse.y), scale]; key _ Score.GetKey[score, time]; pitch _ WhiteKey[score, 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[score, c] ELSE Note.Draw[score, n]; n.sync.time _ time; IF pitch # oldPitch AND ~n.rest AND yellow = up THEN { n.show _ FALSE; [n.pitch, n.spelled] _ DefaultPitch[score, height, key, n.staff, time]}; IF spell # oldSpell AND ~n.rest THEN { score.flash _ FALSE; n.show _ TRUE; SetAccidental[score, n, pitch, spell]}; oldPitch _ pitch; oldSpell _ spell; Event.Adjust[score, n.sync]; IF n.rest THEN [n.pitch, n.spelled] _ RestPosition[score, height, key, n.staff, time]; <> IF c # NIL THEN Chord.Draw[score, c] ELSE Note.Draw[score, n]; ENDLOOP; <> IF score.sheet.display = physical AND c # NIL THEN FOR i: CARDINAL IN [0..c.length) DO c.note[i].toc _ c.note[i].sync.time*score.sheet.density; ENDLOOP ELSE n.toc _ n.sync.time*score.sheet.density; IF c # NIL THEN Chord.Draw[score, c] ELSE Note.Draw[score, n]; s _ Event.Sync[score[Piece.NearestEvent[score: score, t: time, syncsOnly: TRUE]]]; IF s = NIL OR ABS[s.time-time] > 2 THEN { s _ zone.NEW[EventRec.sync[5]]; s.time _ time; score _ Piece.AddEvent[score, s]; }; FOR i: CARDINAL IN [0..(IF c = NIL THEN 1 ELSE c.length)) DO temp: NotePTR _ IF c = NIL THEN n ELSE c.note[i]; s _ Event.AddNote[score, s, temp]; ENDLOOP; IF n.beam # NIL THEN Beam.SetStems[score.sheet, n.beam]; Selection.AddNote[score, NIL]; SetCursorPattern[tempCursor]; score.flash _ FALSE; WHILE YellowBug[] DO NULL; ENDLOOP; n.tie _ backtie; <> WHILE backtie # NIL AND backEqual DO note: NotePTR _ backtie; backtie _ backtie.tie; IF backtie # NIL THEN backEqual _ (backtie.pitch = note.pitch); note.pitch _ pitch; note.spelled _ n.spelled; SetDirty[score, note.sync.time, note.sync.time]; ENDLOOP; WHILE forwardtie # NIL AND forwardEqual DO note: NotePTR _ forwardtie; forwardtie _ Note.GetBackTie[score, forwardtie]; IF forwardtie # NIL THEN forwardEqual _ (forwardtie.pitch = note.pitch); note.pitch _ pitch; note.spelled _ n.spelled; SetDirty[score, note.sync.time, note.sync.time]; ENDLOOP; SetDirty[score, s.time, s.time]; Score.Redraw[score, score.sheet.dirty1, score.sheet.dirty2]; Piece.CleanUpEvents[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[score: ScorePTR, t: Time, height: INTEGER, staff: CARDINAL] RETURNS[INTEGER] = { delta: INTEGER; staffHeight: INTEGER = Sheet.Height[score.sheet, t, , staff]; pitch: INTEGER _ score.sheet[Sheet.FindSection[score.sheet, 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[score: ScorePTR, n: NotePTR, pitch, spell: INTEGER] = { <> <> IF n.rest THEN RETURN; SELECT spell FROM 0 => {n.pitch _ pitch-2; Note.SetAccidental[score, n, doubleFlat]}; 1 => {n.pitch _ pitch-1; Note.SetAccidental[score, n, flat]}; 2 => {n.pitch _ pitch; Note.SetAccidental[score, n, natural]}; 3 => {n.pitch _ pitch+1; Note.SetAccidental[score, n, sharp]}; 4 => {n.pitch _ pitch+2;Note.SetAccidental[score, n, doubleSharp]}; ENDCASE => ERROR; IF score.flash THEN Error; <> <> <> <> <> <> <> <= 0 AND normal = sharp THEN n.spelled _ inKey;>> }; RestPosition: PROC[score: ScorePTR, height, key: INTEGER, staff: CARDINAL, time: Time] RETURNS[pitch: INTEGER, spelled: Accidental] = { w: INTEGER = 8; staffHeight: INTEGER = Sheet.Height[score.sheet, time, , staff]; height _ 8*ModDiv[(height-staffHeight), w] +w-4+staffHeight; pitch _ WhiteKey[score, time, height, staff]; pitch _ Score.ShowPitch[score.sheet, pitch, natural, key]; spelled _ natural; }; StemDirection: PROC[score: ScorePTR, pitch, staff: INTEGER, t: Time] RETURNS[BOOL] = { RETURN[Sheet.Height[score.sheet, t, pitch, staff] < Sheet.Height[score.sheet, t, , staff]+16]; }; END.