DIRECTORY Beam USING [AddChord, Remove], Chord USING [default, InVoice, RemoveNote, Sort], Graphics USING [DrawRectangle, MoveTo, SetTexture], MusicDefs, Note USING [DrawHead, FindChord, Width], Sheet USING [Map, MapNote], Sync USING [AddNote], Utility USING [DrawChar, DrawLine, FreeChord]; ChordImpl: CEDAR PROGRAM IMPORTS Beam, Chord, Graphics, MusicDefs, Note, Sheet, Sync, Utility EXPORTS Chord = BEGIN OPEN Chord, MusicDefs, Graphics, Utility; Beam: PUBLIC PROC[c: ChordPTR] RETURNS[BeamPTR] = {RETURN[IF c.note[0]#NIL THEN c.note[0].beam ELSE NIL]}; GetHeapIndex: PUBLIC PROC[c: ChordPTR] RETURNS[CARDINAL] = {FOR i: CARDINAL IN [0..chordHeapLength) DO IF chordHeap[i]=c THEN RETURN[i]; ENDLOOP; RETURN[chordHeapLength]}; Grace: PUBLIC PROC[c: ChordPTR] RETURNS[BOOL] = {FOR i: CARDINAL IN [0..chordLength) DO IF c.note[i]=NIL THEN EXIT; IF ~c.note[i].grace THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]}; InVoice: PUBLIC PROC[c: ChordPTR, voice: CARDINAL] RETURNS[BOOL] = {FOR i: CARDINAL IN [0..chordLength) DO IF c.note[i]=NIL THEN EXIT; IF c.note[i].voice=voice THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]}; Length: PUBLIC PROC[c: ChordPTR] RETURNS[CARDINAL] = {FOR i: CARDINAL IN [0..chordLength] DO IF i=chordLength THEN RETURN[i]; IF c.note[i]=NIL THEN RETURN[i]; ENDLOOP; ERROR}; Width: PUBLIC PROC[c: ChordPTR] RETURNS[INTEGER] = {RETURN[IF Grace[c] THEN 5 ELSE 8]}; AddNote: PUBLIC PROC[c: ChordPTR, n: NotePTR] = { oldBeam: BeamPTR = n.beam; oldChord: ChordPTR = Note.FindChord[n]; chordSync: SyncPTR = IF c.note[0]#NIL THEN c.note[0].sync ELSE n.sync; chordBeam: BeamPTR = IF c.note[0]#NIL THEN c.note[0].beam ELSE NIL; IF c=oldChord THEN RETURN; IF c.note[chordLength-1]#NIL THEN Overflow[chord]; FOR i: CARDINAL IN [0..chordLength) DO IF c.note[i]=NIL THEN {c.note[i] _ n; EXIT}; ENDLOOP; n.chord _ c; n.beam _ chordBeam; IF chordBeam=NIL AND oldBeam#NIL THEN Beam.AddChord[oldBeam, c]; IF n.sync#chordSync THEN Sync.AddNote[chordSync, n]; IF oldChord#NIL THEN Chord.RemoveNote[oldChord, n]; IF oldBeam#NIL AND oldChord=NIL AND oldBeam#n.beam THEN Beam.Remove[oldBeam, n, NIL, NIL]; }; RemoveNote: PUBLIC PROC[c: ChordPTR, n: NotePTR] = { i, k: CARDINAL _ chordLength; IF n=NIL OR c=NIL THEN RETURN; FOR i DECREASING IN [0..chordLength) DO IF c.note[i]=NIL THEN k _ i; IF c.note[i]#n THEN LOOP; IF n.chord=c THEN n.chord _ NIL; n.beam _ NIL; -- removing a note from a chord also removes it from the beam c.note[i] _ c.note[k-1]; c.note[k-1] _ NIL; ENDLOOP; IF c.note[1]=NIL THEN Utility.FreeChord[@c]; }; Sort: PUBLIC PROC[c: ChordPTR, up: BOOL] RETURNS[n: CARDINAL] = { i, j: CARDINAL; temp: NotePTR; FOR i IN [0..chordLength) DO IF c.note[i]=NIL THEN { n _ i; EXIT; }; FOR j IN (i..chordLength) DO IF c.note[j]=NIL THEN EXIT; IF NOT up AND c.note[i].pitchc.note[j].pitch THEN { temp_ c.note[i]; c.note[i]_ c.note[j]; c.note[j]_ temp; }; ENDLOOP; ENDLOOP; }; SetDefaultStem: PUBLIC PROC[c: ChordPTR] = { n: CARDINAL; x0, xn, y0, yn, middle0, middlen: INTEGER; n _ Chord.Sort[c, TRUE]; [x0, y0] _ Sheet.Map[c.note[0].sync.time, c.note[0].pitch, c.note[0].staff]; [xn, yn] _ Sheet.Map[c.note[n-1].sync.time, c.note[n-1].pitch, c.note[n-1].staff]; middle0 _ Sheet.Map[c.note[0].sync.time,, c.note[0].staff].y+16; middlen _ Sheet.Map[c.note[n-1].sync.time,, c.note[n-1].staff].y+16; SELECT TRUE FROM (yn+y0)/2 > middlen => c.stemUp _ FALSE; (yn+y0)/2 < middle0 => c.stemUp _ TRUE; (yn+y0)/2 > (middlen+middle0)/2 => c.stemUp _ TRUE; ENDCASE => c.stemUp _ FALSE; }; Draw: PUBLIC PROC[c: ChordPTR, stem: INTEGER] = { n: NotePTR; flag: NoteValue; two: REAL = 2; dotX: INTEGER _ 0; inVoice: BOOL; nonGrace: BOOL _ FALSE; minStaff, maxStaff: CARDINAL; x, y, yMin, yMax, mid, width: INTEGER; inVoice _ ~(voice AND NOT Chord.InVoice[c, selectedVoice]); -- draw the note heads FOR i: CARDINAL IN [0..chordLength) DO IF c.note[i]=NIL THEN EXIT ELSE n _ c.note[i]; IF ~n.dotted THEN LOOP; [x, y] _ Sheet.MapNote[n]; dotX _ MAX[dotX, x+Note.Width[n]+2]; ENDLOOP; mid _ Sheet.Map[n.sync.time,, n.staff].y+16; FOR i: CARDINAL IN [0..chordLength) DO IF c.note[i]=NIL THEN EXIT ELSE n _ c.note[i]; [x, y] _ Sheet.MapNote[n]; Note.DrawHead[n, x, y, dotX]; IF i=0 THEN {yMin _ yMax _ y; width _ 0}; width _ MAX[width, Note.Width[n]]; IF ~n.grace THEN nonGrace _ TRUE; IF y<=yMin THEN {yMin _ y; minStaff _ n.staff}; IF y>=yMax THEN {yMax _ y; maxStaff _ n.staff}; ENDLOOP; IF NOT show.notehead THEN RETURN; Graphics.SetTexture[context, IF inVoice THEN black ELSE light]; IF show.display=graphical THEN x _ x - n.delta; --subtract off x offset before drawing stem FOR i: INTEGER IN [3..9] WHILE yMax-mid >= i*d DO IF nonGrace THEN DrawRectangle[context,[x-3, mid+1+i*d],[x+width+3, mid-1+i*d]] ELSE DrawRectangle[context,[x-3, mid+1/two+i*d],[x+width+3, mid-1/two+i*d]]; ENDLOOP; FOR i: INTEGER IN [3..9] WHILE mid-yMin >= i*d DO IF nonGrace THEN DrawRectangle[context,[x-3, mid+1-i*d],[x+width+3, mid-1-i*d]] ELSE DrawRectangle[context,[x-3, mid+1/two-i*d],[x+width+3, mid-1/two-i*d]]; ENDLOOP; IF n.value=whole OR n.value=unknown THEN RETURN; flag _ n.value; IF stem#default -- drawing part of or beam THEN {stem _ (IF c.stemUp THEN stem+1 ELSE stem-1); flag _ quarter} ELSE SELECT TRUE FROM nonGrace AND c.stemUp => stem _ MAX[yMax+(7*d)/2, mid]; nonGrace AND ~c.stemUp => stem _ MIN[yMin-(7*d)/2, mid]; c.stemUp => stem _ yMax+2*d; ~c.stemUp => stem _ yMin-2*d; ENDCASE; IF c.stemUp THEN DrawLine[x+width, yMin, x+width, stem] ELSE DrawLine[x, yMax, x, stem]; IF nonGrace THEN MoveTo[context,[x, IF c.stemUp THEN stem-24 ELSE stem+24]] ELSE MoveTo[context,[x, IF c.stemUp THEN stem-17 ELSE stem+17]]; SELECT TRUE FROM ~nonGrace => IF c.stemUp THEN DrawChar[context, 133C] ELSE DrawChar[context, 134C]; flag=eighth => IF c.stemUp THEN DrawChar[context, 153C] ELSE DrawChar[context, 163C]; flag=sixteenth => IF c.stemUp THEN DrawChar[context, 152C] ELSE DrawChar[context, 162C]; flag=thirtysecond => IF c.stemUp THEN DrawChar[context, 151C] ELSE DrawChar[context, 161C]; flag=sixtyfourth => IF c.stemUp THEN DrawChar[context, 151C] ELSE DrawChar[context, 161C]; ENDCASE; }; d: CARDINAL=8; Adjust: PUBLIC PROC[c: ChordPTR] = { n: NotePTR; pad: ScratchPad; delta: INTEGER; last: BOOL _ FALSE; i, length: CARDINAL; FOR i IN [0..chordLength) DO IF (n _ c.note[i])=NIL THEN { length _ i; EXIT; }; [, pad[i].y] _ Sheet.MapNote[n]; pad[i].n _ n; n.delta _ 0; ENDLOOP; SortPad[c.stemUp,@pad]; c.delta _ 0; IF c.stemUp THEN delta _ 8 ELSE delta _ -8; FOR i IN [1..length) DO IF last THEN { last _ FALSE; LOOP; }; IF ABS[pad[i-1].y-pad[i].y]>= 8 THEN LOOP; pad[i].n.delta _ delta; last _ TRUE; ENDLOOP; }; SortPad: PROC[ascending: BOOL, pad: POINTER TO ScratchPad] = { i, j: CARDINAL; temp: Scratch; FOR i IN [0..syncLength) DO IF pad[i].n=NIL THEN EXIT; FOR j IN (i..syncLength) DO IF pad[j].n=NIL THEN EXIT; IF NOT ascending AND pad[i].ypad[j].y THEN { temp_ pad[i]; pad[i]_ pad[j]; pad[j]_ temp; }; ENDLOOP; ENDLOOP; }; Delta: PROC[n: NotePTR] RETURNS[INTEGER] = { c: ChordPTR _ Note.FindChord[n]; IF c=NIL THEN RETURN[n.delta] ELSE RETURN[n.delta+c.delta]; }; ScratchPad: TYPE= ARRAY [0..syncLength) OF Scratch; Scratch: TYPE = RECORD[x, y, stem: INTEGER _ 0, push: CARDINAL _ syncLength, acc: Accidental, stemUp: BOOL, c: ChordPTR, n: NotePTR _ NIL]; END. ¤ChordImpl.mesa Copyright (C) 1981, 1984 Xerox Corporation. All rights reserved. Author: John Maxwell last modified: October 23, 1981 12: 58 PM Edited by Doug Wyatt, June 14, 1984 3:35:28 pm PDT **************************************************************************** data abstractions for a chord CONSTRAINT: c.note[i].sync = c.note[j].sync for all i, j CONSTRAINT: c.note[i].beam = c.note[j].beam for all i, j **************************************************************************** check for aborted attempts put the note in the chord remove the note from old places keep the notes packed; ****************************************************************** procedures for drawing chords on the screen ****************************************************************** xWide, yWide: INTEGER; IF n.delta#0 THEN { xWide _ MIN[xWide, x]; yWide _ IF y>mid THEN MIN[yWide, y] ELSE MAX[yWide, y]}; draw the ledger lines draw the stem draw the flag **************************************************************************** look graphical **************************************************************************** build the pad, initialize determine the deltas on the notes Ê [˜šœ™Jšœ@™@Jšœ™Jšœ*™*J™2J˜—šÏk ˜ Jšœœ˜Jšœœ&˜1Jšœ œ%˜3J˜ Jšœœ˜(Jšœœ˜Jšœœ ˜Jšœœ!˜.J˜—Jšœ œ˜Jšœ>˜EJšœ˜ Jšœœœ%˜1J˜šÏnœœœœ ˜2Jš œœœ œœœœ˜8J˜—š ž œœœœœ˜;š œœœœœ˜,Jšœœœ˜"Jšœ˜ Jšœ˜J˜——š žœœœœœ˜0šœœœœ˜'Jšœ œœœ˜Jšœœœœ˜'Jšœ˜Jšœœ˜J˜——š žœœœœœœ˜Cšœœœœ˜'Jšœ œœœ˜Jšœœœœ˜+Jšœ˜Jšœœ˜J˜——š žœœœœœ˜5šœœœœ˜'Jšœœœ˜ Jšœ œœœ˜ Jšœ˜Jšœ˜J˜——š žœœœœœ˜3Jš œœœ œœ˜%J˜—JšœL™LJšœ™Jšœ8™8Jšœ8™8JšœL™LJ˜šžœœœ˜1J˜J˜'Jš œœ œœœ˜FJš œœ œœœœ˜CJšœ™Jšœ œœ˜Jšœœœ˜2Jšœ™šœœœ˜&Jšœ œœœ˜,Jšœ˜—J˜ J˜Jš œ œœ œœ˜@Jšœœ˜4Jšœ™Jšœ œœ˜3Jšœ œœ œœœœœ˜ZJšœ˜—J˜šž œœœ˜4Jšœœ˜Jš œœœœœœ˜Jšœ™šœ œœ˜'Jšœ œœ˜Jšœ œœ˜šœ œ œ˜ Jšœ œÏc>˜L—J˜Jšœœ˜Jšœ˜—Jšœ œœ˜,Jšœ˜—J˜š žœœœœœœ˜AJšœœ˜J˜šœœ˜Jšœ œœ œ˜'šœœ˜Jšœ œœœ˜šœœœ!˜.Jšœœ!˜*Jšœ=˜A—Jšœ˜—Jšœ˜—Jšœ˜—J˜šžœœœ˜,Jšœœ˜ Jšœ"œ˜*Jšœœ˜J˜LJ˜RJ˜@J˜Dšœœ˜Jšœ"œ˜(Jšœ"œ˜'Jšœ.œ˜3Jšœœ˜—Jšœ˜—J˜JšœB™BJšœ+™+JšœB™BJ˜šžœœœœ˜1J˜ J˜Jšœœ˜Jšœœ˜Jšœ œ˜Jšœ™Jšœ œœ˜Jšœœ˜Jšœœ˜&Jšœœœ#Ÿ˜Ršœœœ˜&Jš œ œœœœ˜.Jšœ œœ˜J˜Jšœœ˜$Jšœ˜—J˜,šœœœ˜&Jš œ œœœœ˜.J˜J˜Jšœœ˜)Jšœœ˜"—Jšœ™Jšœ™šœ9™9Jšœ œ œ˜!Jšœ œ ˜/Jšœ œ ˜/Jšœ˜—Jšœœœœ˜!Jšœ™Jšœœ œœ˜?JšœœŸ,˜\Jš œœœœ˜1šœ ˜ Jšœ?˜CJšœH˜LJšœ˜ —Jš œœœœœ˜2šœ ˜ Jšœ?˜CJšœH˜LJšœ˜ —Jšœœœœ˜0Jšœ ™ J˜šœŸ˜+Jšœ œ œœ˜Cšœœœ˜Jšœ œœ˜7Jšœ œœ˜8J˜J˜Jšœ˜ ——Jšœ œ(œ˜XJšœ ™ šœ ˜ Jšœœ œ œ ˜?Jšœœ œ œ ˜@—šœœ˜šœ œ ˜Jšœ˜Jšœ˜—šœœ ˜Jšœ˜Jšœ˜—šœœ ˜Jšœ˜Jšœ˜—šœœ ˜!Jšœ˜Jšœ˜—šœœ ˜ Jšœ˜Jšœ˜—Jšœ˜—Jšœ˜—J˜Jšœœ˜J˜JšœL™LJšœ™JšœL™LJ˜šžœœœ˜$J˜ J˜Jšœœ˜Jšœœœ˜Jšœ œ˜Jšœ™šœœ˜Jšœœœœ˜2J˜ J˜ J˜ Jšœ˜—J˜J˜ Jšœ!™!Jšœ œ œ ˜+šœœ ˜Jšœœ œœ˜%Jšœœœœ˜*J˜Jšœœ˜ Jšœ˜—Jšœ˜—J˜š žœœ œœœ˜>Jšœœ˜J˜šœœ˜Jšœ œœœ˜šœœ˜Jšœ œœœ˜šœœ œ˜'Jšœ œ˜#Jšœ1˜5—Jšœ˜—Jšœ˜—Jšœ˜—J˜J˜šžœœ œœ˜,J˜ šœœœœ ˜Jšœœ˜—Jšœ˜—J˜J˜Jšœ œœœ ˜4š œ œœ œ œ˜LJšœœ˜Jšœœ˜J˜J˜—Jšœ˜—…—à-ß