-- Author: John Maxwell -- last modified: November 8, 1983 3:18 pm DIRECTORY Beam USING [Drawn], -- Device USING [Handle], Event USING [Adjust, Draw, GetScoreIndex], Graphics USING [DrawBox, GetBounds, SetCP, SetStipple], MusicDefs, Note USING [DrawTie], Piece USING [AddEvent, NearestEvent, RemoveEvent], -- PressDefs USING [PressFileDescriptor, WritePage], -- PressDeviceImpl USING [DataRef], Score USING [Draw, GetKey, Justify, LogicalToPhysical, maxCacheLength, ScalePhysical, ShowPitch], Selection USING [Draw], Sheet USING [ Draw, FindLine, FindSection, Height, HiLite, Map, MapHeight, MapNote, NearestTime, Reset, Scale, ScreenPoint, SetBegin, SetStyle], String USING [AppendDecimal], Utility; ScoreImpl: PROGRAM IMPORTS Beam, Event, Graphics, MusicDefs, Note, Piece, Score, Selection, Sheet, String, Utility EXPORTS MusicDefs, Score -- SHARES PressDeviceImpl -- = BEGIN OPEN Graphics, MusicDefs, Score, Utility; Error: PUBLIC SIGNAL[s: STRING] = CODE; -- **************************************************************************** -- cache -- **************************************************************************** -- cache: PUBLIC ARRAY [0..maxCacheLength) OF EventPTR; -- cacheLength: PUBLIC CARDINAL _ 0; -- currentKey: INTEGER _ 0; -- keyStart, keyStop: Time _ 0; BuildCache: PUBLIC PROCEDURE[score: ScorePTR] = BEGIN [] _ GetKey[score, 0]; [] _ GetTimeSignature[score, 0]; [] _ GetMetrenome[score, 0]; END; -- **************************************************************************** -- drawing the score -- **************************************************************************** Draw: PUBLIC PROCEDURE[score: ScorePTR, erase: BOOLEAN] = BEGIN Selection.Draw[score.selection]; -- remove selection from screen IF erase THEN { SetBrush[score.sheet.context, white, opaque]; Graphics.DrawBox[score.sheet.context, Graphics.GetBounds[context]]; SetBrush[score.sheet.contextblack, transparent]; Sheet.Draw[score.sheet]}; DrawInterval[score, begin, endTime]; Selection.Draw[score.selection]; END; Redraw: PUBLIC PROCEDURE[score: ScorePTR, t1, t2: Time] = BEGIN x, y: INTEGER; select: BOOLEAN; selection: SelectionPTR _ score.selection; SetBrush[score.sheet.context, black, transparent]; SELECT score.sheet.scale FROM 1 => IF t2-t1 > 700 THEN {Score.Draw[]; RETURN}; 2 => IF t2-t1 > 2000 THEN {Score.Draw[]; RETURN}; 4 => IF t2-t1 > 8000 THEN {Score.Draw[]; RETURN}; ENDCASE; select _ selection.lineSelect AND selection.select2 > t1-40 AND selection.select1 < t2+50; IF select THEN Selection.Draw[selection]; -- remove selection from screen Sheet.HiLite[score.sheet, white, t1-20, t2+30]; DrawInterval[score, t1-30, t2+40]; IF select THEN Selection.Draw[selection]; IF selection.lineSelect THEN RETURN; SetBrush[score.sheet.context, black, invert]; FOR i: CARDINAL IN [0..selection.length) DO IF selection.note[i] = NIL THEN LOOP; IF selection[i].sync.time > t2+40 OR selection[i].sync.time < t1-30 THEN LOOP; IF ~Note.InVoice[selection[i], selection.voice] THEN LOOP; [x, y] _ Sheet.MapNote[score.sheet, selection[i]]; Graphics.SetCP[score.sheet.context, x, y]; DrawChar[score.sheet.context, 170C]; ENDLOOP; END; DrawInterval: PROCEDURE[score: ScorePTR, t1, t2: Time] = BEGIN n: NotePTR; staves: StavesPTR; j: CARDINAL _ 0; sheet: SheetPTR _ score.sheet; [] _ Beam.Drawn[score, NIL]; -- clears the beam cache SetBrush[sheet.context, black, transparent]; -- draw octava markings first staves _ sheet.section[Sheet.FindSection[sheet, t1]].staves; FOR i: CARDINAL IN [0..staves.length) DO IF staves.staff[i].pitch # 15 AND staves.staff[i].pitch # 60 THEN LOOP; FOR j: CARDINAL DECREASING IN [0..score.length) DO IF score.event[j].time > = t1 THEN LOOP; IF score.event[j].type # staves THEN LOOP; WITH ev: score.event[j] SELECT FROM staves => {IF ev.staves NOT IN [octava1..octava2] THEN LOOP; IF score.event[j].index # i THEN LOOP; IF score.event[j].type = octava2 THEN EXIT}; ENDCASE => ERROR; Event.Draw[score.event[j]]; EXIT; ENDLOOP; ENDLOOP; -- pre-Adjust the first 10 syncs (beams may draw notes in syncs downstream) j _ 0; IF score.sheet.display = graphical THEN FOR i: CARDINAL IN [0..score.length) DO IF score.event[i].time < t1 THEN LOOP; IF score.event[i].time > t2 THEN EXIT; IF j = 10 THEN EXIT ELSE j _ j+1; Event.Adjust[score.event[i]]; ENDLOOP; -- draw the syncs j _ 0; FOR i: CARDINAL IN [0..score.length) DO IF score.event[i].time < t1 THEN LOOP; IF score.event[i].time > t2 THEN {j _ i; EXIT}; IF score.sheet.display = graphical THEN Event.Adjust[score.event[MIN[scoreLength-1, i+10]]]; Event.Draw[score.event[i]]; IF NOT print AND AnyBug[] THEN EXIT; ENDLOOP; -- draw ties that go off the end of the section IF j # 0 THEN FOR i: CARDINAL IN [j..score.length) DO IF score.event[i].time > t2+200 THEN EXIT; IF score.event[i].type = sync THEN { sync: SyncPTR _ Event.Sync[score.event[i]]; FOR j: CARDINAL IN [0..sync.length) DO IF (n _ sync.note[j]) = NIL THEN EXIT; IF n.tie = NIL THEN LOOP; IF n.tie.sync.time > t2 THEN LOOP; IF ~Note.InVoice[n, score.selection.voice] THEN Graphics.SetStipple[score.sheet.context, light] ELSE Graphics.SetStipple[score.sheet.context, black]; Note.DrawTie[score, n]; ENDLOOP; ENDLOOP; [] _ Beam.Drawn[score, NIL]; END; -- **************************************************************************** -- printing the score -- **************************************************************************** Print: PUBLIC PROCEDURE[splines: BOOLEAN] = {}; -- **************************************************************************** -- changing the view -- **************************************************************************** Look: PUBLIC PROCEDURE[look: LookCommand, switch: BOOLEAN, n: INTEGER] = BEGIN draw: BOOLEAN _ TRUE; SELECT look FROM accidental => show.accidental _ switch; hardcopy => {Sheet.Scale[IF switch THEN 2 ELSE 1]; hardcopy _ switch}; justified => {TF _ n; Score.Justify[select1, select2]}; logical => Score.LogicalToPhysical[select1, select2]; noCarry => show.noCarry _ switch; notehead => show.structure _ show.notehead _ switch; overview => Overview[switch]; physical => Score.ScalePhysical[512/n]; sheet => Sheet.SetStyle[n, 0, EndOfScore[]]; sync => show.sync _ switch; voice => {voice _ switch; selectedVoice _ n}; ENDCASE; END; Overview: PROCEDURE[switch: BOOLEAN] = BEGIN time: Time; x, y: INTEGER; SELECT TRUE FROM scale < 4 AND ~switch => {flash _ TRUE; RETURN}; scale > 2 AND switch => {flash _ TRUE; RETURN}; switch => {Sheet.Scale[4]; Sheet.SetBegin[0]}; YellowBug[] => { [x, y] _ Sheet.ScreenPoint[]; time _ Sheet.NearestTime[x, y].time; Sheet.Scale[IF hardcopy THEN 2 ELSE 1]; Sheet.SetBegin[time]}; ENDCASE => {Sheet.Scale[IF hardcopy THEN 2 ELSE 1]; Sheet.SetBegin[0]}; END; -- **************************************************************************** -- procedures that handle keys -- **************************************************************************** phi: ARRAY [0..12) OF INTEGER = [6, 1, -4, 3, -2, 5, 0, 7, 2, -3, 4, -1]; flatHeight: ARRAY[0..12) OF INTEGER = [0, 4, 8, 8, 12, 12, 16, 16, 20, 24, 24, 28]; sharpHeight: ARRAY[0..12) OF INTEGER = [0, 4, 4, 8, 8, 12, 12, 16, 20, 20, 24, 24]; SetKey: PUBLIC PROCEDURE[score: ScorePTR, key: INTEGER, time1, time2: Time] = BEGIN oldKey: INTEGER; keySig: LONG POINTER TO EventRec.keySignature _ NIL; IF time1 > time2 THEN RETURN; IF k NOT IN [-7..7] THEN RETURN; score.sheet.min _ 0; score.sheet.max _ EndOfScore[]+2000; 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.DeleteEvent[score, score.event[i]]; -- Utility.FreeEvent[@score.event[i]]; ENDLOOP; -- put in the new key signature IF k # Score.GetKey[score, time1] THEN { keySig _ zone.NEW[EventRec.keySignature]; keySig.time _ time1; keySig.key _ k; Piece.AddEvent[score, keySig]}; -- put back the old signature IF oldKey # k AND time2 < EndOfScore[score] THEN { keySig _ zone.NEW[EventRec.keySignature]; keySig.time _ time2; keySig.key _ oldKey; Piece.AddEvent[score, keySig]}; score.cache.keyStart _ score.cache.keyStop _ 0; -- invalidate cache Sheet.Reset[score.sheet]; -- rebuild sheet END; GetKey: PUBLIC PROCEDURE[score: ScorePTR, t: Time] RETURNS[key: INTEGER _ 0] = BEGIN -- caches the last key range IF t IN [score.cache.keyStart..score.cache.keyStop) THEN RETURN[score.cache.key]; score.cache.key _ 0; score.cache.keyStart _ score.cache.keyStop _ 0; FOR i: CARDINAL IN [0..score.length) DO IF score.event[i].type # keySignature THEN LOOP; IF score.event[i].time > t THEN {score.cache.keyStop _ score.event[i].time; EXIT}; WITH ev: score.event[i] SELECT FROM keySignature => {score.cache.key _ ev.key; score.cache.keyStart _ ev.time}; ENDCASE => ERROR; ENDLOOP; IF score.cache.keyStop = 0 THEN score.cache.keyStop _ EndOfScore[score]; RETURN[score.cache.key]; END; GetAccidental: PUBLIC PROCEDURE[n: NotePTR] RETURNS[Accidental] = BEGIN -- hack to set n.shown n.shown _ GetAccInternal[n]; RETURN[n.shown]; END; GetAccInternal: PROCEDURE[n: NotePTR] RETURNS[Accidental] = INLINE BEGIN a: Accidental; prior: NotePTR; index: CARDINAL; pitch, key: INTEGER; normal: Accidental; noteHeight: INTEGER; IF NOT show.accidental THEN RETURN[inKey]; IF n.tie # NIL AND n.tie.pitch = n.pitch THEN RETURN[inKey]; IF n.show AND n.spelled = inKey THEN Error["show inKey?"]; IF n.show THEN RETURN[n.spelled]; IF show.noCarry THEN { IF n.spelled # inKey THEN RETURN[n.spelled]; a _ DefaultAcc[0, n.pitch]; IF a = natural THEN a _ inKey; RETURN[a]}; key _ Score.GetKey[n.sync.time]; pitch _ Score.ShowPitch[n.pitch, n.spelled, key]; noteHeight _ Sheet.Height[n.sync.time, pitch, n.staff]; index _ Event.GetScoreIndex[n.sync]; IF index = scoreLength THEN index _ EventIndex[n.sync.time]; prior _ PriorNote[pitch, noteHeight, index]; normal _ NormalAcc[key, pitch]; -- no prior note IF prior = NIL THEN SELECT TRUE FROM normal = inKey => RETURN[n.spelled]; n.spelled = inKey => RETURN[normal]; ENDCASE => RETURN[n.spelled]; -- n.spelled = normal => RETURN[inKey]; -- n.spelled # normal => RETURN[n.spelled]; -- ENDCASE; -- prior note IF prior.pitch = n.pitch THEN RETURN[inKey]; -- an accidental MUST be asserted IF n.spelled # inKey THEN RETURN[n.spelled]; IF normal # inKey THEN RETURN[normal]; IF Mod[n.pitch, 12] = 7 AND key < -5 THEN RETURN[flat]; IF Mod[n.pitch, 12] = 0 AND key < -6 THEN RETURN[flat]; IF Mod[n.pitch, 12] = 1 AND key > 5 THEN RETURN[sharp]; IF Mod[n.pitch, 12] = 8 AND key > 6 THEN RETURN[sharp]; normal _ NormalAcc[0, n.pitch]; IF normal = inKey THEN normal _ natural; IF key < 0 AND normal = sharp THEN normal _ flat; RETURN[normal]; END; EventIndex: PROCEDURE[time: Time] RETURNS[s: CARDINAL] = INLINE BEGIN s _ Piece.NearestEvent[score, time]; IF score.event[s] # NIL AND score.event[s].time > = time THEN RETURN[s]; FOR i: CARDINAL DECREASING IN [0..s+10) DO IF score.event[i] = NIL THEN LOOP; IF score.event[i].time > time THEN LOOP; RETURN[i+1]; ENDLOOP; END; PriorNote: PUBLIC PROCEDURE[pitch, height: INTEGER, index: CARDINAL] RETURNS[NotePTR] = BEGIN n: NotePTR; newPitch, key: INTEGER; FOR i: CARDINAL DECREASING IN [0..index) DO IF Measure[score.event[i].type] THEN RETURN[NIL]; IF score.event[i].type # notes THEN LOOP; key _ Score.GetKey[score.event[i].time]; FOR j: CARDINAL IN [0..syncLength) DO IF (n _ score.event[i].event[j]) = NIL THEN EXIT; IF n.rest THEN LOOP; newPitch _ Score.ShowPitch[n.pitch, n.spelled, key]; IF NOT newPitch IN [pitch-2..pitch+2] THEN LOOP; IF Sheet.Height[score.event[i].time, newPitch, n.staff] # height THEN LOOP; RETURN[n]; ENDLOOP; ENDLOOP; RETURN[NIL]; END; assert: Accidental = LOOPHOLE[LOOPHOLE[LAST[Accidental], CARDINAL]+1]; NormalAcc: PUBLIC PROCEDURE[key, pitch: INTEGER] RETURNS[Accidental] = BEGIN strangeness: INTEGER _ phi[Mod[pitch, 12]]; -- i bet you don't really believe this works. SELECT TRUE FROM Mod[(key-strangeness), 12] > 4 => RETURN[inKey]; strangeness > 0 => RETURN[natural]; key < 0 => RETURN[flat]; ENDCASE => RETURN[sharp]; END; DefaultAcc: PROCEDURE[key, pitch: INTEGER] RETURNS[Accidental] = BEGIN SELECT NormalAcc[0, pitch] FROM inKey => RETURN[natural]; sharp => RETURN[IF key < 0 THEN flat ELSE sharp]; ENDCASE => ERROR; END; AddToPitch: PUBLIC PROCEDURE[key, pitch, delta: INTEGER] RETURNS[INTEGER] = BEGIN i: INTEGER; IF delta > 0 THEN FOR i IN (pitch..90] DO IF NormalAcc[key, i] = inKey THEN delta _ delta-1; IF delta = 0 THEN RETURN[i]; ENDLOOP ELSE FOR i DECREASING IN [0..pitch) DO IF NormalAcc[key, i] = inKey THEN delta _ delta+1; IF delta = 0 THEN RETURN[i]; ENDLOOP; ERROR; END; KeyHeight: PUBLIC PROCEDURE[key, pitch: INTEGER] RETURNS[INTEGER] = BEGIN i: CARDINAL _ Mod[pitch, 12]; SELECT TRUE FROM i = 7 AND key < -5 => RETURN[flatHeight[8]]; i = 0 AND key < -6 => RETURN[flatHeight[1]]; key < 0 => RETURN[flatHeight[i]]; i = 1 AND key > 5 => RETURN[sharpHeight[0]]; i = 8 AND key > 6 => RETURN[sharpHeight[7]]; ENDCASE => RETURN[sharpHeight[i]]; END; DrawKey: PUBLIC PROCEDURE[key: INTEGER, time: Time] = BEGIN n: INTEGER = 8; oldStaff: Staff _ [0, 0]; x, y, offset: INTEGER; l: CARDINAL _ Sheet.FindLine[time]; staves: StavesPTR _ sheet[l].staves; IF NOT show.accidental THEN RETURN; IF time IN [sheet[l].time-10..sheet[l].time) THEN RETURN; IF time IN (sheet[l].time..sheet[l].time+15] THEN time _ sheet[l].time; x _ Sheet.MapHeight[time, 0].x; FOR i: CARDINAL IN [0..staves.sl] DO IF staves.staff[i] = oldStaff THEN LOOP; oldStaff _ staves.staff[i]; offset _ Sheet.Height[time, oldStaff.pitch, i]; IF Mod[staves.staff[i].pitch, 12] = 3 THEN offset _ offset - 8; [x, y] _ Sheet.MapHeight[time, offset]; IF sheet[l].time = time THEN x _ 3; IF key > 0 THEN SlapDown[x , 32+y, sharp]; IF key > 1 THEN SlapDown[x+ n, 20+y, sharp]; IF key > 2 THEN SlapDown[x+2*n, 36+y, sharp]; IF key > 3 THEN SlapDown[x+3*n, 24+y, sharp]; IF key > 4 THEN SlapDown[x+4*n, 12+y, sharp]; IF key > 5 THEN SlapDown[x+5*n, 28+y, sharp]; IF key > 6 THEN SlapDown[x+6*n, 16+y, sharp]; IF key < 0 THEN SlapDown[x , 16+y, flat]; IF key < -1 THEN SlapDown[x+ n, 28+y, flat]; IF key < -2 THEN SlapDown[x+2*n, 12+y, flat]; IF key < -3 THEN SlapDown[x+3*n, 24+y, flat]; IF key < -4 THEN SlapDown[x+4*n, 8+y, flat]; IF key < -5 THEN SlapDown[x+5*n, 20+y, flat]; IF key < -6 THEN SlapDown[x+6*n, 4+y, flat]; ENDLOOP; END; SlapDown: PROCEDURE[x, y: INTEGER, a: Accidental] = BEGIN Graphics.SetCP[context, x, y]; SELECT a FROM flat => DrawChar[context, 111C]; natural => DrawChar[context, 112C]; sharp => DrawChar[context, 113C]; ENDCASE; END; -- **************************************************************************** -- score attributes: metrenome -- **************************************************************************** SetMetrenome: PUBLIC PROCEDURE[time1, time2: Time, m: INTEGER] = BEGIN i, j: CARDINAL _ 0; sync: EventPTR _ NIL; IF time1 > time2 THEN RETURN; min _ time1; max _ time1+50; -- remove old metrenomes FOR i DECREASING IN [0..cacheLength) DO IF score.event[i].time > time2 THEN LOOP; IF score.event[i].time < time1 THEN EXIT; IF score.event[i].type # metrenome THEN LOOP; max _ MAX[max, score.event[i].time+50]; Piece.RemoveEvent[score, score.event[i]]; Utility.FreeEvent[@score.event[i]]; ENDLOOP; -- insert new one sync _ Utility.NewEvent[]; sync.time _ time1; sync.type _ metrenome; sync.value _ m; Piece.AddEvent[score, sync]; BuildCache[]; END; GetMetrenome: PUBLIC PROCEDURE[t: Time] RETURNS[INTEGER] = BEGIN i: CARDINAL; sync: EventPTR _ NIL; metrenome: INTEGER _ 0; FOR i IN [0..cacheLength) DO IF score.event[i] = NIL THEN EXIT; IF score.event[i].type # metrenome THEN LOOP; IF score.event[i].time > t THEN EXIT; sync _ score.event[i]; ENDLOOP; IF sync = NIL THEN metrenome _ 128 ELSE metrenome _ sync.value; RETURN[metrenome]; END; DrawMetrenome: PUBLIC PROCEDURE[metrenome: INTEGER, time: Time] = BEGIN x, y: INTEGER; string: STRING _ [10]; IF print THEN RETURN; [x, y] _ Sheet.Map[time, , 0]; Graphics.SetCP[context, x, y+40]; DrawChar[context, 't]; String.AppendDecimal[string, metrenome]; Utility.SetFont[context, text, 12]; DrawChar[context, ' = ]; DrawString[context, string]; Utility.SetFont[context, music, 8]; END; -- **************************************************************************** -- time signature -- **************************************************************************** SetTimeSignature: PUBLIC PROCEDURE[time1, time2: Time, ts: TimeSignature] = BEGIN i, j: CARDINAL _ 0; sync: EventPTR _ NIL; oldTS: TimeSignature _ [0, 0]; IF time1 > time2 THEN RETURN; min _ time1; max _ time1+50; -- remove old time signature FOR i IN [0..cacheLength) DO IF score.event[i].time > time2 THEN EXIT; IF score.event[i].type # timeSignature THEN LOOP; IF score.event[i].time < time1 THEN {oldTS _ score.event[i].ts; LOOP}; sync _ score.event[i]; max _ MAX[max, sync.time+50]; Piece.RemoveEvent[score, sync]; Utility.FreeEvent[@sync]; ENDLOOP; -- insert new time signature IF ts.top # 0 AND ts.bottom # 0 THEN { sync _ Utility.NewEvent[]; sync.time _ time1+10; sync.type _ timeSignature; sync.ts _ ts; Piece.AddEvent[score, sync]}; IF oldTS.top # 0 AND time2 < EndOfScore[] THEN { sync _ Utility.NewEvent[]; sync.time _ time2+10; sync.type _ timeSignature; sync.ts _ oldTS; Piece.AddEvent[score, sync]; SetDirty[sync.time, sync.time]}; BuildCache[]; END; GetTimeSignature: PUBLIC PROCEDURE[t: Time] RETURNS[TimeSignature] = BEGIN i: CARDINAL; sync: EventPTR _ NIL; ts: TimeSignature _ [4, 4]; FOR i IN [0..cacheLength) DO IF score.event[i] = NIL THEN EXIT; IF score.event[i].type # timeSignature THEN LOOP; IF score.event[i].time > t THEN EXIT; sync _ score.event[i]; ENDLOOP; IF sync # NIL THEN ts _ sync.ts; RETURN[ts]; END; DrawTimeSignature: PUBLIC PROCEDURE[ts: TimeSignature, time: Time] = BEGIN i: CARDINAL; x, y: INTEGER; oldStaff: Staff; staves: StavesPTR = sheet[Sheet.FindSection[time]].staves; FOR i IN [0..staves.sl] DO IF staves.staff[i] = oldStaff THEN LOOP; oldStaff _ staves.staff[i]; [x, y] _ Sheet.Map[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; END; END..e6(0, 3648)(1, 4304)(2, 4939)\965b5B22b11B22b5B34b4B25b2B24b8B107i6I81b5B46b11B23b10B387i18I81b4B250b6B952i16I26i26I408i72I240i15I276i44I538i19I81b5B740i17I81b4B1219i27I290b6B500i28I159i26I189i18I8b6B286b13B1835b9B671b9B109i42I383b11B351b9B352b7B1670i27I81b12B596b12B357b13B446i15I81b16B915b16B334b17B GetAccidental: PUBLIC PROCEDURE[note: NotePTR] RETURNS[Accidental] = BEGIN a: Accidental; pitch, newPitch, key: INTEGER; noteHeight: INTEGER; i, j: CARDINAL; t: Time; n: NotePTR; IF NOT show.accidental THEN RETURN[inKey]; IF note.tie # NIL THEN RETURN[inKey]; t _ note.sync.time; -- leftEdge _ sheet[Sheet.FindLine[t]].time; key _ Score.GetKey[t]; IF note.spelled = inKey THEN a _ NormalAccidental[key, note.pitch] ELSE a _ note.spelled; IF show.noCarry THEN RETURN[a]; pitch _ Score.ShowPitch[note.pitch, note.spelled, key]; noteHeight _ Sheet.Height[t, pitch, note.staff]; FOR i DECREASING IN [0..Event.GetScoreIndex[note.sync]) DO IF score.event[i].time > = note.sync.time THEN LOOP; IF score.event[i].type IN Measure THEN RETURN[a]; IF score.event[i].type # notes THEN LOOP; -- IF score.event[i].time < leftEdge THEN RETURN[a]; FOR j IN [0..syncLength) DO IF (n _ score.event[i].event[j]) = NIL THEN EXIT; IF n.rest THEN LOOP; newPitch _ Score.ShowPitch[n.pitch, n.spelled, key]; IF NOT newPitch IN [pitch-2..pitch+2] THEN LOOP; IF Sheet.Height[t, newPitch, n.staff] # noteHeight THEN LOOP; -- there's a note prior to this on the same section IF n.pitch = note.pitch THEN RETURN[inKey]; -- don't assert accidental IF note.spelled # inKey THEN RETURN[note.spelled]; a _ NormalAccidental[0, pitch]; IF a = inKey THEN RETURN[natural] ELSE RETURN[IF key > = 0 THEN sharp ELSE flat]; ENDLOOP; ENDLOOP; RETURN[a]; END; AddToPitch: PUBLIC PROCEDURE[key, pitch, delta: INTEGER] RETURNS[INTEGER] = BEGIN i: INTEGER; IF delta > 0 THEN FOR i IN (pitch..90] DO IF NormalAccidental[key, i] = inKey THEN delta _ delta-1; IF delta = 0 THEN RETURN[i]; ENDLOOP ELSE FOR i DECREASING IN [0..pitch) DO IF NormalAccidental[key, i] = inKey THEN delta _ delta+1; IF delta = 0 THEN RETURN[i]; ENDLOOP; ERROR; END; NormalAccidental: PUBLIC PROCEDURE[key, pitch: INTEGER] RETURNS[Accidental] = BEGIN strangeness: INTEGER _ phi[Mod[pitch, 12]]; -- i bet you don't really believe this works. SELECT TRUE FROM Mod[(key-strangeness), 12] > 4 => RETURN[inKey]; strangeness > 0 => RETURN[natural]; key < 0 => RETURN[flat]; ENDCASE => RETURN[sharp]; END; Print: PUBLIC PROCEDURE[splines: BOOLEAN] = BEGIN printAll: BOOLEAN; oldBegin: Time _ begin; ph: POINTER TO PressDefs.PressFileDescriptor; device: Device.Handle _ Utility.OpenPressDevice[splines]; ph _ LOOPHOLE[device.data, PressDeviceImpl.DataRef].pressHandle; printAll _ ~splines AND scale = 2; IF printAll THEN Sheet.SetBegin[0]; FOR i: CARDINAL IN [0..scoreLength) DO Event.Adjust[score.event[i]]; ENDLOOP; WHILE TRUE DO Sheet.Draw[]; DrawInterval[begin, endTime]; IF endTime > EndOfScore[]-40 THEN EXIT; IF printAll THEN {Sheet.SetBegin[endTime]; PressDefs.WritePage[ph]} ELSE EXIT; ENDLOOP; Utility.ClosePressDevice[@device]; Sheet.SetBegin[oldBegin]; END;