;;;
;;; c:\\program files\\acl62\\music2.cl
;;;
(load "c:\\program files\\acl62\\music1.cl")

(setf *print-length* 1000)

(defun +key-p (key)
  (if (member key '(G +F B E A D +d +g +c +f b e))
    t
   nil))

(defun confine-a-number (n)
  (prog (num)
    (setf num (eval (cons '+ (multiple-value-list (floor n 7.0)))))
    (cond ((and (>= num 0.8) (<= num 1.2)) (return 1.0))
        ((and (>= num 1.3) (<= num 1.7)) (return 1.5))
        ((and (>= num 1.8) (<= num 2.2)) (return 2.0))
        ((and (>= num 2.3) (<= num 2.7)) (return 2.5))
        ((and (>= num 2.8) (<= num 3.2)) (return 3.0))
        ((and (>= num 3.3) (<= num 3.7)) (return 3.5))
        ((and (>= num 3.8) (<= num 4.2)) (return 4.0))
        ((and (>= num 4.3) (<= num 4.7)) (return 4.5))
        ((and (>= num 4.8) (<= num 5.2)) (return 5.0))
        ((and (>= num 5.3) (<= num 5.7)) (return 5.5))
        ((and (>= num 5.8) (<= num 6.2)) (return 6.0))
        ((and (>= num 6.3) (<= num 6.7)) (return 6.5)))))

(defun translate-number-to-sound (n offset key)
  (let ((num (confine-a-number (+ n offset))))
    (case num
      (1.0 "ド")
      (1.5 (if (+key-p key)
           "#ド"
         "♭レ"))
      (2.0 "レ")
      (2.5 (if (+key-p key)
           "#レ"
         "♭ミ"))
      (3.0 "ミ")
      (3.5 "ファ")
      (4.0 (if (+key-p key)
           "#ファ"
          "♭ソ"))
      (4.5 "ソ")
      (5.0 (if (+key-p key)
           "#ソ"
          "♭ラ"))
      (5.5 "ラ")
      (6.0 (if (+key-p key)
           "#ラ"
          "♭シ"))
      (6.5 "シ"))))

(defun translate-list-of-number-to-sound (l offset key)
  (mapcar #'(lambda (e) (translate-number-to-sound e offset key)) l))

(defun translate-alphabet-to-number (c)
  (case c
    (c 1.0)(C 1.0)
    (+c 1.5)(+C 1.5)(-d 1.5)(-D 1.5)
    (d 2.0)(D 2.0)
    (+d 2.5)(+D 2.5)(-e 2.5)(-E 2.5)
    (e 3.0)(E 3.0)
    (f 3.5)(F 3.5)
    (+f 4.0)(+F 4.0)(-g 4.0)(-G 4.0)
    (g 4.5)(G 4.5)
    (+g 5.0)(+G 5.0)(-a 5.0)(-A 5.0)
    (a 5.5)(A 5.5)
    (+a 6.0)(+A 6.0)(-b 6.0)(-B 6.0)
    (b 6.5)(B 6.5)))
;;;
;;; (get-chordscale 'c 'ion) =====> ("ド" "レ" "ミ" "ファ" "ソ" "ラ" "シ" "ド")
;;;
(defun get-chordscale (c csn)
  (translate-list-of-number-to-sound (fget-i 'scale csn)
                          (1- (translate-alphabet-to-number c))
                          c))
;;;
;;; (get-tension-note 'C 'ion)
;;;
(defun get-tension-note (c csn)
  (translate-list-of-number-to-sound (fget-i 'tension-note csn)
                          (1- (translate-alphabet-to-number c))
                          c))
;;;
;;;
;;;
(defun get-chord-type (scn)
  (cond ((search-s1-in-s2 "7(+11 13)" scn) 'd7+1113)
      ((search-s1-in-s2 "7(+9+11)" scn) 'd7+9+11)
      ((search-s1-in-s2 "7(-9+11)" scn) 'd7-9+11)
      ((search-s1-in-s2 "7(9+11)" scn) 'd79+11)
      ((search-s1-in-s2 "M7(+11)" scn) 'M7+11)
      ((search-s1-in-s2 "mM7(11)" scn) 'mM711)
      ((search-s1-in-s2 "mM7(13)" scn) 'mM713)
      ((search-s1-in-s2 "7(+11)" scn) 'd7+11)
      ((search-s1-in-s2 "m7(11)" scn) 'm711)
      ((search-s1-in-s2 "m7(13)" scn) 'm713)
      ((search-s1-in-s2 "M7(13)" scn) 'M713)
      ((search-s1-in-s2 "mM7(9)" scn) 'mM79)
      ((search-s1-in-s2 "dimM7" scn) 'dimM7)
      ((search-s1-in-s2 "augM7" scn) 'augM7)
      ((search-s1-in-s2 "7sus4" scn) 'd7sus4)
      ((search-s1-in-s2 "(+11)" scn) 'M+11)
      ((search-s1-in-s2 "m(11)" scn) 'm11)
      ((search-s1-in-s2 "7(-9)" scn) 'd7-9)
      ((search-s1-in-s2 "madd9" scn) 'madd9)
      ((search-s1-in-s2 "7(+9)" scn) 'd7+9)
      ((search-s1-in-s2 "7(13)" scn) 'd713)
      ((search-s1-in-s2 "m7(9)" scn) 'm79)
      ((search-s1-in-s2 "M7(9)" scn) 'M79)
      ((search-s1-in-s2 "sus4" scn) 'sus4)
      ((search-s1-in-s2 "dim7" scn) 'dim7)
      ((search-s1-in-s2 "m7-5" scn) 'm7-5)
      ((search-s1-in-s2 "aug7" scn) 'aug7)
      ((search-s1-in-s2 "add9" scn) 'Madd9)
      ((search-s1-in-s2 "7(9)" scn) 'd79)
      ((search-s1-in-s2 "aug" scn) 'aug)
      ((search-s1-in-s2 "dim" scn) 'dim)
      ((search-s1-in-s2 "mM7" scn) 'mM7)
      ((search-s1-in-s2 "m69" scn) 'm69)
      ((search-s1-in-s2 "7-5" scn) 'd7-5)
      ((search-s1-in-s2 "-5" scn) 'M-5)
      ((search-s1-in-s2 "m7" scn) 'm7)
      ((search-s1-in-s2 "M7" scn) 'M7)
      ((search-s1-in-s2 "m6" scn) 'm6)
      ((search-s1-in-s2 "69" scn) 'M69)
      ((search-s1-in-s2 "m" scn) 'mt)
      ((search-s1-in-s2 "7" scn) 'd7)
      ((search-s1-in-s2 "6" scn) 'M6)
      (t 'Mt)))

(defun involve-character-p (s)
  (let ((lst '("+C" "-D" "+D" "-E" "+F" "-G" "+G" "-A" "+A" "-B"
         "C" "D" "E" "F" "G" "A" "B")))
    (do ((l lst (cdr l)))
       ((null l))
     (cond ((search-s1-in-s2 (car l) s)
          (return (intern (car l))))))))
;;;
;;; (get-chord-tone "CM7") =====> ("ド" "ミ" "ソ" "シ")
;;;
(defun get-chord-tone (scn)
  (let ((num (1- (translate-alphabet-to-number (involve-character-p scn))))
     (lst (fget-i 'code (get-chord-type scn))))
   (translate-list-of-number-to-sound lst num (involve-character-p scn))))
;;;
;;; (get-guide-tone "CM7")
;;;
(defun get-guide-tone (scn)
  (let ((num (1- (translate-alphabet-to-number (involve-character-p scn))))
     (lst (fget-i 'guide-tone (get-chord-type scn))))
   (translate-list-of-number-to-sound lst num (involve-character-p scn))))
;;;
;;;
;;;
(defun translate-roman-to-number (s)
  (cond ((equal s "I") 1.0)
       ((or (equal s "+I") (equal s "-II")) 1.5)
       ((equal s "II") 2.0)
       ((or (equal s "+II") (equal s "-III")) 2.5)
       ((equal s "III") 3.0)
       ((equal s "IV") 3.5)
       ((or (equal s "+IV") (equal s "-V")) 4.0)
       ((equal s "V") 4.5)
       ((or (equal s "+V") (equal s "-VI")) 5.0)
       ((equal s "VI") 5.5)
       ((or (equal s "+VI") (equal s "-VII")) 6.0)
       ((equal s "VII") 6.5)))

(defun translate-number-to-roman (n offset key)
  (let ((num (confine-a-number (+ n offset))))
    (case num
      (1.0 "I")
      (1.5 (if (+key-p key) "+I" "-II"))
      (2.0 "II")
      (2.5 (if (+key-p key) "+II" "-III"))
      (3.0 "III")
      (3.5 "IV")
      (4.0 (if (+key-p key) "+IV" "-V"))
      (4.5 "V")
      (5.0 (if (+key-p key) "+V" "-VI"))
      (5.5 "VI")
      (6.0 (if (+key-p key) "+VI" "-VII"))
      (6.5 "VII"))))

(defun translate-number-to-alphabet (n offset key)
  (let ((num (confine-a-number (+ n offset))))
    (case num
      (1.0 "C")
      (1.5 (if (+key-p key) "+C" "-D"))
      (2.0 "D")
      (2.5 (if (+key-p key) "+D" "-E"))
      (3.0 "E")
      (3.5 "F")
      (4.0 (if (+key-p key) "+F" "-G"))
      (4.5 "G")
      (5.0 (if (+key-p key) "+G" "-A"))
      (5.5 "A")
      (6.0 (if (+key-p key) "+A" "-B"))
      (6.5 "B"))))
;;;
;;; (translate-roman-to-alphabet "II" 'C) =====> "D"
;;;
(defun translate-roman-to-alphabet (s key)
  (let ((num (translate-roman-to-number s)))
    (translate-number-to-alphabet num (1- (translate-alphabet-to-number key)) key)))
;;;
;;; (translate-alphabet-to-roman 'D 'C) =====> "II"
;;;
(defun translate-alphabet-to-roman (c key)
  (let ((num (translate-alphabet-to-number c)))
   (translate-number-to-roman num (- 6.0 (1- (translate-alphabet-to-number key))) key)))

(defun involve-roman-p (s)
  (let ((lst '("-VII" "-III" "VII" "+VI" "-VI" "+IV" "III" "+II" "-II"
         "+I" "II" "IV" "-V" "+V" "VI" "V" "I")))
    (do ((l lst (cdr l)))
       ((null l))
     (cond ((search-s1-in-s2 (car l) s) (return (car l)))))))
;;;
;;; (get-chord-name-from-roman "IIm7" 'D) =====> "Em7"
;;;
(defun get-chord-name-from-roman (s key)
  (let* ((roman (involve-roman-p s))
      (char (translate-roman-to-alphabet roman key)))
    (replace-s1-with-s2-in-s roman char s)))

(defun replace-roman (l key)
  (cond ((null l) nil)
      ((and (not (listp l)) (involve-roman-p (string l)))
       (get-chord-name-from-roman (string l) key))
      ((atom l) l)
      (t (cons (replace-roman (car l) key)
            (replace-roman (cdr l) key)))))

(defun get-key-type (Mm)
  (if (equal Mm 'major) 'major-key 'minor-key))
;;;
;;; (instantiate-a-key 'C 'major)
;;;
(defun instantiate-a-key (key type)
  (let ((lst (fget-frame (get-key-type type))))
   (replace-roman lst key)))

(defun involve-char-p (s)
  (let ((lst '("+C" "-D" "+D" "-E" "+F" "-G" "+G" "-A" "+A" "-B"
        "C" "D" "E" "F" "G" "A" "B")))
   (do ((l lst (cdr l)))
      ((null l))
    (cond ((search-s1-in-s2 (car l) s)
         (return (car l)))))))

(defun get-roman-from-chord-name (s key)
  (let* ((chord (involve-char-p s))
      (roman (translate-alphabet-to-roman (intern chord) key)))
    (replace-s1-with-s2-in-s chord roman s)))
;;;
;;;
;;;
(defun back-to-roman (l key)
  (cond ((null l) nil)
      ((and (not (listp l)) (involve-char-p (string l)))
       (get-roman-from-chord-name (string l) key))
      ((atom l) l)
      (t (cons (back-to-roman (car l) key)
            (back-to-roman (cdr l) key)))))

(defun get-UST-of-C (s)
  (cond ((equal s "CM7") (cdr (fget-frame 'UST-CM7)))
      ((equal s "Cm7") (cdr (fget-frame 'UST-Cm7)))
      ((equal s "Cm") (cdr (fget-frame 'UST-Cm)))
      ((equal s "C7") (cdr (fget-frame 'UST-C7)))
      ((equal s "Cdim7") (cdr (fget-frame 'UST-Cdim7)))
      ((equal s "C7sus4") (cdr (fget-frame 'UST-C7sus4)))
      ((equal s "Cm7-5") (cdr (fget-frame 'UST-Cm7-5)))
      ((equal s "CmM7") (cdr (fget-frame 'UST-CmM7)))))

(defun get-chord-type2 (s)
  (let ((lst '("7sus4" "dim7" "m7-5" "mM7" "M7" "m7" "m" "7")))
   (do ((l lst (cdr l)))
      ((null l))
    (cond ((search-s1-in-s2 (car l) s)
         (return (car l)))))))

(defun get-C-chord-name (s) (concatenate 'string "C" (get-chord-type2 s)))

;;;
;;; (get-UST "CM7")
;;;
(defun get-UST (s)
  (let* ((lst (get-UST-of-C (get-C-chord-name s)))
      (roman (back-to-roman lst 'C)))
   (replace-roman roman (intern (involve-char-p s)))))
;;;
;;;
;;;
(defun modulate-key1-to-key2 (l key1 key2)
  (let ((lst (back-to-roman l key1)))
    (replace-roman lst key2)))