Patterns finding and replacement can be very useful when composing.
For example, we may want to replace some unwanted motive in a melody, or we may want to generate articulation or velocity based on some patterns of length or pitch.
Another use is to compose a new section based on and old one with patterns replacement from old to new etc, etc... the possibility are naturally endless.
I propose here a function named motive-replace who are able to execute this task.
This function is not in a "good" Lisp but works for me and i hope it can be useful for other users.
Naturally, if you can improve this function, i invite you to share your thoughts on this blog.
First, we define some utility function, starting with a function for find one motive and replace it:
(defun one-motive-replace (old new mat) (flatten (loop for idx from 0 to (-(length mat)1) collect (if (equal (loop for i from 0 to (-(length old)1) collect (nth (+ idx i) mat)) old) (and (setf idx (+ idx (-(length old)1))) new) (nth idx mat))))) #|Usage (one-motive-replace '(a b c) '(1 2 3) '(d b s a b c e j g)) => (d b s 1 2 3 e j g) (one-motive-replace '(a b c) '(1 2) '(d b s a b c e j g)) => (d b s 1 2 e j g) |#
Now, we define a function able to find and replace multiple motives:
(defparameter *res* '()) (defun multi-motives-replace (oldlist newlist mat) (cond ((null oldlist) '()) (t (setf *res* (one-motive-replace (car oldlist) (car newlist) mat)) (multi-motives-replace (cdr oldlist) (cdr newlist) *res*))) *res*) #|Usage (multi-motives-replace '((a b c) (e j)) '((1 2 3) (8 9)) '(d b s a b c e j g)) => (d b s 1 2 3 8 9 g) |#
And finally we define the final function for motivic-replacement who choose between one or multiple motif replace functions based on the list predicate of the first parameter:
(defun motive-replace (old new mat) "motive-replace will find an exact motive (old) in a list and will replace it by a new one (new). Note: It is not pattern matching but can be useful." (do-verbose ("motive-replace") (if (listp (car new)) (multi-motives-replace old new mat) (one-motive-replace old new mat)))) #|Usage (motive-replace '(a b c) '(1 2 3) '(d b s a b c e j g)) => (d b s 1 2 3 e j g) (motive-replace '(a b c) '(1 2) '(d b s a b c e j g)) => (d b s 1 2 e j g) (motive-replace '((a b c) (e j)) '((1 2 3) (8 9)) '(d b s a b c e j g)) => (d b s 1 2 3 8 9 g) |#