[Class]
markov

Implements nth order Markov chains. Each element in the pattern is specified as a transition rule list:

({past}* -> {next | (next weight)}+ )

where past is zero or more identifiers that define the "left hand" side of the transition rule and next are the rule's outcomes. The number of past choices in the left hand side determines the Markov order of the pattern (Table 1). Every transition rule must have the same number of identifiers in the left hand side; those closer to the rule's transition marker -> are more recent past choices. The special "wildcard" identifier * can appear anywhere in the left hand side to match any past value at that position. By default, each outcome in the right side of the rule has the same probability of being selected. To alter the probability of an outcome relative to the other outcomes in the transtion, specify the outcome together with its weight as a list. If weight is a pattern then a new probabilty distribution for the transition rule will be calculated each time the transition rule is triggered.

Table 1. Example transition rules.

RuleDescription
(c -> a (b 2) c)1st order rule, outcome b twice as likely as a or c
(w a -> e r (d 3) g)2nd order rule, outcome d half as likely as e r or g
(* x a -> foo bif zuz)3rd order rule, matches anything followed by x and a
(-> a (b .1) c)0th order rule is weighted random selection.

markov supports the following slot initializations:

:produces ({id value}+)
A list of one or more pairs that associate a value to return from the pattern for each id specified. Values in this list override the default behavior of returning the id itself from the pattern. If value is a pattern then that pattern will produce a period of elements each time id is selected.
:past (past ...)
Initializes the pattern with a list of past choices.

Examples:

Example 1. Name That Tune

(define pat1
  (new markov
       :of '((d4 c4 -> (f4 .5) (g4 .5))
             (d4 bf4 -> bf4)
             (c4 d4 -> c4)
             (c4 c4 -> (d4 .667) (c5 0.333))
             (c4 f4 -> e4)
             (c4 g4 -> f4)
             (c4 c5 -> a4)
             (f4 c4 -> c4) 
             (f4 e4 -> (c4 .5) (d4 .5))
             (f4 g4 -> f4)
             (e4 d4 -> bf4)
             (e4 c4 -> c4)
             (g4 f4 -> c4)
             (c5 a4 -> f4)
             (a4 f4 -> (e4 .5) (g4 .5))
             (bf4 a4 -> f4)
             (bf4 bf4 -> a4))))

(define (play-pat reps pat rate)
  (process repeat reps
           for k = (next pat)
           output (new midi :time (now) :duration (* rate 1.5)
                       :keynum k)
           wait rate))
                                 
(events (play-pat 60 pat1 .125) "test.mid")
 "test.mid"

Example 2. Second order rhythms.

(define pat1
  (new markov :for 20 :past '(q q)
       :of '((e s -> s)
             (q s -> e.)
             (q. s -> s)
             (h s -> e.)
             (e e -> s e e. q q. q.. h)
             (* e -> e)
             (* s -> e e. q q. q.. h)
             (* h -> e e. q q. q.. h)
             (* q.. -> s)
             (* q. -> e s)
             (* q -> e e. q q. q.. h)
             (* e. -> s))))

(define (play-pat reps pat tmpo)
  (process with k = 60
           repeat reps
           for r = (rhythm (next pat) tmpo)
           set k = (drunk k 6 :low 30 :high 90 :mode ':jump)
           output (new midi :time (now) :duration (* r 1.5)
                       :keynum k)
           wait r))

(events (play-pat 60 pat1 120) "test.mid")
 "test.mid"

See also: