DIRECTORY Basics USING [LongMult], Event USING [AddNote, Sync], MusicDefs, Note USING [Duration], Piece USING [AddEvent, CleanUpEvents], Score USING [GetTimeSignature], Selection USING [Enumerate], Sheet USING [HiLite], Voice USING [max, State, StatePTR]; VoiceImpl: CEDAR PROGRAM IMPORTS Basics, Event, MusicDefs, Note, Piece, Score, Selection, Sheet EXPORTS Voice = BEGIN OPEN MusicDefs, Voice; Set: PUBLIC PROC[score: ScorePTR, voice: CARDINAL] = { SetVoice: PROC[score: ScorePTR, n: NotePTR] = {n.voice _ voice}; Selection.Enumerate[SetVoice]; score.maxVoice _ MAX[voice, score.maxVoice]; }; Check: PUBLIC PROC[score: ScorePTR] = { vs: StatePTR ~ NEW[State]; sum, sumTS: Time _ 0; begin, end: CARDINAL _ 0; FOR i: CARDINAL IN [0..score.length) DO WITH score[i] SELECT FROM timeSig: TimeSignaturePTR => { sumTS _ Basics.LongMult[timeSig.ts.top*256, 64/timeSig.ts.bottom] }; ENDCASE; IF ~Measure[score[i]] THEN LOOP; begin _ end; end _ i; IF begin = end THEN LOOP; sum _ Sum[score, begin, end, score.sheet.voice # noVoice, vs]; IF sum = 0 THEN LOOP; IF ABS[sum-sumTS] > 8 THEN Sheet.HiLite[score.sheet, light, score[begin].time, score[end].time]; ENDLOOP; }; Sum: PROC[score: ScorePTR, begin, end: CARDINAL, separate: BOOLEAN, ss: StatePTR] RETURNS[sum: Time] = { sum _ 0; ClearState[ss]; FOR i: CARDINAL IN (begin..end) DO IF score[i].type # sync THEN LOOP; [] _ SetState[ss, score[i], 128, separate]; ENDLOOP; [] _ SetState[ss, score[end], 128, separate]; FOR v: CARDINAL IN [0..Voice.max) DO IF separate AND v # score.sheet.voice THEN LOOP; sum _ MAX[sum, ss[v].sum+ss[v].duration]; ENDLOOP; }; ClearState: PUBLIC PROC[vs: StatePTR] ~ { vs^ _ ALL[[FALSE, FALSE, FALSE, FALSE, 0, 0]]; }; SetState: PUBLIC PROC[vs: StatePTR, event: EventPTR, m: INTEGER, separate: BOOLEAN] RETURNS[max: Time] = { n: NotePTR; i: CARDINAL _ 0; duration, offset: Time; sync: SyncPTR _ NIL; IF event.type = sync THEN sync _ Event.Sync[event]; FOR i: CARDINAL IN [0..10) DO vs[i].found _ vs[i].graced _ FALSE; ENDLOOP; IF sync # NIL THEN FOR i: CARDINAL IN [0..sync.length) DO IF (n _ sync.note[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; IF sync # NIL THEN FOR i: CARDINAL IN [0..Voice.max) DO IF (n _ sync.note[i]) = NIL THEN EXIT; vs[n.voice].grace _ n.grace; ENDLOOP; IF Measure[event] THEN FOR i: CARDINAL IN [0..Voice.max) DO vs[i].found _ TRUE; vs[i].sum _ vs[i].sum+vs[i].duration; vs[i].duration _ 0; ENDLOOP; max _ 0; FOR i: CARDINAL IN [0..Voice.max) 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: CARDINAL IN [0..Voice.max) DO IF vs[i].found THEN vs[i].sum _ max; ENDLOOP; }; Correct: PUBLIC PROC[score: ScorePTR, time1, time2: Time] = { begin, end: CARDINAL _ 0; sumTS, sum: Time _ 0; ts: TimeSignature; vs: StatePTR ~ NEW[State]; FOR i: CARDINAL DECREASING IN [0..score.length) DO IF Measure[score[i]] AND begin = 0 THEN {begin _ i; LOOP}; IF NOT Measure[score[i]] THEN LOOP; end _ begin; begin _ i; IF score[begin].time < time1-1 OR score[end].time > time2+1 THEN LOOP; end _ SeparateGraceNotes[score, begin, end]; -- may update end sum _ Sum[score, begin, end, FALSE, vs]; ts _ Score.GetTimeSignature[score, score[end].time]; sumTS _ Basics.LongMult[ts.top*256, 64/ts.bottom]; IF sum-sumTS < 9 THEN LOOP; -- no complaints [] _ Sum[score, begin, end, TRUE, vs]; FOR v: CARDINAL IN [0..Voice.max) DO vs[v].full _ ABS[vs[i].sum-sumTS] < 9; ENDLOOP; end _ BreakUpEvents[score, begin, end]; -- may update end ReconstructVoices[score, vs, begin, end]; ENDLOOP; Piece.CleanUpEvents[score]; }; SeparateGraceNotes: PROC[score: ScorePTR, start, stop: CARDINAL] RETURNS[newStop: CARDINAL] = { n: NotePTR; sync, new: SyncPTR; skip: CARDINAL _ 0; grace, normal: BOOLEAN; FOR i: CARDINAL IN [start..score.length) DO IF i = stop THEN EXIT; IF skip > 0 THEN {skip _ skip-1; LOOP}; -- skip the syncs that we added IF score[i].type # sync THEN LOOP; sync _ Event.Sync[score[i]]; grace _ normal _ FALSE; FOR j: CARDINAL IN [0..sync.length) DO IF (n _ sync.note[j]) = NIL THEN EXIT; IF n.grace THEN grace _ TRUE ELSE normal _ TRUE; IF NOT (grace AND normal) THEN LOOP; new _ NEW[EventRec[sync][sync.length] _ [variant: sync[note: ]]]; -- separate new.time _ sync.time; FOR k: CARDINAL DECREASING IN [0..sync.length) DO IF (n _ sync.note[k]) = NIL THEN LOOP; IF ~n.grace THEN LOOP; Event.AddNote[score, new, n]; ENDLOOP; Piece.AddEvent[score, new]; stop _ stop+1; skip _ skip+1; EXIT; ENDLOOP; ENDLOOP; RETURN[stop]; }; BreakUpEvents: PROC[score: ScorePTR, start, stop: CARDINAL] RETURNS[newStop: CARDINAL] = { vs: StatePTR ~ NEW[State]; n: NotePTR; sync, new: SyncPTR; skip: CARDINAL _ 0; ClearState[vs]; FOR i: CARDINAL IN (start..score.length) DO IF i = stop THEN EXIT; IF skip > 0 THEN {skip _ skip-1; LOOP}; -- skip the syncs that we added IF score[i].type # sync THEN LOOP; sync _ Event.Sync[score[i]]; [] _ SetState[vs, score[i], 128, TRUE]; FOR v1: CARDINAL IN [0..Voice.max) DO IF NOT (vs[v1].full AND vs[v1].found) THEN LOOP; FOR v2: CARDINAL IN (v1..Voice.max) DO IF NOT (vs[v2].full AND vs[v2].found) THEN LOOP; IF ABS[vs[v1].sum-vs[v2].sum] < 9 THEN LOOP; -- same time (close enough) new _ NEW[EventRec[sync][sync.length] _ [variant: sync[note: ]]]; -- separate new.time _ score[i].time; FOR j: CARDINAL DECREASING IN [0..sync.length) DO IF (n _ sync.note[j]) = NIL THEN LOOP; IF n.voice # v1 THEN LOOP; Event.AddNote[score, new, n]; ENDLOOP; Piece.AddEvent[score, new]; stop _ stop +1; skip _ skip+1; ENDLOOP; ENDLOOP; ENDLOOP; RETURN[stop]; }; ReconstructVoices: PROC[score: ScorePTR, vs: StatePTR, start, stop: CARDINAL] = { FOR v1: CARDINAL IN [0..Voice.max) DO IF NOT vs[v1].full THEN LOOP; FOR v2: CARDINAL IN (v1..Voice.max) DO IF vs[v2].full THEN AdjustVoices[score, v1, v2, start, stop]; ENDLOOP; ENDLOOP; }; AdjustVoices: PROC[score: ScorePTR, a, b: CARDINAL, start, stop: CARDINAL] = { A: StatePTR ~ NEW[State]; B: StatePTR ~ NEW[State]; n: NotePTR; time: Time _ 0; temp: EventPTR; as, bs: CARDINAL _ start; getNextA, getNextB: BOOLEAN; 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; -- catches infinite loops [] _ SetState[A, score[i], 128, TRUE]; IF score[i].type # sync 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; -- catches infinite loops [] _ SetState[B, score[i], 128, TRUE]; IF score[i].type # sync 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].sum < B[b].sum AND bs < as THEN { temp _ score[as]; FOR i: CARDINAL DECREASING IN [bs..as) DO score[i+1] _ score[i]; ENDLOOP; score[bs] _ temp; as _ bs; bs _ bs+ 1; }; IF A[a].sum > B[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 bs < as THEN FOR j: CARDINAL DECREASING IN [0..Event.Sync[score[as]].length) DO IF (n _ Event.Sync[score[as]].note[j]) = NIL THEN LOOP; IF n.voice # a THEN LOOP; Event.AddNote[score, Event.Sync[score[bs]], n]; ENDLOOP ELSE FOR j: CARDINAL DECREASING IN [0..Event.Sync[score[bs]].length) DO IF (n _ Event.Sync[score[bs]].note[j]) = NIL THEN LOOP; IF n.voice # b THEN LOOP; Event.AddNote[score, Event.Sync[score[as]], n]; ENDLOOP; IF A[a].sum = B[b].sum AND bs < as THEN as _ bs; IF A[a].sum = B[b].sum AND as < bs THEN bs _ as; ENDLOOP; }; END. ,VoiceImpl.mesa Copyright (C) 1983, 1984 Xerox Corporation. All rights reserved. Author: John Maxwell Last Edited by: Maxwell, November 22, 1983 8:37 am Last Edited by: Doug Wyatt, June 13, 1984 5:26:16 pm PDT voice: PUBLIC BOOLEAN _ FALSE; selectedVoice: PUBLIC CARDINAL _ 0; maxVoice: PUBLIC CARDINAL _ 0; lightgrey: CARDINAL = 004040B; ***************************************************************** enumerating over voices ***************************************************************** sum contains the total up to but not including the last duration duration contains the duration of the last note found a grace note occurs logically just a little before the note it graces a string of grace notes is treated as one grace note "grace" is set separately to avoid having a second grace note appear to be "graced" by the first. measures are treated special vs[i].graced _ FALSE; IF vs[n.voice].grace THEN vs[n.voice].graced _ TRUE; vs[n.voice].grace _ FALSE; determine the max "time" for this sync align all of the sums ***************************************************************** realignning voices ***************************************************************** ENABLE Piece.Overflow => IF old = score THEN score _ new; we have a candidate measure separate grace notes if there are non-grace notes separate voices if they have different times merge things that should be together step through the two voices asynchronously. adjust them according to their relative order and relative sums. problem: syncs are out of order solution: put the latter one just before the former problem: notes which should be synced, aren't. solution: put the notes in the earlier sync mustn't remove score[as] if it becomes empty! problem: notes which shouldn't be synced, are. solution: already taken care of by BreakUpEvents Ê ì˜šœ™J™@Jšœ™Jšœ2™2Jšœ8™8—J˜šÏk ˜ Jšœœ ˜Jšœœ˜J˜ Jšœœ ˜Jšœœ˜'Jšœœ˜ Jšœ œ˜Jšœœ ˜Jšœœ˜#J˜—Jšœ œœ˜Jšœ@˜GJšœ˜ Jšœœœ˜J˜Jšœ™Jšœ#™#Jšœ™J˜šÏnœœœœ˜6Jšžœœ2˜@J˜Jšœœ˜,Jšœ˜J˜—šžœœœ˜'Jšœœ˜J˜Jšœ œ˜šœœœ˜'šœ œ˜šœ˜J˜AJ˜—Jšœ˜—Jšœœœ˜ J˜Jšœ œœ˜J˜>Jšœ œœ˜šœœœ˜J˜E—Jšœ˜—Jšœ˜J˜—Jšœ œ™"J˜šžœœœ œ˜QJšœ˜J˜J˜šœœœ˜"Jšœœœ˜#J˜+Jšœ˜—J˜-šœœœ˜$Jšœ œœœ˜1Jšœœ!˜*Jšœ˜—Jšœ˜J˜—JšœA™AJšœ™JšœA™AJ˜šž œœœ˜)Jš œœœœœœ ˜.J˜J™—š žœœœ#œ œ˜SJšœ˜Jšœ@™@Jšœ5™5JšœE™EJšœ4™4J˜ Jšœœ˜J˜Jšœœ˜Jšœœ˜3Jš œœœ œœœ˜Jš œœœœœœ˜9Jšœœœœ˜&Jšœœœ˜Jšœœœ˜5šœ œ˜Jšœœ˜J˜;J˜Jšœ˜—J˜šœœœ˜#J˜8J˜ Jšœœ˜šœœœ˜$J˜:J˜0——Jšœ!œ!˜HJšœ˜—Jšœa™aš œœœœœœ˜7Jšœœœœ˜&J˜Jšœ˜—Jšœ™š œœœœœ˜;Jšœœ˜J˜%J˜—Jšœ™Jšœ5™5šœ™Jšœ˜—Jšœ&™&J˜šœœœ˜$Jš œœ œœ œ ˜KJšœœ˜"Jšœ˜—Jšœ œœ˜Jšœ™š œ œœœœ˜6Jšœ œ˜$Jšœ˜ —Jšœ˜J˜—J˜JšœA™AJšœ™JšœA™AJ˜šžœœœ)˜=Jšœœ œ ™9Jšœ œ˜J˜J˜Jšœœ˜š œœ œœ˜2Jšœœ œ œ˜:Jšœœœœ˜#J˜ J˜ Jšœœœœ˜FJšœ™Jšœ-Ïc˜>Jšœœ˜(J˜4J˜2JšœœœŸ˜1Jšœœ˜&šœœœ˜$Jšœ œ˜'Jšœ˜—Jšœ(Ÿ˜9J˜)Jšœ˜—J˜Jšœ˜J˜—šžœœœ˜@Jšœ œ˜J˜ J˜Jšœœ˜Jšœœ˜šœœœ˜+Jšœ œœ˜Jšœ œœŸ˜GJšœœœ˜"J˜Jšœ1™1Jšœœ˜šœœœ˜&Jšœœœœ˜&Jš œ œ œœ œ˜0Jš œœœ œœ˜$Jšœœ9Ÿ ˜MJ˜š œœ œœ˜1Jšœœœœ˜&Jšœ œœ˜J˜Jšœ˜—J˜J˜J˜Jšœœ˜—Jšœ˜—Jšœ˜ Jšœ˜J˜—šž œœœ˜;Jšœ œ˜Jšœœ˜J˜ J˜Jšœœ˜J˜šœœœ˜+Jšœ œœ˜Jšœ œœŸ˜GJšœœœ˜"J˜Jšœ,™,Jšœ!œ˜'šœœœ˜%Jš œœœœœ˜0šœœœ˜&Jš œœœœœ˜0Jš œœœœŸ˜IJšœœ9Ÿ ˜MJ˜š œœ œœ˜1Jšœœœœ˜&Jšœœœ˜J˜Jšœ˜—J˜J˜J˜Jšœ˜—Jšœ˜—Jšœ˜—Jšœ˜ Jšœ˜J˜—šžœœ-œ˜QJšœ$™$šœœœ˜%Jšœœ œœ˜šœœœ˜&Jšœ œ*˜=Jšœ˜—Jšœ˜—Jšœ˜J˜—šž œœœœ˜NJšœ,™,JšœA™AJšœ œ˜Jšœ œ˜J˜ J˜J˜Jšœœ ˜Jšœœ˜Jšœ œ˜Jšœ œ˜Jšœ œ ˜ Jšœ œ œ˜ Jšœ œ œ˜ šœ ˜šœœœ˜"Jšœ œœŸ˜3Jšœœœ˜&Jšœœ œœ˜/Jšœœ œœ˜Jšœœ˜ Jšœ˜——šœ ˜šœœœ˜"Jšœ œœŸ˜3Jšœœœ˜&Jšœœ œœ˜/Jšœœ œœ˜Jšœœ˜ Jšœ˜——Jšœœœœ œœ œ œœ œ ˜QJšœ™Jšœ3™3š œœ œœ œ˜)J˜Jš œœ œœ œœ˜IJ˜J˜Jšœ˜—š œœ œœ œ˜)J˜Jš œœ œœ œœ˜IJ˜J˜Jšœ˜—Jšœ.™.Jšœ+™+š œœ œœ œœ ˜3š œœœ œœ#˜GJšœ'œœœ˜7Jšœ œœ˜J˜0Jšœ-™-Jš˜—š œœœ œœ#˜GJšœ'œœœ˜7Jšœ œœ˜J˜/Jšœ˜——Jš œœ œœ œ ˜0Jš œœ œœ œ ˜0Jšœ.™.Jšœ0™0Jšœ˜Jšœ˜J˜—Jšœ˜—…— œ5´