--Author: John Maxwell
--last modified: November 23, 1981 11:10 AM

DIRECTORY
Graphics USING [DisplayContext,Texture],
MusicDefs: FROM "MusicDefs";

Sheet: DEFINITIONS IMPORTS MusicDefs =
BEGIN
OPEN MusicDefs;

Draw:PROCEDURE;
DrawClef:PROCEDURE[pitch,staff:INTEGER,time:Time];
DrawOctava:PROCEDURE[pitch,staff,height:INTEGER,t1,t2:Time];
FindLine:PROCEDURE[t:Time] RETURNS[INTEGER];
FindSection:PROCEDURE[t:Time] RETURNS[INTEGER];
GetStyle:PROCEDURE[time:Time] RETURNS[INTEGER];
HiLite:PROCEDURE[tex:Graphics.Texture,t1,t2:Time];
Initialize:PROCEDURE[dc:Graphics.DisplayContext];
Reset:PROCEDURE;
Scale:PROCEDURE[newScale:INTEGER];
Scroll:PROCEDURE[lines:INTEGER]; -- "currentLine ← currentLine+lines"
SetBegin:PROCEDURE[now:Time];
SetClef:PROCEDURE[pitch,staff:INTEGER,time:Time];
SetOctava:PROCEDURE[pitch,staff,height:INTEGER,t1,t2:Time];
SetStyle:PROCEDURE[index:INTEGER,t1,t2:Time];

--INLINE Procedures

Last:PROCEDURE[l:CARDINAL] RETURNS[CARDINAL] = INLINE
{FOR i:CARDINAL IN [l..sheetLength-1) DO
IF sheet[i].time#sheet[i+1].time THEN RETURN[i];
ENDLOOP;
RETURN[sheetLength-1]};

LineNumber:PROCEDURE[l:CARDINAL] RETURNS[n:CARDINAL←1] = INLINE
{FOR i:CARDINAL IN (0..l] DO
IF sheet[i].y#sheet[i-1].y THEN n←n+1;
ENDLOOP};

NextLine:PROCEDURE[l:CARDINAL] RETURNS[CARDINAL] = INLINE
{FOR i:CARDINAL IN (l..sheetLength) DO
IF sheet[i].y=sheet[l].y THEN LOOP;
RETURN[Last[i]];
ENDLOOP;
RETURN[sheetLength-1]};

NextStaff:PROCEDURE[s:CARDINAL,t:Time] RETURNS[CARDINAL] = INLINE
{staves:StavesPTR = sheet[FindSection[t]].staves;
FOR i:CARDINAL IN (s..staves.sl] DO
IF staves.staff[i].y#staves.staff[s].y THEN RETURN[i];
ENDLOOP;
RETURN[s]};

NormalPitch:PROCEDURE[staff:CARDINAL] RETURNS[INTEGER] = INLINE
{RETURN[IF staff IN [0..1] THEN 48 ELSE 27]};

PriorLine:PROCEDURE[l:CARDINAL] RETURNS[CARDINAL] = INLINE
{FOR i:CARDINAL DECREASING IN [0..l) DO
IF sheet[i].y#sheet[l].y THEN {l←i; EXIT};
ENDLOOP;
FOR i:CARDINAL DECREASING IN [0..l) DO
IF sheet[i].y#sheet[l].y THEN RETURN[Last[i+1]];
ENDLOOP;
RETURN[Last[0]]};

PriorStaff:PROCEDURE[s:CARDINAL,t:Time] RETURNS[CARDINAL] = INLINE
{staves:StavesPTR = sheet[FindSection[t]].staves;
FOR i:CARDINAL DECREASING IN [0..s) DO
IF staves.staff[i].y#staves.staff[s].y THEN RETURN[i];
ENDLOOP;
RETURN[s]};

OctavaHeight:PROCEDURE[pitch,height:INTEGER] RETURNS[INTEGER] = INLINE
{IF pitch=60 AND height<40 THEN RETURN[40];
IF pitch=60 AND height>90 THEN RETURN[90];
IF pitch=15 AND height<-40 THEN RETURN[-40];
IF pitch=15 AND height>-8 THEN RETURN[-8];
RETURN[height]};

--*************************************************************************
--
mapping from sheet to screen and vice-versa
--*************************************************************************
--NotePTR => [Time,Pitch,Staff] => [Time,Height] => ScreenPoint;
UNAMBIGUOUSLY!
--[Time,Height] <= ScreenPoint;
ambiguous when point is between lines
--[Time,Pitch,Staff] <= [Time,Height];
ambiguous when between staffs
--NotePTR <= [Time,Pitch,Staff];
ambiguous because of graphical adjustments

default:INTEGER = 1000;

AlternateTime:PROCEDURE[t1:Time,h1,lines:INTEGER] RETURNS[time:Time,height:INTEGER];
Height:PROCEDURE[t:Time,pitch:INTEGER←default,staff:CARDINAL] RETURNS[INTEGER];
NearestStaff:PROCEDURE[t:Time,height:INTEGER] RETURNS[INTEGER];
NearestTime:PROCEDURE[x,y:INTEGER←default] RETURNS[time:Time,height:INTEGER];
Map:PROCEDURE[t:Time,pitch:INTEGER←default,staff:CARDINAL] RETURNS[x,y:INTEGER];
MapHeight:PROCEDURE[t:Time,height:INTEGER] RETURNS[x,y:INTEGER];
MapNote:PROCEDURE[n:NotePTR] RETURNS[x,y:INTEGER];
Pitch:PROCEDURE[t:Time,height:INTEGER,staff:CARDINAL] RETURNS[INTEGER];
ScreenPoint:PROCEDURE RETURNS[x,y:INTEGER];

END..