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] = { 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] = { 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]; }; SetTimeSignature: PUBLIC PROC[score: ScorePTR, ts: TimeSignature, time1, time2: Time] = { oldTS: TimeSignature _ [0, 0]; timeSig: TimeSignaturePTR _ NIL; IF time1 > time2 THEN RETURN; SetDirty[score, time1, time1+50]; FOR i: CARDINAL IN [0..score.length) DO event: EventPTR ~ score.event[i]; IF event.time > time2 THEN EXIT; WITH event SELECT FROM timeSig: TimeSignaturePTR => { IF timeSig.time < time1 THEN oldTS _ timeSig.ts ELSE { SetDirty[score, time1, timeSig.time+50]; Piece.RemoveEvent[score, timeSig, TRUE]; }; }; ENDCASE; ENDLOOP; IF ts.top # 0 AND ts.bottom # 0 THEN { timeSig _ NEW[EventRec.timeSignature]; timeSig.time _ time1+10; timeSig.ts _ ts; Piece.AddEvent[score, timeSig]; }; IF oldTS.top # 0 AND time2 < EndOfScore[score] THEN { timeSig _ NEW[EventRec.timeSignature]; timeSig.time _ time2+10; timeSig.ts _ oldTS; Piece.AddEvent[score, timeSig]; SetDirty[score, time1, time2]; }; score.cache.ts1 _ score.cache.ts2 _ NIL; -- invalidate cache }; GetTimeSignature: PUBLIC PROC[score: ScorePTR, t: Time] RETURNS[ts: TimeSignature _ [4, 4]] = { IF score.cache.ts1 # NIL AND t >= score.cache.ts1.time AND (score.cache.ts2 = NIL OR t < score.cache.ts2.time) THEN RETURN[score.cache.ts1.ts]; score.cache.ts1 _ score.cache.ts2 _ NIL; FOR i: CARDINAL IN [0..score.length) DO WITH score.event[i] SELECT FROM timeSig: TimeSignaturePTR => { IF timeSig.time > t THEN { score.cache.ts2 _ timeSig; EXIT }; score.cache.ts1 _ timeSig; }; ENDCASE; ENDLOOP; IF score.cache.ts1 # NIL THEN ts _ score.cache.ts1.ts; }; DrawTimeSignature: PUBLIC PROC[score: ScorePTR, ts: TimeSignature, time: Time] = { x, y: INTEGER; oldStaff: Staff; context: Graphics.Context _ score.sheet.context; staves: StavesPTR = Sheet.FindStaves[score.sheet, time]; FOR i: CARDINAL IN [0..staves.length) DO IF staves.staff[i] = oldStaff THEN LOOP; oldStaff _ staves.staff[i]; [x, y] _ Sheet.Map[score.sheet, time, , i]; x _ x-5; Graphics.SetCP[context, x, y+8]; SELECT ts.bottom FROM 2 => DrawChar[context, 062C]; 4 => DrawChar[context, 064C]; 8 => DrawChar[context, 070C]; ENDCASE; Graphics.SetCP[context, x, y+24]; SELECT ts.top FROM 1 => DrawChar[context, 061C]; 2 => DrawChar[context, 062C]; 3 => DrawChar[context, 063C]; 4 => DrawChar[context, 064C]; 5 => DrawChar[context, 065C]; 6 => DrawChar[context, 066C]; 7 => DrawChar[context, 067C]; 8 => DrawChar[context, 070C]; 9 => DrawChar[context, 071C]; 12 => { Graphics.SetCP[context, x-5, y+24]; DrawString[context, "12"]}; ENDCASE; ENDLOOP; }; SetStyle: PUBLIC PROC[score: ScorePTR, index: INTEGER, t1, t2: Time] = { old: INTEGER _ -1; style: StavesPTR _ NIL; temp, sync: EventPTR _ NIL; endOfScore: Time = EndOfScore[score]; IF index NOT IN [0..20] THEN {score.flash _ TRUE; RETURN}; IF score.style[index] = NIL THEN {score.flash _ TRUE; RETURN}; SetDirty[score, t1, EndOfScore[score]]; sync _ NearestMeasure[score, t1, 10]; temp _ NearestMeasure[score, t2, 10]; IF sync # NIL THEN t1 _ sync.time+1; IF temp # NIL THEN t2 _ temp.time-1; FOR i: CARDINAL IN [0..score.length) DO WITH score.event[i] SELECT FROM staves: StavesPTR => IF staves.staves=style THEN { IF staves.time >= t1-1 THEN EXIT; old _ staves.value; }; ENDCASE; ENDLOOP; FOR i: CARDINAL DECREASING IN [0..score.length) DO event: EventPTR ~ score.event[i]; IF event.time > t2 THEN LOOP; IF event.time < t1-5 THEN EXIT; WITH event SELECT FROM staves: StavesPTR => IF staves.staves=style THEN staves.value _ index; ENDCASE; ENDLOOP; IF old # index THEN { IF sync # NIL THEN Piece.RemoveEvent[score, sync, TRUE]; style _ NEW[EventRec.staves]; style^ _ score.style[index]^; style.value _ index; style.time _ t1; Piece.AddEvent[score, style]}; IF old # index AND old # -1 AND t2 # endOfScore THEN { IF temp # NIL THEN Piece.RemoveEvent[score, temp, TRUE]; style _ NEW[EventRec.staves]; style^ _ score.style[old]^; style.value _ old; style.time _ t2; Piece.AddEvent[score, style]}; Sheet.Reset[score]; FOR i: CARDINAL IN [0..score.beamHeap.length) DO Beam.SetStems[score.sheet, score.beamHeap.beam[i]]; ENDLOOP; Selection.AddLine[score, t1, t2]; }; NearestMeasure: PROC[score: ScorePTR, time, delta: Time] RETURNS[EventPTR] = { s: EventPTR _ NIL; FOR i: CARDINAL IN [0..score.length) DO IF ~Measure[score.event[i]] THEN LOOP; IF ABS[score.event[i].time-time] > delta THEN LOOP; delta _ ABS[score.event[i].time-time]; s _ score.event[i]; ENDLOOP; RETURN[s]; }; GetStyle: PUBLIC PROC[score: ScorePTR, time: Time] RETURNS[INTEGER] = { equal: BOOLEAN; sheet: SheetPTR _ score.sheet; staves: StavesPTR = sheet.section[Sheet.FindLine[sheet, time]].staves; IF staves = NIL THEN RETURN[-1]; FOR i: CARDINAL IN [0..20] DO IF score.style[i].length # staves.length THEN LOOP; equal _ TRUE; FOR j: CARDINAL IN [0..score.style[i].length) DO IF score.style[i].staff[j].y # staves.staff[j].y THEN {equal _ FALSE; EXIT}; ENDLOOP; IF equal THEN RETURN[i]; ENDLOOP; RETURN[-1]; }; SetClef: PUBLIC PROC[score: ScorePTR, pitch, staff: INTEGER, time: Time] = { staves: StavesPTR; staves _ NEW[EventRec.staves]; Event.SetStave[score, staves, Sheet.FindStaves[score.sheet, time]]; staves.staff[staff].pitch _ pitch; staves.staves _ clef; staves.time _ time; staves.value _ staff; Piece.AddEvent[score, staves]; Sheet.Reset[score]; }; SetOctava: PUBLIC PROC[score: ScorePTR, pitch, staff, height: INTEGER, t1, t2: Time] = { s: EventPTR _ NIL; current: INTEGER; section: CARDINAL; staves: StavesPTR; sheet: SheetPTR _ score.sheet; normal: INTEGER = Sheet.NormalPitch[sheet, staff]; IF t1 >= t2 THEN RETURN; FOR i: CARDINAL IN [0..score.length) DO event: EventPTR ~ score.event[i]; IF event.time < t1 THEN LOOP; IF event.time > t2 THEN EXIT; WITH event SELECT FROM staves: StavesPTR => { current _ staves.staff[staff].pitch; IF current#normal THEN { score.flash _ TRUE; RETURN }; }; ENDCASE; ENDLOOP; section _ Sheet.FindSection[sheet, t1]; IF sheet.section[section].staves.staff[staff].pitch # normal THEN {score.flash _ TRUE; RETURN}; staves _ NEW[EventRec.staves]; Event.SetStave[score, staves, sheet.section[section].staves]; staves.staff[staff].pitch _ pitch; staves.height _ Sheet.OctavaHeight[pitch, height]; staves.staves _ octava1; staves.time _ t1; staves.value _ staff; Piece.AddEvent[score, staves]; staves _ NEW[EventRec.staves]; Event.SetStave[score, staves, Sheet.FindStaves[sheet, t2]]; staves.staff[staff].pitch _ normal; staves.staves _ octava2; staves.time _ t2; staves.value _ staff; Piece.AddEvent[score, staves]; Sheet.Reset[score]; }; END. öScoreImplA.mesa Copyright (C) 1983, 1984 Xerox Corporation. All rights reserved. Author: John Maxwell Last Edited by: Maxwell, November 22, 1983 12:23 pm Last Edited by: Doug Wyatt, June 12, 1984 11:25:11 am PDT **************************************************************************** cache **************************************************************************** cache: PUBLIC ARRAY [0..maxCacheLength) OF EventPTR; cacheLength: PUBLIC CARDINAL _ 0; currentKey: INTEGER _ 0; keyStart, keyStop: Time _ 0; pianoroll one staff two staffs two staffs three staffs three staffs four staffs **************************************************************************** key **************************************************************************** ENABLE Piece.Overflow => IF score = old THEN score _ new; Utility.FreeEvent[@score.event[i]]; put in the new key signature put back the old signature caches the last key range **************************************************************************** metronome **************************************************************************** ENABLE Piece.Overflow => IF score = old THEN score _ new; remove old metronomes Utility.FreeEvent[@sync]; insert new one **************************************************************************** time signature **************************************************************************** ENABLE Piece.Overflow => IF score = old THEN score _ new; remove old time signature insert new time signature **************************************************************************** procedures that change the staves attributes **************************************************************************** ENABLE Piece.Overflow => IF score = old THEN score _ new; get the old style change all of the current staves to the new style insert new staves reset world style: PUBLIC ARRAY [0..20] OF Staves; **************************************************************************** clefs switches **************************************************************************** ENABLE Piece.Overflow => IF score = old THEN score _ new; make up a sync ENABLE Piece.Overflow => IF score = old THEN score _ new; check to make sure that the staff is clear add the first sync add the second sync Ê/˜šœ™J™@Jšœ™Jšœ3™3Jšœ9™9J™—šÏk ˜ Jšœœ ˜Jšœœ˜Jšœœ ˜Jšœ œ%˜3J˜ Jšœœ˜%Jšœœœ˜Jšœœ˜Jšœ œ ˜JšœœN˜YJ˜J˜—Jšœ œ˜JšœT˜[Jšœ˜Jšœœœ%˜1J˜Jš œœœ œœ˜*J˜š Ïn œœœœœ˜IJšœœœ˜Jšœœœœ˜*Jšœœœ˜$šœ ˜J˜J˜!J˜J˜J˜ Jšœœ˜—Jšœœœœ ˜4Jšœœœœ ˜4Jšœœœœ ˜3Jšœœœœ ˜3Jšœ˜Jšœ˜—J˜JšœL™LJšœ™JšœL™LJ˜Jšœ4™4Jšœ!™!Jšœ™Jšœ™J˜šž œœœ!˜8Jšœ&œ˜*Jšœ&œ˜*Jšœ$œ˜(J˜J˜#Jšœ˜Jšœ˜J˜—šž œœœ0˜GJ˜Jšœœ˜$J˜$J˜)J˜#Jšœ ™ Jšœœ˜&J˜J˜J˜EJšœ ™ Jšœœ˜&J˜J˜J˜FJšœ ™ Jšœœ˜&J˜J˜J˜HJšœ ™ Jšœœ˜'J˜J˜J˜GJšœ™Jšœœ˜&J˜J˜J˜HJšœ™Jšœœ˜'J˜J˜J˜IJšœ ™ Jšœœ˜&J˜J˜J˜IJ˜J˜Jšœ˜J˜—JšœL™LJšœ™JšœL™LJ˜šžœœœœ˜JJšœœ œ ™9Jšœœ˜Jšœœ˜Jšœœœ˜Jš œœœ œœ˜"Jšœœ˜J˜$š œœ œœ˜2Jšœœœ˜)Jšœœœ˜)šœ$œœ˜0Jšœ)œ˜/—Jšœ#™#Jšœ˜—Jšœ™šœ"œ˜*Jšœ œ˜$J˜J˜J˜J˜—Jšœ™šœœœ˜4Jšœ œ˜$J˜J˜J˜J˜—Jšœ&œÏc˜>Jšœœ˜#JšœŸ˜$Jšœ˜J˜—š žœœœœœ ˜KJšœ™šœœœ˜J˜'J˜%J˜%Jšœœœ˜$Jšœœœ˜$Jšœ™šœœœ˜'šœœ˜šœœœ˜2Jšœœœ˜8—Jšœ˜—Jšœ˜—Jšœ1™1š œœ œœ˜2J˜!Jšœœœ˜Jšœœœ˜šœœ˜Jšœœœ˜FJšœ˜—Jšœ˜—Jšœ™šœ œ˜Jšœœœ œ˜8Jšœœ˜J˜J˜J˜J˜—šœ œ œœ˜6Jšœœœ œ˜8Jšœœ˜J˜J˜J˜J˜—Jšœ ™ J˜šœœœœ˜1J˜4Jšœ˜—J˜"Jšœ˜J˜—šžœœ%œ˜NJšœœ˜šœœœ˜'Jšœœœ˜&Jšœœ#œœ˜3Jšœœ˜&J˜Jšœ˜—Jšœ˜ Jšœ˜J˜—Jšœ&™&J˜š žœœœœœ˜GJšœœ˜J˜J˜FJšœ œœœ˜ šœœœ ˜Jšœ'œœ˜3Jšœœ˜ šœœœ˜0Jšœ/œ œœ˜LJšœ˜—Jšœœœ˜Jšœ˜—Jšœ˜ Jšœ˜J˜—JšœL™LJšœ™JšœL™LJ˜šžœœœ œ˜LJšœœ œ ™9J˜Jšœ™Jšœ œ˜J˜CJ˜"J˜J˜J˜J˜J˜Jšœ˜J˜—šž œœœ(œ˜XJšœœ œ ™9Jšœœ˜Jšœ œ˜Jšœ œ˜J˜J˜Jšœœ#˜2Jšœ œœ˜Jšœ*™*šœœœ˜'Jšœ!˜!Jšœœœ˜Jšœœœ˜šœœ˜˜J˜$Jšœœœœ˜6J˜—Jšœ˜—Jšœ˜—J˜'Jšœ;œœœ˜_Jšœ™Jšœ œ˜J˜=J˜"J˜2J˜J˜J˜J˜Jšœ™Jšœ œ˜J˜;J˜#J˜J˜J˜J˜J˜Jšœ˜J˜—Jšœ˜—…—1 JE