SheetImplB.mesa
Copyright (C) 1981, 1984 Xerox Corporation. All rights reserved.
Author: John Maxwell
last modified: November 21, 1981 11: 33 AM
Edited by Doug Wyatt, June 14, 1984 1:16:19 pm PDT
DIRECTORY
Graphics USING [DisplayContext, Vec, ScreenToUser],
InlineDefs USING [LowHalf],
MusicDefs,
Note USING [Delta],
Real USING [FixI],
Score USING [GetKey, KeyHeight, ShowPitch],
Sheet USING [default, FindLine, FindSection, Height, NextLine, PriorLine];
SheetImplB: CEDAR PROGRAM
IMPORTS Graphics, InlineDefs, MusicDefs, Note, Real, Score, Sheet
EXPORTS Sheet =
BEGIN
OPEN MusicDefs, Sheet;
****************************************************************************
procedures that map from note to screen
****************************************************************************
MapNote: PUBLIC PROC[n: NotePTR] RETURNS[x, y: INTEGER]= {
l: Section;
show: INTEGER;
t: Time ← n.sync.time;
IF n.rest AND n.value=whole THEN t ← t-7;
l ← sheet[FindSection[t]];
x ← InlineDefs.LowHalf[t-l.time+l.x+Note.Delta[n]];
show ← Score.ShowPitch[n.pitch, n.spelled, l.key];
RETURN[x, l.y-top+PitchHeight[t, show, l.staves.staff[n.staff]]];
};
Map: PUBLIC PROC[t: Time, pitch: INTEGER, staff: CARDINAL] RETURNS[x, y: INTEGER]= {
l: Section ← sheet[FindSection[t]];
RETURN[InlineDefs.LowHalf[t-l.time+l.x], l.y-top + PitchHeight[t, pitch, l.staves.staff[staff]]];
};
MapHeight: PUBLIC PROC[t: Time, height: INTEGER] RETURNS[x, y: INTEGER]= {
l: Section ← sheet[FindSection[t]];
RETURN[InlineDefs.LowHalf[t-l.time+l.x], l.y-top + height];
};
Height: PUBLIC PROC[t: Time, pitch: INTEGER, staff: CARDINAL] RETURNS[INTEGER]= {
l: Section ← sheet[FindSection[t]];
RETURN[PitchHeight[t, pitch, l.staves.staff[staff]]];
};
Pitch: PUBLIC PROC[t: Time, height: INTEGER, staff: CARDINAL] RETURNS[INTEGER]= {
i: CARDINAL;
key: INTEGER ← Score.GetKey[t];
pitch: INTEGER ← 12;
keyPitch: INTEGER ← (44+key*7) MOD 12;
octave: INTEGER;
l: Section ← sheet[FindSection[t]];
height ← height - PitchHeight[t, keyPitch, l.staves.staff[staff]];
IF height<0 THEN octave← height/28-1 ELSE octave ← height/28;
octave ← height/28 - (IF height<0 THEN 1 ELSE 0);
height ← Mod[height, 28];
FOR i IN [0..12) DO
IF pitchHeight[i] >= height THEN { pitch ← i; EXIT; };
ENDLOOP;
RETURN[pitch + keyPitch + 12*octave];
};
PitchHeight: PROC[t: Time, pitch: INTEGER, staff: Staff] RETURNS[INTEGER]= {
return the y height of the pitch relative to the top of the staves
if pitch>100 use the staff's pitch
height, octave, key: INTEGER;
IF pitch>100 THEN RETURN[staff.y];
IF NOT show.accidental THEN RETURN[CrackHeight[t, pitch, staff]];
key ← Score.GetKey[t];
octave ← (pitch-Mod[pitch, 12]-staff.pitch+Mod[staff.pitch, 12])/12;
height ← 28*octave + Score.KeyHeight[key, pitch] - Score.KeyHeight[key, staff.pitch];
RETURN[staff.y+height];
};
CrackHeight: PROC[t: Time, pitch: INTEGER, staff: Staff] RETURNS[INTEGER]= {
pitches with accidentals are placed between lines and spaces
height: INTEGER;
octave: INTEGER;
ms: CARDINAL ← Mod[staff.pitch, 12];
mp: CARDINAL ← Mod[pitch, 12];
octave ← (pitch-mp-staff.pitch+ms)/12;
height ← 28*octave + crackHeight[mp] - crackHeight[ms];
RETURN[staff.y+height];
};
crackHeight: ARRAY[0..12) OF INTEGER = [0, 4, 6, 8, 10, 12, 14, 16, 20, 22, 24, 26];
pitchHeight: ARRAY [0..12) OF INTEGER = [0, 1, 4, 5, 8, 12, 13, 16, 17, 20, 21, 24];
****************************************************************************
procedures that map from screen back
****************************************************************************
ScreenPoint: PUBLIC PROC RETURNS[x, y: INTEGER] = {
sp, p: Graphics.Vec;
sp.x ← MouseX^;
sp.y ← MouseY^;
p ← Graphics.ScreenToUser[context, sp];
x ← Real.FixI[p.x];
y ← Real.FixI[p.y]+top;
};
NearestTime: PUBLIC PROC[x, y: INTEGER] RETURNS[time: Time, height: INTEGER]= {
line, next: CARDINAL ← 0;
IF x=default THEN [x, y] ← ScreenPoint[];
WHILE sheet[next].y>=y DO
line ← next;
next ← Sheet.NextLine[line];
ENDLOOP;
IF y<((sheet[line].y+Sheet.Height[sheet[line].time,, 3]+8)/2+sheet[next].y/2) THEN line ← next;
IF x < sheet[line].x THEN x ← sheet[line].x;
IF x > staffLength THEN x ← staffLength;
time ← sheet[line].time+ x- sheet[line].x;
height← y- sheet[line].y;
};
AlternateTime: PUBLIC PROC[t1: Time, h1: INTEGER, lines: INTEGER] RETURNS[time: Time, height: INTEGER] = {
next, prior, l: CARDINAL;
time ← t1;
height ← h1;
l ← Sheet.FindLine[time];
IF lines>0 THEN FOR i: CARDINAL IN [0..ABS[lines]) DO
next ← Sheet.NextLine[l];
time ← time + (staffLength - sheet[next].x);
height ← height - (sheet[next].y - sheet[l].y);
l ← next;
ENDLOOP;
IF lines<0 THEN FOR i: CARDINAL IN [0..ABS[lines]) DO
prior ← Sheet.PriorLine[l];
time ← time - (staffLength - sheet[l].x);
height ← height + (sheet[l].y - sheet[prior].y);
l ← prior;
ENDLOOP;
RETURN[time, height];
};
NearestStaff: PUBLIC PROC[t: Time, height: INTEGER] RETURNS[CARDINAL] = {
i, j, k: CARDINAL ← 10;
staves: StavesPTR = sheet[Sheet.FindSection[t]].staves;
FOR i IN [0..staves.sl] DO
IF i<2 AND staves.staff[i]=staves.staff[i+1] THEN LOOP;
IF height< staves.staff[i].y THEN { j ← i; LOOP; };
IF j=10 THEN RETURN[i];
IF height<(staves.staff[j].y+staves.staff[i].y+34)/2 THEN RETURN[i] ELSE RETURN[j];
ENDLOOP;
RETURN[staves.sl];
};
END.
GetStaves: PROC[time: Time] RETURNS[StavesPTR] = {
sync: SyncPTR ← NIL;
FOR i: CARDINAL IN [0..cacheLength) DO
IF cache[i]=NIL THEN EXIT;
IF cache[i].type#staves THEN LOOP;
IF cache[i].time>time AND sync=NIL THEN sync ← cache[i];
IF cache[i].time>time THEN EXIT;
sync ← cache[i];
ENDLOOP;
IF sync=NIL THEN { Sheet.SetStaves[2, 0, EndOfScore[]]; RETURN[GetStaves[time]]; };
RETURN[LOOPHOLE[@sync.event]];
};
Reset: PUBLIC PROC= {
staves: Staves;
page: INTEGER ← 2;
i, j: CARDINAL ← 0;
sync: SyncPTR ← NIL;
time, break, top, cacheTime: Time ← 0;
height, x, sc, sheetHeight: INTEGER ← 0;
Score.BuildCache[];
MakeSheetConsistent[];
IF scale=2 THEN sc ← 3 ELSE sc ← 2*scale;
FOR i IN [0..cacheLength] DO
IF i#cacheLength AND cache[i].type NOT IN SheetSwitch THEN LOOP;
IF i=cacheLength AND sync=NIL THEN RETURN;
IF i=cacheLength THEN cacheTime ← 400000 ELSE cacheTime ← cache[i].time;
IF sync=NIL THEN {sync ← cache[i]; staves ← LOOPHOLE[sync.event]};
WHILE time<cacheTime DO
sheet[j] ← [, height, 0, Key[time], time, LOOPHOLE[@sync.event]];
IF x=0 AND top-height>(650*sc)/2 THEN {
top ← height; sheet[j].page ← page; page ← page+1; };
SELECT TRUE FROM
x=0 => {x← ABS[8*(sheet[j].key)]; IF x=0 THEN x ← 8};
ENDCASE => x← x + InlineDefs.LowHalf[time-sheet[j-1].time];
sheet[j].x ← x;
IF time>=break THEN break ← break+staffLength-x;
time ← MIN[cacheTime, break];
IF time>=break THEN {
sheetHeight ← -staves.staff[staves.sl].y;
height ← height - sheetHeight - staves.offset;
x ← 0; };
j ← j+1; IF j=sheetLength THEN RETURN;
ENDLOOP;
IF i=cacheLength THEN EXIT;
sync ← cache[i];
staves ← LOOPHOLE[sync.event];
ENDLOOP;
FOR i: CARDINAL IN [0..beamHeapLength) DO
Beam.SetStems[beamHeap[i]];
ENDLOOP;
};