DIRECTORY Beam USING [Draw, Drawn, SetSyncs], Chord USING [Adjust, Draw], Event, MusicDefs, Note USING [Delta, Draw, InVoice], Score, Sheet, Utility USING [DrawBox, DrawChar, DrawLine, SetColor, SetCP]; EventImpl: CEDAR PROGRAM IMPORTS Beam, Chord, Event, Note, Score, Sheet, Utility EXPORTS Event = BEGIN OPEN MusicDefs; GetScoreIndex: PUBLIC PROC[score: ScorePTR, event: EventPTR] RETURNS[index: CARDINAL _ 0] = { binary: CARDINAL _ 8192; IF event = NIL THEN RETURN[score.length]; FOR i: CARDINAL IN [0..13) DO binary _ binary/2; IF index + binary >= score.length THEN LOOP; IF score[index+binary].time <= event.time THEN index _ index + binary; IF score[index].time # event.time THEN LOOP; IF score[index] = event THEN RETURN[index]; FOR j: CARDINAL IN (index..score.length) WHILE score[j].time = event.time DO IF score[j] = event THEN RETURN[j]; ENDLOOP; FOR j: CARDINAL DECREASING IN [0..index) WHILE score[j].time = event.time DO IF score[j] = event THEN RETURN[j]; ENDLOOP; EXIT; ENDLOOP; FOR i: CARDINAL IN [0..score.length) DO IF score[i] = event THEN RETURN[i]; ENDLOOP; RETURN[score.length]; -- not in score }; GetStaff: PUBLIC PROC[staves: StavesPTR, staff: CARDINAL] RETURNS[Staff] ~ { RETURN[staves.staff[staff]]; }; Invisible: PUBLIC PROC[score: ScorePTR, index: CARDINAL, leftEdge: Time] RETURNS[BOOL] = { event: EventPTR ~ score[index]; WITH event SELECT FROM ev: StavesPTR => IF ev.staves # clef THEN RETURN[FALSE]; ev: KeySignaturePTR => NULL; ENDCASE => RETURN[FALSE]; RETURN[event.time-leftEdge <= 15]; }; SetStave: PUBLIC PROC[score: ScorePTR, oldS: StavesPTR, newS: StavesPTR] = { n, o: BOOL; pitch, height: INTEGER; IF newS = NIL THEN RETURN; height _ newS.height; IF newS.staves # style THEN { pitch _ newS.staff[newS.value].pitch; newS^ _ oldS^; newS.height _ height; FOR j: CARDINAL IN [0..newS.length) DO IF newS.staff[j].y # newS.staff[newS.value].y THEN LOOP; newS.staff[j].pitch _ pitch; ENDLOOP; RETURN}; newS^ _ score.style[newS.value]^; newS.height _ height; IF oldS = NIL THEN RETURN; IF oldS.length # newS.length THEN RETURN; FOR i: CARDINAL IN [1..newS.length) DO n _ newS.staff[i].y = newS.staff[i-1].y; o _ oldS.staff[i].y = oldS.staff[i-1].y; IF n # o THEN RETURN; ENDLOOP; FOR i: CARDINAL IN [0..newS.length) DO newS.staff[i].pitch _ oldS.staff[i].pitch; ENDLOOP; }; GetOctava: PUBLIC PROC[score: ScorePTR, octava: StavesPTR] RETURNS[StavesPTR] = { OPEN Event; -- USING [GetScoreIndex, GetStaff]; IF octava#NIL THEN SELECT octava.staves FROM octava1 => FOR i: NAT IN (GetScoreIndex[score, octava]..score.length) DO WITH score[i] SELECT FROM staves: StavesPTR => IF staves.staves=octava2 THEN { IF octava.value = staves.value THEN RETURN[staves]; IF GetStaff[octava, octava.value].y=GetStaff[staves, staves.value].y THEN RETURN[staves]; }; ENDCASE; ENDLOOP; octava2 => FOR i: NAT DECREASING IN[0..GetScoreIndex[score, octava]) DO WITH score[i] SELECT FROM staves: StavesPTR => IF staves.staves=octava1 THEN { IF octava.value = staves.value THEN RETURN[staves]; IF GetStaff[octava, octava.value].y = GetStaff[staves, staves.value].y THEN RETURN[staves]; }; ENDCASE; ENDLOOP; ENDCASE; RETURN[NIL]; }; Draw: PUBLIC PROC[score: ScorePTR, event: EventPTR] = { Utility.SetColor[score.sheet.context, black]; WITH event SELECT FROM sync: SyncPTR => DrawSync[score, sync]; staves: StavesPTR => SELECT staves.staves FROM style => DrawMeasure[score, measure, event.time, 10]; clef => Sheet.DrawClef[ score.sheet, staves.staff[staves.value].pitch, staves.value, staves.time]; octava1 => { octava2: StavesPTR ~ Event.GetOctava[score, staves]; IF octava2 = NIL THEN ERROR; Sheet.DrawOctava[score.sheet, staves.staff[staves.value].pitch, staves.value, staves.height, staves.time, octava2.time]; }; octava2 => IF Event.GetOctava[score, Event.GetOctava[score, staves]]#staves THEN DrawMeasure[score, doubleMeasure, staves.time, 20]; -- ELSE already drawn ENDCASE; event: KeySignaturePTR => Sheet.DrawKey[ score.sheet, event.key, Score.GetKey[score, event.time-1], event.time]; event: TimeSignaturePTR => Score.DrawTimeSignature[score, event.ts, event.time]; event: MetronomePTR => Score.DrawMetronome[score, event.metronome, event.time]; event: MeasurePTR => DrawMeasure[score, event.measure, event.time, 0]; ENDCASE; }; DrawMeasure: PROC[score: ScorePTR, type: MeasureType, time: Time, dy: INTEGER] = { OPEN Utility; staves: StavesPTR; x1, y1, top, delta: INTEGER; IF time = 0 THEN RETURN; IF score.sheet.printing THEN dy _ 0; Utility.SetColor[score.sheet.context, black]; staves _ Sheet.FindStaves[score.sheet, time]; [x1, y1] _ Sheet.Map[score.sheet, time, , staves.length-1]; y1 _ y1 - dy; top _ -staves.staff[staves.length-1].y+2*dy; SELECT type FROM measure => DrawLine[score.sheet.context, x1, y1, x1, y1+top]; doubleMeasure => {DrawLine[score.sheet.context, x1, y1, x1, y1+top]; IF score.sheet.printing OR score.sheet.scale = 1 THEN delta _ 2 ELSE delta _ 3; DrawLine[score.sheet.context, x1-delta, y1, x1-delta, y1+top]}; repeat1 => { DrawBox[score.sheet.context, [x1, y1, x1+3, y1+top]]; DrawLine[score.sheet.context, x1+5, y1, x1+5, y1+top]; }; repeat2, endMeasure => { DrawBox[score.sheet.context, [x1+1, y1, x1-2, y1+top]]; DrawLine[score.sheet.context, x1-5, y1, x1-5, y1+top]; }; ENDCASE; IF type # repeat1 AND type # repeat2 THEN RETURN; IF type = repeat1 THEN delta _ 6 ELSE delta _ -13; FOR i: NAT IN[0..staves.length) DO [x1, y1] _ Sheet.Map[score.sheet, time, , i]; SetCP[score.sheet.context, x1+delta, y1+16+4]; DrawChar[score.sheet.context, '.]; SetCP[score.sheet.context, x1+delta, y1+16-4]; DrawChar[score.sheet.context, '.]; ENDLOOP; }; AddNote: PUBLIC PROC[score: ScorePTR, sync: SyncPTR, note: NotePTR] = { c: ChordPTR _ note.chord; IF note.sync = sync THEN RETURN; -- already in the sync FOR i: CARDINAL IN [0..(IF c = NIL THEN 1 ELSE c.length)) DO IF c # NIL THEN note _ c.note[i]; RemoveNote[score, note.sync, note, FALSE]; note.sync _ sync; sync.note[sync.length] _ note; sync.length _ sync.length + 1; IF note.beam # NIL THEN Beam.SetSyncs[note.beam]; ENDLOOP; }; RemoveNote: PUBLIC PROC[score: ScorePTR, sync: SyncPTR, note: NotePTR, free: BOOL] = { IF note = NIL OR sync = NIL THEN RETURN; FOR i: CARDINAL IN [0..sync.length) DO IF sync.note[i] # note THEN LOOP; sync.length _ sync.length - 1; sync.note[i] _ sync.note[sync.length]; sync.note[sync.length] _ NIL; ENDLOOP; IF free AND sync.length = 0 THEN Event.Free[score, sync]; }; NewSync: PUBLIC PROC[score: ScorePTR, length: CARDINAL] RETURNS[sync: SyncPTR] = { sync _ NEW[EventRec.sync[length]]; }; Free: PUBLIC PROC[score: ScorePTR, event: EventPTR] = { SetBackPointers[score, event, NIL]; }; SetBackPointers: PROC[score: ScorePTR, event, new: EventPTR] = { index: CARDINAL _ Event.GetScoreIndex[score, event]; IF index # score.length THEN score[index] _ new; IF index # score.length AND new = NIL THEN { score.length _ score.length - 1; FOR i: CARDINAL IN [0..score.length) DO score[i] _ score[i+1]; ENDLOOP; score[score.length] _ NIL; }; SELECT event.type FROM sync => { sync: SyncPTR _ Event.Sync[event]; newSync: SyncPTR _ Event.Sync[new]; FOR i: CARDINAL IN [0..sync.length) DO sync[i].sync _ newSync; ENDLOOP}; measure => NULL; timeSignature => { IF score.cache.ts1 = event THEN score.cache.ts1 _ Event.TimeSignature[new]; IF score.cache.ts2 = event THEN score.cache.ts2 _ Event.TimeSignature[new]}; keySignature => { IF score.cache.key1 = event THEN score.cache.key1 _ Event.KeySignature[new]; IF score.cache.key2 = event THEN score.cache.key2 _ Event.KeySignature[new]}; metronome => { IF score.cache.met1 = event THEN score.cache.met1 _ Event.Metronome[new]; IF score.cache.met2 = event THEN score.cache.met2 _ Event.Metronome[new]}; staves => Sheet.Reset[score]; ENDCASE => ERROR; }; AddTimes: PUBLIC PROC[event: EventPTR, time, toc: Time] ~ { -- add times to notes event.time _ event.time + time; WITH event SELECT FROM sync: SyncPTR => FOR i: CARDINAL IN [0..sync.length) DO sync.note[i].toc _ sync.note[i].toc + toc; ENDLOOP; ENDCASE; }; Grace: PUBLIC PROC[sync: SyncPTR] RETURNS[BOOLEAN] ~ { FOR j: CARDINAL IN[0..sync.length) DO IF ~sync.note[j].grace THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE] }; InVoice: PUBLIC PROC[sync: SyncPTR, voice: CARDINAL] RETURNS[BOOLEAN] ~ { FOR j: CARDINAL IN [0..sync.length) DO IF sync.note[j].voice = voice THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; DrawSync: PROC[score: ScorePTR, s: SyncPTR] = { b: BeamPTR; c: ChordPTR; sync: ARRAY [0..16) OF NotePTR; x, y: INTEGER; min, vMin: INTEGER _ 1000; max, vMax: INTEGER _ -1000; FOR i: CARDINAL IN [0..s.length) DO sync[i] _ s[i]; ENDLOOP; FOR i: CARDINAL IN [0..s.length) DO IF s[i] = NIL THEN EXIT; IF sync[i] = NIL THEN LOOP; c _ s[i].chord; b _ s[i].beam; IF b # NIL AND b.beam # NIL THEN b _ b.beam; IF c # NIL THEN FOR j: CARDINAL IN [0..c.length) DO IF c.note[j] = NIL THEN EXIT; FOR k: CARDINAL IN (i..s.length) DO IF sync[k] = c.note[j] THEN sync[k] _ NIL; ENDLOOP; ENDLOOP; IF b # NIL AND NOT Beam.Drawn[score, b] THEN { [] _ Beam.Draw[score, b]; LOOP; }; IF c # NIL AND b = NIL THEN { Chord.Draw[score, c]; LOOP; }; IF b = NIL THEN Note.Draw[score, s[i]]; ENDLOOP; IF NOT score.sheet.sync THEN RETURN; FOR i: CARDINAL IN [0..s.length) DO IF s[i] = NIL THEN EXIT; [x, y] _ Sheet.MapNote[score.sheet, s[i]]; min _ MIN[min, y]; max _ MAX[max, y]; IF ~Note.InVoice[s[i], score.sheet.voice] THEN LOOP; vMin _ MIN[vMin, y]; vMax _ MAX[vMax, y]; ENDLOOP; Utility.SetColor[score.sheet.context, light]; IF min # vMin OR max # vMax THEN Utility.DrawLine[score.sheet.context, x+4, min-6, x+4, max+6]; Utility.SetColor[score.sheet.context, black]; IF vMin # vMax AND vMin # 1000 THEN Utility.DrawLine[score.sheet.context, x+4, vMin-6, x+4, vMax+6]; }; Adjust: PUBLIC PROC[score: ScorePTR, s: SyncPTR] = { n: NotePTR; c: ChordPTR; sync: ARRAY [0..16) OF NotePTR; delta: INTEGER; pad: REF ScratchPad ~ NEW[ScratchPad]; top: NAT _ s.length-1; bottom: NAT _ 0; length: NAT _ 0; IF s = NIL THEN RETURN; FOR i: NAT IN [0..s.length) DO sync[i] _ s[i]; ENDLOOP; FOR i: NAT IN [0..s.length) DO IF (n _ s[i]) = NIL THEN EXIT; n.delta _ n.accDelta _ 0; IF n.rest THEN LOOP; c _ n.chord; pad[length].n _ n; pad[length].c _ c; pad[length].y _ Sheet.MapNote[score.sheet, n].y; pad[length].acc _ Score.GetAccidental[score, n]; pad[length].stemUp _ IF c = NIL THEN n.stemUp ELSE c.stemUp; pad[length].stem _ IF pad[length].stemUp THEN pad[length].y+32 ELSE pad[length].y-32; length _ length+1; ENDLOOP; SortPad[FALSE, pad]; FOR i: NAT IN [0..length) DO IF i # 0 AND pad[i].y = pad[i-1].y AND pad[i].acc = pad[i-1].acc THEN pad[i].acc _ inKey; IF pad[i].acc # inKey THEN top _ MIN[top, i]; IF pad[i].acc # inKey THEN bottom _ MAX[bottom, i]; ENDLOOP; FOR i: NAT IN [0..length) DO IF sync[i] = NIL THEN LOOP; c _ sync[i].chord; IF c # NIL THEN Chord.Adjust[score.sheet, c] ELSE LOOP; FOR j: NAT IN [0..c.length) DO FOR k: NAT IN [0..s.length) DO IF sync[k] = c.note[j] THEN {sync[k] _ NIL; EXIT}; ENDLOOP; ENDLOOP; ENDLOOP; FOR i: NAT IN [1..length) DO FOR j: NAT DECREASING IN [0..i) DO IF pad[j].c = pad[i].c AND pad[i].c # NIL THEN LOOP; IF Overlap[score, i, j, pad, length] THEN LOOP; delta _ Note.Delta[score.sheet, pad[j].n]; IF pad[j].stemUp AND NOT pad[i].stemUp THEN { IF pad[j].y-pad[i].y >= 8 THEN LOOP; MoveRightTo[pad[i], delta]; MoveLeft[pad[i], 8]; EXIT; }; IF pad[j].y-pad[i].y < 8 THEN MoveRightTo[pad[i], delta+(IF pad[j].n.value = whole THEN 10 ELSE 8)]; IF pad[i].n.value = whole OR pad[i].n.value = unknown THEN LOOP; IF pad[j].stem < pad[i].y THEN MoveRightTo[pad[i], delta+2]; IF pad[i].stem > pad[j].y THEN MoveRightTo[pad[i], delta+2]; ENDLOOP; ENDLOOP; IF top > bottom THEN RETURN; FOR i: NAT IN [0..length) DO pad[i].x _ -10; ENDLOOP; FOR i: NAT IN [1..length) DO IF pad[i-1].y-pad[i].y >= 8 THEN LOOP; IF pad[i-1].acc = inKey OR pad[i].acc = inKey THEN LOOP; IF Note.Delta[score.sheet, pad[i-1].n] > Note.Delta[score.sheet, pad[i].n] THEN pad[i-1].push _ i ELSE pad[i].push _ i-1; ENDLOOP; PlaceAccidental[score, pad, top, length]; FOR i: NAT IN [0..length) DO IF i = top THEN LOOP; IF pad[i].push # bottom THEN LOOP; PlaceAccidental[score, pad, i, length]; ENDLOOP; PlaceAccidental[score, pad, bottom, length]; FOR i: NAT IN [0..length) DO IF i = top OR i = bottom THEN LOOP; IF pad[i].push = bottom THEN LOOP; IF pad[i].push = padLength THEN LOOP; PlaceAccidental[score, pad, i, length]; ENDLOOP; FOR i: NAT IN [0..length) DO IF i = top OR i = bottom THEN LOOP; IF pad[i].push # padLength THEN LOOP; PlaceAccidental[score, pad, i, length]; ENDLOOP; FOR i: NAT IN [0..length) DO IF pad[i].acc = inKey THEN LOOP; pad[i].n.accDelta _ -pad[i].n.delta - 8*pad[i].x; ENDLOOP; }; Overlap: PROC[score: ScorePTR, a, b: NAT, pad: REF ScratchPad, length: NAT] RETURNS[BOOL] = { found: BOOL; top, bottom: NAT _ length; PartOf: PROC[i, a: NAT] RETURNS[BOOL] = INLINE { RETURN[a = i OR (pad[i].c = pad[a].c AND pad[a].c # NIL)]}; IF pad[a].c = NIL AND pad[b].c = NIL THEN { -- just single notes IF pad[a].y # pad[b].y THEN RETURN[FALSE]; IF pad[a].n.pitch # pad[b].n.pitch THEN RETURN[FALSE]; IF pad[a].stemUp = pad[b].stemUp THEN RETURN[FALSE]; IF pad[a].n.value = whole OR pad[b].n.value = whole THEN RETURN[FALSE]; RETURN[TRUE]}; FOR i: NAT IN [0..length) DO IF ~PartOf[i, a] THEN LOOP; IF top = length THEN top _ i; bottom _ i; ENDLOOP; IF pad[a].stemUp THEN top _ 0 ELSE bottom _ length-1; FOR i: NAT IN [top..bottom] DO IF ~PartOf[i, b] THEN LOOP; found _ FALSE; FOR j: NAT IN [top..bottom] DO IF ~PartOf[j, a] THEN LOOP; IF pad[i].n.pitch # pad[j].n.pitch OR pad[i].y # pad[j].y THEN LOOP; IF Note.Delta[score.sheet, pad[i].n] # Note.Delta[score.sheet, pad[j].n] THEN LOOP; found _ TRUE; EXIT; ENDLOOP; IF ~found THEN RETURN[FALSE]; ENDLOOP; top _ length; FOR i: NAT IN [0..length) DO IF ~PartOf[i, b] THEN LOOP; IF top = length THEN top _ i; bottom _ i; ENDLOOP; IF pad[b].stemUp THEN top _ 0 ELSE bottom _ length-1; FOR i: NAT IN [top..bottom] DO IF ~PartOf[i, a] THEN LOOP; found _ FALSE; FOR j: NAT IN [top..bottom] DO IF ~PartOf[j, b] THEN LOOP; IF pad[i].n.pitch # pad[j].n.pitch OR pad[i].y # pad[j].y THEN LOOP; IF Note.Delta[score.sheet, pad[i].n] # Note.Delta[score.sheet, pad[j].n] THEN LOOP; found _ TRUE; EXIT; ENDLOOP; IF ~found THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; PlaceAccidental: PROC[score: ScorePTR, pad: REF ScratchPad, i, length: NAT] = { blocked: BOOL; d, h: INTEGER; IF i = padLength THEN RETURN; IF pad[i].acc = inKey THEN RETURN; FOR j: NAT IN [0..length) DO IF pad[j].push = i THEN pad[i].x _ MAX[pad[j].x, pad[i].x]; ENDLOOP; FOR d IN [MAX[pad[i].x, 0]..6) DO blocked _ FALSE; FOR j: NAT IN [0..length) DO SELECT (IF pad[j].y > pad[i].y THEN pad[j].acc ELSE pad[i].acc) FROM flat, doubleFlat, doubleSharp => h _ 8; ENDCASE => h _ 16; SELECT (IF pad[j].y > pad[i].y THEN pad[i].acc ELSE pad[j].acc) FROM doubleSharp => NULL; ENDCASE => h _ h+8; IF pad[j].y-pad[i].y >= h THEN LOOP; IF pad[i].y-pad[j].y >= 24 THEN EXIT; IF pad[i].y-pad[j].y >= h THEN LOOP; IF d = 0 AND Note.Delta[score.sheet, pad[j].n] < 0 THEN {blocked _ TRUE; EXIT}; IF j = i THEN LOOP; IF j = pad[i].push THEN LOOP; IF pad[j].acc # inKey AND pad[j].x = d THEN {blocked _ TRUE; EXIT}; ENDLOOP; IF blocked THEN LOOP; MoveAccTo[pad, i, d]; RETURN; ENDLOOP; ERROR; }; MoveRightTo: PROC[p: Scratch, x: INTEGER] = { IF p.c = NIL THEN p.n.delta _ MAX[p.n.delta, x] ELSE p.c.delta _ MAX[p.c.delta, x - p.n.delta]; }; MoveLeft: PROC[p: Scratch, delta: INTEGER] = { IF p.c = NIL THEN p.n.delta _ MIN[p.n.delta, -delta] ELSE p.c.delta _ MIN[p.c.delta, -delta - p.n.delta]; }; MoveAccTo: PROC[p: REF ScratchPad, i: NAT, delta: INTEGER] = { p[i].x _ MAX[p[i].x, delta]; IF p[i].push # padLength AND p[p[i].push].x > -1 THEN MoveAccTo[p, p[i].push, p[i].x+1]; }; SortPad: PROC[ascending: BOOL, pad: REF ScratchPad] = { temp: Scratch; FOR i: NAT IN [0..padLength) DO IF pad[i].n = NIL THEN EXIT; FOR j: NAT IN (i..padLength) DO IF pad[j].n = NIL THEN EXIT; IF NOT ascending AND pad[i].y < pad[j].y OR ascending AND pad[i].y > pad[j].y THEN { temp _ pad[i]; pad[i] _ pad[j]; pad[j] _ temp; }; ENDLOOP; ENDLOOP; }; padLength: NAT = 16; ScratchPad: TYPE = ARRAY [0..padLength) OF Scratch; Scratch: TYPE = RECORD[ x, y, stem: INTEGER _ 0, push: NAT _ padLength, acc: Accidental, stemUp: BOOL, c: ChordPTR, n: NotePTR _ NIL ]; END. ÚEventImpl.mesa Copyright (C) 1983, 1984 Xerox Corporation. All rights reserved. Author: John Maxwell Last Edited by: Maxwell, November 22, 1983 12:02 pm Last Edited by: Doug Wyatt, June 16, 1984 12:14:42 pm PDT must be a nearby sync FAILURE: score isn't sorted. Try again. ****************************************************************** procedures for handling staves ****************************************************************** newS.staves = staves clef switches carry over if the staff form is the same **************************************************************************** data abstractions for a sync CONSTRAINT: s.note[i] # NIL for all i < s.length CONSTRAINT: s.note[i] = NIL for all s.length <= i < s.max CONSTRAINT: chord.note[i].sync = chord.note[j].sync for all i, j < chord.length **************************************************************************** IF sync.length = sync.max THEN sync _ NewSync[score, sync.max + 4, sync]; does not automatically remove empty syncs! (see Voice.Correct) IF old # NIL THEN { nullSize: CARDINAL = SIZE[EventRec.sync[0]]; oldSize: CARDINAL = SIZE[EventRec.sync[old.max]]; Inline.LongCOPY[from: old, nwords: nullSize-1, to: sync]; -- skip 'max' Inline.LongCOPY[from: old+nullSize, nwords: oldSize-nullSize, to: sync+nullSize]; SetBackPointers[score, old, sync]; zone.FREE[@old]; RETURN}; zone.FREE[@event]; changes all pointers to event to be pointers to new an event can be pointed at by a score, the cache, notes, the sheet and the styles draw the sync line build the pad handle note adjacencies within a chord no need to process a chord more than once determine the deltas special case: allow some notes to overlap special case: higher note with stem down and lower with stem up FOR k: CARDINAL IN [0..i] DO IF pad[j].c = pad[k].c AND pad[k].c # NIL THEN LOOP; MoveLeft[pad[k], IF pad[k].n.value = whole THEN 10 ELSE 8]; ENDLOOP; general case: shift lower note to the right determine the deltas for the accidentals RULES: (in order of precedence) 1) all of the accidentals appear to the left of all of the notes 2) accidentals for notes offset in a chord have the same offset 3) there must be at least three lines vertically between accidentals 4) the highest and lowest accidentals should have the same horizontal position 5) lower accidentals should go to the left of higher accidentals do top, then whatever pushes bottom, then bottom, then whatever pushes, then whatever. put the results in accDelta we have at least one chord; can a and b overlap? find the tops and bottoms for a do all of the notes in b which are within top and bottom have a corresponding note in a? find the tops and bottoms for b do all of the notes in a which are within top and bottom have a corresponding note in b? ʨ˜šœ™Jšœ@™@Jšœ™Jšœ3™3Jšœ9™9J™—šÏk ˜ Jšœœ˜#Jšœœ˜Jšœ˜Jšœ ˜ Jšœœ˜"Jšœ˜Jšœ˜Jšœœ0˜=J˜—Jšœ œ˜Jšœ0˜7Jšœ˜ Jšœœœ ˜J˜šÏn œœœ#˜=Jšœœ ˜ Jšœœ˜Jšœ œœœ˜)šœœœ ˜J˜Jšœ œœ˜,Jšœ(œ˜FJšœ œœ˜,Jšœœœ˜+Jšœ™š œœœœ˜LJšœœœœ˜,—š œœ œœ œ˜LJšœœœœ˜,—Jšœœ˜—Jšœ(™(Jšœœœœœœœœ˜TJšœÏc˜%Jšœ˜J˜—š žœœœœœ ˜LJšœ˜Jšœ˜J˜—š ž œœœœœœ˜ZJ˜šœœ˜Jš œœœœœ˜8Jšœœ˜Jšœœœ˜—Jšœ˜"Jšœ˜J˜—J™JšœB™BJšœ™JšœB™BJ˜šžœœœ7˜LJšœœ˜ Jšœœ˜Jšœœœœ˜J˜šœœ˜J˜%J˜J˜šœœœ˜&Jšœ,œœ˜8J˜Jšœ˜—Jšœ˜—Jšœ™J˜!J˜Jšœ6™6Jšœœœœ˜Jšœœœ˜)šœœœ˜&J˜(J˜(Jšœœœ˜Jšœ˜—šœœœ˜&J˜*Jšœ˜—Jšœ˜J˜—šž œœœ%œ˜QJšœŸ#˜/š œœœœ˜,šœ œœœ.˜Hšœ œ˜šœœœ˜4Jšœœœ ˜3JšœCœœ ˜YJ˜—Jšœ˜—Jšœ˜—š œ œœ œœ"˜Gšœ œ˜šœœœ˜4Jšœœœ ˜3JšœEœœ ˜[J˜—Jšœ˜—Jšœ˜—Jšœ˜—Jšœœ˜ Jšœ˜J˜—J™šžœœœ&˜7J˜-šœœ˜J˜'šœœ˜.J˜5˜J˜J—˜ J˜4Jšœ œœœ˜˜?J˜8—J˜—šœ œ@˜MJšœ5Ÿ˜N—Jšœ˜—˜(J˜G—J˜PJ˜OJ˜FJšœ˜—Jšœ˜J˜—šž œœ5œ˜RJšœ ˜ J˜Jšœœ˜Jšœ œœ˜Jšœœ˜$J˜-J˜-J˜;J˜ J˜,šœ˜J˜=˜EJšœœœ œ ˜OJ˜?—šœC˜CJšœ9˜9—šœQ˜QJšœ:˜:—Jšœ˜—Jšœœœœ˜1Jšœœ œ ˜2šœœœ˜"J˜-J˜QJ˜QJšœ˜—Jšœ˜J˜—J™JšœL™LJšœ™Jšœ0™0Jšœ9™9JšœO™OJšœL™LJ˜šžœœœ3˜GJ˜JšœœœŸ˜7šœœœœœœœ œ˜>Jšœœ,™JJšœœœ˜!Jšœ#œ˜*J˜J˜J˜Jšœ œœ˜2Jšœ˜—Jšœ˜J˜—šž œœœ6œ˜VJšœ?™?Jš œœœœœœ˜(šœœœ˜&Jšœœœ˜!J˜J˜&Jšœœ˜Jšœ˜—Jšœœœ˜9Jšœ˜J˜—š žœœœœœ˜RJšœœ˜"šœœœ™Jšœ œœ™,Jšœ œœ™1Jšœ:Ÿ ™GJ™RJ™"Jšœœ™Jšœ™—Jšœ˜J˜—šžœœœ&˜7Jšœœ˜#Jšœœ ™Jšœ˜J˜—šžœœ)Ÿœ˜@Jšœ3™3JšœQ™QJšœœ%˜4Jšœœ˜0šœœœœ˜,J˜ Jš œœœœœ˜GJšœœ˜Jšœ˜—šœ ˜˜ J˜"J˜#Jš œœœœœ˜H—Jšœ œ˜˜Jšœœ,˜KJšœœ-˜L—˜Jšœœ,˜LJšœœ-˜M—˜Jšœœ)˜IJšœœ*˜J—J˜Jšœœ˜—Jšœ˜J˜—šžœœœ'Ÿ˜QJ˜šœœ˜šœœœœ˜7J˜*Jšœ˜—Jšœ˜—šœ˜J˜——š žœœœœœ˜6šœœœ˜%Jšœœœœ˜*Jšœ˜—Jšœœ˜ šœ˜J˜——š žœœœœœœ˜Išœœœ˜&Jšœœœœ˜0Jšœ˜—Jšœœ˜Jšœ˜J˜—J˜šžœœ!˜/J˜ J˜ Jšœœ œ ˜Jšœœ˜Jšœ œ˜Jšœ œ ˜Jš œœœœœ˜<šœœœ˜#Jšœœœœ˜Jšœ œœœ˜J˜J˜Jš œœœ œœ ˜,š œœœœœœ˜3Jšœ œœœ˜šœœœ˜#Jšœœ œ˜*Jšœ˜—Jšœ˜—Jš œœœœœœ˜QJš œœœœœœ˜˜>—J˜-šœ œ ˜#Jšœ@˜@—Jšœ˜J˜—J˜šžœœœ!˜4J˜ J˜ Jšœœ œ ˜Jšœœ˜Jšœœœ ˜&Jšœœ˜Jšœœ˜Jšœœ˜Jšœœœœ˜Jš œœœœœ˜7Jšœ ™ šœœœ˜Jšœœœœ˜J˜Jšœœœ˜J˜ J˜J˜J˜0J˜0Jš œœœœ œ ˜Jšœ œ˜Jšœœœ#˜XJšœ˜J˜—J˜šžœœ œœ˜7J˜šœœœ˜Jšœ œœœ˜šœœœ˜Jšœ œœœ˜šœœ œ˜)Jšœ œ˜%Jšœ4˜8—Jšœ˜—Jšœ˜—Jšœ˜J˜—Jšœ œ˜Jšœ œœœ ˜4šœ œœ˜Jšœ œ˜Jšœœ˜Jšœ˜Jšœœ˜Jšœ ˜ Jšœ ˜Jšœ˜J˜—J˜Jšœ˜J˜—…—?¬d.