2

I am a composer usually working with Max-MSP and OpenMusic. For porting some work from OM to Max, I have just started to learn LISP.

My problem is rather simple: I want to make chord inversions from a given chord.

From (C E G) it needs to return ((C E G) (E G C) (G C E)). It means that for a 3 notes chord I'll get 3 inversions and for n notes chord n inversions.

I've already built the basic functions:

(defun if-x-under-y-raise-x (x y)
  (if (<= x y) (if-x-under-y-raise-x (+ x 12) y)  x))

(defun transp (chord)
  (append (cdr chord) 
          (cons (if-x-under-y-raise-x (first chord) (list-max chord 0)) nil)))

transp function takes the lowest note of a sorted chord and transpose it by one octave until it is higher than the highest note of the chord recursively. So expressed in MIDI it means that (60 64 67) becomes (64 67 72). This is very easy to do.

Problems come when I want to get the n inversions recursively as explained before. I can do it once with transp but the function below doesn't work:

(defun renverse (chords)
  (if (< (length (first chords)) (length chords))
      chords
    (cons chords (renverse (list (transp (last chords)))))))

chords is the starting list. (renverse '(60 64 67)) should return 3 chord inversions.

Any help will be very welcome. :-)

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
jmdbrady
  • 21
  • 2
  • `(cons X nil)` is better written as `(list X)` – sds May 12 '17 at 16:36
  • `renverse` expects a tree (you are computing `length` of the first element) but in the example you are giving it a simple list. could you please clarify what the function should do. – sds May 12 '17 at 16:38
  • Take a look at: https://stackoverflow.com/questions/2087693/how-can-i-get-all-possible-permutations-of-a-list-with-common-lisp. As far as I can tell, this is just finding all possible permutations of a list (`(C E G)`) with a possible transposition up/down an octave afterwords. – Linuxios May 12 '17 at 16:40
  • @Linuxios - Not exactly; it's finding all _rotations_ of the list, with octavo transpositions. – Jeff Zeitlin May 12 '17 at 19:26
  • @sds yes this is a typing error. I mean '((60 64 67)). – jmdbrady May 12 '17 at 20:29

1 Answers1

3

LOOP:

(defun renverse (chord)
  (loop for chord0 = chord then (transp chord0)
        repeat (length chord)
        collect chord0))

Recursive (with the usual call stack depth limitation):

(defun renverse (chord &optional (n (length chord)))
  (cons chord
        (if (= n 1)
            nil
          (renverse (transp chord) (1- n)))))

Example:

CL-USER 19 > (renverse '(60 64 67))
((60 64 67) (64 67 72) (67 72 76))

You could also write it in some neutral list processing style:

(defun mutate-list-n-times-by-fn (list &key (n (length list)) (fn #'identity))
  (loop for l = list then (funcall fn l)
        repeat n
        collect l))

(defun renverse (chord)
  (mutate-list-n-times-by-fn chord :fn #'transp))
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • Thank you a lot Rainer. Your examples are very helpfull in the present time and inspiring for the future. – jmdbrady May 12 '17 at 20:38