--Author: John Maxwell --last modified: November 28, 1981 8:35 AM DIRECTORY Beam USING [Remove,SetSyncs,Sort,time], Chord USING [Beam,Sort], MusicDefs, Real USING [FixI], Sheet USING [Height], Utility USING [FreeBeam]; BeamImplA: PROGRAM IMPORTS Beam, Chord, MusicDefs, Real, Sheet, Utility EXPORTS Beam, MusicDefs = BEGIN OPEN MusicDefs, Utility; endOfBeam:PUBLIC VariousPTR_[note[NIL]]; --avoids a call to BlockEqualCodeLong --************************************************************************** --data abstractions for a beam --CONSTRAINT: IF b.chord[i]=NIL THEN b.chord[j]=NIL for all j>i --CONSTRAINT: b.chord[i].sync.time<=b.chord[i+1].sync.time for all i --************************************************************************** AddNote:PUBLIC PROCEDURE[b:BeamPTR,n:NotePTR] = BEGIN oldBeam:BeamPTR=n.beam; i,j:CARDINAL_beamLength-1; FOR i IN [0..beamLength) DO IF b.chord[i]=[note[n]] THEN RETURN; ENDLOOP; IF b.sync1=NIL THEN b.sync1_n.sync; IF b.sync2=NIL THEN b.sync2_n.sync; IF n.sync.time < b.sync1.time THEN b.sync1 _ n.sync; IF n.sync.time > b.sync2.time THEN b.sync2 _ n.sync; FOR i IN [0..beamLength) DO IF b.chord[i]=endOfBeam THEN BEGIN j _ i; EXIT; END; IF Beam.time[b.chord[i]]>n.sync.time THEN j _ i; IF j#beamLength-1 THEN EXIT; ENDLOOP; IF b.chord[beamLength-1]#endOfBeam THEN Overflow[beam]; FOR i DECREASING IN (j..beamLength) DO b.chord[i] _ b.chord[i-1]; ENDLOOP; b.chord[j] _ [note[n]]; n.beam _ b; IF oldBeam#NIL AND oldBeam#b THEN Beam.Remove[n.beam,n,NIL,NIL]; IF b.beam#NIL THEN Beam.SetSyncs[b.beam]; END; AddChord:PUBLIC PROCEDURE[b:BeamPTR,c:ChordPTR] = BEGIN i,j:CARDINAL_beamLength-1; oldBeam:BeamPTR = Chord.Beam[c]; FOR i IN [0..beamLength) DO IF b.chord[i]=[chord[c]] THEN RETURN; ENDLOOP; IF b.sync1=NIL THEN b.sync1_c.note[0].sync; IF b.sync2=NIL THEN b.sync2_c.note[0].sync; IF c.note[0].sync.time < b.sync1.time THEN b.sync1 _ c.note[0].sync; IF c.note[0].sync.time > b.sync2.time THEN b.sync2 _ c.note[0].sync; FOR i IN [0..beamLength) DO IF b.chord[i]=endOfBeam THEN BEGIN j _ i; EXIT; END; IF Beam.time[b.chord[i]]>c.note[0].sync.time THEN j _ i; IF j#beamLength-1 THEN EXIT; ENDLOOP; IF b.chord[beamLength-1]#endOfBeam THEN Overflow[beam]; FOR i DECREASING IN (j..beamLength) DO b.chord[i] _ b.chord[i-1]; ENDLOOP; b.chord[j] _ [chord[c]]; FOR i IN [0..chordLength) DO IF c.note[i]=NIL THEN EXIT; c.note[i].beam _ b; ENDLOOP; IF oldBeam#NIL AND oldBeam#b THEN Beam.Remove[oldBeam,NIL,c,NIL]; IF b.beam#NIL THEN Beam.SetSyncs[b.beam]; END; AddBeam:PUBLIC PROCEDURE[b:BeamPTR,new:BeamPTR] = BEGIN oldBeam:BeamPTR=b.beam; i,j:CARDINAL_beamLength-1; FOR i IN [0..beamLength) DO IF b.chord[i]=[beam[new]] THEN RETURN; ENDLOOP; IF b.sync1=NIL THEN b.sync1_new.sync1; IF b.sync2=NIL THEN b.sync2_new.sync2; IF new.sync1.time < b.sync1.time THEN b.sync1 _ new.sync1; IF new.sync2.time > b.sync2.time THEN b.sync2 _ new.sync2; FOR i IN [0..beamLength) DO IF b.chord[i]=endOfBeam THEN BEGIN j _ i; EXIT; END; IF Beam.time[b.chord[i]]>new.sync1.time THEN j_i; IF j#beamLength-1 THEN EXIT; ENDLOOP; IF b.chord[beamLength-1]#endOfBeam THEN Overflow[beam]; FOR i DECREASING IN (j..beamLength) DO b.chord[i] _ b.chord[i-1]; ENDLOOP; b.chord[j] _ [beam[new]]; new.beam _ b; IF oldBeam#NIL AND oldBeam#b THEN Beam.Remove[oldBeam,NIL,NIL,new]; IF b.beam#NIL THEN Beam.SetSyncs[b.beam]; END; Remove:PUBLIC PROCEDURE[beam:BeamPTR,n:NotePTR,c:ChordPTR,b:BeamPTR] = BEGIN i,j:CARDINAL; found:BOOLEAN _ FALSE; sync1,sync2:SyncPTR _ NIL; IF beam=NIL THEN RETURN; FOR i IN [0..beamLength) DO IF beam.chord[i]=endOfBeam THEN EXIT; IF beam.chord[i]#[beam[b]] AND beam.chord[i]#[chord[c]] AND beam.chord[i]#[note[n]] THEN LOOP; IF beam.chord[i]=[note[n]] THEN n.beam_NIL; IF beam.chord[i]=[beam[b]] THEN b.beam_NIL; IF beam.chord[i]=[chord[c]] THEN FOR j IN [0..chordLength) DO IF c.note[j]=NIL THEN EXIT; c.note[j].beam _ NIL; ENDLOOP; FOR j IN [i..beamLength-1) DO beam.chord[j] _ beam.chord[j+1]; ENDLOOP; beam.chord[beamLength-1] _ endOfBeam; found _ TRUE; ENDLOOP; IF NOT found THEN RETURN; IF beam.chord[1]=endOfBeam THEN {FreeBeam[@beam]; RETURN}; -- reset beamsyncs if needed IF n#NIL THEN sync1 _ n.sync; IF c#NIL THEN sync2 _ c.note[0].sync; IF b#NIL THEN BEGIN sync1 _ b.sync1; sync2 _ b.sync2; END; IF beam.sync1=sync1 OR beam.sync1=sync2 THEN beam.sync1_NIL; IF beam.sync2=sync2 OR beam.sync2=sync1 THEN beam.sync2_NIL; IF beam.sync1=NIL OR beam.sync2=NIL THEN Beam.SetSyncs[beam]; END; Sort:PUBLIC PROCEDURE[b:BeamPTR] = BEGIN i,j:CARDINAL; temp:VariousPTR; FOR i IN [0..beamLength) DO IF b.chord[i] = endOfBeam THEN EXIT; FOR j IN (i..beamLength) DO IF b.chord[j] = endOfBeam THEN EXIT; IF Beam.time[b.chord[i]] <= Beam.time[b.chord[j]] THEN LOOP; temp _ b.chord[i]; b.chord[i] _ b.chord[j]; b.chord[j] _ temp; ENDLOOP; ENDLOOP; END; SetSyncs:PUBLIC PROCEDURE[b:BeamPTR] = BEGIN i:CARDINAL; sync1,sync2:SyncPTR; b.sync1 _b.sync2 _ NIL; FOR i IN [0..beamLength) DO IF b.chord[i]=endOfBeam THEN EXIT; sync1 _ sync2 _ NIL; WITH ev:b.chord[i] SELECT FROM note => sync1 _ ev.n.sync; chord=> sync2 _ ev.c.note[0].sync; beam => BEGIN sync1 _ ev.b.sync1; sync2 _ ev.b.sync2; END; ENDCASE; IF sync1=NIL THEN sync1 _ sync2; IF sync2=NIL THEN sync2 _ sync1; IF b.sync1=NIL THEN b.sync1 _ sync1; IF b.sync2=NIL THEN b.sync2 _ sync2; IF sync1=NIL OR sync2=NIL THEN LOOP; IF b.sync1.time>sync1.time THEN b.sync1 _ sync1; IF b.sync2.time<=sync2.time THEN b.sync2 _ sync2; ENDLOOP; Beam.Sort[b]; IF b.beam # NIL THEN SetSyncs[b.beam]; END; SetStems:PUBLIC PROCEDURE[b:BeamPTR] = --make the chord stems consistent with the position of the beam BEGIN i:CARDINAL; height,heighti,heightb:INTEGER; time1,timei:Time _ b.sync1.time; IF NOT b.beamed THEN RETURN; --determine the staff heightb _ b.height+Sheet.Height[b.sync1.time,,b.staff]; FOR i IN [0..beamLength) DO IF b.chord[i]=endOfBeam THEN EXIT; WITH ev:b.chord[i] SELECT FROM note => { heighti _ Sheet.Height[ev.n.sync.time,ev.n.pitch,ev.n.staff]; timei _ Beam.time[b.chord[i]]; height _ Real.FixI[heightb+b.tilt*(timei-time1)]; ev.n.stemUp _ (height > heighti); b.staff _ ev.n.staff}; chord=> { [] _ Chord.Sort[ev.c,FALSE]; heighti _ Sheet.Height[ev.c.note[0].sync.time,ev.c.note[0].pitch,ev.c.note[0].staff]; timei _ Beam.time[b.chord[i]]; height _ Real.FixI[heightb+b.tilt*(timei-time1)]; ev.c.stemUp _ (height > heighti); b.staff _ ev.c.note[0].staff}; beam => { ev.b.tilt _ b.tilt; height _ Real.FixI[heightb+b.tilt*(ev.b.sync1.time-time1)]; ev.b.height _ height-Sheet.Height[0,,ev.b.staff]; SetStems[ev.b]; b.staff _ ev.b.staff}; ENDCASE; ENDLOOP; b.height _ heightb - Sheet.Height[b.sync1.time,,b.staff]; END; --************************************************************************** --beam attributes --************************************************************************** Grace:PUBLIC PROCEDURE[b:BeamPTR] RETURNS[BOOLEAN] = BEGIN -- a grace beam doesn't have ANY non-grace notes i,j:CARDINAL; FOR i IN [0..beamLength) DO IF b.chord[i]=endOfBeam THEN EXIT; WITH ev:b.chord[i] SELECT FROM note => IF ~ev.n.grace THEN RETURN[FALSE]; chord => FOR j IN [0..chordLength) DO IF ev.c.note[j]=NIL THEN EXIT; IF ~ev.c.note[j].grace THEN RETURN[FALSE]; ENDLOOP; beam => IF ~Grace[ev.b] THEN RETURN[FALSE]; ENDCASE; ENDLOOP; RETURN[TRUE]; END; InVoice:PUBLIC PROCEDURE[b:BeamPTR,voice:CARDINAL] RETURNS[BOOLEAN] = BEGIN i,j:CARDINAL; FOR i IN [0..beamLength) DO IF b.chord[i]=endOfBeam THEN EXIT; WITH ev:b.chord[i] SELECT FROM note => IF ev.n.voice=voice THEN RETURN[TRUE]; chord => FOR j IN [0..chordLength) DO IF ev.c.note[j]=NIL THEN EXIT; IF ev.c.note[j].voice=voice THEN RETURN[TRUE]; ENDLOOP; beam => IF InVoice[ev.b,voice] THEN RETURN[TRUE]; ENDCASE; ENDLOOP; RETURN[FALSE]; END; END. (1792)\364b9B35i36I105i4I213b8B805b8B960b7B835b6B1160b4B361b8B703b8B1337b5B477b7B