<> <> <> <> <> 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 beamed _ FALSE; IF n.value> <> <<****************************************************************************>> SetNoteValues: PUBLIC PROC[begin, end: Time] = { sumTS: INTEGER; ts: TimeSignature _ [4, 4]; i, start, stop: CARDINAL _ 0; Heuristic.MakeChords[begin, end]; FOR i DECREASING IN [0..scoreLength) DO IF score[i].time end 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; <score[i+1].value>> 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;