;;;
;;; c:\\program files\\acl62\\music32.cl
;;;
(load "c:\\program files\\acl62\\music31.cl")

(defun measure-an-interval-of-two-notes-upward (s1 s2)
  (let ((n1 (translate-sound-to-number s1))
     (n2 (translate-sound-to-number s2)))
   (if (<= n1 n2)
     (- n2 n1)
    (- (+ n2 6.0) n1))))

(defun measure-an-interval-of-two-notes-downward (s1 s2)
  (measure-an-interval-of-two-notes-upward s2 s1))

(defun relation-of-two-notes (n1 n2)
  (let ((u (measure-an-interval-of-two-notes-upward n1 n2))
     (d (measure-an-interval-of-two-notes-downward n1 n2)))
    (cond ((< u d) (list 'upward u))
        ((> u d) (list 'downward d))
        ((or (= u 3.0) (= d 3.0))
         (case (random 2)
           (0 (list 'upward u))
           (1 (list 'downward d))))
        ((and (= 0.0 u) (= 0.0 d)) '(same-note)))))

;;;
;;; (get-passing-note '("CM7" ion) "ミ" "ソ")) ===> ファ
;;;
(defun get-passing-note (pair n1 n2)
  (let* ((scale (get-chordscale (involve-character-p (first pair))
                     (second pair)))
      (relation (relation-of-two-notes n1 n2))
      (direction (first relation))
      (distance (second relation))
      (num1 (translate-sound-to-number n1))
      (num2 (translate-sound-to-number n2)))
    (case direction
      (upward
       (cond ((> distance 2.0) (values))
           ((= 0.5 distance) (values))
           ((= 1.0 distance)
            (translate-number-to-sound num1 0.5 (involve-character-p (first pair))))
           (t
            (second (rotate-a-scale-from-a-note n1 pair 'left)))))
      (downward
       (cond ((> distance 2.0) (values))
           ((= 0.5 distance) (values))
           ((= 1.0 distance)
            (translate-number-to-sound num1 5.5 (involve-character-p (first pair))))
           (t
            (second (rotate-a-scale-from-a-note n1 pair 'right))))))))

;;;
;;;
;;;
(defun get-auxiliary-note (pair n1 n2)
  (let* ((scale (get-chordscale (involve-character-p (first pair)) (second pair)))
      (num1 (translate-sound-to-number n1))
      (num2 (translate-sound-to-number n2))
      (base (involve-character-p (first pair)))
      (l1 (translate-number-to-sound num1 5.0 base))
      (l2 (translate-number-to-sound num1 5.5 base))
      (u1 (translate-number-to-sound num1 0.5 base))
      (u2 (translate-number-to-sound num1 1.0 base)))
    (cond ((not (= num1 num2)) (values))
        (t
         (cond ((and (member l2 scale :test #'equal) (member u1 scale :test #'equal))
              (list (list 'downward l2) (list 'upward u1)))
             ((and (member l2 scale :test #'equal) (not (member u1 scale :test #'equal)))
              (list (list 'downward l2) (list 'upward u1 u2)))
             ((and (not (member l2 scale :test #'equal)) (member u1 scale :test #'equal))
              (list (list 'downward l1 l2) (list 'upward u1)))
             ((and (not (member l2 scale :test #'equal)) (not (member u1 scale :test #'equal)))
              (list (list 'downward l1 l2) (list 'upward u1 u2))))))))

(defun select-an-auxiliary-note (pair n1 n2)
  (let* ((lst (get-auxiliary-note pair n1 n2))
      (a-n (append (rest (first lst)) (rest (second lst)))))
    (if (not a-n)
      (values)
     (nth (random (length a-n)) a-n))))

;;;
;;; (connect-notes-in-a-chord '(("CM7" ion) ("ミ" "ソ" "シ" "ド")))
;;;
(defun connect-notes-in-a-chord (l)
  (let ((scale (first l))
     (phrase (second l)))
   (do ((lst phrase (rest lst))
      (w)
      (sp)
      (sa))
      ((null (rest lst))
       (push (car lst) w)
       (list scale (reverse w)))
     (push (first lst) w)
     (setf sp (get-passing-note scale (first lst) (second lst)))
     (setf sa (select-an-auxiliary-note scale (first lst) (second lst)))
     (if (not (null sp)) (push sp w))
     (if (not (null sa)) (push sa w)))))

(defun connect-notes-in-a-chord-partially (l)
  (let ((scale (first l))
     (phrase (second l)))
   (do ((lst phrase (rest lst))
      (w)
      (sp)
      (sa))
      ((null (rest lst))
       (push (car lst) w)
       (list scale (reverse w)))
     (push (first lst) w)
     (case (random 2)
       (0
        (setf sp (get-passing-note scale (first lst) (second lst)))
        (setf sa (select-an-auxiliary-note scale (first lst) (second lst))))
       (1
        (setf sp nil)
        (setf sa nil)))
     (if (not (null sp)) (push sp w))
     (if (not (null sa)) (push sa w)))))