local %% MIDI pitch domain reduction: only 'wite keys' (c major) proc {InCMajor Note} {List.forAll [1 3 6 8 10] % list of 'black' pitch classes (c=0) proc {$ BlackKey} {FD.modI {Note getPitch($)} 12} \=: BlackKey end} end proc {StartAndEndWithFundamental Note} C = {Note getTemporalAspect($)} in %% rule with a condition if {Note isFirstItem($ C)} orelse {Note isLastItem($ C)} then {Note getPitch($)} =: 60 end end %% voice leading: only intervals up to a fifth, no pitch repetition %% (context dependent constraint -- getPredecessor -- but this %% context is predetermined by predetermined hierarchic structure) proc {NoBigJump Note} C = {Note getTemporalAspect($)} in if {Note hasPredecessor($ C)} then Pitch1 = {{Note getPredecessor($ C)} getPitch($)} Pitch2 = {Note getPitch($)} in %% all intervals between minor second and fourth are allowed {FD.distance Pitch1 Pitch2 '>=:' 1} {FD.distance Pitch1 Pitch2 '=<:' 5} end end proc {ChoralMelody MyScore} Length = 9 in MyScore = {Score.makeScore seq(items: {LUtils.collectN Length fun {$} note(duration: 4 offsetTime: 0 timeUnit:beats(4) pitch: {FD.int 53#72} amplitude: 80) end} startTime: 0 offsetTime:0) unit} %% %% Apply compositional rules: %% {MyScore forAll(test: isNote proc {$ Note} {InCMajor Note} {StartAndEndWithFundamental Note} {NoBigJump Note} end)} %% search strategy (i.e. distribution strategy) {FD.distribute {SDistro.makeFDDistribution unit(order:size value:random)} {MyScore collect($ test:isParameter)}} end in %%{OS.srand 11} {ExploreOne ChoralMelody} end