   "
   ([root chord-name] (chord root chord-name 4))
   ([root chord-name octave]
-     (let [root (if (keyword? root) (NOTE root) root)
-           chord-name (if (keyword? chord-name) (CHORD chord-name) chord-name)
-           base (octave-note octave root)]
-       (set (map #(+ % base) chord-name)))))
+     (let [root (resolve-note root)
+           chord (resolve-chord chord-name)]
+       (set (map #(+ % root) chord)))))
 
 ; midicps
 (defn midi->hz

     :dim7       dim7
     :i7         dim7}))

(defn chord
  "Returns a set of notes for the specified chord at the specified octave
  (defaulting to 4).

  i.e. the ionian/major scale has an interval sequence of 2 2 1 2 2 2 1
       therefore the 4th degree is (+ 2 2 1 2) semitones from the start of the
       scale."
  ([n] (nth-interval :scale n))
  ([scale n]
     (reduce + (take n (cycle (scale SCALE))))))

(def DEGREE {:i     1
             :ii    2
             :iii   3
             :iv    4
             :v     5
             :vi    6
             :vii   7
             :_     nil})

(defn resolve-degree
  [degree]
  (if (some #{degree} (keys DEGREE))
    (degree DEGREE)
    (throw (Exception. (str "Unable to resolve degree: " degree ". Was expecting a roman numeral in the range :i -> :vii or the nil-note symbol :_")))))

(defn degree->interval
  "Converts the degree of a scale given as a roman numeral keyword and converts
  it to the number of intervals (semitones) from the tonic of the specified
  scale."
  ([degree scale] (degree->interval degree scale 0))
  ([degree scale shift]
     (cond
      (nil? degree) nil
      (= :_ degree) nil

      (number? degree) (+ shift (nth-interval scale (dec degree)))

      (keyword? degree) (cond
                         (.endsWith (name degree) "-")
                         (degree->interval (keyword (chop (name degree))) scale (- shift 12))

                         (.endsWith (name degree) "+")
                         (degree->interval (keyword (chop (name degree))) scale (+ shift 12))

                         :default
                         (+ shift (nth-interval scale (dec (resolve-degree degree))))))))

(defn degrees->pitches
  "Convert intervals to pitches in MIDI number format.  Supports nested collections."
  [degrees scale root]
  (let [root (resolve-note root)
        _ (when (nil? root)
            (throw (Exception. (str "root resolved to a nil value. degrees->pitches requires a non-nil root."))))]
    (map (fn [degree]
           (cond
            (coll? degree) (degrees degree scale root)
            (nil? degree) nil
            :default (let [interval (degree->interval degree scale)]
                       (if (nil? interval) nil
                           (+ root interval)))))
         degrees)))

(defn resolve-degrees
  "Either maps the degrees to integers if they're keywords using the map DEGREE
  or leaves them unmodified"
  [degrees]
  (map #(if (keyword? %) (DEGREE %) %) degrees))

(defn degrees
  [ds scale root]
  (let [ds (resolve-degrees)
        ]))

(defn scale
  ([root scale-name] (scale root scale-name (range 1 8) 4))
  ([root scale-name degrees] (scale root scale-name degrees 4))
  ([root scale-name degrees octave]
     (let [root (resolve-note root)
           degrees (resolve-degrees degrees)
           scale (resolve-scale scale-name)
           base (octave-note octave root)]
       (map #(+ % base) scale))))

(def CHORD
  (let [major  #{0 4 7}
        minor  #{0 3 7}
        major7 #{0 4 7 11}
        dom7   #{0 4 7 10}
        minor7 #{0 3 7 10}
        aug    #{0 4 8}
        dim    #{0 3 6}
        dim7   #{0 3 6 9}]
    {:major      major
     :M          major
     :minor      minor
