【问题标题】:Recursion to make chord inversions递归进行和弦反转
【发布时间】:2017-10-12 00:28:48
【问题描述】:

我是一名作曲家,通常使用 Max-MSP 和 OpenMusic。 为了将一些工作从 OM 移植到 Max,我刚刚开始学习 LISP。

我的问题很简单:我想从给定的和弦进行和弦转位。

(C E G) 需要返回((C E G) (E G C) (G C E))。这意味着对于 3 个音符和弦,我将获得 3 个转位,对于 n 个音符和弦,我将获得 n 个转位。

我已经构建了基本功能:

(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 函数将排序后的和弦的最低音符移调一个八度,直到它递归地高于和弦的最高音符。 所以用 MIDI 表示,这意味着(60 64 67) 变成了(64 67 72)。这很容易做到。

如前所述,当我想以递归方式获取 n 反转时,问题就来了。 我可以用transp 做一次,但下面的功能不起作用:

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

chords 是起始列表。 (renverse '(60 64 67)) 应该返回 3 个和弦转位。

非常欢迎任何帮助。 :-)

【问题讨论】:

  • (cons X nil) 最好写成(list X)
  • renverse 需要一棵树(您正在计算第一个元素的length),但在示例中您给它一个简单的列表。你能澄清一下这个函数应该做什么吗?
  • 看看:stackoverflow.com/questions/2087693/…。据我所知,这只是找到一个列表 ((C E G)) 的所有可能排列,并可能在八度后加/减一个八度音阶。
  • @Linuxios - 不完全是;它正在查找列表的所有 rotations,带有八开换位。
  • @sds 是的,这是一个打字错误。我的意思是'((60 64 67))。

标签: recursion lisp common-lisp


【解决方案1】:

循环:

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

递归(具有通常的调用堆栈深度限制):

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

例子:

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

你也可以用一些中性的列表处理方式来写:

(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))

【讨论】:

  • 非常感谢雷纳。你的例子对现在很有帮助,对未来很有启发。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多