<> <> <> <> <> <<>> DIRECTORY Beam USING [SetStems], Convert USING [RopeFromInt], Event USING [SetStave], Graphics USING [Context, MakeFont, SetCP, SetFat], MusicDefs, Piece USING [AddEvent, RemoveEvent], Rope USING [ROPE], Score USING [GetKey, Look], Selection USING [AddLine], Sheet USING [FindLine, FindSection, FindStaves, Map, NormalPitch, OctavaHeight, Reset], Utility; ScoreImplA: CEDAR PROGRAM IMPORTS Beam, Convert, Event, Graphics, MusicDefs, Piece, Score, Selection, Sheet, Utility EXPORTS MusicDefs, Score = BEGIN OPEN Graphics, MusicDefs, Score, Utility; Error: PUBLIC SIGNAL[s: Rope.ROPE] = CODE; ShowPitch: PUBLIC PROC[pitch: INTEGER, spelled: Accidental, key: INTEGER] RETURNS[INTEGER] = INLINE { IF NOT show.accidental THEN RETURN[pitch]; IF spelled=inKey THEN RETURN[pitch]; SELECT spelled FROM doubleSharp => pitch _ pitch-2; sharp => pitch _ pitch-1; natural => pitch _ pitch-0; flat => pitch _ pitch+1; doubleFlat => pitch _ pitch+2; ENDCASE => ERROR; IF Mod[pitch, 12]=7 AND key<-5 THEN RETURN[pitch-1]; IF Mod[pitch, 12]=0 AND key<-6 THEN RETURN[pitch-1]; IF Mod[pitch, 12]=1 AND key>5 THEN RETURN[pitch+1]; IF Mod[pitch, 12]=8 AND key>6 THEN RETURN[pitch+1]; RETURN[pitch]; }; <<****************************************************************************>> <> <<****************************************************************************>> <> <> <> <> BuildCache: PUBLIC PROC[score: ScorePTR, time: Time] = { score.cache.key1 _ score.cache.key2 _ NIL; score.cache.met1 _ score.cache.met2 _ NIL; score.cache.ts1 _ score.cache.ts2 _ NIL; [] _ GetKey[score, time]; [] _ GetTimeSignature[score, time]; [] _ GetMetronome[score, time]; }; Initialize: PUBLIC PROC[score: ScorePTR, context: Graphics.Context] = { score.sheet.context _ context; [] _ Graphics.SetFat[context, TRUE]; music _ Graphics.MakeFont["music5"]; text _ Graphics.MakeFont["TimesRoman10"]; Utility.SetFont[context, music, 8]; <> score.style[0] _ NEW[EventRec.staves]; score.style[0].height _ 0; score.style[0].offset _ 60; score.style[0].staff _ [[72, -32], [48, -88], [27, -136], [3, -196]]; <> score.style[1] _ NEW[EventRec.staves]; score.style[1].height _ 0; score.style[1].offset _ 80; score.style[1].staff _ [[48, -32], [48, -32], [48, -32], [48, -32]]; <> score.style[2] _ NEW[EventRec.staves]; score.style[2].height _ 0; score.style[2].offset _ 85; score.style[2].staff _ [[48, -32], [48, -32], [27, -125], [27, -125]]; <> score.style[12] _ NEW[EventRec.staves]; score.style[12].height _ 0; score.style[12].offset _ 85; score.style[12].staff _ [[48, -32], [48, -32], [27, -150], [27, -150]]; <> score.style[3] _ NEW[EventRec.staves]; score.style[3].height _ 0; score.style[3].offset _ 75; score.style[3].staff _ [[48, -32], [48, -32], [27, -110], [27, -185]]; <> score.style[13] _ NEW[EventRec.staves]; score.style[13].height _ 0; score.style[13].offset _ 75; score.style[13].staff _ [[48, -32], [48, -32], [27, -130], [27, -220]]; <> score.style[4] _ NEW[EventRec.staves]; score.style[4].height _ 0; score.style[4].offset _ 75; score.style[4].staff _ [[48, -32], [48, -110], [27, -185], [27, -260]]; Score.Look[score, style, , 2]; Selection.AddLine[score, 0, 0]; }; <<****************************************************************************>> <> <<****************************************************************************>> SetKey: PUBLIC PROC[score: ScorePTR, key: INTEGER, time1, time2: Time] = { < IF score = old THEN score _ new;>> oldKey: INTEGER; keySig: KeySignaturePTR _ NIL; IF time1 > time2 THEN RETURN; IF key NOT IN [-7..7] THEN RETURN; score.sheet.accidental _ TRUE; oldKey _ Score.GetKey[score, time2]; FOR i: CARDINAL DECREASING IN [0..score.length) DO IF score.event[i].time > time2 THEN LOOP; IF score.event[i].time < time1 THEN EXIT; IF score.event[i].type # keySignature THEN LOOP; Piece.RemoveEvent[score, score.event[i], TRUE]; <> ENDLOOP; <> IF key # Score.GetKey[score, time1] THEN { keySig _ NEW[EventRec.keySignature]; keySig.time _ time1; keySig.key _ key; Piece.AddEvent[score, keySig]; }; <> IF oldKey # key AND time2 < EndOfScore[score] THEN { keySig _ NEW[EventRec.keySignature]; keySig.time _ time2; keySig.key _ oldKey; Piece.AddEvent[score, keySig]; }; score.cache.key1 _ score.cache.key2 _ NIL; -- invalidate cache SetDirty[score, time1, LAST[Time]]; Sheet.Reset[score]; -- rebuild sheet }; GetKey: PUBLIC PROC[score: ScorePTR, t: Time] RETURNS[key: INTEGER _ 0] = { <> IF score.cache.key1 # NIL AND t >= score.cache.key1.time AND (score.cache.key2 = NIL OR t < score.cache.key2.time) THEN RETURN[score.cache.key1.key]; score.cache.key1 _ score.cache.key2 _ NIL; FOR i: CARDINAL IN [0..score.length) DO WITH score.event[i] SELECT FROM key: KeySignaturePTR => { IF key.time > t THEN { score.cache.key2 _ key; EXIT }; score.cache.key1 _ key; }; ENDCASE; ENDLOOP; IF score.cache.key1 # NIL THEN key _ score.cache.key1.key; }; <<****************************************************************************>> <> <<****************************************************************************>> SetMetronome: PUBLIC PROC[score: ScorePTR, m: INTEGER, time1, time2: Time] = { < IF score = old THEN score _ new;>> metronome: MetronomePTR _ NIL; IF time1 > time2 THEN RETURN; SetDirty[score, time1, time1+50]; <> FOR i: CARDINAL DECREASING IN [0..score.length) DO IF score.event[i].time > time2 THEN LOOP; IF score.event[i].time < time1 THEN EXIT; IF score.event[i].type # metronome THEN LOOP; SetDirty[score, time1, score.event[i].time+50]; Piece.RemoveEvent[score, score.event[i], TRUE]; <> ENDLOOP; <> metronome _ NEW[EventRec.metronome]; metronome.time _ time1; metronome.metronome _ m; Piece.AddEvent[score, metronome]; score.cache.met1 _ score.cache.met2 _ NIL; -- invalidates cache }; GetMetronome: PUBLIC PROC[score: ScorePTR, t: Time] RETURNS[metronome: INTEGER _ 128] = { IF score.cache.met1 # NIL AND t >= score.cache.met1.time AND (score.cache.met2 = NIL OR t < score.cache.met2.time) THEN RETURN[score.cache.met1.metronome]; score.cache.met1 _ score.cache.met2 _ NIL; FOR i: CARDINAL IN [0..score.length) DO WITH score.event[i] SELECT FROM met: MetronomePTR => { IF met.time > t THEN { score.cache.met2 _ met; EXIT }; score.cache.met1 _ met; }; ENDCASE; ENDLOOP; IF score.cache.met1 # NIL THEN metronome _ score.cache.met1.metronome; }; DrawMetronome: PUBLIC PROC[score: ScorePTR, metronome: INTEGER, time: Time] = { x, y: INTEGER; context: Graphics.Context _ score.sheet.context; IF score.sheet.printing THEN RETURN; [x, y] _ Sheet.Map[score.sheet, time, , 0]; Graphics.SetCP[context, x, y+40]; DrawChar[context, 't]; Utility.SetFont[context, text, 12]; DrawChar[context, '= ]; DrawString[context, Convert.RopeFromInt[metronome]]; Utility.SetFont[context, music, 8]; }; <<****************************************************************************>> <