--Author: John Maxwell --last modified: December 15, 1981 4:15 PM DIRECTORY Beam USING [Height,InVoice], MusicDefs, Note USING [Delete,Delta,FindChord], Piece USING [CleanUpSyncs, Length, RemoveSync], Real USING [FixI], Score USING [GetKey, ShowPitch], Sheet USING [FindLine, FindSection, Height, NearestTime, NextLine], Sync USING [GetScoreIndex, Octava], Utility USING [FreeSync]; PieceImplA: PROGRAM IMPORTS Beam, MusicDefs, Note, Piece, Real, Score, Sheet, Sync, Utility EXPORTS MusicDefs, Piece = BEGIN OPEN MusicDefs; dataStructureInFlux:PUBLIC BOOLEAN _ FALSE; --**************************************************************************** --data abstractions for a piece --CONSTRAINT: piece[i-1].time <= piece[i].time <= piece[i+1].time --CONSTRAINT: piece[i]#NIL for all i such that 0 <= i < pieceLength --CONSTRAINT: piece[pieceLength]=NIL --CONSTRAINT: a sync may be entered at most one time --**************************************************************************** AddSync:PUBLIC PROCEDURE[p:PiecePTR,s:SyncPTR] = BEGIN --any procedure that inserts syncs should process syncs in decreasing order length:CARDINAL=Piece.Length[p]; IF s=NIL THEN RETURN; --check for overflow IF p=score AND length+1=maxScoreLength THEN Overflow[score]; IF p#score AND length+1=maxPieceLength THEN Overflow[piece]; --insert sync IF p=score THEN dataStructureInFlux_TRUE; FOR i:CARDINAL DECREASING IN [0..length) DO IF p[i]=NIL THEN LOOP; IF p[i].time < s.time THEN {p[i+1]_s; s_NIL; EXIT}; IF p[i].time = s.time AND ~LessThan[s.type,p[i].type] THEN {p[i+1]_s; s_NIL; EXIT}; p[i+1] _ p[i]; ENDLOOP; IF s#NIL THEN p[0] _ s; IF p=score THEN scoreLength _ scoreLength+1; IF p=score THEN dataStructureInFlux_FALSE; END; LessThan:PROCEDURE[a,b:EventType] RETURNS[BOOLEAN] = INLINE BEGIN SELECT TRUE FROM a=staves => RETURN[TRUE]; b=staves => RETURN[FALSE]; a=keySignature => RETURN[TRUE]; b=keySignature => RETURN[FALSE]; Measure[a] => RETURN[TRUE]; Measure[b] => RETURN[FALSE]; a=metrenome => RETURN[TRUE]; b=metrenome => RETURN[FALSE]; a=timeSignature => RETURN[TRUE]; b=timeSignature => RETURN[FALSE]; a IN SheetSwitch => RETURN[TRUE]; b IN SheetSwitch => RETURN[FALSE]; ENDCASE => RETURN[TRUE]; END; RemoveSync:PUBLIC PROCEDURE[p:PiecePTR,s:SyncPTR] = BEGIN --DOES NOT free notes or itself! --any procedure that removes syncs should process syncs in decreasing order i,j:CARDINAL_0; length:CARDINAL_Piece.Length[p]; FOR i IN [0..length) DO IF p[i]=s THEN LOOP; IF i#j THEN p[j] _ p[i]; j _ j+1; ENDLOOP; FOR i IN [0..syncLength) DO IF s.event[i]=NIL THEN EXIT; s.event[i].sync _ NIL; ENDLOOP; length _ j; p[length] _ NIL; IF p=score THEN scoreLength_length; END; DeleteSync:PUBLIC PROCEDURE[s:SyncPTR] = BEGIN octava:SyncPTR _ NIL; index:CARDINAL_Sync.GetScoreIndex[s]; IF s.type IN [octava1..octava2] THEN octava _ Sync.Octava[s]; Piece.RemoveSync[score,s]; IF octava#NIL THEN { SetDirty[octava.time,octava.time]; Piece.RemoveSync[score,octava]; Utility.FreeSync[@octava]}; Utility.FreeSync[@s]; END; Sort:PUBLIC PROCEDURE[p:PiecePTR] = --useful when going from physical to logical files BEGIN i,j:CARDINAL; temp:SyncPTR; length:CARDINAL = Piece.Length[p]; FOR i IN [0..length) DO FOR j IN (i..length) DO IF p[j] = NIL THEN LOOP; IF p[i] = NIL THEN {p[i]_p[j]; p[j]_NIL; LOOP}; IF p[i].time > p[j].time THEN {temp_p[i]; p[i]_p[j]; p[j]_temp}; IF p[i].time= p[j].time THEN {IF p[i].event[0]=NIL OR p[j].event[0]=NIL THEN LOOP; IF p[i].event[0].toc=length THEN LOOP; IF p[index+binary].time<=t THEN index_index+binary; IF p[index].time=t THEN EXIT; ENDLOOP; --the above will fail when the p isn't strictly ordered FOR i:CARDINAL IN [(IF index<5 THEN 0 ELSE index-5)..MIN[index+5,length]) DO IF notesOnly AND p[i].type#notes THEN LOOP; IF ABS[p[i].time-t] > delta THEN LOOP; index _ i; delta _ ABS[p[i].time-t]; ENDLOOP; IF notesOnly AND index#length AND p[index].type#notes THEN index_length; END; NearestNote:PUBLIC PROCEDURE[x,y:INTEGER] RETURNS[p:NotePTR] = BEGIN n:NotePTR; key:INTEGER; time,dt,t:Time_11; i,j,k,l,next:CARDINAL; height,dy,show:INTEGER_8; [time,height] _ Sheet.NearestTime[x,y]; next _ Sheet.FindLine[time]; time _ time - (staffLength - sheet[next].x); l _ Sheet.FindLine[time]; height _ height + (sheet[next].y - sheet[l].y); FOR k IN [0..2] DO FOR i IN [0..scoreLength) DO IF score[i].time< time - 40 THEN LOOP; IF score[i].time> time + 40 THEN EXIT; IF score[i].time=sheet[next].time THEN EXIT; FOR j IN [0..syncLength) DO IF (n_score[i].event[j]) = NIL THEN EXIT; IF voice AND n.voice#selectedVoice THEN LOOP; t _ ABS[score[i].time+5+Note.Delta[n]-time]; key _ Score.GetKey[n.sync.time]; show _ Score.ShowPitch[n.pitch,n.spelled,key]; y _ ABS[height-Sheet.Height[n.sync.time,show,n.staff]]; IF y+t>dy+dt THEN LOOP; IF y+t=dy+dt AND t>dt THEN LOOP; dt _ t; dy _ y; p _ n; ENDLOOP; ENDLOOP; time _ time+ (staffLength - sheet[next].x); height _ height- (sheet[next].y - sheet[l].y); l _ next; next _ Sheet.NextLine[l]; ENDLOOP; IF dt>10 OR dy>7 THEN p_NIL; END; NearestObject:PUBLIC PROCEDURE[x,y:INTEGER] RETURNS[obj:ObjectType,p:UnspecifiedPTR_NIL] = BEGIN n:NotePTR; l:CARDINAL; key:INTEGER; staves:StavesPTR; i,j,k,s,next:CARDINAL_0; time,dt,t:Time _ 11; height,dy,show:INTEGER _ 8; [time,height] _ Sheet.NearestTime[x,y]; next _ Sheet.FindLine[time]; time _ time - (staffLength - sheet[next].x); l _ Sheet.FindLine[time]; height _ height + (sheet[next].y - sheet[l].y); FOR k IN [0..2] DO --left and right corners of a beam FOR i IN [0..beamHeapLength) DO IF beamHeap[i].beam#NIL AND beamHeap[i].beam.beamed THEN LOOP; IF beamHeap[i].sync1.time-5 > time THEN LOOP; IF beamHeap[i].sync2.time+5 < time THEN LOOP; IF voice AND ~Beam.InVoice[beamHeap[i],selectedVoice] THEN LOOP; y _ Beam.Height[beamHeap[i],time]; IF ABS[y-height]+4 > dt+dy THEN LOOP; IF ABS[y-height]+4 = dt+dy THEN IF y>height THEN LOOP; dt _ 4; dy _ ABS[y-height]; IF time < (beamHeap[i].sync1.time+beamHeap[i].sync2.time+4)/2 THEN obj _leftBeam ELSE obj _rightBeam; p _ beamHeap[i]; ENDLOOP; --measure sections, signatures and other events FOR i IN [s..scoreLength) DO IF score[i].time< time - 300 THEN LOOP; IF score[i].time> time + 300 THEN {s_i; EXIT}; IF score[i].timetime THEN LOOP; t _ ABS[(n.sync.time+n.tie.sync.time)/2-time]; key _ Score.GetKey[n.sync.time]; show _ Score.ShowPitch[n.pitch,n.spelled,key]; y _ ABS[height-(Sheet.Height[n.sync.time,show,n.staff]+n.tieHeight/2)]; IF y+t>dy+dt THEN LOOP; IF y+t=dy+dt THEN IF t>dt THEN LOOP; dt _ t; dy _ y; obj _ tie; p _ n; ENDLOOP; IF score[i].time>=sheet[next].time THEN LOOP; IF ABS[score[i].time-time]>40 THEN LOOP; IF score[i].type IN SheetSwitch AND score[i].type#staves THEN { octava:SyncPTR_NIL; staff,top,bottom:INTEGER _ score[i].value; t _ score[i].time; IF score[i].type=clef THEN t_t+6; IF ABS[t-time]+6> dt + dy THEN LOOP; IF ABS[t-time]+6=dt+dy AND t