-- Author: John Maxwell
-- Last Edited by: Maxwell, November 22, 1983 12:06 pm

DIRECTORY
    MusicDefs: FROM "MusicDefs";

Event: DEFINITIONS IMPORTS MusicDefs = 
BEGIN
OPEN MusicDefs;

Draw: PROCEDURE[score: ScorePTR, event: EventPTR];
Invisible: PROCEDURE[score: ScorePTR, index: CARDINAL, leftEdge: Time] 
	RETURNS[BOOLEAN]; -- Hidden
GetScoreIndex: PROCEDURE[score: ScorePTR, event: EventPTR] RETURNS[index: CARDINAL];
-- returns score.length if not found (score[score.length] is always NIL)


-- ************************************************
-- Type coersion
-- ************************************************

Sync: PROC[e: EventPTR] RETURNS[SyncPTR] = INLINE
	{RETURN[IF e # NIL AND e.type = sync THEN LOOPHOLE[e] ELSE NIL]};

TimeSignature: PROC[e: EventPTR] RETURNS[LONG POINTER TO EventRec.timeSignature] = 
	INLINE {RETURN[IF e # NIL AND e.type = timeSignature THEN LOOPHOLE[e] ELSE NIL]};

KeySignature: PROC[e: EventPTR] RETURNS[LONG POINTER TO EventRec.keySignature] = 
	INLINE{RETURN[IF e # NIL AND e.type = keySignature THEN LOOPHOLE[e] ELSE NIL]};

Measure: PROC[e: EventPTR] RETURNS[LONG POINTER TO EventRec.measure] = INLINE
	{RETURN[IF e # NIL AND e.type = measure THEN LOOPHOLE[e] ELSE NIL]};

Metrenome: PROC[e: EventPTR] RETURNS[LONG POINTER TO EventRec.metrenome] = INLINE
	{RETURN[IF e # NIL AND e.type = metrenome THEN LOOPHOLE[e] ELSE NIL]};

Staves: PROC[e: EventPTR] RETURNS[StavesPTR] = INLINE
	{RETURN[IF e # NIL AND e.type = staves THEN LOOPHOLE[e] ELSE NIL]};

-- ************************************************
-- Procedures that only apply to staves
-- ************************************************

Octava: PROC[event: EventPTR] RETURNS[BOOLEAN] = INLINE
	{WITH ev: event SELECT FROM 
		staves => RETURN[ev.staves IN [octava1..octava2]]; 
		ENDCASE => RETURN[FALSE]};

Clef: PROC[event: EventPTR] RETURNS[BOOLEAN] = INLINE
	{WITH ev: event SELECT FROM 
		staves => RETURN[ev.staves = clef]; 
		ENDCASE => RETURN[FALSE]};

GetOctava: PROCEDURE[score: ScorePTR, octava: StavesPTR] RETURNS[other: StavesPTR];
SetStave: PROCEDURE[score: ScorePTR, oldS, newS: StavesPTR]; -- copy info from old to new

GetStaff: PROCEDURE[staves: StavesPTR, staff: CARDINAL] RETURNS[LONG POINTER TO Staff] = INLINE {RETURN[@staves.staff[staff]]};

-- ************************************************
-- Procedures that only apply to syncs
-- ************************************************

AddNote: PROCEDURE[score: ScorePTR, sync: SyncPTR, note: NotePTR]
	RETURNS[new: SyncPTR]; -- may create a new sync
RemoveNote: PROCEDURE[score: ScorePTR, sync: SyncPTR, note: NotePTR, free: BOOLEAN ← FALSE];
-- removes note from sync.  If sync.length = 0 and free = TRUE, then sync is freed.
Adjust: PROCEDURE[score: ScorePTR, s: SyncPTR]; -- space the notes so they don't overlap


NewSync: PROC[score: ScorePTR, length: CARDINAL ← 12, old: SyncPTR ← NIL] 
	RETURNS[sync: SyncPTR]; -- frees old after copying data
Free: PROC[score: ScorePTR, event: EventPTR]; 
-- removes sync from anything that points to it, then frees it.

-- INLINE Procedures

AddTimes: PROCEDURE[event: EventPTR, time, toc: Time] = INLINE { -- add times to notes
	sync: SyncPTR;
	event.time ← event.time + time;
	IF event.type = sync THEN sync ← Sync[event] ELSE RETURN;
	FOR i: CARDINAL IN [0..sync.length) DO
		sync.note[i].toc ← sync.note[i].toc + toc;
		ENDLOOP};
		
Grace: PROCEDURE[sync: SyncPTR] RETURNS[BOOLEAN] = INLINE
   {FOR j: CARDINAL IN [0..sync.length) DO
			IF ~sync.note[j].grace THEN RETURN[FALSE];
			ENDLOOP;
    	RETURN[TRUE]};

InVoice: PROCEDURE[sync: SyncPTR, voice: CARDINAL] RETURNS[BOOLEAN] = INLINE
   {FOR j: CARDINAL IN [0..sync.length) DO
			IF sync.note[j].voice = voice THEN RETURN[TRUE];
			ENDLOOP;
    	RETURN[FALSE]};
    
-- Length: PROC[sync: SyncPTR] RETURNS[CARDINAL] = INLINE {RETURN[s.length]};

END..