--Author: John Maxwell
--last modified: December 9, 1981 8:22 AM

DIRECTORY
Graphics USING [DisplayContext, FontId, PaintingFunction, SetTexture, SetPaint, Texture],
InlineDefs USING [BITAND];

MusicDefs: DEFINITIONS IMPORTS Graphics, InlineDefs =
BEGIN
OPEN Graphics;

Error:SIGNAL[s:STRING];
Notify:SIGNAL[s:STRING];
Overflow:SIGNAL[type:Sequence];
Sequence:TYPE = {beam,beamHeap,chord,chordHeap,piece,score,sheet,sync};

--****************************************************************************************
--
the basic music types
--****************************************************************************************

PieceArray:TYPE = ARRAY [0..maxScoreLength) OF SyncPTR; -- most pieces are maxPieceLength
SyncRec
:TYPE = RECORD[
time:Time ← 0, --placement on the page
type:EventType← notes,
ts:TimeSignature ← [0,0],
value:INTEGER ← 0,
event:ARRAY [0..syncLength) OF NotePTR ← ALL[NIL]];
NoteRec:TYPE = RECORD[
sync:SyncPTR←NIL,
beam:BeamPTR←NIL,
chord:ChordPTR←NIL,
tie:NotePTR←NIL,
tieHeight:INTEGER←0,
show:BOOLEAN←FALSE,
spare:[0..2000)←0,
staff:[0..16)←1, --the index of the staff
delta:[-128..128)←0,
accDelta:[-128..128)←0,
voice:CARDINAL←0,
toc:LONG CARDINAL←0,
duration:CARDINAL←0,
pitch:INTEGER←44,
tied:BOOLEAN←FALSE,
rest:BOOLEAN←FALSE,
dotted:BOOLEAN←FALSE,
doubleDotted:BOOLEAN←FALSE,
grace:BOOLEAN←FALSE,
stemUp:BOOLEAN←TRUE,
embellish:Embellishment←none, --3 bits
value:NoteValue←unknown, --3 bits
spelled:Accidental←inKey]; --3 bits
PhysicalNote: TYPE = RECORD[
pitch: INTEGER,
duration: CARDINAL,
loudness: CARDINAL,
toc: LONG CARDINAL]; --toc is the physical time of occurrance
ChordRec:TYPE = RECORD[
stemUp:BOOLEAN,
delta:INTEGER←0,
note:ARRAY [0..chordLength) OF NotePTR];
BeamRec:TYPE = RECORD[
tilt:REAL,
beamed:BOOLEAN,
ntuple,against:[0..128),
sync1,sync2:SyncPTR,
beam:BeamPTR,
height:INTEGER,
invisible:BOOLEAN,
spare1:[0..1024),
staff:[0..32),--graphical information
chord:ARRAY[0..beamLength) OF VariousPTR];
endOfBeam:VariousPTR; --avoids a call to BlockEqualCodeLong

--****************************************************************************************
--
other types
--****************************************************************************************

Time:TYPE = LONG INTEGER;
EventType:TYPE = {notes, measure, repeat1, repeat2, endMeasure, doubleMeasure, m5, timeSignature,
keySignature, metrenome, staves, clef, octava1, octava2, spare5, spare6,
spare7, spare8, spare9, spare10, spare11, spare12, spare13, spare14};
SheetSwitch:TYPE = EventType [staves..octava2];
TimeSignature:TYPE = RECORD[top,bottom:[0..32)];
Embellishment:TYPE = {none, trill, mordent1, mordent2, e1, e2, e3, e4};
NoteValue:TYPE= {whole, half, quarter, eighth, sixteenth, thirtysecond, sixtyfourth, unknown};
Accidental:TYPE={doubleSharp, sharp, natural, inKey, flat, doubleFlat};
Section:TYPE = RECORD[
x,y,page,key:INTEGER,
time:Time,
staves:StavesPTR];
DocumentProfile:TYPE = RECORD[
sheet:Staves,
accidental,notehead,noCarry,sync,structure:BOOLEAN,
display:DisplayMode];
DisplayMode:TYPE = {physical,logical,graphical};
Staves: TYPE = RECORD[
junk1:NotePTR←NIL,
height,offset:INTEGER,
sl:CARDINAL,
staff:ARRAY [0..4) OF Staff,
junk2:Junk←[0,ALL[0]]];
Staff:TYPE = RECORD[pitch,y:INTEGER];
Junk:TYPE = RECORD[j1:INTEGER,j2:ARRAY [0..syncLength-7) OF LONG INTEGER];
ObjectType:TYPE = {measure,note,leftBeam,rightBeam,tie};
LookCommand:TYPE = {accidental, graphical, hardcopy, justified, logical, noCarry, notehead, overview, physical, sheet, sync, voice};

VariousPTR:TYPE = RECORD[SELECT type:{note,chord,beam} FROM
note => [n:NotePTR], chord=> [c:ChordPTR], beam=>[b:BeamPTR], ENDCASE];
SyncPTR:TYPE = LONG POINTER TO SyncRec;
StavesPTR:TYPE = LONG POINTER TO Staves;
ChordPTR:TYPE = LONG POINTER TO ChordRec; --later may be LONG POINTERs
NotePTR:TYPE = LONG POINTER TO NoteRec;
BeamPTR:TYPE = LONG POINTER TO BeamRec;
PiecePTR:TYPE = POINTER TO PieceArray;
UnspecifiedPTR:TYPE = LONG POINTER TO UNSPECIFIED;

chordLength:CARDINAL = 10;
syncLength:CARDINAL = 13;
beamLength:CARDINAL = 16;
sheetLength:CARDINAL= 350;
maxScoreLength:CARDINAL = MAX[maxPieceLength,3000]; --6000
maxPieceLength:CARDINAL = 1000;
maxBeamHeapLength:CARDINAL = 1000; --2000
maxChordHeapLength:CARDINAL = 1000; --2000
maxSelectionLength:CARDINAL = 100;

--****************************************************************************************
--
global variables
--****************************************************************************************

score:PiecePTR;
scoreLength:CARDINAL;
sheet:ARRAY [0..sheetLength) OF Section;
style:ARRAY [0..20] OF Staves;
--view on score
TF:CARDINAL; -- "Time Factor" = horizontal scale of score on sheet.
show:DocumentProfile;
voice:BOOLEAN;
selectedVoice:CARDINAL;
maxVoice:CARDINAL;
begin,endTime:Time;
scale,staffLength,top:INTEGER;
hardcopy:BOOLEAN;
--selection
lineSelect:READONLY BOOLEAN;
selection:ARRAY [0..maxSelectionLength) OF NotePTR;
selectionLength:CARDINAL;
select1,select2,greySelect1,greySelect2:READONLY Time;
--return info for commands
min,max:Time; -- extent of change
command,flash:BOOLEAN; -- flash = "error"
--graphics
context:Graphics.DisplayContext;
text,music:Graphics.FontId;
print:BOOLEAN;
--communicating with the synthesizer
dataStructureInFlux:BOOLEAN;
playing,listening:READONLY BOOLEAN;
--data storage
chordHeap:POINTER TO ARRAY [0..maxChordHeapLength) OF ChordPTR;
chordHeapLength:CARDINAL;
beamHeap:POINTER TO ARRAY [0..maxBeamHeapLength) OF BeamPTR;
beamHeapLength:CARDINAL;

--****************************************************************************************
--
INLINE Procedures
--****************************************************************************************

white: Texture=0;
light: Texture;
grey: Texture=122645B;
black: Texture=177777B;

Measure:PROC[e:EventType] RETURNS[BOOLEAN] = INLINE
{RETURN[e IN [measure..m5] OR e=staves]};

EndOfScore:PROCEDURE RETURNS[Time] =INLINE
{IF scoreLength#0 THEN RETURN[score[scoreLength-1].time+40] ELSE RETURN[10]};

LMod:PROCEDURE[m,n:Time] RETURNS[k:Time] = INLINE
{k ← m - n*(m/n); IF k>n THEN k ← k+n};

Mod:PROCEDURE[m,n:INTEGER] RETURNS[k:INTEGER] = INLINE
{k← m MOD n; IF k<0 THEN k ← k+n};

SetBrush:PROCEDURE[tex:Graphics.Texture,pnt:Graphics.PaintingFunction] = INLINE
{Graphics.SetTexture[context,tex]; Graphics.SetPaint[context,pnt]};

SetDirty:PROCEDURE[begin,end:Time] = INLINE
{min ← MIN[min,begin]; max ← MAX[max,end]};

--*************************************************************************
--
mouse and keyboard
--*************************************************************************

AnyBug:PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[RedBug[] OR BlueBug[] OR YellowBug[]]};

RedBug:PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[(MouseButtons↑ MOD 8) < 4]};

BlueBug:PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[(MouseButtons↑ MOD 4) < 2]};

YellowBug:PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[(MouseButtons↑ MOD 2) = 0]};

Shift:PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[InlineDefs.BITAND[KeyBoard3↑,000100B]=0
OR InlineDefs.BITAND[KeyBoard4↑,000010B]=0
OR InlineDefs.BITAND[KeyBoard4↑,000200B]=0]};

Control:PROCEDURE RETURNS[BOOLEAN] =
INLINE {RETURN[InlineDefs.BITAND[KeyBoard3↑,004000B]=0]};

MouseButtons: POINTER TO CARDINAL = LOOPHOLE[177030B];
KeyBoard1: POINTER TO CARDINAL = LOOPHOLE[177034B];
KeyBoard2: POINTER TO CARDINAL = LOOPHOLE[177035B];
KeyBoard3: POINTER TO CARDINAL = LOOPHOLE[177036B];
KeyBoard4: POINTER TO CARDINAL = LOOPHOLE[177037B];
MouseX: POINTER TO INTEGER = LOOPHOLE[424B];
MouseY: POINTER TO INTEGER = LOOPHOLE[425B];
CursorX: POINTER TO CARDINAL = LOOPHOLE[426B];
CursorY: POINTER TO CARDINAL = LOOPHOLE[427B];

END.