            :A  9  :a  9
            :A# 10 :a# 10 :Bb 10 :bb 10
            :B  11 :b  11})
+
+
+(defn resolve-note
+  "Resolves note to MIDI number format. Resolves upper and lower-case keywords
+  and strings in MIDI note format. If given an integer or nil, returns them
+  unmodified. All other inputs will raise an exception.
+
+  Usage examples:
+
+  (resolve-note \"C4\")  ;=> 60
+  (resolve-note \"C#4\") ;=> 61
+  (resolve-note \"eb2\") ;=> 39
+  (resolve-note :F#7)    ;=> 102
+  (resolve-note :db5)    ;=> 73
+  (resolve-note 60)      ;=> 60
+  (resolve-note nil)     ;=> nil"
+
+  [note]
+  (cond
+   (nil? note) nil
+   (integer? note) (if (>= note 0)
+                    note
+                    (throw (Exception.
+                            (str "Unable to resolve note: " note ". Value is out of range. Lowest value is 0"))))
+   (keyword? note) (resolve-note (name note))
+   (string? note) (let [midi-note-re #"\A([a-gA-G][#b]?)([-0-9]+\Z)"
+                        separated (re-find midi-note-re note)
+                        _ (when (nil? separated)
+                            (throw (Exception.
+                                    (str "Unable to resolve note: " note ". Does not appear to be in MIDI format i.e. C#4"))))
+
+                        [_ pitch-class octave] separated
+                        octave (Integer. octave)
+                        _ (when (< octave -1)
+                            (throw (Exception.
+                                    (str "Unable to resolve note: " note ". Octave is out of range. Lowest octave value is -1"))))
+                        _ (println "pc: " pitch-class)
+                        interval (NOTE (keyword pitch-class))
+                        _                        (println "int" interval)
+
+                        _ (when (nil? interval)
+                            (throw (Exception.
+                                    (str "Unable to resolve note: " note ". Not a valid pitch class such as C or Db"))))]
+                    (+ interval 12 (* 12 octave)))
+   :else (throw (Exception. (str "Unable to resolve note: " note ". Wasn't a recognised format (either an integer, keyword, string or nil)")))))
 
 ;; * Each note in a scale acts as either a generator or a collector of other notes,
 ;; depending on their relations in time within a sequence.

  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 :ionian 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})

(defn degree->interval
  "Converts the degree of a scale given as a roman numeral keyword or integer
   and converts it to the number of intervals (semitones) from the tonic of the
   specified scale."
  [scale degree & [shift]]
  (let [shift (or shift 0)]
    (cond 
      (.endsWith (name degree) ".") 
      (degree->interval scale (keyword (chop (name degree))) (- shift 12))

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

      :default
      (+ shift
         (if-let [deg (DEGREE degree)]
           (nth-interval scale (dec deg))
           (nth-interval scale (dec degree)))))))

(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

     :dim7       dim7
     :i7         dim7}))

(defn resolve-chord
  "Either looks the chord up in the map of CHORDs if it's a keyword or simply
  returns it unnmodified. Allows users to specify a chord either with a set
  such as #{0 4 7} or by keyword such as :major"
  [chord]
  (if (keyword? chord)
    (CHORD chord)
    chord))

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