NoteImpl.mesa
Copyright (C) 1981, 1984 Xerox Corporation. All rights reserved.
Author: John Maxwell
last modified: December 18, 1981 8: 51 AM
Edited by Doug Wyatt, June 14, 1984 1:07:46 pm PDT
DIRECTORY
Beam USING [Remove],
Chord USING [RemoveNote],
Graphics USING [MoveTo, DrawRectangle, SetTexture],
InlineDefs USING [LowHalf],
MusicDefs,
Note USING [default, DrawHead, DrawTie, Duration, GetBackTie, FindChord, Width],
Piece USING [NearestSync],
Real USING [Fix],
Score USING [GetAccidental, ShowPitch],
Sheet USING [FindLine, Height, Map, MapNote],
Sync USING [RemoveNote],
Utility USING [DrawChar, DrawCubic, DrawLine, FreeNote, FreeSync];
NoteImpl: CEDAR PROGRAM
IMPORTS Beam, Chord, Graphics, InlineDefs, MusicDefs, Note, Piece, Real, Score, Sheet, Sync, Utility
EXPORTS Note
= BEGIN OPEN Graphics, MusicDefs, Note, Utility;
Error: SIGNAL;
Delta: PUBLIC PROC[n: NotePTR] RETURNS[INTEGER] = {
IF show.display#graphical THEN RETURN[0]
ELSE RETURN[n.delta + (IF FindChord[n]=NIL THEN 0 ELSE FindChord[n].delta)]
};
GetSyncIndex: PUBLIC PROC[a: SyncPTR, p: NotePTR] RETURNS[NAT] = {
FOR i: NAT IN [0..syncLength) DO IF a.event[i]=p THEN RETURN[i]; ENDLOOP;
ERROR;
};
****************************************************************************
note procedures
****************************************************************************
Delete: PUBLIC PROC[n: NotePTR, free: BOOL] = {
s: SyncPTR = n.sync;
c: ChordPTR = Note.FindChord[n];
Sync.RemoveNote[s, n];
IF c#NIL THEN Chord.RemoveNote[c, n];
IF c=NIL AND n.beam#NIL THEN Beam.Remove[n.beam, n, NIL, NIL];
IF NOT free THEN RETURN;
IF s.event[0]=NIL THEN Utility.FreeSync[@n.sync];
Utility.FreeNote[@n];
};
SetAccidental: PUBLIC PROC[n: NotePTR, a: Accidental] = {
IF voice AND n.voice#selectedVoice THEN RETURN;
flash ← TRUE;
SELECT n.pitch MOD 12 FROM
0 => IF a=doubleFlat OR a=sharp THEN RETURN; 
1 => IF a=flat OR a=doubleSharp THEN RETURN; 
2 => IF a=doubleFlat OR a=natural THEN RETURN; 
3 => IF a=flat OR a=sharp THEN RETURN; 
4 => IF a=doubleFlat OR a=natural OR a=doubleSharp THEN RETURN;
5 => IF a=flat OR a=sharp THEN RETURN; 
6 => IF a=natural OR a=doubleSharp THEN RETURN; 
7 => IF a=doubleFlat OR a=sharp THEN RETURN; 
8 => IF a=flat OR a=doubleSharp THEN RETURN; 
9 => IF a=doubleFlat OR a=natural THEN RETURN; 
10=> IF a=flat OR a=sharp THEN RETURN; 
11=> IF a=natural OR a=doubleSharp THEN RETURN;
ENDCASE;
flash ← FALSE;
n.spelled ← a;
SetDirty[n.sync.time, n.sync.time];
};
SetEmbellishment: PUBLIC PROC[n: NotePTR, e: Embellishment] = {
IF voice AND n.voice#selectedVoice THEN RETURN;
IF n.rest THEN RETURN;
n.embellish ← e;
SetDirty[n.sync.time, n.sync.time];
};
Duration: PUBLIC PROC[n: NotePTR, metrenome: INTEGER] RETURNS[d: Time] = {
m, t, rem: Time;
l: REAL ← 1;
b: BeamPTR;
IF metrenome#128 THEN m ← Real.Fix[128*(l*256/metrenome)] ELSE m ← 256;
d ← SELECT n.value FROM
whole=>64, half=>32, quarter=>16, eighth=>8,
sixteenth=>4, thirtysecond=>2, ENDCASE=>1;
IF n.dotted THEN d ← (d*3)/2;
d ← d*m;
FOR b ← n.beam, b.beam WHILE b#NIL DO
IF b.ntuple=0 THEN LOOP;
t ← (d*b.against)/b.ntuple;
rem ← d*(b.against)-t*b.ntuple;
IF b.sync2.time=n.sync.time THEN d ← t+rem ELSE d ← t;
ENDLOOP;
};
GetBackTie: PUBLIC PROC[n: NotePTR] RETURNS[t: NotePTR] = {
i, j: CARDINAL;
start: CARDINAL;
IF n=NIL THEN RETURN[NIL];
IF n.sync=NIL THEN RETURN[NIL];
IF ~n.tied THEN RETURN[NIL];
start ← Piece.NearestSync[p: score, t: n.sync.time, notesOnly: TRUE];
FOR i IN [start..scoreLength) DO
FOR j IN [0..syncLength) DO
IF score[i].event[j]=NIL THEN EXIT;
IF score[i].event[j].tie=n THEN RETURN[score[i].event[j]];
ENDLOOP;
ENDLOOP;
Error;
};
****************************************************************************
drawing notes
****************************************************************************
Draw: PUBLIC PROC[n: NotePTR, stem: INTEGER] = {
two: REAL = 2;
flag: NoteValue;
x, y, mid, width: INTEGER ← 0;
width ← Note.Width[n];
[x, y] ← Sheet.MapNote[n];
Note.DrawHead[n, x, y, x+width+2]; --includes x delta
IF n.rest OR NOT show.notehead THEN RETURN;
draw the ledger lines
mid ← Sheet.Map[n.sync.time,, n.staff].y+16;
FOR i: INTEGER IN [3..9] WHILE y-mid >= i*d DO IF ~n.grace
note above mid
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-y >= i*d DO IF ~n.grace
note below mid
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;
draw the stem
flag ← n.value;
IF stem#default -- drawing part of or beam
THEN {stem ← (IF n.stemUp THEN stem+1 ELSE stem-1); flag ← quarter}
ELSESELECT TRUE FROM
n.grace AND n.stemUp => stem ← y+2*d;
n.grace AND ~n.stemUp => stem ← y-2*d;
n.stemUp => stem ← MAX[y+(7*d)/2, mid];
~n.stemUp => stem ← MIN[y-(7*d)/2, mid];
ENDCASE;
IF n.stemUp THEN DrawLine[x+width, y, x+width, stem] ELSE DrawLine[x, y, x, stem];
draw the flag
IF n.grace
THEN MoveTo[context,[x, IF n.stemUp THEN stem-17 ELSE stem+17]]
ELSE MoveTo[context,[x, IF n.stemUp THEN stem-24 ELSE stem+24]];
SELECT TRUE FROM
flag=quarter => NULL;
n.grace  => IF n.stemUp THEN DrawChar[context, 133C]
ELSE DrawChar[context, 134C];
flag=eighth => IF n.stemUp THEN DrawChar[context, 153C]
ELSE DrawChar[context, 163C];
flag=sixteenth => IF n.stemUp THEN DrawChar[context, 152C]
ELSE DrawChar[context, 162C];
flag=thirtysecond => IF n.stemUp THEN DrawChar[context, 151C]
ELSE DrawChar[context, 161C];
flag=sixtyfourth => IF n.stemUp THEN DrawChar[context, 151C]
ELSE DrawChar[context, 161C];
ENDCASE;
};
DrawHead: PUBLIC PROC[n: NotePTR, x, y, dotX: INTEGER] = {
inVoice: BOOL;
width, dotY: INTEGER;
draw notehead (physical, rest, or normal), dot, and accidental
inVoice← ~(voice AND n.voice#selectedVoice);  Graphics.SetTexture[context, IF inVoice THEN black ELSE light];
IF NOT show.notehead THEN {DrawPhysical[n, x, y]; RETURN};
IF n.tie#NIL THEN Note.DrawTie[n];
MoveTo[context,[x, y]];
IF n.grace
THEN IF n.rest
THEN SELECT n.value FROM
ENDCASE => DrawChar[context, 172C]
ELSE SELECT n.value FROM
ENDCASE => DrawChar[context, 132C]
ELSE IF n.rest
THEN SELECT n.value FROM
whole => {MoveTo[context,[x, y+(IF print THEN -5 ELSE 3)]] ;
DrawChar[context, 145C]};
half => {IF print THEN MoveTo[context,[x, y-9]];
DrawChar[context, 145C]};
quarter => DrawChar[context, 144C];
eighth => DrawChar[context, 143C];
sixteenth => DrawChar[context, 142C];
thirtysecond => DrawChar[context, 141C];
ENDCASE => DrawChar[context, 114C]
ELSE SELECT n.value FROM
whole => DrawChar[context, 156C];
half => DrawChar[context, 155C];
ENDCASE => DrawChar[context, 154C];
width ← Note.Width[n];
IF DottedOnLine[n] THEN dotY ← y+4 ELSE dotY ← y;
IF n.dotted THEN {
MoveTo[context,[dotX, dotY]];
DrawChar[context, 056C];
dotX ← dotX+3;
};
IF n.doubleDotted THEN {
MoveTo[context,[dotX, dotY]]; DrawChar[context, 056C]; dotX ← dotX+3;
MoveTo[context,[dotX, dotY]]; DrawChar[context, 056C];
};
IF n.embellish#none THEN {
sy: INTEGER;
sy ← MAX[y, Sheet.Map[n.sync.time,, n.staff].y+28];
IF n.embellish=trill THEN MoveTo[context,[x, sy+10]] ELSE MoveTo[context,[x-2, sy+10]];
SELECT n.embellish FROM
trill => DrawChar[context,'U];
mordent1 => DrawChar[context,'V];
mordent2 => DrawChar[context,'W];
ENDCASE;
};
IF n.rest OR NOT show.accidental THEN RETURN;
x ← x-9+(IF show.display=graphical THEN n.accDelta ELSE 0);
MoveTo[context,[x, y]];
SELECT Score.GetAccidental[n] FROM
doubleFlat => {MoveTo[context,[x-4, y]]; DrawChar[context, 110C]};
flat => DrawChar[context, 111C];
natural => DrawChar[context, 112C];
sharp => DrawChar[context, 113C];
doubleSharp => DrawChar[context, 114C];
ENDCASE;
};
DottedOnLine: PROC[n: NotePTR] RETURNS[BOOL]=INLINE {
IF NOT n.dotted THEN RETURN[FALSE];
RETURN[Mod[Sheet.Height[n.sync.time, Score.ShowPitch[n.pitch, n.spelled, 0], n.staff]- Sheet.Height[n.sync.time , , n.staff ], 8]=0];
};
Mod: PROC[k, m: INTEGER] RETURNS[n: INTEGER] =
{ n ← k MOD m; IF n<0 THEN n ← n+m; };
DrawPhysical: PROC[n: NotePTR, x, y: INTEGER] = {
duration: INTEGER;
IF n.rest THEN RETURN;
IF show.display#physical THEN duration ←
InlineDefs.LowHalf[7*(Note.Duration[n, 128]/8)/TF];
IF show.display=physical OR n.value=unknown THEN duration ← n.duration/TF;
DrawRectangle[context,[x, y-2],[MIN[x+duration, staffLength+12], y+1]];
};
DrawTie: PUBLIC PROC[n: NotePTR] = {
temp: NotePTR;
oneTie: BOOL;
x1, x2, y1, y2, xe, ye: INTEGER;
IF n.sync.time<n.tie.sync.time THEN { --swap the notes
temp ← n.tie;
IF n.tied THEN Note.GetBackTie[n].tie ← n.tie;
temp.tied ← n.tied; n.tied ← TRUE;
n.tie ← temp.tie; temp.tie ← n;
n ← temp;
};
x1 ← Sheet.Map[n.tie.sync.time, n.tie.pitch, n.tie.staff].x;
x2 ← Sheet.Map[n.sync.time, n.pitch, n.staff].x;
[xe, y1] ← Sheet.MapNote[n.tie]; x1 ← MAX[x1, xe];
[xe, y2] ← Sheet.MapNote[n]; x2 ← MIN[x2, xe];
IF n.tieHeight>0 THEN y1 ← y1+2 ELSE y1 ← y1-2;
IF n.tieHeight>0 THEN y2 ← y2+2 ELSE y2 ← y2-2;
IF ABS[n.sync.time-n.tie.sync.time]<28 THEN {
x1 ← x1-5; x2 ← x2+5;
IF n.tieHeight>0 THEN y1 ← y1+4 ELSE y1 ← y1-4;
IF n.tieHeight>0 THEN y2 ← y2+4 ELSE y2 ← y2-4};
IF x1>x2 THEN { oneTie ← FALSE; xe ← staffLength; ye ← y1; }
ELSE { oneTie ← TRUE; xe ← x2-2; ye ← y2; };
x1 ← x1 + 10;
IF n.tie.sync.time>=begin THEN DrawCubic[x1, y1, xe, ye, n.tieHeight];
IF oneTie THEN RETURN;
IF n.sync.time<=endTime THEN {
xe ← sheet[Sheet.FindLine[n.sync.time]].x-6;
ye ← y2;
DrawCubic[xe, ye, x2, y2, n.tieHeight];
};
};
d: CARDINAL = 8;
END.
DrawStem: PUBLIC PROC[x, y1, y2, stem, staff: INTEGER, stemUp, grace: BOOL, flag: NoteValue] = {
x is the left edge of the note,
y1 & y2 are the y coordinates of the top and bottom notes of a chord
stem is the y coordinate (stem=default is a request for the default stem)
n: INTEGER;
line: REAL ← 1;
IF stem#default -- drawing part of or beam
THEN stem ← (IF stemUp THEN stem+1 ELSE stem-1)
ELSE {[, middle] ← Sheet.Map[n.sync.time, 1000, n.staff]+16;
IF stemUp THEN stem ← MAX[y+(7*d)/2, middle] ELSE stem ← MIN[y-(7*d)/2, middle]};
FOR n IN [3..9] WHILE MAX[head, head2]-middle >= n*d DO
note above middle
DrawRectangle[context,[x-3, middle+line+n*d],[x+w, middle-line+n*d]];
ENDLOOP;
FOR n IN [3..9] WHILE middle-MIN[head, head2] >= n*d DO
note below middle
DrawRectangle[context,[x-3, middle+line-n*d],[x+w, middle-line-n*d]];
ENDLOOP;
IF flag=whole OR flag=unknown THEN RETURN;
MoveTo[context,[x, IF stemUp THEN tail-24 ELSE tail+24]];
SELECT flag FROM
eighth => IF stemUp THEN DrawChar[context, 153C]
ELSE DrawChar[context, 163C];
sixteenth => IF stemUp THEN DrawChar[context, 152C]
ELSE DrawChar[context, 162C];
thirtysecond => IF stemUp THEN DrawChar[context, 151C]
ELSE DrawChar[context, 161C];
ENDCASE;
IF stemUp THEN x ← x+8;
DrawLine[x, head, x, tail];
};
Vector: TYPE = RECORD[x, y: INTEGER];
DisplayAcc: PROC[x, y: INTEGER, n: NotePTR] = {
c: Accidental;
MoveTo[context,[x, y]];
c ← GetAccidental[n];
SELECT c FROM
doubleFlat => { MoveTo[context,[x-4, y]]; DrawChar[context, 110C]; };
flat => DrawChar[context, 111C];
natural => DrawChar[context, 112C];
sharp => DrawChar[context, 113C];
doubleSharp => DrawChar[context, 114C];
ENDCASE;
};