DIRECTORY Graphics USING [Texture], InlineDefs USING [LongMult], MusicDefs, Note USING [Duration], Piece USING [AddSync, CleanUpSyncs], Score USING [GetTimeSignature], Sheet USING [HiLite], Sync USING [AddNote], Utility USING [NewSync], Voice USING [ClearState, State, StatePTR]; VoiceImpl: CEDAR PROGRAM IMPORTS InlineDefs, MusicDefs, Note, Piece, Score, Sheet, Sync, Utility, Voice EXPORTS MusicDefs, Voice = BEGIN OPEN MusicDefs, Voice; Error: SIGNAL = CODE; voice: PUBLIC BOOL _ FALSE; selectedVoice: PUBLIC CARDINAL _0; maxVoice: PUBLIC CARDINAL _ 0; Set: PUBLIC PROC[v: CARDINAL] = { n: NotePTR; i, j: CARDINAL; IF lineSelect THEN FOR i IN [0..scoreLength) DO IF score[i]=NIL THEN LOOP; IF score[i].time < select1 OR score[i].time > select2 THEN LOOP; FOR j IN [0..syncLength) DO IF score[i].event[j]=NIL THEN EXIT; IF voice AND score[i].event[j].voice#selectedVoice THEN LOOP; score[i].event[j].voice _ v; ENDLOOP; ENDLOOP ELSE FOR i IN [0..selectionLength) DO IF (n _ selection[i])=NIL THEN LOOP; IF voice AND n.voice#selectedVoice THEN LOOP; SetDirty[n.sync.time, n.sync.time]; n.voice _ v; ENDLOOP; IF lineSelect THEN SetDirty[select1, select2]; maxVoice _ MAX[v, maxVoice]; }; Check: PUBLIC PROC = { vs: State; i: CARDINAL; sum, sumTS: Time _ 0; begin, end: CARDINAL _ 0; FOR i IN [0..scoreLength) DO IF score[i].type = timeSignature THEN sumTS _ InlineDefs.LongMult[score[i].ts.top*256, 64/score[i].ts.bottom]; IF ~Measure[score[i].type] THEN LOOP; begin _ end; end _ i; IF begin=end THEN LOOP; sum _ Sum[begin, end, voice,@vs]; IF sum=0 THEN LOOP; IF ABS[sum-sumTS]>8 THEN Sheet.HiLite[lightgrey, score[begin].time, score[end].time]; ENDLOOP; }; lightgrey: Graphics.Texture = 004040B; Sum: PROC[begin, end: CARDINAL, separate: BOOL, ss: StatePTR] RETURNS[sum: Time] = { sum _ 0; ClearState[ss]; FOR i: CARDINAL IN (begin..end) DO IF score[i].type#notes THEN LOOP; [] _SetState[ss, score[i], 128, separate]; ENDLOOP; [] _SetState[ss, score[end], 128, separate]; FOR v: CARDINAL IN [0..maxVoice] DO IF separate AND v#selectedVoice THEN LOOP; sum _ MAX[sum, ss[v].sum+ss[v].duration]; ENDLOOP; }; SetState: PUBLIC PROC[vs: StatePTR, s: SyncPTR, m: INTEGER, separate: BOOL] RETURNS[max: Time]= { n: NotePTR; i: CARDINAL _ 0; duration, offset: Time; FOR i IN [0..10) DO vs[i].found _ vs[i].graced _ FALSE; ENDLOOP; FOR i IN [0..syncLength) DO IF (n _ s.event[i])=NIL THEN EXIT; IF n.value=unknown THEN LOOP; IF vs[n.voice].grace THEN vs[n.voice].graced _ TRUE; IF n.grace THEN { vs[n.voice].found _ TRUE; vs[n.voice].sum _ vs[n.voice].sum+ vs[n.voice].duration-10; vs[n.voice].duration _ 10; LOOP}; duration _ Note.Duration[n, m]; IF vs[n.voice].found=FALSE THEN { vs[n.voice].sum _ vs[n.voice].sum+ vs[n.voice].duration; vs[n.voice].duration _ duration; vs[n.voice].found _ TRUE; IF n.rest AND n.value=whole THEN { vs[n.voice].sum _ vs[n.voice].sum+ vs[n.voice].duration/2; vs[n.voice].duration _ vs[n.voice].duration/2}}; IF vs[n.voice].duration>duration THEN vs[n.voice].duration _ duration; ENDLOOP; FOR i IN [0..syncLength) DO IF (n _ s.event[i])=NIL THEN EXIT; vs[n.voice].grace _ n.grace; ENDLOOP; IF Measure[s.type] THEN FOR i IN [0..maxVoice] DO vs[i].found _ TRUE; vs[i].sum _ vs[i].sum+vs[i].duration; vs[i].duration _ 0; ENDLOOP; max _ 0; FOR i IN [0..maxVoice] DO IF NOT vs[i].found AND vs[i].duration#0 THEN offset _ 10 ELSE offset _ 0; max _ MAX[max, vs[i].sum+ offset]; ENDLOOP; IF max=0 THEN RETURN; IF ~separate THEN FOR i IN [0..maxVoice] DO IF vs[i].found THEN vs[i].sum _ max; ENDLOOP; }; Correct: PUBLIC PROC[time1, time2: Time] = { s, i: CARDINAL; begin, end: CARDINAL _ 0; sumTS, sum: Time _ 0; ts: TimeSignature; vs: State; FOR s DECREASING IN [0..scoreLength) DO IF Measure[score[s].type] AND begin=0 THEN {begin _ s; LOOP}; IF NOT Measure[score[s].type] THEN LOOP; end _ begin; begin _ s; IF score[begin].timetime2+1 THEN LOOP; SeparateGraceNotes[@begin,@end]; -- may update end sum _ Sum[begin, end, FALSE,@vs]; ts _ Score.GetTimeSignature[score[end].time]; sumTS _ InlineDefs.LongMult[ts.top*256, 64/ts.bottom]; IF sum-sumTS< 9 THEN LOOP; -- no complaints [] _ Sum[begin, end, TRUE,@vs]; voicefull _ ALL[FALSE]; FOR i IN [0..maxVoice] DO IF ABS[vs[i].sum-sumTS]<9 THEN voicefull[i] _ TRUE; ENDLOOP; BreakUpSyncs[@begin,@end]; -- may update end ReconstructVoices[begin, end]; ENDLOOP; Piece.CleanUpSyncs[score]; }; SeparateGraceNotes: PROC[start, stop: POINTER TO CARDINAL] = { n: NotePTR; sync: SyncPTR; skip: CARDINAL _ 0; grace, normal: BOOL; FOR i: CARDINAL IN [start^..scoreLength) DO IF i=stop^ THEN EXIT; IF skip>0 THEN {skip _ skip-1; LOOP}; -- skip the syncs that we added IF score[i].type#notes THEN LOOP; grace _ normal _ FALSE; FOR j: CARDINAL IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF n.grace THEN grace _ TRUE ELSE normal _ TRUE; IF NOT (grace AND normal) THEN LOOP; sync _ Utility.NewSync[]; --separate sync.time _ score[i].time; FOR k: CARDINAL DECREASING IN [0..syncLength) DO IF (n _ score[i].event[k])=NIL THEN LOOP; IF ~n.grace THEN LOOP; Sync.AddNote[sync, n]; ENDLOOP; Piece.AddSync[score, sync]; stop^ _ stop^+1; skip _ skip+1; EXIT; ENDLOOP; ENDLOOP; }; BreakUpSyncs: PROC[start, stop: POINTER TO CARDINAL] = { vs: State; n: NotePTR; sync: SyncPTR; skip: CARDINAL _ 0; ClearState[@vs]; FOR i: CARDINAL IN (start^..scoreLength) DO IF i=stop^ THEN EXIT; IF skip>0 THEN {skip _ skip-1; LOOP}; -- skip the syncs that we added IF score[i].type#notes THEN LOOP; [] _ SetState[@vs, score[i], 128, TRUE]; FOR v1: CARDINAL IN [0..maxVoice] DO IF NOT (voicefull[v1] AND vs[v1].found) THEN LOOP; FOR v2: CARDINAL IN (v1..maxVoice] DO IF NOT (voicefull[v2] AND vs[v2].found) THEN LOOP; IF ABS[vs[v1].sum-vs[v2].sum]<9 THEN LOOP; -- same time (close enough) sync _ Utility.NewSync[]; sync.time _ score[i].time; FOR j: CARDINAL DECREASING IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN LOOP; IF n.voice#v1 THEN LOOP; Sync.AddNote[sync, n]; ENDLOOP; Piece.AddSync[score, sync]; stop^ _ stop^ +1; skip _ skip+1; ENDLOOP; ENDLOOP; ENDLOOP; }; ReconstructVoices: PROC[start, stop: CARDINAL] = { v1, v2: CARDINAL; FOR v1 IN [0..maxVoice] DO IF NOT voicefull[v1] THEN LOOP; FOR v2 IN (v1..maxVoice] DO IF voicefull[v2] THEN AdjustVoices[v1, v2, start, stop]; ENDLOOP; ENDLOOP; }; AdjustVoices: PROC[a, b: CARDINAL, start, stop: CARDINAL] = { A, B: State; n: NotePTR; time: Time _ 0; temp: SyncPTR; as, bs: CARDINAL _ start; getNextA, getNextB: BOOL; ClearState[@A]; ClearState[@B]; WHILE as#stop AND bs#stop DO getNextA _ A[a].sum<=B[b].sum; getNextB _ B[b].sum<=A[a].sum; IF getNextA THEN FOR i: CARDINAL IN (as..stop+1] DO IF i=stop+1 THEN {Error; EXIT}; -- catches infinite loops [] _ SetState[@A, score[i], 128, TRUE]; IF score[i].type#notes AND i#stop THEN LOOP; IF ~A[a].found THEN LOOP; as _ i; EXIT; ENDLOOP; IF getNextB THEN FOR i: CARDINAL IN (bs..stop+1] DO IF i=stop+1 THEN {Error; EXIT}; -- catches infinite loops [] _ SetState[@B, score[i], 128, TRUE]; IF score[i].type#notes AND i#stop THEN LOOP; IF ~B[b].found THEN LOOP; bs _ i; EXIT; ENDLOOP; IF ABS[A[a].sum-B[b].sum]<5 THEN A[a].sum _ B[b].sum _ MAX[A[a].sum, B[b].sum]; IF A[a].sumB[b].sum AND bs>as THEN { temp _ score[bs]; FOR i: CARDINAL DECREASING IN [as..bs) DO score[i+1] _ score[i]; ENDLOOP; score[as] _ temp; bs _ as; as _ as+ 1; }; IF A[a].sum=B[b].sum AND as#bs THEN IF bsJ˜ J˜Jšœœ˜Jšœœ˜šœœœ˜+Jšœ œœ˜JšœœœŸ˜EJšœœœ˜!Jšœ1™1Jšœœ˜šœœœ˜%Jšœœœœ˜)Jš œ œ œœ œ˜0Jš œœœ œœ˜$JšœŸ ˜$J˜š œœ œœ˜0Jšœœœœ˜)Jšœ œœ˜J˜Jšœ˜—J˜J˜J˜Jšœœ˜—Jšœ˜—Jšœ˜—J˜š ž œœœœœ˜9J˜ J˜ J˜Jšœœ˜J˜šœœœ˜+Jšœ œœ˜JšœœœŸ˜EJšœœœ˜!Jšœ,™,Jšœ"œ˜(šœœœ˜$Jš œœœœœ˜2šœœœ˜%Jš œœœœœ˜2Jš œœœœŸ˜GJ˜J˜š œœ œœ˜0Jšœœœœ˜)Jšœ œœ˜J˜Jšœ˜—J˜J˜J˜Jšœ˜—Jšœ˜—Jšœ˜—Jšœ˜—J˜šžœœœ˜2Jšœ$™$Jšœœ˜šœœ˜Jšœœœœ˜šœœ˜Jšœœ#˜8Jšœ˜—Jšœ˜—Jšœ˜—J˜šž œœœœ˜=Jšœ-™-JšœA™AJšœœ˜ J˜ J˜J˜Jšœœ ˜Jšœœ˜Jšœ œ˜Jšœ œ˜Jšœ œ ˜Jšœ œ œ˜Jšœ œ œ˜šœ ˜šœœœ˜"Jšœ œ œŸ˜9Jšœœœ˜'Jšœœœœ˜,Jšœœ œœ˜Jšœœ˜ Jšœ˜——šœ ˜šœœœ˜"Jšœ œ œŸ˜9Jšœœœ˜'Jšœœœœ˜,Jšœœ œœ˜Jšœœ˜ Jšœ˜——Jšœœœœ œœ œ œœ œ ˜OJšœ™Jšœ3™3š œœœœ˜#Jšœ˜J˜Jš œœ œœ œœ˜IJ˜J˜Jšœ˜—š œœœœ˜#Jšœ˜J˜Jš œœ œœ œœ˜IJ˜J˜Jšœ˜—Jšœ.™.Jšœ+™+š œœœœœœ˜-š œœœ œœ˜5Jšœœœœ˜*Jšœ œœ˜JšœŸ+˜GJš˜—š œœœ œœ˜5Jšœœœœ˜*Jšœ œœ˜J˜Jšœ˜——Jš œœœœœ ˜,Jš œœœœœ ˜,Jšœ.™.Jšœ/™/Jšœ˜Jšœ˜—J˜Jšœ œ œœ˜!J˜Jšœ˜—…—4n