DIRECTORY InlineDefs USING [LowHalf], Heuristic USING [MakeChords], MusicDefs, Note USING [Duration], Score USING [GetTimeSignature], Selection USING [AddLine, AddNote, Clear, MakeBeam, MakeChord, MakeSync], Voice USING [ClearState, SetState, State]; HeuristicImpl: CEDAR PROGRAM IMPORTS InlineDefs, Heuristic, MusicDefs, Note, Score, Selection, Voice EXPORTS Heuristic = BEGIN OPEN MusicDefs; MakeSyncs: PUBLIC PROC[begin, end: Time] = { i, j: CARDINAL; n: NotePTR; current: Time _ 0; Selection.Clear[]; FOR i DECREASING IN [0..scoreLength) DO IF score[i].time end THEN LOOP; IF ABS[current-score[i].time]>3 THEN { IF selectionLength>1 THEN Selection.MakeSync[]; Selection.Clear[]; current _ score[i].time; }; FOR j IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF voice AND selectedVoice#n.voice THEN LOOP; Selection.AddNote[n]; ENDLOOP; ENDLOOP; Selection.MakeSync[]; Selection.AddLine[begin, end]; }; MakeChords: PUBLIC PROC[begin, end: Time] = { i, j, v: CARDINAL; n: NotePTR; FOR v IN [0..maxVoice] DO IF voice AND selectedVoice#v THEN LOOP; FOR i IN [0..scoreLength) DO IF score[i].time end THEN LOOP; Selection.Clear[]; FOR j IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF n.beam#NIL THEN LOOP; IF n.voice#v THEN LOOP; Selection.AddNote[n]; ENDLOOP; IF selectionLength>1 THEN Selection.MakeChord[]; ENDLOOP; ENDLOOP; Selection.AddLine[begin, end]; }; MakeBeams: PUBLIC PROC[begin, end: Time] = { n: NotePTR; vs: Voice.State; i, j, v: CARDINAL; change, found: BOOL; sum, sumTS, start, duration: Time _ 0; count: INTEGER _ 0; Beam: PROC= { IF selection[1]#NIL THEN Selection.MakeBeam[]; Selection.Clear[]; count _ 0; duration _ 0; start _ sum; change _ FALSE; }; min _ begin; max _ end; FOR v IN [0..maxVoice] DO Voice.ClearState[@vs]; sum _ 0; change _ FALSE; Selection.Clear[]; IF voice AND selectedVoice#v THEN LOOP; FOR i IN [0..scoreLength) DO IF score[i].timemax THEN LOOP; IF score[i].type IN [measure..repeat2] THEN { Voice.ClearState[@vs]; sum _ 0; Beam[]; LOOP; }; sum _ Voice.SetState[@vs, score[i]]; IF NOT vs[v].found THEN LOOP; IF vs[v].duration>=4096 THEN Beam[]; FOR j IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF n.voice#v THEN LOOP; IF n.beam#NIL THEN Beam[]; IF n.rest THEN Beam[]; IF n.value=unknown THEN Beam[]; ENDLOOP; IF change THEN SELECT sum FROM 4096 => Beam[]; 8192 => Beam[]; 12288 => Beam[]; 16384 => Beam[]; ENDCASE; IF duration#0 AND vs[v].duration#duration THEN change _ TRUE; duration _ vs[v].duration; IF count>3 THEN Beam[]; IF sum=4096 AND duration<2000 THEN Beam[]; IF sum=8192 AND duration<4000 THEN Beam[]; IF sum=12288 AND duration<2000 THEN Beam[]; IF sum=16384 AND duration<4000 THEN Beam[]; found _ FALSE; FOR j IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF n.voice#v THEN LOOP; IF n.beam#NIL THEN LOOP; IF n.rest THEN LOOP; IF n.value=unknown THEN LOOP; Selection.AddNote[n]; found _ TRUE; ENDLOOP; IF found THEN count _ count+1; ENDLOOP; ENDLOOP; }; MakeNTuplets: PUBLIC PROC[nt, a: INTEGER, begin, end: Time] = { n: NotePTR; b: BeamPTR; i, j, v: CARDINAL; count: INTEGER _ 0; found, beamed: BOOL; value: NoteValue _ unknown; Beam: PROC= {IF selection[1]#NIL AND count=nt THEN Selection.MakeBeam[FALSE]; IF selection[0]#NIL THEN b _ selection[0].beam ELSE b _ NIL; IF b#NIL THEN { b.against _ a; b.ntuple _ nt; }; IF b#NIL THEN b.beamed _ beamed; beamed _ TRUE; Selection.Clear[]; count _ 0; value _ unknown}; beamed _ TRUE; min _ begin; max _ end; FOR v IN [0..maxVoice] DO IF voice AND selectedVoice#v THEN LOOP; Selection.Clear[]; FOR i IN [0..scoreLength) DO IF score[i].timemax THEN LOOP; IF score[i].type IN [measure..repeat2] THEN { Beam[]; LOOP; }; FOR j IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF n.voice#v THEN LOOP; IF n.beam#NIL THEN Beam[]; IF n.value=unknown THEN Beam[]; IF value=unknown THEN value _ n.value; IF value#n.value THEN Beam[]; value _ n.value; ENDLOOP; IF count=nt THEN Beam[]; found _ FALSE; FOR j IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF n.voice#v THEN LOOP; IF n.beam#NIL THEN LOOP; IF n.rest THEN beamed _ FALSE; IF n.valueend THEN LOOP; IF NOT Measure[score[i].type] THEN LOOP; stop _ start; start _ i; IF start>=end THEN LOOP; ts _ Score.GetTimeSignature[score[stop].time]; sumTS _ (ts.top*256)*(64/ts.bottom); GuessMeasure[start, stop, sumTS]; ENDLOOP; SetDirty[begin, end]; }; GuessMeasure: PROC[begin, end: CARDINAL, time: INTEGER] = { n: NotePTR; j, i: CARDINAL; firstTime, priorTime, totalTime: Time; delta, bestComplexity, current: INTEGER; firstValue, nextValue, priorValue: INTEGER; maxValue, bestValue, totalValue: INTEGER; IF begin=end OR time=0 THEN RETURN; vs _ ALL[[0]]; firstValue _ InlineDefs.LowHalf[time+256]; firstTime _ score[begin].time; priorValue _ 0; priorTime _ score[end].time+3; FOR i DECREASING IN (begin..end) DO { IF score[i].type#notes THEN LOOP; FOR j IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF n.value=unknown THEN LOOP; delta _ InlineDefs.LowHalf[Note.Duration[n, 128]]; bestValue _ delta+vs[n.voice].value; GOTO done; ENDLOOP; totalTime _ priorTime-firstTime; totalValue _ firstValue-priorValue; nextValue _ firstValue; FOR j DECREASING IN [begin..i) DO IF score[j].type#notes THEN LOOP; delta _ InlineDefs.LowHalf[(totalValue*(priorTime-score[j].time))/totalTime]; nextValue _ priorValue + Quantize[delta, 32]; EXIT; ENDLOOP; delta _ InlineDefs.LowHalf[(totalValue*(priorTime-score[i].time))/totalTime]; bestValue _ priorValue+Quantize[delta, 64]; maxValue _ 32000; FOR j IN [0..maxVoice] DO maxValue _ MIN[maxValue,(bestValue-vs[j].value)/4]; ENDLOOP; bestComplexity _ Complexity[score[i], bestValue,@vs]; current _ bestValue-Quantize[maxValue, 64]; maxValue _ bestValue+Quantize[maxValue, 64]+256; delta _ bestValue; WHILE TRUE DO current _ current+256; IF current <= priorValue THEN LOOP; IF current >= maxValue THEN EXIT; IF current >= nextValue THEN EXIT; IF Complexity[score[i], current,@vs]>bestComplexity THEN LOOP; IF Complexity[score[i], current,@vs]=bestComplexity AND ABS[bestValue-delta]<=ABS[current-delta] THEN LOOP; bestComplexity _ Complexity[score[i], current,@vs]; bestValue _ current; ENDLOOP; GOTO done; EXITS done => { FOR j IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF n.value#unknown THEN LOOP; IF voice AND n.voice#selectedVoice THEN LOOP; maxValue _ 64*256; delta _ bestValue-vs[n.voice].value; FOR nv: NoteValue IN [whole..unknown) DO IF delta=3*(maxValue/2) THEN n.dotted _ TRUE; n.value _ nv; EXIT; ENDLOOP; IF n.value=unknown THEN n.value _ thirtysecond; ENDLOOP; SetVoiceSyncs[score[i], bestValue, @vs]; priorTime _ score[i].time; priorValue _ bestValue}}; ENDLOOP; }; VoiceSyncs: TYPE = ARRAY [0..10) OF RECORD[value: INTEGER]; vs: VoiceSyncs; SetVoiceSyncs: PROC[s: SyncPTR, value: INTEGER, vs: POINTER TO VoiceSyncs]= INLINE { i: CARDINAL; FOR i IN [0..syncLength) DO IF s.event[i]=NIL THEN EXIT; vs[s.event[i].voice].value _ value; ENDLOOP; }; Quantize: PROC[d: Time, q: INTEGER] RETURNS[INTEGER] = { delta: Time _ (256*(64/q)); RETURN[InlineDefs.LowHalf[delta*((d+delta/2)/delta)]]; }; Complexity: PROC[s: SyncPTR, value: INTEGER, vs: POINTER TO VoiceSyncs] RETURNS[INTEGER]= { x, d: Time _ 128; c, y: INTEGER _ 0; j, k, start: CARDINAL; v: ARRAY [0..10) OF BOOL _ ALL[FALSE]; FOR j IN [0..syncLength) DO IF s.event[j]=NIL THEN EXIT; IF s.event[j].value#unknown THEN LOOP; IF voice AND s.event[j].voice#selectedVoice THEN LOOP; IF v[s.event[j].voice] THEN LOOP; d _ value-vs[s.event[j].voice].value; v[s.event[j].voice] _ TRUE; x _ x*256; start _ 10; FOR k IN [0..7] DO x _ x/2; IF x>d THEN LOOP; d _ d-x; IF start>7 THEN start _ k; IF d#0 THEN LOOP; c _ c+(k-start); EXIT; ENDLOOP; ENDLOOP; FOR j IN [0..10) DO IF v[j] THEN y _ y+1; ENDLOOP; RETURN[(c*10)/y]; }; END. GuessLogical: PROC[begin, end: CARDINAL, time: Time] = { i, j: CARDINAL; voice: ARRAY [0..10) OF CARDINAL _ ALL[0]; vs: Voice.State; max: Time; Voice.ClearState[@vs]; FOR i IN [begin..end] DO max _ Voice.SetState[@vs, score[i]]; FOR j IN [0..maxVoice] DO IF NOT vs[j].found THEN LOOP; voice[j] _ i; ENDLOOP; ENDLOOP; }; FOR v IN [0..maxVoice] DO duration _ (time*(vs[v]-score[i].time))/measure; SELECT TRUE FROM duration IN [15000..19000] => value _ whole; duration IN [7500..9000] => value _ half; duration IN [3500..4500] => value _ quarter; duration IN [1600..2400] => value _ eighth; duration IN [900..1200] => value _ sixteenth; duration IN [200..600] => value _ thirtysecond; ENDCASE => value _ unknown; FOR j IN [0..syncLength) DO IF (n _ score[i].event[j])=NIL THEN EXIT; IF n.voice#v THEN LOOP; vs[v] _ score[i].time; IF n.value#unknown THEN LOOP; n.value _ value; ENDLOOP; ENDLOOP; ENDLOOP; }; PortionOutTime: PROC[voice, s1, s2: CARDINAL, duration, ratio: INTEGER] = { beats, units, d: INTEGER; i, j, r1, r2, count: CARDINAL _ 0; index _ 1; FOR i IN (s1..s2) DO IF NOT Sync.InVoice[score[i], voice] THEN LOOP; list[index] _ [score[i], FALSE]; index _ index + 1; IF score[i].value=0 THEN LOOP; PortionOutTime[voice, s1, i, score[i].value-score[s1].value, ratio]; PortionOutTime[voice, i, s2, score[s2].value-score[i].value, ratio]; RETURN; ENDLOOP; IF index=1 THEN RETURN; list[0] _ [score[s1], FALSE]; list[index] _ [score[s2], FALSE]; index _ index+1; [beats, units] _ Tranlate[duration]; --3/4, 6/8, 3/16, 15/24, etc. d _ list[1].value-list[0].value; FOR i IN [0..index) DO list[i].ts.top _ 0; ENDLOOP; FOR i IN [2..index) DO IF ABS[d-list[i].value-list[i-1].value]1 THEN FOR j IN (r1..r2] DO list[j].ts.top _ 1; d _ list[i].value-list[i-1].value; r1 _ i-1; ENDLOOP; FOR i IN [0..index) DO IF NOT list[i].tuple THEN count _ count+1; ENDLOOP; WHILE units<=128 DO IF count>beats THEN {units _ units*2; beats _ beats*2; LOOP}; IF units=128 THEN RETURN; d _ CheckGrid[s1, s2, beats, units, voice]; IF dsum DO sum _ sum+d; ENDLOOP; IF NOT Sync.InVoice[score[i], voice] THEN LOOP; WHILE score[i].time*ratio-delta/2>sum DO sum _ sum+d; ENDLOOP; delta_ delta+ABS[score[i].time*ratio-sum]; sum _ sum+d; ENDLOOP; RETURN[InlineDefs.LowHalf[delta]]; }; AssignGrid: PROC[s1, s2: CARDINAL, unit, voice: INTEGER]= { i: CARDINAL; d: Time _ 256*(64/unit); sum: Time _ score[s1].value; FOR i IN (s1..s2) DO WHILE score[i].value>sum DO sum _ sum+d; ENDLOOP; IF NOT Sync.InVoice[score[i], voice] THEN LOOP; WHILE score[i].time*ratio-delta/2>sum DO sum _ sum+d; ENDLOOP; score[i].value _ InlineDefs.LowHalf[sum]; sum _ sum+d; ENDLOOP; }; Translate: PROC[duration: INTEGER] RETURNS[INTEGER]= { units: INTEGER _ 64; duration _ duration/256; WHILE (duration MOD 2)=0 DO duration _ duration/2; units _ units/2; IF units=1 THEN EXIT; ENDLOOP; RETURN[duration, units]; }; index: CARDINAL; list: ARRAY [0..30) OF RECORD[sync: SyncPTR, tuple: BOOL]; ss: ARRAY [0..10) OF Time; NHeuristicImpl.mesa Copyright (C) 1981, 1984 Xerox Corporation. All rights reserved. Author: John Maxwell last modified: December 8, 1981 8: 40 AM Edited by Doug Wyatt, June 14, 1984 1:07:30 pm PDT *************************************************************************** guessing structures *************************************************************************** ts: TimeSignature; determine the sync's logical position decide whether or not to break the current beam select appropriate notes for beaming decide whether or not to break the current beam select appropriate notes for beaming **************************************************************************** guessing note values **************************************************************************** SUGGESTION: use a note in the prior measure as the beginning rather than the measure line events are processed in DESCENDING order, and score[i].value>score[i+1].value check for durations already given by the user obtain the next note sync's value find the tic within a certain range that has the smallest complexity event done, assign durations duration is the logical duration of the interval (64*256=whole) ratio is the number of tics that a quarter note occupies look for runs of equally spaced notes then try successively finer grids all durations must be strictly ordered ÊQ˜šœ™Jšœ@™@Jšœ™Jšœ)™)J™2J˜—šÏk ˜ Jšœ œ ˜Jšœ œ˜J˜ Jšœœ ˜Jšœœ˜Jšœ œ:˜IJšœœ˜*J˜—Jšœœ˜JšœA˜HJšœ ˜Jšœœœ ˜J˜JšœK™KJšœ™JšœK™KJ˜šÏn œœœ˜,Jšœœ˜J˜ J˜J˜šœ œœ˜'Jšœœœ˜!Jšœœœ˜!šœœ˜$Jšœ˜Jšœœ˜/J˜J˜Jšœ˜—šœœ˜Jšœœœœ˜)Jšœœœœ˜-J˜Jšœ˜—Jšœ˜—J˜J˜Jšœ˜—J˜šž œœœ˜-Jšœ œ˜J˜ šœœ˜Jšœœœœ˜'šœœ˜Jšœœœ˜!Jšœœœ˜!J˜šœœ˜Jšœœœœ˜)Jšœœœœ˜Jšœ œœ˜J˜Jšœ˜—Jšœœ˜0Jšœ˜—Jšœ˜—J˜Jšœ˜—J˜šž œœœ˜,J˜ J˜Jšœ™Jšœ œ˜Jšœœ˜J˜&Jšœœ˜š žœœœœœ˜=JšœBœ˜K—J˜ J˜ šœœ˜J˜Jšœœ˜J˜Jšœœœœ˜'šœœ˜Jšœœœ˜Jšœœœ˜ šœœœ˜,Jšœ*œ˜2—Jšœ%™%J˜$Jšœœ œœ˜Jšœ/™/Jšœœ˜$šœœ˜Jšœœœœ˜)Jšœ œœ˜Jšœœœ˜Jšœœ˜Jšœœ˜Jšœ˜—šœœœ˜J˜J˜J˜J˜Jšœ˜—Jšœ œœ œ˜=J˜šœ œ˜Jšœ œœ˜*Jšœ œœ˜*Jšœ œœ˜+Jšœ œœ˜+Jšœ$™$Jšœœ˜šœœ˜Jšœœœœ˜)Jšœ œœ˜Jšœœœœ˜Jšœœœ˜Jšœœœ˜Jšœœ˜#Jšœ˜—Jšœœ˜Jšœ˜——Jšœ˜—Jšœ˜—J˜šž œœœœ˜?J˜ J˜ Jšœ œ˜Jšœœ˜Jšœœ˜J˜šžœœœœœ œœ˜MJš œœœœœ˜Jšœ/™/šœœ˜Jšœœœœ˜)Jšœ œœ˜Jšœœœ˜Jšœœ˜Jšœœ˜&Jšœœ˜J˜Jšœ˜—šœ œ˜Jšœ$™$—šœœ˜šœœ˜Jšœœœœ˜)Jšœ œœ˜Jšœœœœ˜Jšœœ œ˜Jšœœ œ˜&Jšœœœ˜Jšœœ˜$Jšœ˜—Jšœœ˜Jšœ˜——Jšœ˜—J˜Jšœ˜—J˜JšœL™LJšœ™JšœL™LJ˜šž œœœ˜0Jšœœ˜J˜Jšœœ˜J˜!šœ œœ˜'Jšœœœ˜"Jšœœœ˜ Jšœœœœ˜(J˜ J˜ Jšœ œœ˜J˜.J˜$J˜!Jšœ˜—J˜Jšœ˜—J˜J˜šž œœ œœ˜;J˜ Jšœœ˜J˜&Jšœ œ˜(Jšœ#œ˜+Jšœ!œ˜)Jšœ œœœ˜$JšœY™YJšœœ˜J˜*J˜J˜J˜JšœM™Mšœ œœœ˜%Jšœœœ˜!Jšœ-™-šœœ˜Jšœœœœ˜)Jšœœœ˜J˜2J˜$Jšœ˜ Jšœ˜—J˜ J˜$Jšœ!™!J˜šœ œœ œ˜"Jšœœœ˜!J˜MJ˜-Jšœœ˜JšœD™DJ˜MJ˜+J˜šœœ˜Jšœ œ%˜3Jšœ˜—J˜5J˜+J˜0J˜šœœ˜ J˜Jšœœœ˜#Jšœœœ˜!Jšœœœ˜"Jšœ2œœ˜>šœ2œ˜8Jšœœœœ˜3—J˜3J˜Jšœ˜—Jšœ˜ Jšœ ˜Jšœ™šœœ˜Jšœœœœ˜)Jšœœœ˜Jšœœœœ˜-J˜J˜$šœœ˜(Jšœœœ˜5Jšœœ œ˜.Jšœœ˜Jšœ˜—Jšœœ˜/Jšœ˜—J˜(J˜J˜Jšœ˜——Jšœ˜—J˜Jš œ œœ œœœ˜;J˜J˜J˜š ž œœœœœœ˜TJšœœ˜ šœœœ˜Jšœ œœœ˜J˜$Jšœ˜ —Jšœ˜—J˜š žœœ œœœ˜8J˜Jšœ0˜6Jšœ˜—J˜šž œœœœœ œœ˜[J˜Jšœœ˜Jšœ œ˜Jš œœ œœœœ˜&šœœ˜Jšœ œœœ˜Jšœœœ˜&Jšœœ œœ˜6Jšœœœ˜!J˜%Jšœœ˜J˜šœœ˜Jšœ œœœ˜Jšœ œ œ ˜#Jšœœœ˜Jšœœ˜Jšœ˜—Jšœ˜—Jš œœ œœœ œ˜2Jšœ ˜Jšœ˜—J˜Jšœ˜J˜J˜šž œœ œ˜8Jšœœ˜Jš œœ œœœ˜*J˜J˜ J˜šœœœ˜J˜$šœœ˜Jšœœ œœ˜J˜ Jšœ˜—Jšœ˜—Jšœ˜—˜šœœ˜J˜0šœœ˜Jšœ œ!˜,Jšœ œ˜)Jšœ œ!˜,Jšœ œ ˜+Jšœ œ"˜-Jšœ œ$˜/Jšœ˜—šœœ˜Jšœœœœ˜)Jšœ œœ˜J˜Jšœœœ˜J˜Jšœ˜—Jšœ˜—Jšœ˜—Jšœ˜J˜J˜šžœœœœ˜KJšœ?™?Jšœ8™8Jšœœ˜Jšœœ˜-šœœ ˜Jšœœœœ˜/Jšœœ˜3Jšœœœ˜J˜FJ˜DJšœ˜Jšœ˜—Jšœ œœ˜Jšœœ˜Jšœœ˜"J˜Jšœ&Ïc˜CJšœ&™&Jšœ!™!Jšœ&™&J˜ Jšœœ œœ˜3šœœ ˜Jšœœ&œ œ˜EJš œ œœœ œ˜8J˜,Jšœ˜—Jšœœ œœœœœ˜Jšœ ˜Jšœ œ$œ˜=Jšœ œœ˜J˜+Jšœœœ˜J˜J˜Jšœ˜—J˜(J˜šœœ ˜Jšœœœ˜Jšœœ œ˜!J˜,Jšœœ œ*œ˜EJšœœ˜—Jšœ˜—J˜š ž œœ œœœœ˜KJšœœ˜ J˜J˜J˜šœœ ˜Jšœœœ˜1Jšœœœœ˜/Jšœ!œœ˜>Jšœ œ˜*J˜ Jšœ˜—Jšœ˜"Jšœ˜—J˜šž œœ œœ˜;Jšœœ˜ J˜J˜šœœ ˜Jšœœœ˜1Jšœœœœ˜/Jšœ!œœ˜>J˜)J˜ Jšœ˜—Jšœ˜—J˜š ž œœ œœœ˜6Jšœœ˜J˜šœ œœ˜J˜J˜Jšœ œœ˜Jšœ˜—Jšœ˜Jšœ˜—J˜Jšœœ˜Jš œœ œœœ˜:Jšœœ œ˜—…—.àG