Class
rewriteGenerates elements according to user specified rewrite rules. Rewrite rules are expressed in terms of nodes and node identifiers. Two different styles of rule specification are supported:
Context-free rules
Context-free rules are rules that depend only on the nodes they are associated with in the pattern. The element is specified as a node list similar to the graph pattern:
(element {property value}+)
where element is the element to return from the pattern followed by one or more property value pairs:
:id datum:-> {id
| ({id}+) | pattern
| false}Context-sensitive rules
Context-sensitive rules are associated with the entire pattern rather than with the nodes in the pattern. This means that each rule may reference more than one node in its left-hand side and there may be more (or fewer) rules than there are nodes. The list of rules is interpreted as an ordered set: to produce a new generation, nodes in the current generation are matched against the rules to find the first rule whose left-hand side is true (matches). This rule is then "triggered" and the id(s) in its right-hand side are added to the next generation.
Node specification in a context sensitive rewrite pattern are simlar to the context-free pattern except that:
:-> marker appears in rules, not
in node descriptions
:id value is the same as
the element then it can be specified in place of a node list
Each rule in a context-sensitive patter is a list of the form:
({id}+
:->{id}*)
The :-> marker divides each rule into
two sides (Table 1). The left-hand side of the
rule defines the "matching target" and the right-hand side defines the
rewrite succession. Either or both sides may contain more than one
id. If the left-hand side of the rule is a single id then the rule
matches any node with the same id. If the left-hand side has more than
one id (a context-sensitive rule) then the rule matches if the "strict
predecessor" in the left-hand side matches the current node and the
ids around the strict predecessor match match the nodes around the
current node. The strict predecessor id is marked in the left-hand
side by making it a single element list. Every context rule must
contain exactly one strict predecessor in its left hand side.
Table 1.Three examples of context sensitive rules: Note that the right-hand side may be empty and that the left-hand side may use the wild card * to matches any single element in the current generation.
| Rule | Description |
|---|---|
(1 (1) 2 :->
3) | 1 rewrites to 3 wherever it is preceded by itself and followed by 2 |
(1 * (2) :-> 1 2) | 2 rewrites to 1 2 whenever 1 occurs two positions earlier |
(5 (3) 3 4 :->) | 3 rewrites to nothing if preceded by 5 and followed by itself and 4 |
rewrite supports the following slot initializations:
:of list :intially list:rules list:generations numberSee generic pattern initializations for documentation on additional keyword initializations to the pattern.
;; Context free melody. (define pat1 (new rewrite :of '(( 2 :-> ( 2 -2 2)) (-2 :-> (-2 -2 2))))) (define (stepper pat end rate from) (let ((pat (new range :initially (keynum from) :stepping pat))) (process while (< (now) end) output (new midi :time (now) :keynum (next pat) :duration rate) wait rate)) (events (list (stepper 20 (rhythm 's 100) 'c5) (stepper 20 (rhythm 'te 100) 'f4) (stepper 20 (rhythm 'e 100) 'bf3) (stepper 20 (rhythm 'tq 100) 'ef3)) "test.mid") ⇒ "test.mid" ;; Context sensitive harmony. (define pat1 (new rewrite :of '(((0 4 7) :id f) ((0 3 7) :id g) ( 1 :id +) (-1 :id -)) :initially '(f + f - g - f) :rules '((f :-> f f - g - - g - f) (g :-> g f + f))) (define (lsystem-harmony lsys len rhy dur) (let ((term #f) (knum 60)) (process repeat len do (set! term #f) (loop until term for x = (next lsys) do (if (list? x) (set! term x) (set! knum (fit (+ knum x) 48 72)))) each c in (transpose term knum) output (new midi :time (now) :keynum c :duration dur :amplitude .7) wait rhy))) (events (lsystem-harmony 200 .2 .35) "test.mid") ⇒ "test.mid"
rewrite-generation [Function]